Files
Heyue_test/document/Vault金库系统操作流程文档.md

1185 lines
106 KiB
Markdown
Raw Normal View History

2025-12-15 14:45:51 +00:00
Vault金库系统操作流程文档
目录
1. [创建Vault流程](#1-创建vault流程)
2. [用户存款流程depositYT](#2-用户存款流程deposityt)
3. [用户提款流程withdrawYT](#3-用户提款流程withdrawyt)
4. [价格更新流程](#4-价格更新流程)
5. [资产管理流程 - 提取投资](#5-资产管理流程---提取投资)
6. [资产管理流程 - 归还资产](#6-资产管理流程---归还资产)
7. [批量操作流程](#7-批量操作流程)
8. [查询信息流程](#8-查询信息流程)
1. 创建Vault流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Owner (系统管理员) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 createVault()
│ name: "YT-A Token"
│ symbol: "YT-A"
│ manager: 0x123...
│ hardCap: 1,000,000 YT
│ wusd: 0x7Cd...或0使用默认
│ redemptionTime: 2025-02-15 00:00:00
│ initialWusdPrice: 1.05e30
│ initialYtPrice: 1.05e30
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetFactory.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function createVault(...) │
│ │
│ 权限检查: │
│ ✓ onlyOwner - 只有Factory owner可以创建 │
│ ✓ manager != address(0) - 管理员地址有效 │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 确定硬顶值
│ _hardCap == 0 ? defaultHardCap : _hardCap
│ → 使用传入的 1,000,000 YT
┌─────────────────────────────────────────────────────────────────────┐
│ 编码初始化数据 │
│ ───────────────────────────────────────────────────────────────── │
│ bytes memory initData = abi.encodeWithSelector( │
│ YTAssetVault.initialize.selector, │
│ "YT-A Token", │
│ "YT-A", │
│ 0x123..., // manager │
│ 1000000e18, // hardCap │
│ 0x7Cd..., // wusd │
│ 1739577600, // redemptionTime (Unix时间戳) │
│ 1050000000000000000000000000000, // 1.05e30 │
│ 1050000000000000000000000000000 // 1.05e30 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 部署ERC1967代理合约
│ new ERC1967Proxy(vaultImplementation, initData)
┌─────────────────────────────────────────────────────────────────────┐
│ 部署并初始化YTAssetVault │
│ ───────────────────────────────────────────────────────────────── │
│ 新合约地址: 0xVault001... │
│ │
│ ① __ERC20_init("YT-A Token", "YT-A") │
│ • 初始化ERC20代币 │
│ • name: "YT-A Token" │
│ • symbol: "YT-A" │
│ • decimals: 18 │
│ │
│ ② __UUPSUpgradeable_init() │
│ • 初始化UUPS升级模式 │
│ │
│ ③ __ReentrancyGuard_init() │
│ • 初始化重入保护 │
│ │
│ ④ 设置基本参数 │
│ factory = msg.sender (YTAssetFactory地址) │
│ manager = 0x123... │
│ hardCap = 1,000,000 * 1e18 │
│ wusdAddress = 0x7Cd... │
│ │
│ ⑤ 设置价格精度1e30
│ wusdPrice = 1.05e30 (初始价格1.05) │
│ ytPrice = 1.05e30 (初始价格1.05) │
│ │
│ ⑥ 设置赎回时间 │
│ nextRedemptionTime = 1739577600 (2025-02-15) │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 记录到Factory
┌─────────────────────────────────────────────────────────────────────┐
│ Factory状态更新 │
│ ───────────────────────────────────────────────────────────────── │
│ allVaults.push(0xVault001...) │
│ isVault[0xVault001...] = true │
│ │
│ 触发事件: │
│ emit VaultCreated( │
│ 0xVault001..., │
│ 0x123..., // manager │
│ "YT-A Token", │
│ "YT-A", │
│ 1000000e18, // hardCap │
│ 0 // index │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 返回vault地址
┌─────────────────────────────────────────────────────────────────────┐
│ 创建完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 返回值: 0xVault001... │
│ │
│ Vault状态
│ • totalSupply: 0 │
│ • totalAssets: 0 WUSD │
│ • wusdPrice: 1.05 (精度1e30) │
│ • ytPrice: 1.05 (精度1e30) │
│ • hardCap: 1,000,000 YT │
│ • nextRedemptionTime: 2025-02-15 00:00:00 │
│ • 可接受用户存款 ✓ │
└─────────────────────────────────────────────────────────────────────┘
2. 用户存款流程depositYT
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 用户 (User) │
│ 持有: 10,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 0. 预览操作(可选)
│ 调用 previewBuy(10000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function previewBuy(10000e18) returns (uint256 ytAmount) │
│ │
│ 计算逻辑: │
│ ytAmount = (wusdAmount × wusdPrice) ÷ ytPrice │
│ = (10,000 × 1.05e30) ÷ 1.05e30 │
│ = 10,000 YT │
│ │
│ 返回预览结果: 10,000 YT │
└─────────────────────────────────────────────────────────────────────┘
│ 1. 授权WUSD给Vault
│ WUSD.approve(vault, 10000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ WUSD授权检查 │
│ ✓ allowance[user][vault] >= 10,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 调用 depositYT(10000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.depositYT() │
│ ───────────────────────────────────────────────────────────────── │
│ function depositYT(uint256 _wusdAmount) │
│ • 非重入保护: nonReentrant │
│ • 参数: 10,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 参数验证
┌─────────────────────────────────────────────────────────────────────┐
│ 参数检查 │
│ ───────────────────────────────────────────────────────────────── │
│ ① _wusdAmount > 0 │
│ ✓ 10,000 > 0 通过 │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 计算可获得的YT数量
┌─────────────────────────────────────────────────────────────────────┐
│ 计算YT数量 │
│ ───────────────────────────────────────────────────────────────── │
│ 公式ytAmount = (wusdAmount × wusdPrice) ÷ ytPrice │
│ │
│ 当前价格: │
│ • wusdPrice = 1.05e30 │
│ • ytPrice = 1.05e30 │
│ │
│ 计算过程: │
│ ytAmount = (10,000e18 × 1.05e30) ÷ 1.05e30 │
│ = 10,000e18 │
│ = 10,000 YT │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 检查硬顶限制
┌─────────────────────────────────────────────────────────────────────┐
│ 硬顶检查 │
│ ───────────────────────────────────────────────────────────────── │
│ if (hardCap > 0 && totalSupply() + ytAmount > hardCap) │
│ revert HardCapExceeded() │
│ │
│ 当前状态: │
│ • hardCap = 1,000,000 YT │
│ • totalSupply() = 0 YT (首次存款) │
│ • ytAmount = 10,000 YT │
│ • 0 + 10,000 = 10,000 ≤ 1,000,000 ✓ 通过 │
└────────────────────────────┬────────────────────────────────────────┘
│ 6. 转入WUSDCEI模式 - Checks完成
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移Effects
│ ───────────────────────────────────────────────────────────────── │
│ IERC20(wusdAddress).safeTransferFrom( │
│ msg.sender, // 用户地址 │
│ address(this), // Vault地址 │
│ 10000e18 // 转入10,000 WUSD │
│ ) │
│ │
│ 结果: │
│ • 用户WUSD余额: 10,000 → 0 │
│ • Vault WUSD余额: 0 → 10,000 │
└────────────────────────────┬────────────────────────────────────────┘
│ 7. 铸造YT代币给用户
┌─────────────────────────────────────────────────────────────────────┐
│ 铸造YT代币 │
│ ───────────────────────────────────────────────────────────────── │
│ _mint(msg.sender, 10000e18) │
│ │
│ ERC20铸造
│ • balanceOf[user] += 10,000 YT │
│ • totalSupply += 10,000 YT │
│ │
│ 结果: │
│ • 用户YT余额: 0 → 10,000 YT │
│ • 总供应量: 0 → 10,000 YT │
└────────────────────────────┬────────────────────────────────────────┘
│ 8. 触发事件
┌─────────────────────────────────────────────────────────────────────┐
│ 事件记录Interactions
│ ───────────────────────────────────────────────────────────────── │
│ emit Buy( │
│ msg.sender, // 用户地址 │
│ 10000e18, // WUSD数量 │
│ 10000e18 // YT数量 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 9. 返回YT数量
┌─────────────────────────────────────────────────────────────────────┐
│ 存款完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 用户最终状态: │
│ • WUSD余额: 0 │
│ • YT余额: 10,000 YT │
│ │
│ Vault最终状态
│ • totalSupply: 10,000 YT │
│ • totalAssets: 10,000 WUSD │
│ • idleAssets: 10,000 WUSD │
│ • managedAssets: 0 WUSD │
│ │
│ 返回值: 10,000 YT │
└─────────────────────────────────────────────────────────────────────┘
3. 用户提款流程withdrawYT
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 用户 (User) │
│ 持有: 5,000 YT │
└────────────────────────────┬────────────────────────────────────────┘
│ 0. 预览操作(可选)
│ 调用 previewSell(5000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.sol │
│ ───────────────────────────────────────────────────────────────── │
│ function previewSell(5000e18) returns (uint256 wusdAmount) │
│ │
│ 计算逻辑: │
│ wusdAmount = (ytAmount × ytPrice) ÷ wusdPrice │
│ = (5,000 × 1.05e30) ÷ 1.05e30 │
│ = 5,000 WUSD │
│ │
│ 返回预览结果: 5,000 WUSD │
└─────────────────────────────────────────────────────────────────────┘
│ 1. 检查赎回时间(可选)
│ 调用 canRedeemNow()
┌─────────────────────────────────────────────────────────────────────┐
│ 赎回时间检查 │
│ ───────────────────────────────────────────────────────────────── │
│ function canRedeemNow() returns (bool) │
│ return block.timestamp >= nextRedemptionTime │
│ │
│ 检查: │
│ • 当前时间: 2025-02-16 10:00:00 (1739692800) │
│ • 赎回时间: 2025-02-15 00:00:00 (1739577600) │
│ • 1739692800 >= 1739577600 ✓ 可以赎回 │
│ │
│ getTimeUntilNextRedemption() = 0 秒 │
└─────────────────────────────────────────────────────────────────────┘
│ 2. 调用 withdrawYT(5000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.withdrawYT() │
│ ───────────────────────────────────────────────────────────────── │
│ function withdrawYT(uint256 _ytAmount) │
│ • 非重入保护: nonReentrant │
│ • 参数: 5,000 YT │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 多重验证
┌─────────────────────────────────────────────────────────────────────┐
│ 参数检查 │
│ ───────────────────────────────────────────────────────────────── │
│ ① _ytAmount > 0 │
│ ✓ 5,000 > 0 通过 │
│ │
│ ② balanceOf(msg.sender) >= _ytAmount │
│ ✓ 10,000 >= 5,000 通过 │
│ (用户持有足够的YT) │
│ │
│ ③ block.timestamp >= nextRedemptionTime │
│ ✓ 2025-02-16 >= 2025-02-15 通过 │
│ (已到赎回时间) │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 计算可获得的WUSD数量
┌─────────────────────────────────────────────────────────────────────┐
│ 计算WUSD数量 │
│ ───────────────────────────────────────────────────────────────── │
│ 公式wusdAmount = (ytAmount × ytPrice) ÷ wusdPrice │
│ │
│ 假设价格已更新: │
│ • wusdPrice = 1.00e30 (WUSD价格回落到1.0) │
│ • ytPrice = 1.10e30 (YT价格上涨到1.1) │
│ │
│ 计算过程: │
│ wusdAmount = (5,000e18 × 1.10e30) ÷ 1.00e30 │
│ = (5,000e18 × 1.10) ÷ 1.00 │
│ = 5,500e18 │
│ = 5,500 WUSD │
│ │
│ 用户获得收益: 5,500 - 5,000 = 500 WUSD (10%增值) │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 检查Vault流动性
┌─────────────────────────────────────────────────────────────────────┐
│ 流动性检查 │
│ ───────────────────────────────────────────────────────────────── │
│ uint256 availableWUSD = IERC20(wusdAddress).balanceOf(vault) │
│ if (wusdAmount > availableWUSD) revert InsufficientWUSD() │
│ │
│ 当前状态: │
│ • Vault中WUSD余额: 10,000 WUSD │
│ • 需要支付: 5,500 WUSD │
│ • 5,500 ≤ 10,000 ✓ 流动性充足 │
│ │
│ 注意: │
│ 如果manager已提取部分资金进行投资availableWUSD可能不足 │
│ 此时用户需要等待manager归还资金 │
└────────────────────────────┬────────────────────────────────────────┘
│ 6. 销毁用户的YTCEI - Effects
┌─────────────────────────────────────────────────────────────────────┐
│ 销毁YT代币 │
│ ───────────────────────────────────────────────────────────────── │
│ _burn(msg.sender, 5000e18) │
│ │
│ ERC20销毁
│ • balanceOf[user] -= 5,000 YT │
│ • totalSupply -= 5,000 YT │
│ │
│ 结果: │
│ • 用户YT余额: 10,000 → 5,000 YT │
│ • 总供应量: 10,000 → 5,000 YT │
└────────────────────────────┬────────────────────────────────────────┘
│ 7. 转出WUSD给用户
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移Interactions
│ ───────────────────────────────────────────────────────────────── │
│ IERC20(wusdAddress).safeTransfer( │
│ msg.sender, // 用户地址 │
│ 5500e18 // 转出5,500 WUSD │
│ ) │
│ │
│ 结果: │
│ • Vault WUSD余额: 10,000 → 4,500 │
│ • 用户WUSD余额: 0 → 5,500 │
└────────────────────────────┬────────────────────────────────────────┘
│ 8. 触发事件
┌─────────────────────────────────────────────────────────────────────┐
│ 事件记录 │
│ ───────────────────────────────────────────────────────────────── │
│ emit Sell( │
│ msg.sender, // 用户地址 │
│ 5000e18, // YT数量 │
│ 5500e18 // WUSD数量 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 9. 返回WUSD数量
┌─────────────────────────────────────────────────────────────────────┐
│ 提款完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 用户最终状态: │
│ • YT余额: 5,000 YT (剩余) │
│ • WUSD余额: 5,500 WUSD (获得) │
│ • 收益: 500 WUSD (10%增值) │
│ │
│ Vault最终状态
│ • totalSupply: 5,000 YT │
│ • totalAssets: 4,500 WUSD (假设无managedAssets) │
│ • idleAssets: 4,500 WUSD │
│ │
│ 返回值: 5,500 WUSD │
└─────────────────────────────────────────────────────────────────────┘
4. 价格更新流程
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Oracle / Manager │
│ 接收到最新价格数据: │
│ • WUSD价格: $1.02 │
│ • YT-A价格: $1.15 │
└────────────────────────────┬────────────────────────────────────────┘
│ 方式1: Manager直接更新
│ 调用 vault.updatePrices()
│ 方式2: Factory批量更新
│ 调用 factory.updateVaultPrices()
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.updatePrices() │
│ ───────────────────────────────────────────────────────────────── │
│ function updatePrices( │
│ uint256 _wusdPrice, // 1.02e30 │
│ uint256 _ytPrice // 1.15e30 │
│ ) external onlyManager │
│ │
│ 权限检查: │
│ • msg.sender == manager ✓ 或 │
│ • msg.sender == factory ✓ │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 价格验证
┌─────────────────────────────────────────────────────────────────────┐
│ 价格有效性检查 │
│ ───────────────────────────────────────────────────────────────── │
│ if (_wusdPrice == 0 || _ytPrice == 0) │
│ revert InvalidPrice() │
│ │
│ 检查: │
│ • _wusdPrice = 1.02e30 ≠ 0 ✓ │
│ • _ytPrice = 1.15e30 ≠ 0 ✓ │
│ │
│ 注意: │
│ • 价格必须 > 0 │
│ • 价格精度为1e30 │
│ • 没有时间间隔限制,可随时更新 │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 更新价格状态
┌─────────────────────────────────────────────────────────────────────┐
│ 更新存储状态 │
│ ───────────────────────────────────────────────────────────────── │
│ wusdPrice = _wusdPrice │
│ ytPrice = _ytPrice │
│ │
│ 更新前: │
│ • wusdPrice: 1.05e30 → 1.02e30 (下降2.86%) │
│ • ytPrice: 1.05e30 → 1.15e30 (上涨9.52%) │
│ │
│ 影响: │
│ ① 后续depositYT计算变化 │
│ ytAmount = wusdAmount × 1.02 / 1.15 │
│ → 用户用相同WUSD获得更少YT │
│ │
│ ② 后续withdrawYT计算变化 │
│ wusdAmount = ytAmount × 1.15 / 1.02 │
│ → 用户用相同YT获得更多WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 触发事件
┌─────────────────────────────────────────────────────────────────────┐
│ 事件记录 │
│ ───────────────────────────────────────────────────────────────── │
│ emit PriceUpdated( │
│ 1020000000000000000000000000000, // wusdPrice │
│ 1150000000000000000000000000000, // ytPrice │
│ 1739692800 // timestamp │
│ ) │
│ │
│ 链下监听: │
│ • 前端可监听此事件更新UI显示 │
│ • 用户可看到最新的兑换比率 │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 完成更新
┌─────────────────────────────────────────────────────────────────────┐
│ 更新完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 当前兑换比率示例: │
│ │
│ 存款 (depositYT): │
│ • 1,000 WUSD → (1,000 × 1.02) / 1.15 = 886.96 YT │
│ │
│ 提款 (withdrawYT): │
│ • 1,000 YT → (1,000 × 1.15) / 1.02 = 1,127.45 WUSD │
│ │
│ YT持有者收益
│ • 价格从1.05到1.15增值9.52% │
│ • 持有1,000 YT相当于价值1,127.45 WUSD │
└─────────────────────────────────────────────────────────────────────┘
5. 资产管理流程 - 提取投资
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Manager (资产管理员) │
│ 计划: 提取50,000 WUSD进行外部投资 │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 调用 withdrawForManagement()
│ _to: manager地址
│ _amount: 50,000 WUSD
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.withdrawForManagement() │
│ ───────────────────────────────────────────────────────────────── │
│ function withdrawForManagement( │
│ address _to, // 0x123... (manager) │
│ uint256 _amount // 50,000 WUSD │
│ ) external onlyManager nonReentrant │
│ │
│ 权限检查: │
│ ✓ onlyManager - 只有manager可调用 │
│ ✓ nonReentrant - 重入保护 │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 参数验证
┌─────────────────────────────────────────────────────────────────────┐
│ 验证检查 │
│ ───────────────────────────────────────────────────────────────── │
│ ① if (_amount == 0) revert InvalidAmount() │
│ ✓ 50,000 > 0 通过 │
│ │
│ ② uint256 availableAssets = vault.balance(WUSD) │
│ if (_amount > availableAssets) revert InvalidAmount() │
│ │
│ Vault当前状态
│ • totalAssets: 100,000 WUSD │
│ • idleAssets: 100,000 WUSD (全部在vault中) │
│ • managedAssets: 0 WUSD │
│ │
│ 检查: │
│ • availableAssets = 100,000 WUSD │
│ • 50,000 ≤ 100,000 ✓ 通过 │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 更新managedAssetsCEI - Effects
┌─────────────────────────────────────────────────────────────────────┐
│ 状态更新 │
│ ───────────────────────────────────────────────────────────────── │
│ managedAssets += _amount │
│ │
│ 更新: │
│ • managedAssets: 0 → 50,000 WUSD │
│ │
│ 重要说明: │
│ managedAssets记录了被管理员提取、正在进行外部投资的WUSD数量 │
│ 这部分资产不在vault合约中但仍计入totalAssets │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 转出WUSDInteractions
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移 │
│ ───────────────────────────────────────────────────────────────── │
│ IERC20(wusdAddress).safeTransfer( │
│ _to, // manager地址 │
│ 50000e18 // 50,000 WUSD │
│ ) │
│ │
│ 转账结果: │
│ • Vault WUSD余额: 100,000 → 50,000 WUSD │
│ • Manager WUSD余额: +50,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 触发事件
┌─────────────────────────────────────────────────────────────────────┐
│ 事件记录 │
│ ───────────────────────────────────────────────────────────────── │
│ emit AssetsWithdrawn( │
│ 0x123..., // manager地址 │
│ 50000e18 // 提取数量 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 6. 提取完成
┌─────────────────────────────────────────────────────────────────────┐
│ 提取完成 │
│ ───────────────────────────────────────────────────────────────── │
│ Vault最终状态
│ • totalAssets(): 100,000 WUSD (不变!) │
│ 计算: idleAssets + managedAssets │
│ = 50,000 + 50,000 = 100,000 │
│ │
│ • idleAssets(): 50,000 WUSD │
│ (vault合约实际持有的WUSD) │
│ │
│ • managedAssets: 50,000 WUSD │
│ (manager正在管理的WUSD) │
│ │
│ • totalSupply: 100,000 YT (不变) │
│ │
│ 用户影响: │
│ ✓ totalAssets不变YT价值不受影响 │
│ ✓ 用户依然持有相同价值的YT份额 │
│ ✗ 暂时无法提款流动性不足需等待manager归还 │
│ │
│ Manager后续操作
│ → 用50,000 WUSD进行DeFi投资 │
│ → 赚取收益 │
│ → 通过depositManagedAssets归还 │
└─────────────────────────────────────────────────────────────────────┘
6. 资产管理流程 - 归还资产
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Manager (资产管理员) │
│ 投资收益情况: │
│ • 提取: 50,000 WUSD │
│ • 投资收益: +5,000 WUSD │
│ • 准备归还: 55,000 WUSD (本金+利润) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 授权WUSD给Vault
│ WUSD.approve(vault, 55000e18)
┌─────────────────────────────────────────────────────────────────────┐
│ WUSD授权检查 │
│ ✓ allowance[manager][vault] >= 55,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 调用 depositManagedAssets()
│ _amount: 55,000 WUSD
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.depositManagedAssets() │
│ ───────────────────────────────────────────────────────────────── │
│ function depositManagedAssets( │
│ uint256 _amount // 55,000 WUSD │
│ ) external onlyManager nonReentrant │
│ │
│ 权限检查: │
│ ✓ onlyManager - 只有manager可调用 │
│ ✓ nonReentrant - 重入保护 │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 参数验证
┌─────────────────────────────────────────────────────────────────────┐
│ 验证检查 │
│ ───────────────────────────────────────────────────────────────── │
│ if (_amount == 0) revert InvalidAmount() │
│ ✓ 55,000 > 0 通过 │
│ │
│ 当前Vault状态
│ • idleAssets: 50,000 WUSD │
│ • managedAssets: 50,000 WUSD │
│ • totalAssets: 100,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 更新managedAssetsCEI - Effects
┌─────────────────────────────────────────────────────────────────────┐
│ 状态更新(关键逻辑) │
│ ───────────────────────────────────────────────────────────────── │
│ if (_amount >= managedAssets) { │
│ // 归还金额 >= 提取金额清零managedAssets │
│ managedAssets = 0 │
│ } else { │
│ // 归还金额 < 提取金额部分归还
│ managedAssets -= _amount │
│ } │
│ │
│ 本例计算: │
│ • _amount = 55,000 WUSD │
│ • managedAssets = 50,000 WUSD │
│ • 55,000 >= 50,000 ✓ 进入第一个分支 │
│ • managedAssets = 0 │
│ │
│ 多余的5,000 WUSD如何处理
│ → 自动增加到vault余额成为利润 │
│ → totalAssets会增加 │
│ → 所有YT持有者共享这部分收益 │
└────────────────────────────┬────────────────────────────────────────┘
│ 5. 转入WUSDInteractions
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移 │
│ ───────────────────────────────────────────────────────────────── │
│ IERC20(wusdAddress).safeTransferFrom( │
│ msg.sender, // manager地址 │
│ address(this), // vault地址 │
│ 55000e18 // 55,000 WUSD │
│ ) │
│ │
│ 转账结果: │
│ • Manager WUSD余额: -55,000 WUSD │
│ • Vault WUSD余额: 50,000 → 105,000 WUSD │
└────────────────────────────┬────────────────────────────────────────┘
│ 6. 触发事件
┌─────────────────────────────────────────────────────────────────────┐
│ 事件记录 │
│ ───────────────────────────────────────────────────────────────── │
│ emit AssetsDeposited( │
│ 55000e18 // 归还数量 │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 7. 归还完成
┌─────────────────────────────────────────────────────────────────────┐
│ 归还完成 │
│ ───────────────────────────────────────────────────────────────── │
│ Vault最终状态
│ • totalAssets(): 105,000 WUSD (增加了5,000!) │
│ 计算: idleAssets + managedAssets │
│ = 105,000 + 0 = 105,000 │
│ │
│ • idleAssets(): 105,000 WUSD │
│ (vault合约实际持有的WUSD包含收益) │
│ │
│ • managedAssets: 0 WUSD │
│ (所有资产已归还) │
│ │
│ • totalSupply: 100,000 YT (不变) │
│ │
│ 收益分配: │
│ • 投资收益: 5,000 WUSD │
│ • 收益率: 5,000 / 50,000 = 10% │
│ • 每个YT的价值提升: │
│ 之前: 100,000 WUSD / 100,000 YT = 1.0 WUSD/YT │
│ 现在: 105,000 WUSD / 100,000 YT = 1.05 WUSD/YT │
│ │
│ 用户影响: │
│ ✓ 所有YT持有者自动获得5%增值 │
│ ✓ 可以提款了(流动性恢复) │
│ ✓ 如果用户提取YT会按1.05的比例获得更多WUSD │
│ │
│ 示例: │
│ 用户持有10,000 YT提取时可获得
│ (10,000 × 1.05 WUSD/YT) = 10,500 WUSD │
│ 相比初始存入的10,000 WUSD获利500 WUSD (5%) │
└─────────────────────────────────────────────────────────────────────┘
7. 批量操作流程
7.1 批量创建Vault
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Owner (系统管理员) │
│ 计划: 批量创建3个不同的YT Vault │
└────────────────────────────┬────────────────────────────────────────┘
│ 调用 createVaultBatch()
│ • names: ["YT-A", "YT-B", "YT-C"]
│ • symbols: ["YTA", "YTB", "YTC"]
│ • managers: [0x111, 0x222, 0x333]
│ • hardCaps: [1000000e18, 500000e18, 2000000e18]
│ • wusd: 0x7Cd...
│ • redemptionTimes: [time1, time2, time3]
│ • initialWusdPrices: [1.05e30, 1.05e30, 1.05e30]
│ • initialYtPrices: [1.05e30, 1.02e30, 1.10e30]
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetFactory.createVaultBatch() │
│ ───────────────────────────────────────────────────────────────── │
│ 1. 参数长度验证 │
│ require(所有数组长度相等) │
│ ✓ 所有数组长度都是3 │
│ │
│ 2. 循环创建 │
│ for (i = 0; i < 3; i++) {
│ vaults[i] = this.createVault(...) │
│ } │
└────────────────────────────┬────────────────────────────────────────┘
├─────────┬─────────┐
│ │ │
第1个Vault │ 第2个Vault │ 第3个Vault
▼ │ ▼ │ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ YT-A Token │ │ YT-B Token │ │ YT-C Token │
│ Symbol: YTA │ │ Symbol: YTB │ │ Symbol: YTC │
│ Manager: 0x111 │ │ Manager: 0x222 │ │ Manager: 0x333 │
│ HardCap: 1M YT │ │ HardCap: 500K YT │ │ HardCap: 2M YT │
│ YT Price: 1.05 │ │ YT Price: 1.02 │ │ YT Price: 1.10 │
│ 地址: 0xVault001 │ │ 地址: 0xVault002 │ │ 地址: 0xVault003 │
└───────────────────┘ └───────────────────┘ └───────────────────┘
│ │ │
└─────────┴─────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 批量创建完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 返回值: [0xVault001, 0xVault002, 0xVault003] │
│ │
│ Factory状态
│ • allVaults.length: 3 │
│ • isVault[0xVault001] = true │
│ • isVault[0xVault002] = true │
│ • isVault[0xVault003] = true │
│ │
│ 优势: │
│ ✓ 一次交易创建多个vault节省gas │
│ ✓ 原子操作,全部成功或全部失败 │
│ ✓ 统一管理多个资产池 │
└─────────────────────────────────────────────────────────────────────┘
7.2 批量更新价格
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Oracle / Owner │
│ 接收到3个vault的最新价格数据 │
└────────────────────────────┬────────────────────────────────────────┘
│ 调用 updateVaultPricesBatch()
│ • vaults: [0xVault001, 0xVault002, 0xVault003]
│ • wusdPrices: [1.02e30, 1.03e30, 1.01e30]
│ • ytPrices: [1.15e30, 1.08e30, 1.20e30]
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetFactory.updateVaultPricesBatch() │
│ ───────────────────────────────────────────────────────────────── │
│ 1. 参数验证 │
│ require(数组长度相等) │
│ ✓ 所有数组长度都是3 │
│ │
│ 2. 循环更新 │
│ for (i = 0; i < 3; i++) {
│ YTAssetVault(vaults[i]).updatePrices( │
│ wusdPrices[i], │
│ ytPrices[i] │
│ ) │
│ emit PricesUpdated(vaults[i], wusdPrices[i], ytPrices[i]) │
│ } │
└────────────────────────────┬────────────────────────────────────────┘
├─────────┬─────────┐
│ │ │
Vault001 │ Vault002 │ Vault003
价格更新 │ 价格更新 │ 价格更新
▼ │ ▼ │ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ WUSD: 1.02 │ │ WUSD: 1.03 │ │ WUSD: 1.01 │
│ YT: 1.15 │ │ YT: 1.08 │ │ YT: 1.20 │
│ 涨幅: +9.52% │ │ 涨幅: +2.88% │ │ 涨幅: +9.09% │
└───────────────────┘ └───────────────────┘ └───────────────────┘
│ │ │
└─────────┴─────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 批量更新完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 优势: │
│ ✓ 一次交易更新多个vault价格 │
│ ✓ 节省gas费用 │
│ ✓ 确保所有vault价格同时更新 │
│ ✓ 适合定时任务批量更新 │
│ │
│ 触发的事件: │
│ • PricesUpdated × 3 │
│ • PriceUpdated × 3 (从各个vault) │
└─────────────────────────────────────────────────────────────────────┘
7.3 批量设置赎回时间
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ Owner (系统管理员) │
│ 统一设置赎回时间: 2025-03-15 00:00:00 │
└────────────────────────────┬────────────────────────────────────────┘
│ 调用 setVaultNextRedemptionTimeBatch()
│ • vaults: [0xVault001, 0xVault002, 0xVault003]
│ • nextRedemptionTime: 1741996800
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetFactory.setVaultNextRedemptionTimeBatch() │
│ ───────────────────────────────────────────────────────────────── │
│ for (i = 0; i < vaults.length; i++) {
│ YTAssetVault(vaults[i]).setNextRedemptionTime( │
│ _nextRedemptionTime │
│ ) │
│ emit NextRedemptionTimeSet(vaults[i], _nextRedemptionTime) │
│ } │
└────────────────────────────┬────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 批量设置完成 │
│ ───────────────────────────────────────────────────────────────── │
│ 所有3个vault的赎回时间都设置为: │
│ 2025-03-15 00:00:00 │
│ │
│ 用户影响: │
│ ✓ 所有vault的用户在同一天可以赎回 │
│ ✓ 统一管理赎回周期 │
│ ✓ 类似基金的统一开放日 │
└─────────────────────────────────────────────────────────────────────┘
8. 查询信息流程
8.1 查询单个Vault信息
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 前端应用 / 查询者 │
└────────────────────────────┬────────────────────────────────────────┘
│ 调用 vault.getVaultInfo()
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetVault.getVaultInfo() │
│ ───────────────────────────────────────────────────────────────── │
│ function getVaultInfo() returns ( │
│ uint256 _totalAssets, │
│ uint256 _idleAssets, │
│ uint256 _managedAssets, │
│ uint256 _totalSupply, │
│ uint256 _hardCap, │
│ uint256 _wusdPrice, │
│ uint256 _ytPrice, │
│ uint256 _nextRedemptionTime │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 读取状态
┌─────────────────────────────────────────────────────────────────────┐
│ 返回完整信息 │
│ ───────────────────────────────────────────────────────────────── │
│ 返回示例: │
│ { │
│ totalAssets: 105000e18, // 105,000 WUSD │
│ idleAssets: 105000e18, // 105,000 WUSD │
│ managedAssets: 0, // 0 WUSD │
│ totalSupply: 100000e18, // 100,000 YT │
│ hardCap: 1000000e18, // 1,000,000 YT │
│ wusdPrice: 1020000000000000000000000000000, // 1.02 │
│ ytPrice: 1150000000000000000000000000000, // 1.15 │
│ nextRedemptionTime: 1739577600 // 2025-02-15 00:00:00 │
│ } │
│ │
│ 计算衍生指标: │
│ • 每YT价值: 105,000 / 100,000 = 1.05 WUSD │
│ • 资金利用率: (105,000 - 0) / 105,000 = 100% │
│ • 硬顶使用率: 100,000 / 1,000,000 = 10% │
│ • 当前兑换率: 1 WUSD = 1.02/1.15 = 0.887 YT │
└─────────────────────────────────────────────────────────────────────┘
8.2 通过Factory查询Vault信息
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 前端应用 / 查询者 │
└────────────────────────────┬────────────────────────────────────────┘
│ 调用 factory.getVaultInfo(vaultAddress)
┌─────────────────────────────────────────────────────────────────────┐
│ YTAssetFactory.getVaultInfo() │
│ ───────────────────────────────────────────────────────────────── │
│ function getVaultInfo(address _vault) returns ( │
│ bool exists, │
│ uint256 totalAssets, │
│ uint256 idleAssets, │
│ uint256 managedAssets, │
│ uint256 totalSupply, │
│ uint256 hardCap, │
│ uint256 wusdPrice, │
│ uint256 ytPrice, │
│ uint256 nextRedemptionTime │
│ ) │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 检查vault是否存在
┌─────────────────────────────────────────────────────────────────────┐
│ 存在性检查 │
│ ───────────────────────────────────────────────────────────────── │
│ exists = isVault[_vault] │
│ if (!exists) return (false, 0, 0, 0, 0, 0, 0, 0, 0) │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 调用vault获取信息
┌─────────────────────────────────────────────────────────────────────┐
│ 返回完整信息 │
│ ───────────────────────────────────────────────────────────────── │
│ { │
│ exists: true, // ✓ vault存在 │
│ totalAssets: 105000e18, │
│ idleAssets: 105000e18, │
│ managedAssets: 0, │
│ totalSupply: 100000e18, │
│ hardCap: 1000000e18, │
│ wusdPrice: 1020000000000000000000000000000, │
│ ytPrice: 1150000000000000000000000000000, │
│ nextRedemptionTime: 1739577600 │
│ } │
│ │
│ 优势: │
│ ✓ 通过factory统一查询 │
│ ✓ 可验证vault是否为合法vault │
│ ✓ 一次调用获取所有信息 │
└─────────────────────────────────────────────────────────────────────┘
8.3 查询所有Vault列表
Plain Text
┌─────────────────────────────────────────────────────────────────────┐
│ 前端应用 / 查询者 │
└────────────────────────────┬────────────────────────────────────────┘
│ 1. 获取总数量
│ factory.getVaultCount()
┌─────────────────────────────────────────────────────────────────────┐
│ 获取Vault总数 │
│ ───────────────────────────────────────────────────────────────── │
│ function getVaultCount() returns (uint256) │
│ return allVaults.length │
│ │
│ 返回: 3 (有3个vault) │
└────────────────────────────┬────────────────────────────────────────┘
│ 2. 获取所有vault地址
│ factory.getAllVaults()
┌─────────────────────────────────────────────────────────────────────┐
│ 获取所有Vault地址 │
│ ───────────────────────────────────────────────────────────────── │
│ function getAllVaults() returns (address[] memory) │
│ return allVaults │
│ │
│ 返回: [0xVault001, 0xVault002, 0xVault003] │
└────────────────────────────┬────────────────────────────────────────┘
│ 3. 或分页查询
│ factory.getVaults(0, 2)
┌─────────────────────────────────────────────────────────────────────┐
│ 分页查询Vault地址 │
│ ───────────────────────────────────────────────────────────────── │
│ function getVaults(uint256 _start, uint256 _end) │
│ │
│ 参数: │
│ • _start: 0 (起始索引) │
│ • _end: 2 (结束索引,不包含) │
│ │
│ 返回: [0xVault001, 0xVault002] │
│ │
│ 优势: │
│ ✓ 适合vault数量很多时的分页加载 │
│ ✓ 减少单次调用的gas消耗 │
│ ✓ 改善前端加载性能 │
└─────────────────────────────────────────────────────────────────────┘
附录:重要概念说明
A. 价格精度 (PRICE_PRECISION)
Plain Text
精度: 1e30 (10^30)
示例:
• 价格 1.0 表示为: 1000000000000000000000000000000 (1e30)
• 价格 1.05 表示为: 1050000000000000000000000000000 (1.05e30)
• 价格 0.98 表示为: 980000000000000000000000000000 (0.98e30)
为什么使用1e30而不是1e18
✓ 更高的精度,减少舍入误差
✓ 适合复杂的价格计算
✓ 支持更精确的价格波动
B. 兑换计算公式
Plain Text
存款 (depositYT):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ytAmount = (wusdAmount × wusdPrice) ÷ ytPrice
示例:
• 存入1,000 WUSD
• wusdPrice = 1.05e30
• ytPrice = 1.10e30
• ytAmount = (1,000 × 1.05) ÷ 1.10 = 954.55 YT
提款 (withdrawYT):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
wusdAmount = (ytAmount × ytPrice) ÷ wusdPrice
示例:
• 提取1,000 YT
• ytPrice = 1.10e30
• wusdPrice = 1.05e30
• wusdAmount = (1,000 × 1.10) ÷ 1.05 = 1,047.62 WUSD
C. 资产状态计算
Plain Text
Vault资产状态
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
totalAssets = idleAssets + managedAssets
• idleAssets: vault合约中实际持有的WUSD
• managedAssets: manager提取、正在投资的WUSD
• totalAssets: 用户可赎回的总价值
示例:
vault余额: 50,000 WUSD
managedAssets: 50,000 WUSD
totalAssets: 100,000 WUSD (不变)
用户持有10,000 YT价值:
(10,000 / 100,000) × 100,000 = 10,000 WUSD
D. 硬顶机制
Plain Text
硬顶 (Hard Cap):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
限制YT代币的最大供应量
作用:
✓ 控制vault规模
✓ 风险管理
✓ 防止过度铸造
检查时机:
• 每次depositYT时检查
• if (totalSupply + ytAmount > hardCap) revert
动态调整:
• Factory owner可以通过setHardCap调整
• 但不能低于当前totalSupply
E. 统一赎回时间
Plain Text
赎回时间 (nextRedemptionTime):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
所有用户统一的赎回开放时间
特点:
✓ 类似基金的开放日
✓ 所有用户同时可赎回
✓ 不是个人锁定期
检查:
• block.timestamp >= nextRedemptionTime
• 未到时间调用withdrawYT会revert
管理:
• Factory owner可以设置
• 支持批量设置多个vault