Files
Heyue_test/document/Vault金库系统操作流程文档.md
2025-12-15 14:45:51 +00:00

1185 lines
106 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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