Files
assetxContracts/doc/YT-Lending借贷系统操作流程图.md
2025-12-29 15:38:25 +08:00

171 KiB
Raw Blame History

YT Lending 借贷系统操作流程图

重要说明

本系统使用 USDC 作为基础借贷代币baseTokenYT 资产代币作为抵押品。USDC 价格通过 Chainlink 价格预言机实时获取YT 代币价格从其 Vault 合约的 ytPrice() 方法读取。

目录

  1. 存入 USDCSupply
  2. 提取 USDCWithdraw
  3. 存入抵押品SupplyCollateral
  4. 取出抵押品WithdrawCollateral
  5. 借款流程Borrow
  6. 清算流程Absorb
  7. 购买清算抵押品BuyCollateral
  8. 利息计提机制
  9. 储备金管理WithdrawReserves

1. 存入 USDCSupply

┌─────────────────────────────────────────────────────────────────────┐
│                         用户 (Alice)                                  │
│  持有: 10,000 USDC                                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 授权 USDC 给 Lending
                             │    USDC.approve(lending, 10000e6)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      USDC 授权检查                                    │
│  ✓ allowance[Alice][Lending] >= 10,000 USDC                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 调用 supply(10000e6)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.supply()                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  function supply(uint256 amount)                                      │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: 10,000 USDC (10000e6)                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  计算自上次计提以来的时间:                                            │
│  timeElapsed = block.timestamp - lastAccrualTime                      │
│                                                                       │
│  如果 timeElapsed > 0:                                                │
│  ① 计算当前利用率:                                                    │
│     totalSupply = totalSupplyBase × supplyIndex / 1e18               │
│     totalBorrow = totalBorrowBase × borrowIndex / 1e18               │
│     utilization = totalBorrow / totalSupply                           │
│                                                                       │
│  ② 根据利用率和拐点计算供应利率和借款利率(每秒):                   │
│     supplyRate = getSupplyRate(utilization, ...)                     │
│     borrowRate = getBorrowRate(utilization, ...)                     │
│                                                                       │
│  ③ 更新利息累计因子:                                                  │
│     supplyIndex += supplyIndex × supplyRate × timeElapsed / 1e18     │
│     borrowIndex += borrowIndex × borrowRate × timeElapsed / 1e18     │
│                                                                       │
│  ④ 更新上次计提时间:                                                  │
│     lastAccrualTime = block.timestamp                                 │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 转入 USDC
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(baseToken).transferFrom(                                      │
│      Alice,                // 用户地址                                │
│      address(this),        // Lending 地址                            │
│      10000e6               // 10,000 USDC                             │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Alice USDC 余额: 10,000 → 0                                       │
│  • Lending USDC 余额: +10,000                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 计算用户余额变化
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      余额计算                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  获取用户当前本金:                                                    │
│  oldPrincipal = userBasic[Alice].principal  // 假设为 0新用户     │
│                                                                       │
│  计算旧余额(含利息):                                                │
│  index = oldPrincipal >= 0 ? supplyIndex : borrowIndex                │
│        = supplyIndex  (因为是0属于存款)                             │
│  oldBalance = oldPrincipal × index / 1e18 = 0                        │
│                                                                       │
│  计算新余额:                                                          │
│  newBalance = oldBalance + 10000e6 = 10000e6                         │
│                                                                       │
│  确定新余额使用的索引:                                                │
│  newIndex = newBalance >= 0 ? supplyIndex : borrowIndex               │
│           = supplyIndex  (正数,是存款)                               │
│                                                                       │
│  转换为新本金:                                                        │
│  newPrincipal = (newBalance × 1e18) / newIndex                       │
│               = (10000e6 × 1e18) / supplyIndex                       │
│               = 10000e6  (假设 supplyIndex = 1e18)                   │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 计算状态变化量
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算 repayAmount 和 supplyAmount                 │
│  ─────────────────────────────────────────────────────────────────  │
│  调用: repayAndSupplyAmount(oldPrincipal=0, newPrincipal=10000e6)    │
│                                                                       │
│  判断逻辑:                                                            │
│  • newPrincipal (10000e6) > oldPrincipal (0) ✓                       │
│  • newPrincipal >= 0 ✓                                                │
│  • oldPrincipal >= 0 ✓                                                │
│  → 两个都是正数(增加存款)                                          │
│                                                                       │
│  结果:                                                                │
│  repayAmount = 0                                                      │
│  supplyAmount = newPrincipal - oldPrincipal = 10000e6                │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 更新全局状态
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新全局余额                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  totalBorrowBase -= repayAmount  (0)                                  │
│  totalSupplyBase += supplyAmount  (10000e6)                           │
│                                                                       │
│  更新前:                                                              │
│  • totalSupplyBase: 0                                                 │
│  • totalBorrowBase: 0                                                 │
│                                                                       │
│  更新后:                                                              │
│  • totalSupplyBase: 10000e6                                           │
│  • totalBorrowBase: 0                                                 │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 更新用户本金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新用户状态                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  userBasic[Alice].principal = newPrincipal = 10000e6                 │
│                                                                       │
│  用户状态:                                                            │
│  • principal: 0 → 10000e6 (正数 = 存款本金)                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 9. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit Supply(Alice, Alice, 10000e6)                                   │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 10. 存款完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         存款完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  Alice 最终状态:                                                     │
│  • USDC 余额: 0                                                       │
│  • Lending principal: 10000e6 (存款本金)                              │
│  • 实际余额 (含利息): principal × supplyIndex / 1e18                 │
│    = 10000e6  (刚存入,尚未计息)                                      │
│                                                                       │
│  协议状态:                                                           │
│  • totalSupplyBase: 10000e6                                           │
│  • totalBorrowBase: 0                                                 │
│  • 实际总供应: 10000e6 (含利息)                                       │
│  • 实际总借款: 0                                                      │
│  • 利用率: 0%                                                         │
│                                                                       │
│  收益说明:                                                           │
│  随着时间推移supplyIndex 会增长                                     │
│  Alice 的实际余额 = principal × supplyIndex / 1e18 会增加             │
│  这就是利息收益的体现                                                 │
└─────────────────────────────────────────────────────────────────────┘

2. 提取 USDCWithdraw

┌─────────────────────────────────────────────────────────────────────┐
│                         用户 (Alice)                                  │
│  当前状态:                                                            │
│  • principal: 10000e6                                                 │
│  • supplyIndex: 1.1e18 (经过一段时间,利息累积了 10%)                │
│  • 实际余额: 10000e6 × 1.1e18 / 1e18 = 11000e6 USDC                 │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 调用 withdraw(5000e6)
                             │    提取 5,000 USDC
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.withdraw()                                 │
│  ─────────────────────────────────────────────────────────────────  │
│  function withdraw(uint256 amount)                                    │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: 5,000 USDC (5000e6)                                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  (过程同 supply更新 supplyIndex 和 borrowIndex                  │
│  假设更新后 supplyIndex = 1.1e18 (已包含最新利息)                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 计算余额变化
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      余额计算                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  获取用户当前本金:                                                    │
│  oldPrincipal = userBasic[Alice].principal = 10000e6                 │
│                                                                       │
│  计算旧余额(含利息):                                                │
│  index = oldPrincipal >= 0 ? supplyIndex : borrowIndex                │
│        = supplyIndex  (正数,是存款)                                  │
│  oldBalance = oldPrincipal × index / 1e18                            │
│             = 10000e6 × 1.1e18 / 1e18 = 11000e6                      │
│                                                                       │
│  计算新余额(减去提取额):                                            │
│  newBalance = oldBalance - 5000e6 = 6000e6                           │
│                                                                       │
│  确定新余额使用的索引:                                                │
│  newIndex = newBalance >= 0 ? supplyIndex : borrowIndex               │
│           = supplyIndex  (正数,仍是存款)                             │
│                                                                       │
│  转换为新本金:                                                        │
│  newPrincipal = (newBalance × 1e18) / newIndex                       │
│               = (6000e6 × 1e18) / 1.1e18                             │
│               = 5454.54e6 (约)                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 计算状态变化量
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算 withdrawAmount 和 borrowAmount              │
│  ─────────────────────────────────────────────────────────────────  │
│  调用: withdrawAndBorrowAmount(                                       │
│      oldPrincipal=10000e6,                                            │
│      newPrincipal=5454.54e6                                           │
│  )                                                                    │
│                                                                       │
│  判断逻辑:                                                            │
│  • newPrincipal (5454.54e6) < oldPrincipal (10000e6) ✓               │
│  • newPrincipal >= 0 ✓                                                │
│  → 还是正数(提取存款)                                              │
│                                                                       │
│  结果:                                                                │
│  withdrawAmount = oldPrincipal - newPrincipal = 4545.46e6            │
│  borrowAmount = 0                                                     │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 更新全局状态
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新全局余额                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  totalSupplyBase -= withdrawAmount  (4545.46e6)                       │
│  totalBorrowBase += borrowAmount  (0)                                 │
│                                                                       │
│  更新后:                                                              │
│  • totalSupplyBase: 10000e6 → 5454.54e6                              │
│  • totalBorrowBase: 0 (不变)                                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 更新用户本金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新用户状态                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  userBasic[Alice].principal = newPrincipal = 5454.54e6               │
│                                                                       │
│  用户状态:                                                            │
│  • principal: 10000e6 → 5454.54e6                                    │
│  • 实际余额: 5454.54e6 × 1.1e18 / 1e18 = 6000e6 USDC                │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 转出 USDC
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(baseToken).safeTransfer(                                      │
│      Alice,                // 用户地址                                │
│      5000e6                // 5,000 USDC                              │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Lending USDC 余额: -5000e6                                        │
│  • Alice USDC 余额: +5000e6                                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit Withdraw(Alice, Alice, 5000e6)                                  │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 9. 提取完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         提取完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  Alice 最终状态:                                                     │
│  • USDC 余额: +5000e6                                                 │
│  • Lending principal: 5454.54e6                                       │
│  • 实际余额 (含利息): 6000e6 USDC                                    │
│                                                                       │
│  收益说明:                                                           │
│  • 初始存入: 10000 USDC                                               │
│  • 利息收益: 1000 USDC (10%)                                          │
│  • 提取: 5000 USDC                                                    │
│  • 剩余: 6000 USDC (包含利息)                                         │
│                                                                       │
│  注意:                                                               │
│  如果提取金额大于实际余额,会自动转为借款                             │
│  例如:提取 12000 USDC超过 11000 USDC 余额                         │
│  → principal 会变成负数(-1000表示借款 1000 USDC                │
└─────────────────────────────────────────────────────────────────────┘

3. 存入抵押品SupplyCollateral

┌─────────────────────────────────────────────────────────────────────┐
│                         用户 (Bob)                                    │
│  持有: 1000 YT-A 代币                                                 │
│  YT-A 价格: $2000 (2000e30)                                           │
│  价值: $2,000,000                                                     │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 授权 YT-A 给 Lending
                             │    YTA.approve(lending, 1000e18)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      YT-A 授权检查                                    │
│  ✓ allowance[Bob][Lending] >= 1000 YT-A                              │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 调用 supplyCollateral(YTA, 1000e18)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.supplyCollateral()                         │
│  ─────────────────────────────────────────────────────────────────  │
│  function supplyCollateral(address asset, uint256 amount)             │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: asset=YTA, amount=1000e18                                │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 验证资产配置
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      资产配置检查                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  AssetConfig memory config = assetConfigs[YTA]                        │
│                                                                       │
│  检查:                                                                │
│  • config.asset != address(0) ✓  (资产已配置)                        │
│                                                                       │
│  配置示例:                                                            │
│  • asset: YTA                                                         │
│  • decimals: 18                                                       │
│  • borrowCollateralFactor: 0.7e18 (70% LTV)                          │
│  • liquidateCollateralFactor: 0.75e18 (75% 清算阈值)                 │
│  • liquidationFactor: 0.9e18 (清算时价值打 90 折)                    │
│  • supplyCap: 10000e18 (最多可存入 10,000 YT-A)                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 检查供应上限
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      供应上限检查                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  uint256 newTotal = userCollateral[Bob][YTA] + 1000e18               │
│                   = 0 + 1000e18 = 1000e18                             │
│                                                                       │
│  if (newTotal > config.supplyCap) revert SupplyCapExceeded()         │
│  • 1000e18 <= 10000e18  ✓ 通过                                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 转入 YT-A 代币
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(asset).transferFrom(                                          │
│      Bob,                  // 用户地址                                │
│      address(this),        // Lending 地址                            │
│      1000e18               // 1000 YT-A                               │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Bob YT-A 余额: 1000 → 0                                           │
│  • Lending YT-A 余额: +1000                                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 更新用户抵押品余额
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新抵押品记录                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  userCollateral[Bob][YTA] += 1000e18                                 │
│                                                                       │
│  更新后:                                                              │
│  • userCollateral[Bob][YTA]: 0 → 1000e18                             │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit SupplyCollateral(Bob, Bob, YTA, 1000e18)                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 存入完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         抵押品存入完成                                │
│  ─────────────────────────────────────────────────────────────────  │
│  Bob 最终状态:                                                       │
│  • YT-A 余额: 0                                                       │
│  • 抵押品: 1000 YT-A (在 Lending 中)                                  │
│  • 抵押品价值: $2,000,000                                             │
│                                                                       │
│  借款能力计算:                                                       │
│  • 抵押品价值: 1000 × $2000 = $2,000,000                             │
│  • borrowCollateralFactor: 70%                                        │
│  • 最大借款额: $2,000,000 × 70% = $1,400,000                         │
│  • 以 USDC 计算 (假设 USDC = $1):                                     │
│    最大借款: 1,400,000 USDC                                           │
│                                                                       │
│  清算阈值:                                                           │
│  • liquidateCollateralFactor: 75%                                     │
│  • 清算阈值: $2,000,000 × 75% = $1,500,000                           │
│  • 当债务超过 $1,500,000 时会被清算                                  │
│                                                                       │
│  注意:                                                               │
│  • 存入抵押品不计提利息(不影响债务)                                │
│  • 抵押品价值根据 LendingPriceFeed.getPrice() 实时获取                │
│  • YT-A 价格从 YTAssetVault.ytPrice() 获取                            │
│  • USDC 价格从 Chainlink 获取                                         │
└─────────────────────────────────────────────────────────────────────┘

4. 取出抵押品WithdrawCollateral

┌─────────────────────────────────────────────────────────────────────┐
│                         用户 (Bob)                                    │
│  当前状态:                                                            │
│  • 抵押品: 1000 YT-A                                                  │
│  • 借款: 0 USDC (未借款)                                              │
│  计划: 取出 500 YT-A                                                  │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 调用 withdrawCollateral(YTA, 500e18)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.withdrawCollateral()                       │
│  ─────────────────────────────────────────────────────────────────  │
│  function withdrawCollateral(address asset, uint256 amount)           │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: asset=YTA, amount=500e18                                 │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  (过程同前,更新 supplyIndex 和 borrowIndex                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 检查余额
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      余额检查                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  if (userCollateral[Bob][YTA] < 500e18) revert InsufficientBalance()│
│  • 1000e18 >= 500e18  ✓ 通过                                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 更新抵押品余额
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新抵押品记录                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  userCollateral[Bob][YTA] -= 500e18                                  │
│                                                                       │
│  更新后:                                                              │
│  • userCollateral[Bob][YTA]: 1000e18 → 500e18                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 检查偿付能力(如果有债务)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      偿付能力检查                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  int104 principal = userBasic[Bob].principal  // 假设为 0            │
│                                                                       │
│  if (principal < 0) {                                                 │
│      if (!_isSolvent(Bob)) revert InsufficientCollateral()          │
│  }                                                                    │
│                                                                       │
│  本例中 principal = 0无债务跳过检查 ✓                            │
│                                                                       │
│  偿付能力检查逻辑 (_isSolvent):                                       │
│  ① 计算实际债务 (含利息):                                            │
│     balance = principal × borrowIndex / 1e18                          │
│     debt = -balance  (转为正数)                                       │
│                                                                       │
│  ② 计算债务价值 (USD):                                                │
│     basePrice = LendingPriceFeed.getPrice(USDC)                      │
│     debtValue = (debt × basePrice) / 10^usdcDecimals                 │
│                                                                       │
│  ③ 计算抵押品借款能力:                                                │
│     borrowCapacity = _getCollateralValue(account)                    │
│     • 遍历所有抵押品资产                                              │
│     • 计算每个资产的价值 (USD)                                        │
│     • 乘以 borrowCollateralFactor                                     │
│     • 汇总所有抵押品的借款能力                                        │
│                                                                       │
│  ④ 比较:                                                              │
│     return borrowCapacity >= debtValue                                │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 转出 YT-A 代币
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(asset).safeTransfer(                                          │
│      Bob,                  // 用户地址                                │
│      500e18                // 500 YT-A                                │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Lending YT-A 余额: -500e18                                        │
│  • Bob YT-A 余额: +500e18                                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit WithdrawCollateral(Bob, Bob, YTA, 500e18)                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 取出完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         抵押品取出完成                                │
│  ─────────────────────────────────────────────────────────────────  │
│  Bob 最终状态:                                                       │
│  • YT-A 余额: +500e18                                                 │
│  • 抵押品: 500 YT-A (在 Lending 中)                                   │
│  • 剩余抵押品价值: $1,000,000                                         │
│                                                                       │
│  借款能力变化:                                                       │
│  • 之前: $2,000,000 × 70% = $1,400,000                               │
│  • 现在: $1,000,000 × 70% = $700,000                                 │
│                                                                       │
│  注意:                                                               │
│  如果 Bob 有借款,取出抵押品后必须确保:                               │
│  借款能力 (borrowCapacity) >= 债务价值 (debtValue)                   │
│  否则交易会 revert                                                    │
└─────────────────────────────────────────────────────────────────────┘

5. 借款流程Withdraw如果余额不足会自动借款

┌─────────────────────────────────────────────────────────────────────┐
│                         用户 (Bob)                                    │
│  当前状态:                                                            │
│  • 抵押品: 1000 YT-A (价值 $2,000,000)                                │
│  • principal: 0 (无存款/借款)                                         │
│  • 借款能力: $2,000,000 × 70% = $1,400,000 USDC                      │
│  计划: 借款 1,000,000 USDC                                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 调用 withdraw(1000000e6)进行借款
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.withdraw()                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  function withdraw(uint256 amount)                                      │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: 1,000,000 USDC (1000000e6)                               │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  更新 supplyIndex 和 borrowIndex 到最新状态                           │
│  假设: borrowIndex = 1e18 (初始状态)                                  │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 计算余额变化
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      余额计算                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  获取用户当前本金:                                                    │
│  oldPrincipal = userBasic[Bob].principal = 0                         │
│                                                                       │
│  计算旧余额(含利息):                                                │
│  index = oldPrincipal >= 0 ? supplyIndex : borrowIndex                │
│        = supplyIndex  (0 视为存款)                                    │
│  oldBalance = 0 × supplyIndex / 1e18 = 0                             │
│                                                                       │
│  计算新余额(减去借款额):                                            │
│  newBalance = oldBalance - 1000000e6 = -1000000e6                    │
│                                                                       │
│  检查最小借款额:                                                      │
│  if (newBalance < 0 && -newBalance < baseBorrowMin)                  │
│      revert BorrowTooSmall()                                          │
│  • baseBorrowMin = 100e6  (最小借款 100 USDC)                        │
│  • 1000000e6 >= 100e6  ✓ 通过                                        │
│                                                                       │
│  确定新余额使用的索引:                                                │
│  newIndex = newBalance >= 0 ? supplyIndex : borrowIndex               │
│           = borrowIndex  (负数,是借款)                               │
│                                                                       │
│  转换为新本金:                                                        │
│  newPrincipal = (newBalance × 1e18) / newIndex                       │
│               = (-1000000e6 × 1e18) / 1e18                           │
│               = -1000000e6                                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 计算状态变化量
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算 withdrawAmount 和 borrowAmount              │
│  ─────────────────────────────────────────────────────────────────  │
│  调用: withdrawAndBorrowAmount(                                       │
│      oldPrincipal=0,                                                  │
│      newPrincipal=-1000000e6                                          │
│  )                                                                    │
│                                                                       │
│  判断逻辑:                                                            │
│  • newPrincipal (-1000000e6) < oldPrincipal (0) ✓                    │
│  • newPrincipal < 0 ✓                                                 │
│  • oldPrincipal >= 0 ✓                                                │
│  → 从正数或0变负数提取所有存款并借款                        │
│                                                                       │
│  结果:                                                                │
│  withdrawAmount = oldPrincipal = 0                                    │
│  borrowAmount = -newPrincipal = 1000000e6                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 更新全局状态
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新全局余额                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  totalSupplyBase -= withdrawAmount  (0)                               │
│  totalBorrowBase += borrowAmount  (1000000e6)                         │
│                                                                       │
│  更新后:                                                              │
│  • totalSupplyBase: 不变                                              │
│  • totalBorrowBase: 0 → 1000000e6                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 更新用户本金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新用户状态                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  userBasic[Bob].principal = newPrincipal = -1000000e6                │
│                                                                       │
│  用户状态:                                                            │
│  • principal: 0 → -1000000e6 (负数 = 借款本金)                       │
│  • 实际债务: -1000000e6 × borrowIndex / 1e18 = -1000000e6           │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 检查抵押品是否充足
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      偿付能力检查 (_isSolvent)                        │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 计算债务价值 (USD):                                                │
│     debt = 1000000e6                                                  │
│     basePrice = LendingPriceFeed.getPrice(USDC)                      │
│              = 1e30  (假设 USDC = $1.00)                             │
│     baseDecimals = 6                                                  │
│     debtValue = (1000000e6 × 1e30) / 10^6                            │
│               = 1000000e30  ($1,000,000 USD)                         │
│                                                                       │
│  ② 计算抵押品借款能力 (_getCollateralValue):                         │
│     遍历所有抵押品:                                                   │
│     • YT-A: 1000e18                                                   │
│       - price = LendingPriceFeed.getPrice(YTA)                       │
│               = IYTAssetVault(YTA).ytPrice()                         │
│               = 2000e30  ($2000)                                      │
│       - decimals = 18                                                 │
│       - value = (1000e18 × 2000e30) / 10^18                          │
│               = 2000000e30  ($2,000,000 USD)                         │
│       - borrowCollateralFactor = 0.7e18  (70%)                       │
│       - borrowCapacity = 2000000e30 × 0.7e18 / 1e18                  │
│                        = 1400000e30  ($1,400,000 USD)                │
│                                                                       │
│  ③ 比较:                                                              │
│     borrowCapacity (1400000e30) >= debtValue (1000000e30) ✓         │
│     → 抵押品充足,可以借款                                           │
│                                                                       │
│  如果不充足,会 revert InsufficientCollateral()                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 转出 USDC
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(baseToken).safeTransfer(                                      │
│      Bob,                  // 用户地址                                │
│      1000000e6             // 1,000,000 USDC                          │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Lending USDC 余额: -1000000e6                                     │
│  • Bob USDC 余额: +1000000e6                                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 9. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit Withdraw(Bob, Bob, 1000000e6)                                   │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 10. 借款完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         借款完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  Bob 最终状态:                                                       │
│  • USDC 余额: +1,000,000 USDC                                         │
│  • Lending principal: -1000000e6 (负数表示借款)                      │
│  • 实际债务: -1000000e6 × borrowIndex / 1e18                         │
│  • 抵押品: 1000 YT-A                                                  │
│                                                                       │
│  借款状态:                                                           │
│  • 借款金额: 1,000,000 USDC                                           │
│  • 借款价值: $1,000,000                                               │
│  • 抵押品价值: $2,000,000                                             │
│  • LTV (Loan-to-Value): 50%                                           │
│  • 借款能力使用率: 1,000,000 / 1,400,000 = 71.4%                     │
│  • 距离清算阈值: $1,500,000 - $1,000,000 = $500,000                  │
│                                                                       │
│  利息累积:                                                           │
│  随着时间推移borrowIndex 会增长                                     │
│  Bob 的实际债务 = principal × borrowIndex / 1e18 会增加              │
│  这就是借款利息的体现                                                 │
│                                                                       │
│  重要风险提示:                                                       │
│  ⚠️ 如果 YT-A 价格下跌,抵押品价值减少                                │
│  ⚠️ 如果债务增长(利息累积),债务价值增加                            │
│  ⚠️ 当债务价值 > 清算阈值($1,500,000会被清算                  │
└─────────────────────────────────────────────────────────────────────┘

6. 清算流程Absorb

┌─────────────────────────────────────────────────────────────────────┐
│                         场景设定                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  Bob 的状态(价格变化后):                                           │
│  • 抵押品: 1000 YT-A                                                  │
│  • YT-A 价格: $2000 → $1400 (下跌 30%)                               │
│  • 抵押品价值: $1,400,000                                             │
│  • 借款本金: -1000000e6                                               │
│  • borrowIndex: 1.1e18 (利息累积 10%)                                 │
│  • 实际债务: 1000000e6 × 1.1 = 1,100,000 USDC                        │
│  • 债务价值: $1,100,000                                               │
│                                                                       │
│  清算判断:                                                           │
│  • liquidateCollateralFactor: 75%                                     │
│  • 清算阈值: $1,400,000 × 75% = $1,050,000                           │
│  • 债务价值 ($1,100,000) > 清算阈值 ($1,050,000) ✓                  │
│  → 可以被清算                                                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 清算人调用 absorb(Bob)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.absorb()                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  function absorb(address borrower)                                    │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
│      • 参数: borrower=Bob                                             │
│      • 调用者: 任何人都可以(清算人/机器人)                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  更新到最新状态,确保债务和利息都是最新的                             │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 检查是否可清算
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      清算资格检查 (isLiquidatable)                    │
│  ─────────────────────────────────────────────────────────────────  │
│  if (!isLiquidatable(Bob)) revert NotLiquidatable()                  │
│                                                                       │
│  isLiquidatable 逻辑:                                                 │
│  ① 检查是否有债务:                                                    │
│     principal = -1000000e6 < 0  ✓                                    │
│                                                                       │
│  ② 计算实际债务 (含利息):                                            │
│     balance = principal × borrowIndex / 1e18                          │
│             = -1000000e6 × 1.1e18 / 1e18 = -1100000e6                │
│     debt = -balance = 1100000e6                                       │
│                                                                       │
│  ③ 计算债务价值 (USD):                                                │
│     basePrice = LendingPriceFeed.getPrice(USDC) = 1e30               │
│     debtValue = (1100000e6 × 1e30) / 10^6 = 1100000e30               │
│                                                                       │
│  ④ 计算抵押品清算阈值价值:                                            │
│     YT-A: 1000e18                                                     │
│     price = 1400e30  ($1400)                                          │
│     value = (1000e18 × 1400e30) / 10^18 = 1400000e30                 │
│     liquidateCollateralFactor = 0.75e18  (75%)                       │
│     collateralValue = 1400000e30 × 0.75e18 / 1e18                    │
│                     = 1050000e30  ($1,050,000)                        │
│                                                                       │
│  ⑤ 比较:                                                              │
│     debtValue (1100000e30) > collateralValue (1050000e30) ✓         │
│     → 可以清算                                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 计算抵押品总价值
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算抵押品价值(清算折扣)                       │
│  ─────────────────────────────────────────────────────────────────  │
│  遍历所有抵押品资产:                                                  │
│                                                                       │
│  YT-A:                                                                │
│  • collateralAmount = 1000e18                                         │
│  • assetPrice = 1400e30                                               │
│  • liquidationFactor = 0.9e18  (清算时价值打 90 折)                  │
│  • decimals = 18                                                      │
│                                                                       │
│  ① 计算原始价值 (USD, 用于事件):                                      │
│     collateralValueUSD = (1000e18 × 1400e30) / 10^18                 │
│                        = 1400000e30                                   │
│                                                                       │
│  ② 计算折扣后价值:                                                    │
│     discountedValue = (1000e18 × 1400e30 × 0.9e18) / (10^18 × 1e18) │
│                     = 1260000e30  ($1,260,000)                        │
│                                                                       │
│  ③ 将抵押品转移到清算库存:                                            │
│     userCollateral[Bob][YTA] = 0                                      │
│     collateralReserves[YTA] += 1000e18                                │
│                                                                       │
│  ④ 触发抵押品吸收事件:                                                │
│     emit AbsorbCollateral(                                            │
│         msg.sender,    // 清算人                                      │
│         Bob,           // 借款人                                      │
│         YTA,           // 资产                                        │
│         1000e18,       // 数量                                        │
│         1400000e30     // 原始价值 USD                                │
│     )                                                                 │
│                                                                       │
│  totalCollateralValue = 1260000e30                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 将抵押品价值转换为 baseToken
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      转换为 USDC 数量                                 │
│  ─────────────────────────────────────────────────────────────────  │
│  basePrice = 1e30  (USDC = $1.00)                                    │
│  baseScale = 10^6  (USDC 6位小数)                                    │
│                                                                       │
│  collateralInBase = (totalCollateralValue × baseScale) / basePrice   │
│                   = (1260000e30 × 10^6) / 1e30                        │
│                   = 1260000e6  (1,260,000 USDC)                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 计算新余额
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算清算后余额                                   │
│  ─────────────────────────────────────────────────────────────────  │
│  oldBalance = -1100000e6  (债务)                                      │
│  collateralInBase = 1260000e6  (抵押品价值)                           │
│                                                                       │
│  newBalance = oldBalance + collateralInBase                           │
│             = -1100000e6 + 1260000e6                                  │
│             = 160000e6  (正数!抵押品价值 > 债务)                    │
│                                                                       │
│  ⚠️ 注意:如果 newBalance < 0说明坏账会强制归零                  │
│  if (newBalance < 0) {                                                │
│      newBalance = 0  // 坏账由协议储备金承担                         │
│  }                                                                    │
│                                                                       │
│  本例中 newBalance > 0无坏账                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 转换为新本金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算新本金                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  newPrincipal = (newBalance × 1e18) / supplyIndex                    │
│               = (160000e6 × 1e18) / 1e18                             │
│               = 160000e6                                              │
│                                                                       │
│  余额从负数变为正数:                                                 │
│  • 旧本金: -1000000e6 (借款)                                          │
│  • 新本金: 160000e6 (存款!)                                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 更新用户本金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新用户状态                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  userBasic[Bob].principal = newPrincipal = 160000e6                  │
│                                                                       │
│  用户状态变化:                                                        │
│  • principal: -1000000e6 → 160000e6                                  │
│  • 从借款人变为存款人!                                              │
│  • 抵押品: 1000 YT-A → 0 (全部被清算)                                │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 9. 计算并更新全局状态
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新全局余额                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  调用: repayAndSupplyAmount(                                          │
│      oldPrincipal=-1000000e6,                                         │
│      newPrincipal=160000e6                                            │
│  )                                                                    │
│                                                                       │
│  判断逻辑:                                                            │
│  • newPrincipal (160000e6) > oldPrincipal (-1000000e6) ✓            │
│  • newPrincipal > 0 ✓                                                 │
│  • oldPrincipal < 0 ✓                                                 │
│  → 从负数变正数(偿还所有债务并存款)                                │
│                                                                       │
│  结果:                                                                │
│  repayAmount = -oldPrincipal = 1000000e6                             │
│  supplyAmount = newPrincipal = 160000e6                              │
│                                                                       │
│  更新:                                                                │
│  totalSupplyBase += supplyAmount  (160000e6)                          │
│  totalBorrowBase -= repayAmount  (1000000e6)                          │
│                                                                       │
│  ⚠️ 注意:储备金通过减少 totalBorrowBase 和增加 totalSupplyBase      │
│           来承担坏账(如果有)                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 10. 计算坏账(如果有)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      坏账计算                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  if (collateralInBase < -oldBalance) {                               │
│      // 抵押品不足以覆盖债务,差额由协议储备金承担                   │
│      basePaidOut = -oldBalance - collateralInBase                    │
│  } else {                                                             │
│      // 抵押品足够,无坏账                                            │
│      basePaidOut = 0                                                  │
│  }                                                                    │
│                                                                       │
│  本例中:                                                              │
│  • -oldBalance = 1100000e6                                            │
│  • collateralInBase = 1260000e6                                       │
│  • 1260000e6 >= 1100000e6  ✓ 无坏账                                  │
│  • basePaidOut = 0                                                    │
│                                                                       │
│  坏账价值:                                                            │
│  valueOfBasePaidOut = (basePaidOut × basePrice) / baseScale = 0      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 11. 触发债务吸收事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit AbsorbDebt(                                                     │
│      msg.sender,       // 清算人                                      │
│      Bob,              // 借款人                                      │
│      0,                // basePaidOut (坏账)                          │
│      0                 // valueOfBasePaidOut (坏账价值)               │
│  )                                                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 12. 清算完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         清算完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  Bob 最终状态:                                                       │
│  • principal: 160000e6 (正数 = 存款)                                  │
│  • 实际余额: 160000 USDC                                              │
│  • 抵押品: 0 (全部被清算)                                             │
│  • 债务: 0 (已清偿)                                                   │
│                                                                       │
│  协议状态:                                                           │
│  • collateralReserves[YTA]: +1000e18                                  │
│  • 清算的抵押品进入协议库存,可以被购买                               │
│                                                                       │
│  清算流程总结:                                                       │
│  ① 没收所有抵押品 (1000 YT-A)                                        │
│  ② 按清算折扣 (90%) 计算抵押品价值 ($1,260,000)                      │
│  ③ 用于偿还债务 ($1,100,000)                                         │
│  ④ 剩余价值 ($160,000) 转为用户存款                                  │
│  ⑤ 抵押品进入协议库存,等待被购买                                    │
│                                                                       │
│  清算收益:                                                           │
│  • Bob 损失: 1000 YT-A (价值 $1,400,000)                             │
│  • Bob 保留: 160,000 USDC (价值 $160,000)                            │
│  • 净损失: $1,400,000 - $160,000 = $1,240,000                        │
│                                                                       │
│  清算人收益:                                                         │
│  • 清算人调用 absorb() 不直接获得收益                                │
│  • 但可以稍后通过 buyCollateral() 折价购买抵押品获利                 │
│                                                                       │
│  坏账场景示例:                                                       │
│  如果 YT-A 价格跌到 $1000:                                            │
│  • 抵押品价值: 1000 × $1000 × 90% = $900,000                         │
│  • 债务价值: $1,100,000                                               │
│  • 差额: $200,000 (坏账,由协议储备金承担)                           │
│  • Bob principal: 0 (债务被清零)                                      │
│  • basePaidOut: 200000 USDC                                           │
└─────────────────────────────────────────────────────────────────────┘

7. 购买清算抵押品BuyCollateral

┌─────────────────────────────────────────────────────────────────────┐
│                         清算人 (Liquidator)                           │
│  当前状态:                                                            │
│  • 持有: 足够的 USDC                                                  │
│  • 目标: 购买清算后的 YT-A 抵押品                                     │
│                                                                       │
│  协议状态:                                                            │
│  • collateralReserves[YTA]: 1000e18 (可购买)                          │
│  • 协议储备金不足 (< targetReserves)                                  │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 查询可购买数量
                             │    quoteCollateral(YTA, 100000e6)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.quoteCollateral()                          │
│  ─────────────────────────────────────────────────────────────────  │
│  function quoteCollateral(address asset, uint256 baseAmount)         │
│                                                                       │
│  计算逻辑(支付 100,000 USDC 可购买多少 YT-A:                      │
│                                                                       │
│  ① 获取价格:                                                          │
│     assetPrice = LendingPriceFeed.getPrice(YTA) = 1400e30            │
│     basePrice = LendingPriceFeed.getPrice(USDC) = 1e30               │
│                                                                       │
│  ② 获取配置:                                                          │
│     liquidationFactor = 0.9e18  (90%)                                 │
│     storeFrontPriceFactor = 0.95e18  (额外 5% 折扣)                  │
│                                                                       │
│  ③ 计算折扣因子:                                                      │
│     discountFactor = storeFrontPriceFactor × (1 - liquidationFactor) │
│                    = 0.95e18 × (1e18 - 0.9e18) / 1e18                │
│                    = 0.95e18 × 0.1e18 / 1e18                          │
│                    = 0.095e18  (9.5%)                                 │
│                                                                       │
│  ④ 计算有效资产价格:                                                  │
│     effectiveAssetPrice = assetPrice × (1 - discountFactor)          │
│                         = 1400e30 × (1e18 - 0.095e18) / 1e18         │
│                         = 1400e30 × 0.905e18 / 1e18                   │
│                         = 1267e30  ($1267)                            │
│                                                                       │
│  ⑤ 计算可购买数量:                                                    │
│     baseScale = 10^6  (USDC)                                          │
│     assetScale = 10^18  (YT-A)                                        │
│                                                                       │
│     由于精度相同简化:                                                 │
│     result = (baseAmount × basePrice) / effectiveAssetPrice          │
│            = (100000e6 × 1e30) / 1267e30                             │
│            = 78.93e6 × 10^12                                          │
│            = 78.93e18  (78.93 YT-A)                                   │
│                                                                       │
│  返回: 78.93e18 YT-A                                                  │
└─────────────────────────────────────────────────────────────────────┘
                             │
                             │ 2. 调用 buyCollateral()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.buyCollateral()                            │
│  ─────────────────────────────────────────────────────────────────  │
│  function buyCollateral(                                              │
│      address asset,        // YTA                                     │
│      uint256 minAmount,    // 75e18 (最少要买 75 YT-A滑点保护)     │
│      uint256 baseAmount,   // 100000e6 (支付 100,000 USDC)           │
│      address recipient     // Liquidator (接收地址)                   │
│  )                                                                    │
│      • 非重入保护: nonReentrant                                       │
│      • 暂停检查: whenNotPaused                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 检查库存
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      库存检查                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  if (collateralReserves[YTA] == 0) revert InsufficientBalance()      │
│  • collateralReserves[YTA] = 1000e18  ✓ 有库存                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 检查储备金状态
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      储备金检查                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  int256 currentReserves = getReserves()                               │
│                                                                       │
│  getReserves() 计算:                                                  │
│  ① 计算最新索引 (含未计提的利息):                                    │
│     (newSupplyIndex, newBorrowIndex) = accruedInterestIndices(...)   │
│                                                                       │
│  ② 计算实际总供应和总借款:                                            │
│     balance = IERC20(USDC).balanceOf(address(this))                  │
│     totalSupply = totalSupplyBase × newSupplyIndex / 1e18            │
│     totalBorrow = totalBorrowBase × newBorrowIndex / 1e18            │
│                                                                       │
│  ③ 计算储备金:                                                        │
│     reserves = balance - totalSupply + totalBorrow                    │
│                                                                       │
│  假设 reserves = 400000e6 (< targetReserves = 5000000e6)             │
│                                                                       │
│  if (reserves >= 0 && reserves >= targetReserves) {                  │
│      revert NotForSale()  // 储备金充足,无需出售                    │
│  }                                                                    │
│  • 400000e6 < 5000000e6  ✓ 储备金不足,可以出售                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 计算可购买数量
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      计算购买数量                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  collateralAmount = quoteCollateral(YTA, 100000e6) = 78.93e18       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 验证数量
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      数量验证                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 滑点保护:                                                          │
│     if (collateralAmount < minAmount) revert InsufficientBalance()   │
│     • 78.93e18 >= 75e18  ✓ 通过                                      │
│                                                                       │
│  ② 库存检查:                                                          │
│     if (collateralAmount > collateralReserves[YTA])                  │
│         revert InsufficientBalance()                                  │
│     • 78.93e18 <= 1000e18  ✓ 通过                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 收取支付
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      收取 USDC                                        │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(baseToken).transferFrom(                                      │
│      msg.sender,           // 清算人                                  │
│      address(this),        // Lending 地址                            │
│      100000e6              // 100,000 USDC                            │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • 清算人 USDC 余额: -100,000                                        │
│  • Lending USDC 余额: +100,000                                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 抵押品出库
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新库存                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  collateralReserves[YTA] -= collateralAmount                          │
│                                                                       │
│  更新:                                                                │
│  • collateralReserves[YTA]: 1000e18 → 921.07e18                      │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 9. 转出抵押品
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      转账抵押品                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(asset).safeTransfer(                                          │
│      recipient,            // Liquidator                              │
│      78.93e18              // 78.93 YT-A                              │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Lending YT-A 余额: -78.93                                         │
│  • 清算人 YT-A 余额: +78.93                                          │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 10. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit BuyCollateral(                                                  │
│      msg.sender,           // 清算人                                  │
│      YTA,                  // 资产                                    │
│      100000e6,             // 支付的 USDC                             │
│      78.93e18              // 购买的 YT-A                             │
│  )                                                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 11. 购买完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         购买完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  清算人收益分析:                                                     │
│  • 支付: 100,000 USDC                                                 │
│  • 获得: 78.93 YT-A                                                   │
│  • 市场价: 78.93 × $1400 = $110,502                                  │
│  • 购买价: $100,000                                                   │
│  • 折扣: 9.5% (storeFrontPriceFactor)                                │
│  • 利润: $10,502 (10.5%)                                              │
│                                                                       │
│  协议收益:                                                           │
│  • 收到 100,000 USDC增加储备金                                     │
│  • 储备金: 400,000 → 500,000 USDC                                    │
│  • 距离目标: 5,000,000 - 500,000 = 4,500,000 USDC                    │
│                                                                       │
│  折扣机制说明:                                                       │
│  • liquidationFactor (90%): 清算时抵押品打 9 折                      │
│  • storeFrontPriceFactor (95%): 在 liquidationFactor 基础上额外打折 │
│  • 总折扣 = 1 - (1 - 0.1) × 0.95 = 1 - 0.905 = 9.5%                 │
│  • 这个折扣激励清算人购买抵押品,补充协议储备金                       │
│                                                                       │
│  限制条件:                                                           │
│  • 只有当协议储备金 < targetReserves 时才能购买                      │
│  • 储备金充足时会 revert NotForSale()                                │
│  • 这确保协议不会过度出售抵押品                                       │
│                                                                       │
│  注意:                                                               │
│  收入会自动体现在 getReserves() 中                                    │
│  因为 balance 增加了,而 totalSupply 和 totalBorrow 不变             │
└─────────────────────────────────────────────────────────────────────┘

8. 利息计提机制

┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提触发时机                                 │
│  ─────────────────────────────────────────────────────────────────  │
│  每次以下操作时都会自动调用 accrueInterest():                         │
│  • supply() - 存入 USDC                                               │
│  • withdraw() - 提取 USDC / 借款                                      │
│  • withdrawCollateral() - 取出抵押品                                  │
│  • absorb() - 清算                                                    │
│  • buyCollateral() - 购买清算抵押品                                   │
│                                                                       │
│  作用:                                                               │
│  确保所有操作使用最新的利息累计因子,实现公平的利息分配               │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 检查是否需要计提
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      时间检查                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  timeElapsed = block.timestamp - lastAccrualTime                      │
│                                                                       │
│  if (timeElapsed == 0) {                                              │
│      return  // 同一区块内已计提过,直接返回                         │
│  }                                                                    │
│                                                                       │
│  例如:                                                               │
│  • lastAccrualTime: 1704067200 (2024-01-01 00:00:00)                 │
│  • block.timestamp: 1704153600 (2024-01-02 00:00:00)                 │
│  • timeElapsed: 86400 秒 (1 天)                                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计算当前利用率
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利用率计算                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 计算实际总供应和总借款(使用当前索引):                           │
│     totalSupply = totalSupplyBase × supplyIndex / 1e18               │
│     totalBorrow = totalBorrowBase × borrowIndex / 1e18               │
│                                                                       │
│  ② 计算利用率:                                                        │
│     utilization = totalBorrow / totalSupply                           │
│                 = (totalBorrow × 1e18) / totalSupply                  │
│                                                                       │
│  示例数据:                                                            │
│  • totalSupplyBase: 10000000e6 (1000万 USDC 本金)                    │
│  • supplyIndex: 1.05e18                                               │
│  • totalSupply: 10000000e6 × 1.05e18 / 1e18 = 10500000e6            │
│                                                                       │
│  • totalBorrowBase: 7000000e6 (700万 USDC 本金)                      │
│  • borrowIndex: 1.15e18                                               │
│  • totalBorrow: 7000000e6 × 1.15e18 / 1e18 = 8050000e6              │
│                                                                       │
│  • utilization = (8050000e6 × 1e18) / 10500000e6                     │
│               = 0.7666...e18  (约 76.67%)                             │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 计算供应利率(每秒)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      供应利率计算 (getSupplyRate)                     │
│  ─────────────────────────────────────────────────────────────────  │
│  利率模型(双斜率模型):                                              │
│                                                                       │
│  if (utilization <= supplyKink) {                                     │
│      // 拐点前:线性增长                                              │
│      rate = supplyPerSecondInterestRateBase +                         │
│             (utilization × supplyPerSecondInterestRateSlopeLow) / 1e18│
│  } else {                                                             │
│      // 拐点后:陡峭增长                                              │
│      excessUtil = utilization - supplyKink                            │
│      rate = supplyPerSecondInterestRateBase +                         │
│             supplyPerSecondInterestRateSlopeLow +                     │
│             (excessUtil × supplyPerSecondInterestRateSlopeHigh) / 1e18│
│  }                                                                    │
│                                                                       │
│  配置示例(年化利率转换为每秒利率):                                  │
│  • supplyKink: 0.8e18 (80%)                                           │
│  • supplyPerYearInterestRateBase: 0.02e18 (2% APY)                   │
│    → supplyPerSecondInterestRateBase: 634e9  (2%/31536000)           │
│  • supplyPerYearInterestRateSlopeLow: 0.1e18 (10% APY)               │
│    → supplyPerSecondInterestRateSlopeLow: 3170e9                      │
│  • supplyPerYearInterestRateSlopeHigh: 2e18 (200% APY)               │
│    → supplyPerSecondInterestRateSlopeHigh: 63419e9                    │
│                                                                       │
│  本例计算utilization = 76.67% < 80%:                              │
│  rate = 634e9 + (0.7667e18 × 3170e9) / 1e18                          │
│       = 634e9 + 2430e9                                                │
│       = 3064e9  (约 9.67% APY)                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 计算借款利率(每秒)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      借款利率计算 (getBorrowRate)                     │
│  ─────────────────────────────────────────────────────────────────  │
│  利率模型(双斜率模型,同供应利率):                                  │
│                                                                       │
│  配置示例:                                                            │
│  • borrowKink: 0.8e18 (80%)                                           │
│  • borrowPerYearInterestRateBase: 0.03e18 (3% APY)                   │
│    → borrowPerSecondInterestRateBase: 951e9                           │
│  • borrowPerYearInterestRateSlopeLow: 0.15e18 (15% APY)              │
│    → borrowPerSecondInterestRateSlopeLow: 4756e9                      │
│  • borrowPerYearInterestRateSlopeHigh: 3e18 (300% APY)               │
│    → borrowPerSecondInterestRateSlopeHigh: 95129e9                    │
│                                                                       │
│  本例计算utilization = 76.67% < 80%:                              │
│  rate = 951e9 + (0.7667e18 × 4756e9) / 1e18                          │
│       = 951e9 + 3646e9                                                │
│       = 4597e9  (约 14.5% APY)                                        │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 更新供应索引
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      供应索引更新                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  计算利息累积:                                                        │
│  interestAccrued = (supplyIndex × supplyRate × timeElapsed) / 1e18   │
│                  = (1.05e18 × 3064e9 × 86400) / 1e18                 │
│                  = 1.05e18 × 264729600e9 / 1e18                       │
│                  = 0.00027796608e18  (约 0.02780%)                    │
│                                                                       │
│  更新索引:                                                            │
│  newSupplyIndex = supplyIndex + interestAccrued                       │
│                 = 1.05e18 + 0.00027796608e18                          │
│                 = 1.05027796608e18                                    │
│                                                                       │
│  supplyIndex = newSupplyIndex                                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 更新借款索引
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      借款索引更新                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  计算利息累积:                                                        │
│  interestAccrued = (borrowIndex × borrowRate × timeElapsed) / 1e18   │
│                  = (1.15e18 × 4597e9 × 86400) / 1e18                 │
│                  = 1.15e18 × 397180800e9 / 1e18                       │
│                  = 0.00045675792e18  (约 0.04568%)                    │
│                                                                       │
│  更新索引:                                                            │
│  newBorrowIndex = borrowIndex + interestAccrued                       │
│                 = 1.15e18 + 0.00045675792e18                          │
│                 = 1.15045675792e18                                    │
│                                                                       │
│  borrowIndex = newBorrowIndex                                         │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 更新计提时间
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      更新时间戳                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  lastAccrualTime = block.timestamp                                    │
│  • 1704067200 → 1704153600                                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 8. 利息计提完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提效果                                     │
│  ─────────────────────────────────────────────────────────────────  │
│  用户视角Alice - 存款人):                                          │
│  • 存款本金: 10000e6 (不变)                                           │
│  • 旧余额: 10000e6 × 1.05e18 / 1e18 = 10500e6                        │
│  • 新余额: 10000e6 × 1.05027796608e18 / 1e18 = 10502.7796608e6      │
│  • 利息收益: 2.7796608 USDC (1天)                                     │
│                                                                       │
│  用户视角Bob - 借款人):                                            │
│  • 借款本金: -7000000e6 (不变)                                        │
│  • 旧债务: 7000000e6 × 1.15e18 / 1e18 = 8050000e6                    │
│  • 新债务: 7000000e6 × 1.15045675792e18 / 1e18 = 8053197.30544e6    │
│  • 利息成本: 3197.30544 USDC (1天)                                    │
│                                                                       │
│  协议储备金增长:                                                      │
│  储备金 = 合约 USDC 余额 - 总供应 + 总借款                            │
│  • 借款利息 > 供应利息,差额进入协议储备金                            │
│  • 本例储备金增长: 3197.30544 - 2.7796608 = 3194.52578 USDC         │
│                                                                       │
│  关键概念:                                                           │
│  • 本金principal用户的基础金额不含利息                       │
│  • 索引index利息累计因子初始为 1e18随时间增长              │
│  • 实际余额balance本金 × 索引 / 1e18含利息                   │
│  • 利息:通过索引的增长自动体现,无需手动分配                         │
│                                                                       │
│  利率曲线特点:                                                       │
│  ① 低利用率(< kink: 缓慢增长,鼓励借款                            │
│  ② 高利用率(> kink: 急剧增长,激励还款和存款                      │
│  ③ 借款利率 > 供应利率: 差额为协议收益                               │
│  ④ 动态调整: 每次操作都重新计算,实时响应市场状况                    │
└─────────────────────────────────────────────────────────────────────┘

9. 储备金管理WithdrawReserves

┌─────────────────────────────────────────────────────────────────────┐
│                         协议管理员 (Owner)                            │
│  当前状态:                                                            │
│  • 协议储备金: 6,000,000 USDC                                         │
│  • 目标储备金: 5,000,000 USDC                                         │
│  • 可提取: 1,000,000 USDC (超出目标的部分)                            │
│  计划: 提取 500,000 USDC 到指定地址                                   │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 1. 调用 withdrawReserves(recipient, 500000e6)
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Lending.withdrawReserves()                         │
│  ─────────────────────────────────────────────────────────────────  │
│  function withdrawReserves(address to, uint256 amount)                │
│      • 权限检查: onlyOwner                                            │
│      • 非重入保护: nonReentrant                                       │
│      • 参数: to=recipient, amount=500000e6                            │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 2. 计提利息
                             │    accrueInterest()
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      利息计提                                         │
│  更新到最新状态,确保储备金计算准确                                   │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 3. 计算当前储备金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      储备金计算 (getReserves)                         │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 获取合约 USDC 余额:                                                │
│     balance = IERC20(USDC).balanceOf(address(this))                  │
│                                                                       │
│  ② 计算实际总供应(含利息):                                          │
│     totalSupply = totalSupplyBase × supplyIndex / 1e18               │
│                                                                       │
│  ③ 计算实际总借款(含利息):                                          │
│     totalBorrow = totalBorrowBase × borrowIndex / 1e18               │
│                                                                       │
│  ④ 计算储备金:                                                        │
│     reserves = balance - totalSupply + totalBorrow                    │
│              = 6000000e6 (假设)                                       │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 4. 检查可提取金额
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      可提取检查                                       │
│  ─────────────────────────────────────────────────────────────────  │
│  if (reserves < 0) revert InsufficientBalance()                      │
│  • reserves = 6000000e6 >= 0  ✓                                      │
│                                                                       │
│  availableReserves = reserves - targetReserves                        │
│                    = 6000000e6 - 5000000e6                            │
│                    = 1000000e6  (可提取 100万)                        │
│                                                                       │
│  if (availableReserves < 0) revert InsufficientBalance()             │
│  • 1000000e6 >= 0  ✓                                                  │
│                                                                       │
│  if (amount > availableReserves) revert InsufficientBalance()        │
│  • 500000e6 <= 1000000e6  ✓ 通过                                     │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 5. 转出储备金
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      代币转移                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  IERC20(baseToken).safeTransfer(                                      │
│      to,                   // 接收地址                                │
│      500000e6              // 500,000 USDC                            │
│  )                                                                    │
│                                                                       │
│  结果:                                                               │
│  • Lending USDC 余额: -500000e6                                      │
│  • 接收地址 USDC 余额: +500000e6                                     │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 6. 触发事件
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      事件记录                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  emit WithdrawReserves(to, 500000e6)                                  │
└────────────────────────────┬────────────────────────────────────────┘
                             │
                             │ 7. 提取完成
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         提取完成                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  协议状态:                                                           │
│  • 储备金: 6,000,000 → 5,500,000 USDC                                │
│  • 目标储备金: 5,000,000 USDC                                         │
│  • 剩余可提取: 500,000 USDC                                           │
│                                                                       │
│  储备金来源:                                                         │
│  • 借款利息 > 供应利息的差额                                          │
│  • 清算时的抵押品折扣收益(如有)                                     │
│  • 清算后抵押品出售收益                                               │
│                                                                       │
│  储备金用途:                                                         │
│  • 覆盖坏账风险                                                       │
│  • 维持协议流动性                                                     │
│  • 协议治理和运营                                                     │
│                                                                       │
│  限制条件:                                                           │
│  • 只有 Owner 可以提取                                                │
│  • 只能提取超出 targetReserves 的部分                                │
│  • 确保协议始终保持足够的安全垫                                       │
└─────────────────────────────────────────────────────────────────────┘

10. 关键概念说明

10.1 本金 vs 余额

┌─────────────────────────────────────────────────────────────────────┐
│  本金Principal                                                    │
│  ─────────────────────────────────────────────────────────────────  │
│  • 定义:用户的基础金额,不含利息                                    │
│  • 类型int104有符号整数                                         │
│  • 正数:表示存款本金                                                │
│  • 负数:表示借款本金                                                │
│  • 零:表示既无存款也无借款                                          │
│  • 存储userBasic[user].principal                                    │
│                                                                       │
│  示例:                                                                │
│  • Alice 存入 10,000 USDC → principal = 10000e6                      │
│  • Bob 借出 5,000 USDC → principal = -5000e6                         │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  余额Balance                                                      │
│  ─────────────────────────────────────────────────────────────────  │
│  • 定义:实际金额,包含利息                                          │
│  • 计算balance = principal × index / 1e18                          │
│  • 动态:随时间和利息累积变化                                        │
│  • 不存储:每次需要时动态计算                                        │
│                                                                       │
│  示例(假设 supplyIndex = 1.05e18:                                 │
│  • Alice 实际余额 = 10000e6 × 1.05e18 / 1e18 = 10500e6              │
│  • Alice 利息收益 = 10500e6 - 10000e6 = 500e6                       │
│                                                                       │
│  示例(假设 borrowIndex = 1.15e18:                                 │
│  • Bob 实际债务 = -5000e6 × 1.15e18 / 1e18 = -5750e6                │
│  • Bob 利息成本 = 5750e6 - 5000e6 = 750e6                           │
└─────────────────────────────────────────────────────────────────────┘

10.2 利息索引Index

┌─────────────────────────────────────────────────────────────────────┐
│  利息索引机制                                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  • supplyIndex: 供应利息累计因子                                      │
│  • borrowIndex: 借款利息累计因子                                      │
│  • 初始值1e18即 1.0                                             │
│  • 单调递增:每次计提利息时增加                                      │
│  • 全局共享:所有用户使用相同的索引                                  │
│                                                                       │
│  增长公式:                                                            │
│  newIndex = oldIndex + (oldIndex × rate × timeElapsed) / 1e18        │
│                                                                       │
│  其中:                                                                │
│  • rate: 每秒利率(从年化利率转换)                                  │
│  • timeElapsed: 自上次计提以来的秒数                                 │
│                                                                       │
│  示例1年后假设年化利率 5%:                                      │
│  • 初始: supplyIndex = 1.0e18                                         │
│  • 1年后: supplyIndex ≈ 1.05e18                                      │
│  • 用户存款本金 10000e6 的实际余额:                                  │
│    10000e6 × 1.05e18 / 1e18 = 10500e6 (+5%)                         │
└─────────────────────────────────────────────────────────────────────┘

10.3 抵押率和清算阈值

┌─────────────────────────────────────────────────────────────────────┐
│  三个关键比率                                                         │
│  ─────────────────────────────────────────────────────────────────  │
│  ① borrowCollateralFactor借款抵押率例如 70%                    │
│     • 决定最大借款能力                                                │
│     • 最大借款 = 抵押品价值 × 70%                                     │
│     • 例:$2000 抵押品 → 最多借 $1400                                │
│                                                                       │
│  ② liquidateCollateralFactor清算阈值例如 75%                   │
│     • 决定何时可被清算                                                │
│     • 清算条件: 债务 > 抵押品价值 × 75%                              │
│     • 例:$2000 抵押品 → 债务超过 $1500 时清算                       │
│                                                                       │
│  ③ liquidationFactor清算折扣例如 90%                           │
│     • 清算时抵押品价值打折                                            │
│     • 清算价值 = 抵押品市价 × 90%                                     │
│     • 例:$2000 抵押品 → 清算时按 $1800 计算                         │
│     • 10% 差额作为清算惩罚和协议安全垫                                │
│                                                                       │
│  关系约束:                                                            │
│  • borrowCollateralFactor < liquidateCollateralFactor < 1             │
│  • 例70% < 75% < 100%                                               │
│  • 留出安全缓冲区,避免频繁清算                                      │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  健康度示例YT-A 抵押品 1000个价格 $2000                        │
│  ─────────────────────────────────────────────────────────────────  │
│  安全状态:                                                            │
│  • 抵押品价值: $2,000,000                                             │
│  • 债务: $1,000,000                                                   │
│  • LTV: 50%                                                           │
│  • 距离清算: $1,500,000 - $1,000,000 = $500,000 ✓                   │
│                                                                       │
│  接近清算:                                                            │
│  • 抵押品价值: $2,000,000                                             │
│  • 债务: $1,480,000                                                   │
│  • LTV: 74%                                                           │
│  • 距离清算: $1,500,000 - $1,480,000 = $20,000 ⚠️                   │
│                                                                       │
│  可清算状态:                                                          │
│  • 抵押品价值: $2,000,000                                             │
│  • 债务: $1,510,000                                                   │
│  • LTV: 75.5%                                                         │
│  • $1,510,000 > $1,500,000 ❌ 会被清算                               │
└─────────────────────────────────────────────────────────────────────┘

10.4 利率曲线(双斜率模型)

┌─────────────────────────────────────────────────────────────────────┐
│  利率随利用率变化示意图                                               │
│  ─────────────────────────────────────────────────────────────────  │
│  利率                                                                 │
│   │                                                                   │
│   │                                                                  │
│   │                                                                  │
│   │                                            借款利率              │
│   │                                                                  │
│   │                                                                  │
│   │                                                                  │
│ 20│                                                                  │
│ % │                                                                  │
│   │                                                                  │
│   │                                                                  │
│ 10│                  ← Kink (拐点80%)                             │
│ % │                                                                  │
│   │                                                                  │
│   │                             供应利率                             │
│  5│                                                                  │
│ % │                                                                  │
│   │_____________________________________                             │
│  0│         40%        80%        100%                                │
│   └─────────────────────────────────────→ 利用率                     │
│                                                                       │
│  特点:                                                                │
│  • Kink 前0-80%: 缓慢线性增长                                    │
│  • Kink 后80-100%: 急剧陡峭增长                                  │
│  • 借款利率始终高于供应利率(协议收益)                              │
│  • 高利用率时大幅提高借款成本,激励还款                              │
│  • 低利用率时降低借款成本,鼓励借款                                  │
└─────────────────────────────────────────────────────────────────────┘

11. 系统部署和配置流程

11.1 合约部署顺序

1. 部署核心基础设施07-deployLending.ts
   ├── LendingFactory
   ├── LendingPriceFeed (UUPS Proxy)
   ├── Configurator (UUPS Proxy)
   └── Lending Implementation

2. 配置市场参数并部署代理08-configureLending.ts
   ├── 设置 Configuration利率、抵押品等
   ├── 通过 Configurator 注册配置
   └── 部署 Lending Proxy使用 LendingFactory

3. 合约升级09-upgradeLending.ts可选
   ├── 升级 LendingPriceFeed
   ├── 升级 Configurator
   └── 升级 Lending

11.2 配置参数说明

Configuration {
    // 基础资产
    baseToken: USDC地址
    lendingPriceSource: LendingPriceFeed Proxy地址
    
    // 供应利率参数
    supplyKink: 0.8e18                          // 80% 拐点
    supplyPerYearInterestRateBase: 0.02e18      // 2% 基础年化
    supplyPerYearInterestRateSlopeLow: 0.1e18   // 拐点前斜率 10%
    supplyPerYearInterestRateSlopeHigh: 2e18    // 拐点后斜率 200%
    
    // 借款利率参数
    borrowKink: 0.8e18                          // 80% 拐点
    borrowPerYearInterestRateBase: 0.03e18      // 3% 基础年化
    borrowPerYearInterestRateSlopeLow: 0.15e18  // 拐点前斜率 15%
    borrowPerYearInterestRateSlopeHigh: 3e18    // 拐点后斜率 300%
    
    // 清算参数
    storeFrontPriceFactor: 0.95e18              // 清算购买折扣 5%
    baseBorrowMin: 100e6                        // 最小借款 100 USDC
    targetReserves: 5000000e6                   // 目标储备 500万
    
    // 抵押资产配置
    assetConfigs: [
        {
            asset: YT-A地址,
            decimals: 18,
            borrowCollateralFactor: 0.7e18,       // 70% LTV
            liquidateCollateralFactor: 0.75e18,   // 75% 清算阈值
            liquidationFactor: 0.9e18,            // 90% 清算价值
            supplyCap: 10000e18                   // 最多1万个
        },
        // 更多抵押资产...
    ]
}

12. 风险提示和最佳实践

12.1 用户风险

┌─────────────────────────────────────────────────────────────────────┐
│  存款人风险                                                           │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 流动性风险                                                         │
│     • 高利用率时可能无法立即提取全部存款                             │
│     • 建议:关注利用率,避免在极高利用率时大额存入                   │
│                                                                       │
│  ② 智能合约风险                                                       │
│     • 合约漏洞可能导致资金损失                                        │
│     • 建议:使用经过审计的版本,小额试用                             │
│                                                                       │
│  ③ 预言机风险                                                         │
│     • 价格数据异常可能影响协议运行                                    │
│     • 建议:关注 Chainlink 和 YT Vault 价格源状态                    │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  借款人风险                                                           │
│  ─────────────────────────────────────────────────────────────────  │
│  ① 清算风险                                                           │
│     • 抵押品价格下跌或债务增长可能导致清算                           │
│     • 清算损失:抵押品 × (1 - liquidationFactor)                     │
│     • 建议:保持健康的 LTV至少低于清算阈值 10%                     │
│                                                                       │
│  ② 利率风险                                                           │
│     • 利用率上升导致借款利率快速增长                                 │
│     • 建议:监控利用率和利率变化,及时还款                           │
│                                                                       │
│  ③ 抵押品波动风险                                                     │
│     • YT 代币价格波动较大                                             │
│     • 建议:使用多种抵押品分散风险,定期补充抵押品                   │
└─────────────────────────────────────────────────────────────────────┘

12.2 最佳实践

┌─────────────────────────────────────────────────────────────────────┐
│  存款人建议                                                           │
│  ─────────────────────────────────────────────────────────────────  │
│  • 分散存款:不要将全部资金存入单一协议                             │
│  • 定期复利:提取利息后重新存入,实现复利增长                       │
│  • 关注利用率:利用率过高(>90%)时谨慎存入                         │
│  • 预留流动性:保留部分资金在钱包,应对紧急需求                     │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  借款人建议                                                           │
│  ─────────────────────────────────────────────────────────────────  │
│  • 保守借款LTV 保持在 50-60%,低于清算阈值 20%+                   │
│  • 设置预警:监控抵押品价格,接近清算线时补充抵押品                 │
│  • 及时还款:利率上升时优先偿还高息债务                             │
│  • 多元抵押:如果支持,使用多种抵押品降低单一资产风险               │
│  • 准备金:保留一定 USDC 以应对紧急还款或补仓需求                   │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  清算人建议                                                           │
│  ─────────────────────────────────────────────────────────────────  │
│  • 自动化监控:运行机器人持续监控可清算账户                         │
│  • Gas 优化批量清算absorbMultiple降低成本                     │
│  • 快速响应:第一时间清算获得购买抵押品的机会                       │
│  • 价格监控:关注抵押品市场价格,计算套利空间                       │
│  • 充足准备:保持足够 USDC 购买清算抵押品                            │
└─────────────────────────────────────────────────────────────────────┘

13. 常见问题FAQ

Q1: 为什么我的余额和本金不一样?

  • 余额包含利息,本金是基础金额。余额 = 本金 × index / 1e18随时间增长。

Q2: 如何计算我的借款利率?

  • 借款利率根据协议利用率动态调整。查看 getBorrowRate() 获取当前每秒利率,乘以 31536000 得到年化利率。

Q3: 什么时候会被清算?

  • 当你的债务价值超过抵押品价值 × liquidateCollateralFactor 时会被清算。

Q4: 清算后我的资金怎么办?

  • 抵押品被没收按折扣价计算,用于偿还债务。如有剩余会转为你的存款,可以提取。

Q5: 为什么无法提取全部存款?

  • 协议需要保持足够流动性满足借款人。高利用率时可能需要等待借款被还款后才能提取。

Q6: storeFrontPriceFactor 是什么?

  • 清算抵押品出售时的额外折扣,激励清算人购买抵押品,补充协议储备金。

Q7: 如何查看协议储备金?

  • 调用 getReserves() 查看当前储备金。储备金 = 合约余额 - 总供应 + 总借款。

Q8: 可以同时存款和借款吗?

  • 不可以。每个账户只能有一个 principal正数=存款,负数=借款,零=无)。如需同时操作,使用多个地址。

Q9: 利息多久结算一次?

  • 每次交互时自动计提利息,无需手动操作。利息通过 index 增长自动体现在余额中。

Q10: 支持哪些抵押品?

  • 由配置决定。默认支持 YT 资产代币。每种抵押品有独立的 LTV 和清算参数。