上传文件至 document

This commit is contained in:
xie
2025-12-15 14:45:51 +00:00
parent faeb8e2f45
commit c3e0bafe1a
5 changed files with 9647 additions and 0 deletions

View File

@@ -0,0 +1,681 @@
ytLp流动性池系统操作流程文档
目录
1. [添加流动性流程](#1-添加流动性流程)
2. [移除流动性流程](#2-移除流动性流程)
3. [代币互换流程](#3-代币互换流程)
4. [添加白名单代币流程](#4-添加白名单代币流程)
5. [移除白名单代币流程](#5-移除白名单代币流程)
1. 添加流动性流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 用户 (User) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 addLiquidity(token, amount, minUsdy, minYtLP)
┌─────────────────────────────────────────────────────────────────────┐
│ YTRewardRouter.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function addLiquidity( │
│ address _token, // YT-A 代币地址 │
│ uint256 _amount, // 1000 个代币 │
│ uint256 _minUsdy, // 最小997 USDY滑点保护
│ uint256 _minYtLP // 最小995 ytLP滑点保护
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. transferFrom(user → YTRewardRouter)
│ 转移1000个YT-A到Router
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移检查 │
│ ✓ 检查用户授权额度 │
│ ✓ 转移代币到Router │
│ ✓ approve(YTPoolManager, amount) │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 调用 addLiquidityForAccount()
┌─────────────────────────────────────────────────────────────────────┐
│ YTPoolManager.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function addLiquidityForAccount( │
│ address _fundingAccount, // YTRewardRouter │
│ address _account, // 用户地址 │
│ address _token, // YT-A │
│ uint256 _amount, // 1000 │
│ uint256 _minUsdy, // 997 │
│ uint256 _minYtLP // 995 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 计算当前AUM使用MaxPrice
│ getAumInUsdy(true)
┌─────────────────────────────────────────────────────────────────────┐
│ AUM 计算(对用户保守) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ YTVault.getPoolValue(true) │ │
│ │ • 获取池中所有YT代币数量 │ │
│ │ • 使用 MaxPrice上浮价差计算每个代币价值 │ │
│ │ • 汇总得到 AUM = $100,200 │ │
│ └───────────────────────────────────────────────────────┘ │
│ 当前ytLP供应量: 100,000 │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 调用 buyUSDY()
┌─────────────────────────────────────────────────────────────────────┐
│ YTVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function buyUSDY(address _token, address _receiver) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① transferIn(_token) │ │
│ │ • 接收1000个YT-A │ │
│ │ │ │
│ │ ② 获取价格使用MinPrice低估用户资产 │ │
│ │ price = _getPrice(_token, false) │ │
│ │ • 基础价格: $1.00 │ │
│ │ • MinPrice: $0.998 (下压0.2%价差) │ │
│ │ │ │
│ │ ③ 计算理论USDY价值 │ │
│ │ usdyAmount = 1000 × $0.998 = $998 │ │
│ │ │ │
│ │ ④ 获取手续费率(动态) │ │
│ │ feeBps = getSwapFeeBasisPoints(_token, usdy, 998) │ │
│ │ • 检查是否稳定币互换 │ │
│ │ • YT代币: 30 bps (0.3%) │ │
│ │ • 稳定币: 4 bps (0.04%) │ │
│ │ • 根据池子平衡动态调整 │ │
│ │ → 本次: 30 bps │ │
│ │ │ │
│ │ ⑤ 计算扣费后的USDY │ │
│ │ feeAmount = 1000 × 0.3% = 3个代币 │ │
│ │ amountAfterFees = 997个代币 │ │
│ │ usdyAmountAfterFees = 997 × $0.998 = $995.006 │ │
│ │ │ │
│ │ ⑥ 池子记账 │ │
│ │ _increasePoolAmount(_token, 1000) // 全部代币入池 │ │
│ │ _increaseUsdyAmount(_token, 995) // 只记扣费后的债务 │ │
│ │ │ │
│ │ ⑦ 铸造USDY │ │
│ │ USDY.mint(_receiver, 995) │ │
│ │ • 手续费3个代币留在池中 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 返回: 995 USDY │
└────────────────────────────┬────────────────────────────────────────┘
│ 6. 检查 USDY 数量
│ require(995 >= 997) ❌ 会失败
│ (实际应该传入更小的 minUsdy)
┌─────────────────────────────────────────────────────────────────────┐
│ 回到 YTPoolManager - 铸造 ytLP │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 计算铸造数量: │ │
│ │ ytLPSupply = 100,000 │ │
│ │ aumInUsdy = $100,200 │ │
│ │ usdyAmount = $995 │ │
│ │ │ │
│ │ mintAmount = 995 × 100,000 / 100,200 = 993.03 ytLP │ │
│ │ │ │
│ │ 检查滑点保护: │ │
│ │ require(993.03 >= 995) ❌ 会失败 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 执行铸造: │
│ YTLPToken.mint(user, 993.03) │
│ lastAddedAt[user] = block.timestamp // 记录时间(冷却期) │
└────────────────────────────┬────────────────────────────────────────┘
│ 7. 返回结果
┌─────────────────────────────────────────────────────────────────────┐
│ 用户收到 │
│ ✓ 993.03 ytLP │
│ ✓ 代表在池中的份额 │
│ │
│ 成本分析: │
│ 存入: 1000 YT-A │
│ 手续费: 3 YT-A (0.3%) │
│ 价差损失: ~4 YT-A (0.4%) │
│ 总成本: ~0.7% │
└─────────────────────────────────────────────────────────────────────┘
涉及的合约函数:
合约 函数 作用
YTRewardRouter addLiquidity() 用户入口,处理代币转移
YTPoolManager addLiquidityForAccount() 流动性管理计算ytLP
YTPoolManager getAumInUsdy(true) 获取AUM使用MaxPrice
YTVault buyUSDY() 接收代币铸造USDY
YTVault getPoolValue(true) 计算池子总价值
YTVault getSwapFeeBasisPoints() 获取动态手续费率
YTPriceFeed getPrice(_token, false) 获取MinPrice
USDY mint() 铸造USDY代币
YTLPToken mint() 铸造ytLP代币
2. 移除流动性流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 用户 (User) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 removeLiquidity(tokenOut, ytLPAmount, minOut, receiver)
┌─────────────────────────────────────────────────────────────────────┐
│ YTRewardRouter.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function removeLiquidity( │
│ address _tokenOut, // YT-B 代币地址 │
│ uint256 _ytLPAmount, // 1000 ytLP │
│ uint256 _minOut, // 最小990 YT-B滑点保护
│ address _receiver // 接收地址 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 调用 removeLiquidityForAccount()
┌─────────────────────────────────────────────────────────────────────┐
│ YTPoolManager.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function removeLiquidityForAccount(...) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① 检查冷却期 │ │
│ │ require(lastAddedAt[user] + 15分钟 <= now) │ │
│ │ │ │
│ │ ② 计算AUM使用MinPrice对用户保守 │ │
│ │ aumInUsdy = getAumInUsdy(false) │ │
│ │ • YTVault.getPoolValue(false) │ │
│ │ • 使用MinPrice下压价差 │ │
│ │ • AUM = $99,800 │ │
│ │ │ │
│ │ ③ 计算USDY价值 │ │
│ │ ytLPSupply = 100,000 │ │
│ │ usdyAmount = 1000 × 99,800 / 100,000 = $998 │ │
│ │ │ │
│ │ ④ 检查并铸造USDY如果余额不足 │ │
│ │ balance = USDY.balanceOf(PoolManager) │ │
│ │ if (998 > balance) { │ │
│ │ USDY.mint(PoolManager, 998 - balance) │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 销毁ytLP
│ YTLPToken.burn(user, 1000)
┌─────────────────────────────────────────────────────────────────────┐
│ ytLP 销毁完成 │
│ 用户的ytLP余额 -1000 │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 调用 sellUSDY()
┌─────────────────────────────────────────────────────────────────────┐
│ YTVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function sellUSDY(address _token, address _receiver) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① transferIn(usdy) │ │
│ │ • 接收998 USDY │ │
│ │ │ │
│ │ ② 获取价格使用MaxPrice高估需支付的价值 │ │
│ │ price = _getPrice(_token, true) │ │
│ │ • 基础价格: $1.00 │ │
│ │ • MaxPrice: $1.002 (上浮0.2%价差) │ │
│ │ │ │
│ │ ③ 计算理论赎回数量 │ │
│ │ redemptionAmount = 998 / 1.002 = 996.01 YT-B │ │
│ │ │ │
│ │ ④ 获取赎回手续费率 │ │
│ │ feeBps = getRedemptionFeeBasisPoints(_token, 998) │ │
│ │ • USDY已被标记为稳定币 │ │
│ │ • 如果_token也是稳定币: 4 bps │ │
│ │ • 如果_token是YT代币: 30 bps │ │
│ │ → 本次(YT-B): 30 bps │ │
│ │ │ │
│ │ ⑤ 计算扣费后的输出 │ │
│ │ amountOut = 996.01 × (1 - 0.3%) │ │
│ │ = 993.02 YT-B │ │
│ │ │ │
│ │ ⑥ 池子记账 │ │
│ │ _decreasePoolAmount(_token, 993.02) // 减少池中代币 │ │
│ │ _decreaseUsdyAmount(_token, ...) // 减少债务 │ │
│ │ │ │
│ │ ⑦ 销毁USDY │ │
│ │ USDY.burn(address(this), 998) │ │
│ │ │ │
│ │ ⑧ 转出代币 │ │
│ │ transfer(_receiver, 993.02 YT-B) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 返回: 993.02 YT-B │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 检查滑点保护
│ require(993.02 >= 990) ✓
┌─────────────────────────────────────────────────────────────────────┐
│ 用户收到 │
│ ✓ 993.02 YT-B │
│ │
│ 成本分析: │
│ 赎回: 1000 ytLP │
│ 手续费: ~3 YT-B (0.3%) │
│ 价差损失: ~4 YT-B (0.4%) │
│ 总成本: ~0.7% │
└─────────────────────────────────────────────────────────────────────┘
涉及的合约函数:
合约 函数 作用
YTRewardRouter removeLiquidity() 用户入口
YTPoolManager removeLiquidityForAccount() 计算USDY价值
YTPoolManager getAumInUsdy(false) 获取AUM使用MinPrice
YTVault sellUSDY() 用USDY换回代币
YTVault getRedemptionFeeBasisPoints() 获取赎回手续费率
YTPriceFeed getPrice(_token, true) 获取MaxPrice
USDY mint() 补充USDY如需要
USDY burn() 销毁USDY
YTLPToken burn() 销毁ytLP
3. 代币互换流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 用户 (User) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 swapYT(tokenIn, tokenOut, amountIn, minOut, receiver)
┌─────────────────────────────────────────────────────────────────────┐
│ YTRewardRouter.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function swapYT( │
│ address _tokenIn, // YT-A │
│ address _tokenOut, // YT-B │
│ uint256 _amountIn, // 1000 │
│ uint256 _minOut, // 990滑点保护
│ address _receiver // 接收地址 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. transferFrom(user → YTVault)
│ 转移1000个YT-A直接到Vault
┌─────────────────────────────────────────────────────────────────────┐
│ YTVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function swap( │
│ address _tokenIn, // YT-A │
│ address _tokenOut, // YT-B │
│ address _receiver // 用户 │
│ ) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① 安全检查 │ │
│ │ ✓ swap已启用 │ │
│ │ ✓ tokenIn已白名单 │ │
│ │ ✓ tokenOut已白名单 │ │
│ │ ✓ tokenIn != tokenOut │ │
│ │ │ │
│ │ ② transferIn(_tokenIn) │ │
│ │ • 检测转入的YT-A数量: 1000 │ │
│ │ │ │
│ │ ③ 检查单笔交易限额 │ │
│ │ if (maxSwapAmount[tokenIn] > 0) { │ │
│ │ require(1000 <= maxSwapAmount[tokenIn]) │ │
│ │ } │ │
│ │ │ │
│ │ ④ 获取价格(对协议有利的定价) │ │
│ │ priceIn = _getPrice(_tokenIn, false) // MinPrice │ │
│ │ = $0.998 (低估输入) │ │
│ │ priceOut = _getPrice(_tokenOut, true) // MaxPrice │ │
│ │ = $1.002 (高估输出) │ │
│ │ │ │
│ │ ⑤ 计算中间USDY价值 │ │
│ │ usdyAmount = 1000 × $0.998 / 1e30 = $998 │ │
│ │ │ │
│ │ ⑥ 检查每日交易量限制 │ │
│ │ _checkDailySwapLimit(998) │ │
│ │ │ │
│ │ ⑦ 计算理论输出(扣费前) │ │
│ │ amountOut = 998 × 1e30 / $1.002 │ │
│ │ = 996.01 YT-B │ │
│ │ │ │
│ │ ⑧ 获取swap手续费率动态 │ │
│ │ feeBps = getSwapFeeBasisPoints(tokenIn, tokenOut, 998) │ │
│ │ │ │
│ │ 判断逻辑: │ │
│ │ • 是否稳定币互换? │ │
│ │ isStableSwap = stableTokens[YT-A] && stableTokens[YT-B] │ │
│ │ = false && false = false │ │
│ │ │ │
│ │ • 基础费率: 30 bps (非稳定币) │ │
│ │ • 税率: 50 bps │ │
│ │ │ │
│ │ • 动态调整(改善平衡 → 降低费率): │ │
│ │ ├─ YT-A: 当前50k, 目标40k → 过多 → 增加费率 │ │
│ │ └─ YT-B: 当前30k, 目标40k → 不足 → 减少费率 │ │
│ │ │ │
│ │ • 计算两个代币的费率,取较高者 │ │
│ │ fee_A = getFeeBasisPoints(YT-A, 998, 30, 50, true) │ │
│ │ = 40 bps (恶化平衡,提高) │ │
│ │ fee_B = getFeeBasisPoints(YT-B, 998, 30, 50, false) │ │
│ │ = 20 bps (改善平衡,降低) │ │
│ │ │ │
│ │ → 最终费率: max(40, 20) = 40 bps (0.4%) │ │
│ │ │ │
│ │ ⑨ 扣除手续费 │ │
│ │ amountOutAfterFees = 996.01 × (1 - 0.4%) │ │
│ │ = 992.02 YT-B │ │
│ │ │ │
│ │ ⑩ 全局滑点保护 │ │
│ │ _validateSwapSlippage(1000, 992.02, priceIn, priceOut) │ │
│ │ │ │
│ │ ⑪ 更新池子状态 │ │
│ │ _increasePoolAmount(YT-A, 1000) // YT-A入池 │ │
│ │ _decreasePoolAmount(YT-B, 992.02) // YT-B出池 │ │
│ │ _increaseUsdyAmount(YT-A, 998) // YT-A债务+998 │ │
│ │ _decreaseUsdyAmount(YT-B, 998) // YT-B债务-998 │ │
│ │ │ │
│ │ ⑫ 转出代币 │ │
│ │ transfer(_receiver, 992.02 YT-B) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 返回: 992.02 YT-B │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 检查滑点保护
│ require(992.02 >= 990) ✓
┌─────────────────────────────────────────────────────────────────────┐
│ 用户收到 │
│ ✓ 992.02 YT-B │
│ │
│ 成本分析: │
│ 输入: 1000 YT-A │
│ 价差损失: ~4 YT (0.4%) │
│ 手续费: ~4 YT (0.4% 动态) │
│ 输出: 992.02 YT-B │
│ 总成本: ~0.8% │
│ │
│ 有效汇率: 1 YT-A = 0.9920 YT-B │
└─────────────────────────────────────────────────────────────────────┘
涉及的合约函数:
合约 函数 作用
YTRewardRouter swapYT() 用户入口,转移代币
YTVault swap() 执行代币互换
YTVault getSwapFeeBasisPoints() 获取动态swap费率
YTVault getFeeBasisPoints() 计算单个代币的动态费率
YTVault _validateSwapSlippage() 全局滑点保护
YTVault _checkDailySwapLimit() 检查每日限额
YTPriceFeed getMinPrice() 输入代币价格
YTPriceFeed getMaxPrice() 输出代币价格
4. 添加白名单代币流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 管理员 (Gov) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 setWhitelistedToken(...)
┌─────────────────────────────────────────────────────────────────────┐
│ YTVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function setWhitelistedToken( │
│ address _token, // 新YT代币地址 │
│ uint256 _decimals, // 18 │
│ uint256 _weight, // 权重 10000 (10%) │
│ uint256 _maxUsdyAmount, // 最大USDY债务 1000000e18 │
│ bool _isStable // false (YT代币非稳定币) │
│ ) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① 安全检查 │ │
│ │ require(_token != address(0)) │ │
│ │ require(msg.sender == gov) // 只有管理员 │ │
│ │ │ │
│ │ ② 检查是否已在白名单 │ │
│ │ if (!whitelistedTokens[_token]) { │ │
│ │ allWhitelistedTokens.push(_token) // 添加到数组 │ │
│ │ whitelistedTokens[_token] = true // 标记为白名单 │ │
│ │ } │ │
│ │ │ │
│ │ ③ 更新总权重 │ │
│ │ oldWeight = tokenWeights[_token] // 0新代币 │ │
│ │ totalTokenWeights = totalTokenWeights - oldWeight + 10000 │ │
│ │ │ │
│ │ 示例(自动比例调整): │ │
│ │ ┌──────────────┬────────┬──────────┬──────────┐ │ │
│ │ │ 代币 │ 权重 │ 旧占比 │ 新占比 │ │ │
│ │ ├──────────────┼────────┼──────────┼──────────┤ │ │
│ │ │ YT-A (原有) │ 30000 │ 30.0% │ 27.27% │ ← 自动变化│ │
│ │ │ YT-B (原有) │ 30000 │ 30.0% │ 27.27% │ │ │
│ │ │ YT-C (原有) │ 30000 │ 30.0% │ 27.27% │ │ │
│ │ │ WUSD (原有) │ 10000 │ 10.0% │ 9.09% │ │ │
│ │ │ YT-D (新增) │ 10000 │ - │ 9.09% │ ← 新增 │ │
│ │ ├──────────────┼────────┼──────────┼──────────┤ │ │
│ │ │ 总计 │ 110000 │ 100% │ 100% │ │ │
│ │ └──────────────┴────────┴──────────┴──────────┘ │ │
│ │ │ │
│ │ ⚠️ 重要使用相对权重不需要保持总和为100000 │ │
│ │ totalTokenWeights可以是任意值关键是相对比例 │ │
│ │ │ │
│ │ ④ 设置代币参数 │ │
│ │ tokenDecimals[_token] = 18 │ │
│ │ tokenWeights[_token] = 10000 │ │
│ │ maxUsdyAmounts[_token] = 1000000e18 // 最大100万USDY债务 │ │
│ │ stableTokens[_token] = false // 标记非稳定币 │ │
│ │ │ │
│ │ ⑤ 白名单添加完成 │ │
│ │ ✓ 代币可以被存入 │ │
│ │ ✓ 代币可以被swap │ │
│ │ ✓ 代币开始计入AUM │ │
│ └─────────────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 需要配置价格预言机
┌─────────────────────────────────────────────────────────────────────┐
│ YTPriceFeed.sol │
│ ───────────────────────────────────────────────────────────────── │
│ 需要执行的配置: │
│ │
│ ① 设置价差 (可选但推荐) │
│ setSpreadBasisPoints(YT-D, 20) // 0.2% 价差 │
│ │
│ ② 初始化价格 (如果需要) │
│ forceUpdatePrice(YT-D, 1e30) // 初始价格 $1.00 │
│ │
│ 注意: YT代币需要实现 assetPrice() 接口 │
│ 价格预言机会自动读取该接口获取价格 │
└─────────────────────────────────────────────────────────────────────┘
│ 3. 配置完成
┌─────────────────────────────────────────────────────────────────────┐
│ 白名单生效 │
│ │
│ 用户可以: │
│ ✓ 用YT-D添加流动性 │
│ ✓ 用ytLP换回YT-D │
│ ✓ YT-D与其他YT代币互换 │
│ │
│ 协议会: │
│ ✓ 将YT-D计入AUM按10%权重) │
│ ✓ 对YT-D使用0.3%的swap费率非稳定币
│ ✓ 动态调整费率以维持池子平衡 │
└─────────────────────────────────────────────────────────────────────┘
涉及的合约函数:
合约 函数 作用
YTVault setWhitelistedToken() 添加代币到白名单
YTPriceFeed setSpreadBasisPoints() 设置代币价差
YTPriceFeed forceUpdatePrice() 初始化价格(可选)
白名单代币要求:
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ YT代币必须实现的接口 │
│ │
│ interface IYTToken { │
│ // 必需返回当前资产价格30位精度
│ function assetPrice() external view returns (uint256); │
│ │
│ // ERC20标准接口 │
│ function decimals() external view returns (uint8); │
│ function balanceOf(address) external view returns (uint256); │
│ function transfer(address, uint256) external returns (bool); │
│ function transferFrom(address, address, uint256) │
│ external returns (bool); │
│ } │
│ │
│ 价格示例: │
│ $1.00 = 1 × 10^30 = 1000000000000000000000000000000 │
│ $0.998 = 998000000000000000000000000000 │
└─────────────────────────────────────────────────────────────────────┘
5. 移除白名单代币流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 管理员 (Gov) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 先确保池中该代币已清空
│ (用户需先移除流动性)
┌─────────────────────────────────────────────────────────────────────┐
│ 检查代币状态 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 检查池子余额: │ │
│ │ poolAmounts[YT-D] = ? │ │
│ │ usdyAmounts[YT-D] = ? │ │
│ │ │ │
│ │ 安全建议: │ │
│ │ ✓ 池中余额应为0或接近0 │ │
│ │ ✓ USDY债务应为0 │ │
│ │ ✓ 没有待处理的用户流动性 │ │
│ └─────────────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 调用 clearWhitelistedToken(token)
┌─────────────────────────────────────────────────────────────────────┐
│ YTVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function clearWhitelistedToken(address _token) │
│ │
│ 步骤: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ① 安全检查 │ │
│ │ require(whitelistedTokens[_token]) // 必须已在白名单 │ │
│ │ require(msg.sender == gov) // 只有管理员 │ │
│ │ │ │
│ │ ② 更新总权重 │ │
│ │ oldWeight = tokenWeights[YT-D] = 10000 │ │
│ │ totalTokenWeights = totalTokenWeights - 10000 │ │
│ │ │ │
│ │ 结果: │ │
│ │ ┌──────────────┬────────┬────────┐ │ │
│ │ │ 代币 │ 权重 │ 占比 │ │ │
│ │ ├──────────────┼────────┼────────┤ │ │
│ │ │ YT-A │ 30000 │ 30% │ │ │
│ │ │ YT-B │ 30000 │ 30% │ │ │
│ │ │ YT-C │ 30000 │ 30% │ │ │
│ │ │ WUSD │ 10000 │ 10% │ │ │
│ │ │ YT-D (删除) │ 0 │ - │ ← 已移除 │ │
│ │ ├──────────────┼────────┼────────┤ │ │
│ │ │ 总计 │ 100000 │ 100% │ │ │
│ │ └──────────────┴────────┴────────┘ │ │
│ │ │ │
│ │ ③ 清除所有配置 │ │
│ │ delete whitelistedTokens[_token] // 从白名单移除 │ │
│ │ delete stableTokens[_token] // 清除稳定币标记 │ │
│ │ delete tokenDecimals[_token] // 清除精度 │ │
│ │ delete tokenWeights[_token] // 清除权重 │ │
│ │ delete maxUsdyAmounts[_token] // 清除最大债务限制 │ │
│ │ │ │
│ │ ④ 白名单移除完成 │ │
│ │ ✓ 代币无法被存入 │ │
│ │ ✓ 代币无法被swap │ │
│ │ ✓ 代币不再计入AUM │ │
│ └─────────────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 后续处理(可选)
┌─────────────────────────────────────────────────────────────────────┐
│ 可选的清理操作 │
│ │
│ ① 从 allWhitelistedTokens 数组中移除 │
│ (注意: 合约当前没有自动移除需要考虑gas成本) │
│ │
│ ② 如果池中还有少量余额,可以提取 │
│ (启用紧急模式后) │
│ emergencyMode = true │
│ withdrawToken(YT-D, gov, amount) │
│ │
│ ③ 从价格预言机移除配置(可选) │
│ 不强制,但可以节省存储 │
└─────────────────────────────────────────────────────────────────────┘
│ 4. 完成
┌─────────────────────────────────────────────────────────────────────┐
│ 移除完成 │
│ │
│ 用户无法: │
│ ✗ 用YT-D添加流动性 │
│ ✗ 用ytLP换回YT-D │
│ ✗ YT-D与其他YT代币互换 │
│ │
│ 协议: │
│ ✓ YT-D不再计入AUM计算 │
│ ✓ 权重已重新分配 │
└─────────────────────────────────────────────────────────────────────┘
涉及的合约函数:
合约 函数 作用
YTVault clearWhitelistedToken() 从白名单移除代币
YTVault setEmergencyMode() 启用紧急模式(如需提取余额)
YTVault withdrawToken() 提取剩余代币(紧急模式下)
移除白名单的注意事项:
Plain Text
⚠️ 重要提示:
1. 移除前确保:
• 所有用户已移除该代币的流动性
• poolAmounts[token] = 0 或接近0
• usdyAmounts[token] = 0
• 没有pending的交易
2. 移除后影响:
• 该代币的所有操作立即失效
• 如果用户还持有该代币的ytLP无法再换回该代币
• 需要重新调整其他代币的权重以维持池子平衡
3. 不可逆操作:
• 移除后该代币在 allWhitelistedTokens 数组中仍然存在(历史记录)
• 但所有配置和权限已清除
• 如需重新添加,需要再次调用 setWhitelistedToken()
4. 最佳实践:
• 提前公告,给用户足够时间移除流动性
• 移除前暂停该代币的新增流动性
• 记录剩余余额,在紧急模式下安全提取
• 移除后验证AUM计算正确
核心合约职责:
合约 职责 关键功能
YTRewardRouter 用户入口 接收用户请求,处理代币转移
YTPoolManager 流动性管理 计算ytLP管理AUM
YTVault 资金池 存储资产执行swap管理手续费
YTPriceFeed 价格预言机 提供价格,应用价差
USDY 计价代币 内部记账单位
YTLPToken LP代币 代表用户份额