2189 lines
175 KiB
Markdown
2189 lines
175 KiB
Markdown
# YT资产金库系统操作流程图
|
||
|
||
## 重要说明
|
||
本系统使用 USDC 作为支付代币,USDC 价格通过 Chainlink 价格预言机实时获取。
|
||
|
||
## 目录
|
||
1. [创建Vault流程](#1-创建vault流程)
|
||
2. [用户存款流程(depositYT)](#2-用户存款流程deposityt)
|
||
3. [用户提款流程(withdrawYT - 两阶段提现)](#3-用户提款流程withdrawyt---两阶段提现)
|
||
- 3.1 [第一阶段:提交提现请求](#31-第一阶段提交提现请求)
|
||
- 3.2 [第二阶段:批量处理提现请求](#32-第二阶段批量处理提现请求)
|
||
- 3.3 [资金不足时的处理](#33-资金不足时的处理)
|
||
4. [价格更新流程](#4-价格更新流程)
|
||
5. [资产管理流程 - 提取投资](#5-资产管理流程---提取投资)
|
||
6. [资产管理流程 - 归还资产](#6-资产管理流程---归还资产)
|
||
7. [批量操作流程](#7-批量操作流程)
|
||
8. [查询信息流程](#8-查询信息流程)
|
||
9. [暂停功能流程](#9-暂停功能流程)
|
||
|
||
---
|
||
|
||
## 1. 创建Vault流程
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Owner (系统管理员) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 createVault()
|
||
│ name: "YT-A Token"
|
||
│ symbol: "YT-A"
|
||
│ manager: 0x123...
|
||
│ hardCap: 1,000,000 YT
|
||
│ usdc: 0x7Cd...(或0使用默认BSC USDC)
|
||
│ redemptionTime: 2025-02-15 00:00:00
|
||
│ initialYtPrice: 1.05e30
|
||
│ usdcPriceFeed: 0xABC...(Chainlink价格Feed)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 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..., // usdc地址 │
|
||
│ 1739577600, // redemptionTime (Unix时间戳) │
|
||
│ 1050000000000000000000000000000, // initialYtPrice (1.05e30) │
|
||
│ 0xABC... // usdcPriceFeed地址 │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 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 │
|
||
│ usdcAddress = 0x7Cd... │
|
||
│ usdcPriceFeed = 0xABC... (Chainlink价格Feed) │
|
||
│ usdcDecimals = 18 (从USDC合约读取,BSC主网为18) │
|
||
│ │
|
||
│ ⑤ __Pausable_init() │
|
||
│ • 初始化暂停功能(默认未暂停) │
|
||
│ │
|
||
│ ⑥ 设置价格(精度1e30) │
|
||
│ ytPrice = 1.05e30 (初始YT价格1.05) │
|
||
│ 注意:USDC价格通过Chainlink实时获取,不存储 │
|
||
│ │
|
||
│ ⑦ 设置赎回时间 │
|
||
│ 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 USDC │
|
||
│ • ytPrice: 1.05 (精度1e30) │
|
||
│ • usdcPrice: 通过Chainlink实时获取 (~$1.00, 精度1e8) │
|
||
│ • hardCap: 1,000,000 YT │
|
||
│ • nextRedemptionTime: 2025-02-15 00:00:00 │
|
||
│ • 可接受用户存款 ✓ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 用户存款流程(depositYT)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 用户 (User) │
|
||
│ 持有: 10,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 0. 预览操作(可选)
|
||
│ 调用 previewBuy(10000e18)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.sol │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function previewBuy(10000e18) returns (uint256 ytAmount) │
|
||
│ │
|
||
│ 计算逻辑: │
|
||
│ ytAmount = (usdcAmount × usdcPrice) ÷ ytPrice │
|
||
│ = (10,000 × 1.05e30) ÷ 1.05e30 │
|
||
│ = 10,000 YT │
|
||
│ │
|
||
│ 返回预览结果: 10,000 YT │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
│ 1. 授权USDC给Vault
|
||
│ USDC.approve(vault, 10000e18)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ USDC授权检查 │
|
||
│ ✓ allowance[user][vault] >= 10,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 调用 depositYT(10000e18)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.depositYT() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function depositYT(uint256 _usdcAmount) │
|
||
│ • 非重入保护: nonReentrant │
|
||
│ • 暂停检查: whenNotPaused │
|
||
│ • 参数: 10,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 参数验证
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 参数检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ ① _usdcAmount > 0 │
|
||
│ ✓ 10,000 > 0 通过 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 计算可获得的YT数量
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 计算YT数量 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 公式:ytAmount = (usdcAmount × usdcPrice) ÷ ytPrice │
|
||
│ │
|
||
│ 当前价格: │
|
||
│ • usdcPrice = 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. 转入USDC(CEI模式 - Checks完成)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 代币转移(Effects) │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ IERC20(usdcAddress).safeTransferFrom( │
|
||
│ msg.sender, // 用户地址 │
|
||
│ address(this), // Vault地址 │
|
||
│ 10000e18 // 转入10,000 USDC │
|
||
│ ) │
|
||
│ │
|
||
│ 结果: │
|
||
│ • 用户USDC余额: 10,000 → 0 │
|
||
│ • Vault USDC余额: 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, // USDC数量 │
|
||
│ 10000e18 // YT数量 │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 9. 返回YT数量
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 存款完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 用户最终状态: │
|
||
│ • USDC余额: 0 │
|
||
│ • YT余额: 10,000 YT │
|
||
│ │
|
||
│ Vault最终状态: │
|
||
│ • totalSupply: 10,000 YT │
|
||
│ • totalAssets: 10,000 USDC │
|
||
│ • idleAssets: 10,000 USDC │
|
||
│ • managedAssets: 0 USDC │
|
||
│ │
|
||
│ 返回值: 10,000 YT │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 用户提款流程(withdrawYT - 两阶段提现)
|
||
|
||
### 3.1 第一阶段:提交提现请求
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 用户 (User) │
|
||
│ 持有: 5,000 YT │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 0. 预览操作(可选)
|
||
│ 调用 previewSell(5000e18)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.sol │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function previewSell(5000e18) returns (uint256 usdcAmount) │
|
||
│ │
|
||
│ 计算逻辑: │
|
||
│ usdcAmount = (ytAmount × ytPrice) ÷ usdcPrice │
|
||
│ = (5,000 × 1.05e30) ÷ 1.05e30 │
|
||
│ = 5,000 USDC │
|
||
│ │
|
||
│ 返回预览结果: 5,000 USDC │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
│ 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) returns (uint256 requestId) │
|
||
│ • 非重入保护: nonReentrant │
|
||
│ • 暂停检查: whenNotPaused │
|
||
│ • 参数: 5,000 YT │
|
||
│ │
|
||
│ 🔴 重要变化:此函数不再立即发放USDC! │
|
||
│ 只创建提现请求,进入排队等待 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 多重验证
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 参数检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ ① _ytAmount > 0 │
|
||
│ ✓ 5,000 > 0 通过 │
|
||
│ │
|
||
│ ② balanceOf(msg.sender) >= _ytAmount │
|
||
│ ✓ 10,000 >= 5,000 通过 │
|
||
│ (用户持有足够的YT) │
|
||
│ │
|
||
│ ③ block.timestamp >= nextRedemptionTime │
|
||
│ ✓ 2025-02-16 >= 2025-02-15 通过 │
|
||
│ (已到赎回时间) │
|
||
│ │
|
||
│ ⚠️ 不再检查流动性!即使vault中USDC不足也可以提交请求 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 计算应得的USDC数量
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 计算USDC数量 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 公式:usdcAmount = (ytAmount × ytPrice) ÷ usdcPrice │
|
||
│ │
|
||
│ 假设价格已更新: │
|
||
│ • usdcPrice = 1.00e30 (USDC价格回落到1.0) │
|
||
│ • ytPrice = 1.10e30 (YT价格上涨到1.1) │
|
||
│ │
|
||
│ 计算过程: │
|
||
│ usdcAmount = (5,000e18 × 1.10e30) ÷ 1.00e30 │
|
||
│ = 5,500e18 │
|
||
│ = 5,500 USDC │
|
||
│ │
|
||
│ 💡 这个金额会锁定在请求中,不受后续价格变化影响 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 5. 立即销毁YT代币(CEI - 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 │
|
||
│ │
|
||
│ ⚠️ 注意:YT已销毁,但USDC还未发放! │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 6. 创建提现请求记录
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 创建WithdrawRequest │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ requestId = requestIdCounter // 当前假设为 requestId = 42 │
|
||
│ │
|
||
│ withdrawRequests[42] = WithdrawRequest({ │
|
||
│ user: msg.sender, // 用户地址 │
|
||
│ ytAmount: 5000e18, // 5,000 YT │
|
||
│ usdcAmount: 5500e18, // 应得5,500 USDC │
|
||
│ requestTime: block.timestamp, // 当前时间戳 │
|
||
│ queueIndex: 42, // 队列位置 │
|
||
│ processed: false // 未处理 │
|
||
│ }) │
|
||
│ │
|
||
│ userRequestIds[msg.sender].push(42) // 记录到用户请求列表 │
|
||
│ requestIdCounter++ // 43 │
|
||
│ pendingRequestsCount++ // 待处理计数+1 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 7. 触发事件
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 事件记录 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ emit WithdrawRequestCreated( │
|
||
│ 42, // requestId │
|
||
│ msg.sender, // 用户地址 │
|
||
│ 5000e18, // YT数量 │
|
||
│ 5500e18, // 应得USDC数量 │
|
||
│ 42 // queueIndex │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 8. 返回请求ID
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 请求提交完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 返回值: requestId = 42 │
|
||
│ │
|
||
│ 用户当前状态: │
|
||
│ • YT余额: 5,000 YT (已减少) │
|
||
│ • USDC余额: 0 USDC (尚未到账) ⏳ │
|
||
│ • 提现请求: requestId = 42 (排队中) │
|
||
│ │
|
||
│ Vault状态: │
|
||
│ • totalSupply: 5,000 YT (已减少) │
|
||
│ • pendingRequestsCount: +1 │
|
||
│ • requestIdCounter: 43 │
|
||
│ │
|
||
│ 📍 下一步: │
|
||
│ 用户需要等待Manager或Factory调用processBatchWithdrawals() │
|
||
│ 批量处理提现请求后,USDC才会到账 │
|
||
│ │
|
||
│ 查询请求状态: │
|
||
│ • getRequestDetails(42) - 查看请求详情 │
|
||
│ • getUserPendingRequests(user) - 查看所有待处理请求 │
|
||
│ • getQueueProgress() - 查看队列处理进度 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.2 第二阶段:批量处理提现请求
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Manager/Factory (资产管理方) │
|
||
│ 当前状态: │
|
||
│ • Vault中有足够的USDC (基金赎回资金已到账) │
|
||
│ • 待处理请求: 150个 │
|
||
│ • 准备批量发放USDC给用户 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 查询队列状态(可选)
|
||
│ getQueueProgress()
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 查询队列进度 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getQueueProgress() returns ( │
|
||
│ uint256 currentIndex, // 当前处理到的位置: 100 │
|
||
│ uint256 totalRequests, // 总请求数: 250 │
|
||
│ uint256 pendingRequests // 待处理数: 150 │
|
||
│ ) │
|
||
│ │
|
||
│ 状态信息: │
|
||
│ • 已处理: 100个请求 │
|
||
│ • 待处理: 150个请求 │
|
||
│ • 处理进度: 100/250 = 40% │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
│ 2. 调用 processBatchWithdrawals(50)
|
||
│ 每批处理50个请求
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.processBatchWithdrawals() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function processBatchWithdrawals(uint256 _batchSize) │
|
||
│ returns (uint256 processedCount, uint256 totalDistributed) │
|
||
│ │
|
||
│ 参数: │
|
||
│ • _batchSize: 50 (本批次最多处理50个) │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ • msg.sender == manager ✓ 或 │
|
||
│ • msg.sender == factory ✓ │
|
||
│ │
|
||
│ 保护机制: │
|
||
│ • nonReentrant - 重入保护 │
|
||
│ • whenNotPaused - 暂停检查 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 验证批次大小
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 参数检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ if (_batchSize == 0) revert InvalidBatchSize() │
|
||
│ ✓ 50 > 0 通过 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 获取可用USDC并开始循环处理
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 循环处理请求 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ uint256 availableUSDC = vault.balance(USDC) // 假设: 100,000 USDC │
|
||
│ uint256 processedCount = 0 │
|
||
│ uint256 totalDistributed = 0 │
|
||
│ │
|
||
│ for (i = processedUpToIndex; i < requestIdCounter; i++) { │
|
||
│ if (processedCount >= _batchSize) break // 达到批次限制 │
|
||
│ │
|
||
│ WithdrawRequest storage request = withdrawRequests[i] │
|
||
│ │
|
||
│ if (request.processed) continue // 跳过已处理的 │
|
||
│ │
|
||
│ if (availableUSDC >= request.usdcAmount) { │
|
||
│ // ✅ 可以处理此请求 │
|
||
│ 处理逻辑 ▼ │
|
||
│ } else { │
|
||
│ // ❌ USDC不足,停止处理 │
|
||
│ break │
|
||
│ } │
|
||
│ } │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 5. 处理单个请求(循环内)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 处理请求详细步骤 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 以 requestId = 42 为例: │
|
||
│ │
|
||
│ ① 转账USDC给用户 │
|
||
│ IERC20(usdc).safeTransfer(request.user, 5500e18) │
|
||
│ • 用户USDC余额: 0 → 5,500 USDC ✅ │
|
||
│ │
|
||
│ ② 标记为已处理 │
|
||
│ request.processed = true │
|
||
│ │
|
||
│ ③ 更新统计数据 │
|
||
│ availableUSDC -= 5500e18 // 剩余可用USDC减少 │
|
||
│ totalDistributed += 5500e18 // 累计发放增加 │
|
||
│ processedCount++ // 处理计数+1 │
|
||
│ pendingRequestsCount-- // 待处理计数-1 │
|
||
│ │
|
||
│ ④ 触发事件 │
|
||
│ emit WithdrawRequestProcessed(42, user, 5500e18) │
|
||
│ │
|
||
│ 然后继续处理下一个请求... │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 6. 更新处理进度指针
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 更新processedUpToIndex │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ if (processedCount > 0) { │
|
||
│ // 找到下一个未处理的位置 │
|
||
│ for (i = processedUpToIndex; i < requestIdCounter; i++) { │
|
||
│ if (!withdrawRequests[i].processed) { │
|
||
│ processedUpToIndex = i │
|
||
│ break │
|
||
│ } │
|
||
│ } │
|
||
│ } │
|
||
│ │
|
||
│ 更新结果: │
|
||
│ • processedUpToIndex: 100 → 150 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 7. 触发批次处理事件
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 批次处理完成事件 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ emit BatchProcessed( │
|
||
│ 100, // startIndex (开始位置) │
|
||
│ 150, // endIndex (结束位置) │
|
||
│ 50, // processedCount (实际处理数量) │
|
||
│ 275000e18 // totalDistributed (总发放USDC) │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 8. 返回处理结果
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 批量处理完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 返回值: │
|
||
│ • processedCount: 50 (处理了50个请求) │
|
||
│ • totalDistributed: 275,000 USDC (总共发放) │
|
||
│ │
|
||
│ 更新后的状态: │
|
||
│ • pendingRequestsCount: 150 → 100 (还剩100个待处理) │
|
||
│ • processedUpToIndex: 100 → 150 │
|
||
│ • Vault USDC余额: 100,000 → (100,000 - 275,000) = -175,000 ❌ │
|
||
│ (这里假设vault有足够资金,实际会提前检查) │
|
||
│ │
|
||
│ 用户影响(requestId = 42的用户): │
|
||
│ ✅ YT余额: 5,000 YT (已销毁) │
|
||
│ ✅ USDC余额: 5,500 USDC (已到账!) │
|
||
│ ✅ 提现完成,可以自由使用USDC │
|
||
│ │
|
||
│ 队列状态: │
|
||
│ • 已处理: 150/250 = 60% │
|
||
│ • 待处理: 100个 │
|
||
│ • 可继续调用processBatchWithdrawals()处理剩余请求 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.3 资金不足时的处理
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 场景:USDC资金不足 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 当前状态: │
|
||
│ • Vault中USDC: 50,000 │
|
||
│ • 待处理请求: 100个 │
|
||
│ • 前10个请求需要: 60,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 调用 processBatchWithdrawals(100)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 处理过程 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 循环处理: │
|
||
│ • Request 1: 需要5,000 USDC ✅ 处理成功 (剩余45,000) │
|
||
│ • Request 2: 需要5,000 USDC ✅ 处理成功 (剩余40,000) │
|
||
│ • Request 3: 需要5,000 USDC ✅ 处理成功 (剩余35,000) │
|
||
│ • Request 4: 需要5,000 USDC ✅ 处理成功 (剩余30,000) │
|
||
│ • Request 5: 需要5,000 USDC ✅ 处理成功 (剩余25,000) │
|
||
│ • Request 6: 需要5,000 USDC ✅ 处理成功 (剩余20,000) │
|
||
│ • Request 7: 需要5,000 USDC ✅ 处理成功 (剩余15,000) │
|
||
│ • Request 8: 需要5,000 USDC ✅ 处理成功 (剩余10,000) │
|
||
│ • Request 9: 需要5,000 USDC ✅ 处理成功 (剩余5,000) │
|
||
│ • Request 10: 需要5,000 USDC ✅ 处理成功 (剩余0) │
|
||
│ • Request 11: 需要5,000 USDC ❌ 资金不足,停止处理 │
|
||
│ │
|
||
│ 处理结果: │
|
||
│ • processedCount: 10 (只处理了10个,而不是100个) │
|
||
│ • totalDistributed: 50,000 USDC │
|
||
│ • 剩余90个请求继续排队 │
|
||
│ │
|
||
│ ⚠️ 不会revert,优雅地停止! │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 后续处理
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 等待资金到账 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ Manager操作: │
|
||
│ ① 等待基金赎回下一批资金到账 │
|
||
│ ② 调用 depositManagedAssets(100000e18) 充值 │
|
||
│ ③ 再次调用 processBatchWithdrawals(100) 继续处理 │
|
||
│ │
|
||
│ 用户体验: │
|
||
│ • Request 1-10的用户: ✅ USDC已到账 │
|
||
│ • Request 11+的用户: ⏳ 继续排队等待 │
|
||
│ • 可通过getUserPendingRequests()查询状态 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 价格更新流程
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Price Oracle / Manager │
|
||
│ YT价格更新: │
|
||
│ • YT-A新价格: $1.15 │
|
||
│ 注意:USDC价格通过Chainlink自动获取,无需手动更新 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 方式1: Factory更新
|
||
│ 调用 factory.updateVaultPrices()
|
||
│
|
||
│ 方式2: 直接更新(仅Factory)
|
||
│ 调用 vault.updatePrices()
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.updatePrices() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function updatePrices( │
|
||
│ uint256 _ytPrice // 1.15e30 │
|
||
│ ) external onlyFactory │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ • msg.sender == factory ✓ │
|
||
│ 注意:只有Factory可以调用,Manager无权限 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 价格验证
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 价格有效性检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ if (_ytPrice == 0) │
|
||
│ revert InvalidPrice() │
|
||
│ │
|
||
│ 检查: │
|
||
│ • _ytPrice = 1.15e30 ≠ 0 ✓ │
|
||
│ │
|
||
│ 注意: │
|
||
│ • 价格必须 > 0 │
|
||
│ • 价格精度为1e30 │
|
||
│ • 没有时间间隔限制,可随时更新 │
|
||
│ • USDC价格由Chainlink提供,实时获取 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 更新价格状态
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 更新存储状态 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ ytPrice = _ytPrice │
|
||
│ │
|
||
│ 更新前: │
|
||
│ • ytPrice: 1.05e30 → 1.15e30 (上涨9.52%) │
|
||
│ │
|
||
│ USDC价格说明: │
|
||
│ • USDC价格不存储在合约中 │
|
||
│ • 每次交易时从Chainlink实时获取 │
|
||
│ • Chainlink价格精度:1e8 (如 $1.00 = 100000000) │
|
||
│ • 自动转换为合约内部计算精度 │
|
||
│ │
|
||
│ 影响: │
|
||
│ ① 后续depositYT计算变化 │
|
||
│ ytAmount = usdcAmount × usdcPrice(Chainlink) × 10^22 / ytPrice │
|
||
│ → 用户用相同USDC可能获得更少YT │
|
||
│ │
|
||
│ ② 后续withdrawYT计算变化 │
|
||
│ usdcAmount = ytAmount × ytPrice / (usdcPrice(Chainlink) × 10^22)│
|
||
│ → 用户用相同YT可能获得更多USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 触发事件
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 事件记录 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ emit PriceUpdated( │
|
||
│ 1150000000000000000000000000000, // ytPrice │
|
||
│ 1739692800 // timestamp │
|
||
│ ) │
|
||
│ │
|
||
│ 链下监听: │
|
||
│ • 前端可监听此事件更新UI显示 │
|
||
│ • 用户可看到最新的YT价格 │
|
||
│ • USDC价格可直接从Chainlink获取 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 完成更新
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 更新完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 当前兑换比率示例(假设USDC = $1.00): │
|
||
│ │
|
||
│ 存款 (depositYT): │
|
||
│ • 1,000 USDC → (1,000 × 1.00 × 10^22) / 1.15e30 = 869.57 YT │
|
||
│ │
|
||
│ 提款 (withdrawYT): │
|
||
│ • 1,000 YT → (1,000 × 1.15e30) / (1.00 × 10^22) = 1,150 USDC │
|
||
│ │
|
||
│ YT持有者收益: │
|
||
│ • 价格从1.05到1.15,增值9.52% │
|
||
│ • 持有1,000 YT相当于价值1,150 USDC(在USDC=$1时) │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 资产管理流程 - 提取投资
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Manager (资产管理员) │
|
||
│ 计划: 提取50,000 USDC进行外部投资 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 withdrawForManagement()
|
||
│ _to: manager地址
|
||
│ _amount: 50,000 USDC
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.withdrawForManagement() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function withdrawForManagement( │
|
||
│ address _to, // 0x123... (manager) │
|
||
│ uint256 _amount // 50,000 USDC │
|
||
│ ) external onlyManager nonReentrant whenNotPaused │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ ✓ onlyManager - 只有manager可调用 │
|
||
│ ✓ nonReentrant - 重入保护 │
|
||
│ ✓ whenNotPaused - 暂停检查 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 参数验证
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 验证检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ ① if (_amount == 0) revert InvalidAmount() │
|
||
│ ✓ 50,000 > 0 通过 │
|
||
│ │
|
||
│ ② uint256 availableAssets = vault.balance(USDC) │
|
||
│ if (_amount > availableAssets) revert InvalidAmount() │
|
||
│ │
|
||
│ Vault当前状态: │
|
||
│ • totalAssets: 100,000 USDC │
|
||
│ • idleAssets: 100,000 USDC (全部在vault中) │
|
||
│ • managedAssets: 0 USDC │
|
||
│ │
|
||
│ 检查: │
|
||
│ • availableAssets = 100,000 USDC │
|
||
│ • 50,000 ≤ 100,000 ✓ 通过 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 更新managedAssets(CEI - Effects)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 状态更新 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ managedAssets += _amount │
|
||
│ │
|
||
│ 更新: │
|
||
│ • managedAssets: 0 → 50,000 USDC │
|
||
│ │
|
||
│ 重要说明: │
|
||
│ managedAssets记录了被管理员提取、正在进行外部投资的USDC数量 │
|
||
│ 这部分资产不在vault合约中,但仍计入totalAssets │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 转出USDC(Interactions)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 代币转移 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ IERC20(usdcAddress).safeTransfer( │
|
||
│ _to, // manager地址 │
|
||
│ 50000e18 // 50,000 USDC │
|
||
│ ) │
|
||
│ │
|
||
│ 转账结果: │
|
||
│ • Vault USDC余额: 100,000 → 50,000 USDC │
|
||
│ • Manager USDC余额: +50,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 5. 触发事件
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 事件记录 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ emit AssetsWithdrawn( │
|
||
│ 0x123..., // manager地址 │
|
||
│ 50000e18 // 提取数量 │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 6. 提取完成
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 提取完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ Vault最终状态: │
|
||
│ • totalAssets(): 100,000 USDC (不变!) │
|
||
│ 计算: idleAssets + managedAssets │
|
||
│ = 50,000 + 50,000 = 100,000 │
|
||
│ │
|
||
│ • idleAssets(): 50,000 USDC │
|
||
│ (vault合约实际持有的USDC) │
|
||
│ │
|
||
│ • managedAssets: 50,000 USDC │
|
||
│ (manager正在管理的USDC) │
|
||
│ │
|
||
│ • totalSupply: 100,000 YT (不变) │
|
||
│ │
|
||
│ 用户影响: │
|
||
│ ✓ totalAssets不变,YT价值不受影响 │
|
||
│ ✓ 用户依然持有相同价值的YT份额 │
|
||
│ ✗ 暂时无法提款(流动性不足),需等待manager归还 │
|
||
│ │
|
||
│ Manager后续操作: │
|
||
│ → 用50,000 USDC进行DeFi投资 │
|
||
│ → 赚取收益 │
|
||
│ → 通过depositManagedAssets归还 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 资产管理流程 - 归还资产
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Manager (资产管理员) │
|
||
│ 投资收益情况: │
|
||
│ • 提取: 50,000 USDC │
|
||
│ • 投资收益: +5,000 USDC │
|
||
│ • 准备归还: 55,000 USDC (本金+利润) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 授权USDC给Vault
|
||
│ USDC.approve(vault, 55000e18)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ USDC授权检查 │
|
||
│ ✓ allowance[manager][vault] >= 55,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 调用 depositManagedAssets()
|
||
│ _amount: 55,000 USDC
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.depositManagedAssets() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function depositManagedAssets( │
|
||
│ uint256 _amount // 55,000 USDC │
|
||
│ ) external onlyManager nonReentrant whenNotPaused │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ ✓ onlyManager - 只有manager可调用 │
|
||
│ ✓ nonReentrant - 重入保护 │
|
||
│ ✓ whenNotPaused - 暂停检查 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 参数验证
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 验证检查 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ if (_amount == 0) revert InvalidAmount() │
|
||
│ ✓ 55,000 > 0 通过 │
|
||
│ │
|
||
│ 当前Vault状态: │
|
||
│ • idleAssets: 50,000 USDC │
|
||
│ • managedAssets: 50,000 USDC │
|
||
│ • totalAssets: 100,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 4. 更新managedAssets(CEI - Effects)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 状态更新(关键逻辑) │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ if (_amount >= managedAssets) { │
|
||
│ // 归还金额 >= 提取金额,清零managedAssets │
|
||
│ managedAssets = 0 │
|
||
│ } else { │
|
||
│ // 归还金额 < 提取金额,部分归还 │
|
||
│ managedAssets -= _amount │
|
||
│ } │
|
||
│ │
|
||
│ 本例计算: │
|
||
│ • _amount = 55,000 USDC │
|
||
│ • managedAssets = 50,000 USDC │
|
||
│ • 55,000 >= 50,000 ✓ 进入第一个分支 │
|
||
│ • managedAssets = 0 │
|
||
│ │
|
||
│ 多余的5,000 USDC如何处理? │
|
||
│ → 自动增加到vault余额,成为利润 │
|
||
│ → totalAssets会增加 │
|
||
│ → 所有YT持有者共享这部分收益 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 5. 转入USDC(Interactions)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 代币转移 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ IERC20(usdcAddress).safeTransferFrom( │
|
||
│ msg.sender, // manager地址 │
|
||
│ address(this), // vault地址 │
|
||
│ 55000e18 // 55,000 USDC │
|
||
│ ) │
|
||
│ │
|
||
│ 转账结果: │
|
||
│ • Manager USDC余额: -55,000 USDC │
|
||
│ • Vault USDC余额: 50,000 → 105,000 USDC │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 6. 触发事件
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 事件记录 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ emit AssetsDeposited( │
|
||
│ 55000e18 // 归还数量 │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 7. 归还完成
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 归还完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ Vault最终状态: │
|
||
│ • totalAssets(): 105,000 USDC (增加了5,000!) │
|
||
│ 计算: idleAssets + managedAssets │
|
||
│ = 105,000 + 0 = 105,000 │
|
||
│ │
|
||
│ • idleAssets(): 105,000 USDC │
|
||
│ (vault合约实际持有的USDC,包含收益) │
|
||
│ │
|
||
│ • managedAssets: 0 USDC │
|
||
│ (所有资产已归还) │
|
||
│ │
|
||
│ • totalSupply: 100,000 YT (不变) │
|
||
│ │
|
||
│ 收益分配: │
|
||
│ • 投资收益: 5,000 USDC │
|
||
│ • 收益率: 5,000 / 50,000 = 10% │
|
||
│ • 每个YT的价值提升: │
|
||
│ 之前: 100,000 USDC / 100,000 YT = 1.0 USDC/YT │
|
||
│ 现在: 105,000 USDC / 100,000 YT = 1.05 USDC/YT │
|
||
│ │
|
||
│ 用户影响: │
|
||
│ ✓ 所有YT持有者自动获得5%增值 │
|
||
│ ✓ 可以提款了(流动性恢复) │
|
||
│ ✓ 如果用户提取YT,会按1.05的比例获得更多USDC │
|
||
│ │
|
||
│ 示例: │
|
||
│ 用户持有10,000 YT,提取时可获得: │
|
||
│ (10,000 × 1.05 USDC/YT) = 10,500 USDC │
|
||
│ 相比初始存入的10,000 USDC,获利500 USDC (5%) │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 批量操作流程
|
||
|
||
### 7.1 批量创建Vault
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Owner (系统管理员) │
|
||
│ 计划: 批量创建3个不同的YT Vault │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 调用 createVaultBatch()
|
||
│ • names: ["YT-A", "YT-B", "YT-C"]
|
||
│ • symbols: ["YTA", "YTB", "YTC"]
|
||
│ • managers: [0x111, 0x222, 0x333]
|
||
│ • hardCaps: [1000000e18, 500000e18, 2000000e18]
|
||
│ • usdc: 0x7Cd... (USDC代币地址)
|
||
│ • redemptionTimes: [time1, time2, time3]
|
||
│ • initialYtPrices: [1.05e30, 1.02e30, 1.10e30]
|
||
│ • usdcPriceFeed: 0xABC... (Chainlink价格Feed)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 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 批量更新价格
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Price Oracle / Owner │
|
||
│ 接收到3个vault的最新YT价格数据 │
|
||
│ 注意:USDC价格通过Chainlink自动获取,无需批量更新 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 调用 updateVaultPricesBatch()
|
||
│ • vaults: [0xVault001, 0xVault002, 0xVault003]
|
||
│ • ytPrices: [1.15e30, 1.08e30, 1.20e30]
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.updateVaultPricesBatch() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 1. 参数验证 │
|
||
│ require(数组长度相等) │
|
||
│ ✓ 所有数组长度都是3 │
|
||
│ │
|
||
│ 2. 循环更新 │
|
||
│ for (i = 0; i < 3; i++) { │
|
||
│ YTAssetVault(vaults[i]).updatePrices( │
|
||
│ ytPrices[i] │
|
||
│ ) │
|
||
│ emit PricesUpdated(vaults[i], ytPrices[i]) │
|
||
│ } │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
├─────────┬─────────┐
|
||
│ │ │
|
||
Vault001 │ Vault002 │ Vault003
|
||
价格更新 │ 价格更新 │ 价格更新
|
||
▼ │ ▼ │ ▼
|
||
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
|
||
│ YT: 1.15 │ │ YT: 1.08 │ │ YT: 1.20 │
|
||
│ 涨幅: +9.52% │ │ 涨幅: +2.88% │ │ 涨幅: +9.09% │
|
||
│ USDC: Chainlink │ │ USDC: Chainlink │ │ USDC: Chainlink │
|
||
└───────────────────┘ └───────────────────┘ └───────────────────┘
|
||
│ │ │
|
||
└─────────┴─────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 批量更新完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 优势: │
|
||
│ ✓ 一次交易更新多个vault的YT价格 │
|
||
│ ✓ 节省gas费用 │
|
||
│ ✓ 确保所有vault价格同时更新 │
|
||
│ ✓ 适合定时任务批量更新 │
|
||
│ ✓ USDC价格由Chainlink提供,无需手动维护 │
|
||
│ │
|
||
│ 触发的事件: │
|
||
│ • PricesUpdated × 3 (from factory) │
|
||
│ • PriceUpdated × 3 (from vaults) │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 7.3 批量设置赎回时间
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 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信息](#81-查询单个vault信息)
|
||
- 8.2 [通过Factory查询Vault信息](#82-通过factory查询vault信息)
|
||
- 8.3 [查询所有Vault列表](#83-查询所有vault列表)
|
||
- 8.4 [查询提现请求信息(新增)](#84-查询提现请求信息新增)
|
||
|
||
### 8.1 查询单个Vault信息
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 前端应用 / 查询者 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 调用 vault.getVaultInfo()
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.getVaultInfo() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getVaultInfo() returns ( │
|
||
│ uint256 _totalAssets, │
|
||
│ uint256 _idleAssets, │
|
||
│ uint256 _managedAssets, │
|
||
│ uint256 _totalSupply, │
|
||
│ uint256 _hardCap, │
|
||
│ uint256 _usdcPrice, │
|
||
│ uint256 _ytPrice, │
|
||
│ uint256 _nextRedemptionTime │
|
||
│ ) │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 读取状态
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 返回完整信息 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 返回示例: │
|
||
│ { │
|
||
│ totalAssets: 105000e18, // 105,000 USDC │
|
||
│ idleAssets: 105000e18, // 105,000 USDC │
|
||
│ managedAssets: 0, // 0 USDC │
|
||
│ totalSupply: 100000e18, // 100,000 YT │
|
||
│ hardCap: 1000000e18, // 1,000,000 YT │
|
||
│ usdcPrice: 1020000000000000000000000000000, // 1.02 │
|
||
│ ytPrice: 1150000000000000000000000000000, // 1.15 │
|
||
│ nextRedemptionTime: 1739577600 // 2025-02-15 00:00:00 │
|
||
│ } │
|
||
│ │
|
||
│ 计算衍生指标: │
|
||
│ • 每YT价值: 105,000 / 100,000 = 1.05 USDC │
|
||
│ • 资金利用率: (105,000 - 0) / 105,000 = 100% │
|
||
│ • 硬顶使用率: 100,000 / 1,000,000 = 10% │
|
||
│ • 当前兑换率: 1 USDC = 1.02/1.15 = 0.887 YT │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 8.2 通过Factory查询Vault信息
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 前端应用 / 查询者 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 调用 factory.getVaultInfo(vaultAddress)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.getVaultInfo() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getVaultInfo(address _vault) returns ( │
|
||
│ bool exists, │
|
||
│ uint256 totalAssets, │
|
||
│ uint256 idleAssets, │
|
||
│ uint256 managedAssets, │
|
||
│ uint256 totalSupply, │
|
||
│ uint256 hardCap, │
|
||
│ uint256 usdcPrice, │
|
||
│ 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, │
|
||
│ usdcPrice: 1020000000000000000000000000000, │
|
||
│ ytPrice: 1150000000000000000000000000000, │
|
||
│ nextRedemptionTime: 1739577600 │
|
||
│ } │
|
||
│ │
|
||
│ 优势: │
|
||
│ ✓ 通过factory统一查询 │
|
||
│ ✓ 可验证vault是否为合法vault │
|
||
│ ✓ 一次调用获取所有信息 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 8.3 查询所有Vault列表
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 前端应用 / 查询者 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 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消耗 │
|
||
│ ✓ 改善前端加载性能 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 8.4 查询提现请求信息(新增)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 用户 / 前端应用 │
|
||
│ 需求:查询提现请求的状态 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
├──────────────┬──────────────┬──────────────┐
|
||
│ │ │ │
|
||
方式1: 查询单个请求 方式2: 查询用户请求 方式3: 查询队列进度
|
||
│ │ │ │
|
||
▼ ▼ ▼ ▼
|
||
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
|
||
│ getRequestDetails │ │getUserRequestIds │ │ getQueueProgress │
|
||
│ (requestId) │ │(userAddress) │ │() │
|
||
└──────────┬──────────┘ └──────────┬──────────┘ └──────────┬──────────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 方式1: 查询单个请求详情 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getRequestDetails(uint256 _requestId) │
|
||
│ returns (WithdrawRequest memory) │
|
||
│ │
|
||
│ 输入: requestId = 42 │
|
||
│ │
|
||
│ 返回: │
|
||
│ { │
|
||
│ user: 0xUser123..., │
|
||
│ ytAmount: 5000e18, // 提现的YT数量 │
|
||
│ usdcAmount: 5500e18, // 应得USDC数量 │
|
||
│ requestTime: 1739692800, // 请求时间戳 │
|
||
│ queueIndex: 42, // 队列位置 │
|
||
│ processed: false // 是否已处理 │
|
||
│ } │
|
||
│ │
|
||
│ 前端展示: │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ 📋 提现请求 #42 │ │
|
||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||
│ │ 状态: ⏳ 排队中 │ │
|
||
│ │ YT数量: 5,000 YT │ │
|
||
│ │ 应得USDC: 5,500 USDC │ │
|
||
│ │ 提交时间: 2025-02-16 10:00:00 │ │
|
||
│ │ 队列位置: 第42位 │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 方式2: 查询用户所有请求 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 步骤1: 获取用户的请求ID列表 │
|
||
│ function getUserRequestIds(address _user) │
|
||
│ returns (uint256[] memory) │
|
||
│ │
|
||
│ 返回: [15, 42, 68] (用户有3个请求) │
|
||
│ │
|
||
│ 步骤2: 获取用户待处理的请求 │
|
||
│ function getUserPendingRequests(address _user) │
|
||
│ returns (WithdrawRequest[] memory) │
|
||
│ │
|
||
│ 返回: 只返回 processed = false 的请求 │
|
||
│ [ │
|
||
│ { │
|
||
│ user: 0xUser123..., │
|
||
│ ytAmount: 5000e18, │
|
||
│ usdcAmount: 5500e18, │
|
||
│ requestTime: 1739692800, │
|
||
│ queueIndex: 42, │
|
||
│ processed: false │
|
||
│ } │
|
||
│ ] │
|
||
│ │
|
||
│ 前端展示: │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ 👤 我的提现请求 │ │
|
||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||
│ │ ✅ 请求#15 1,000 YT → 1,100 USDC │ │
|
||
│ │ 状态: 已完成 2025-02-10 │ │
|
||
│ │ │ │
|
||
│ │ ⏳ 请求#42 5,000 YT → 5,500 USDC │ │
|
||
│ │ 状态: 排队中 队列第42位 │ │
|
||
│ │ 提交于: 2025-02-16 10:00 │ │
|
||
│ │ │ │
|
||
│ │ ⏳ 请求#68 3,000 YT → 3,300 USDC │ │
|
||
│ │ 状态: 排队中 队列第68位 │ │
|
||
│ │ 提交于: 2025-02-16 15:30 │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 方式3: 查询队列处理进度 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getQueueProgress() returns ( │
|
||
│ uint256 currentIndex, │
|
||
│ uint256 totalRequests, │
|
||
│ uint256 pendingRequests │
|
||
│ ) │
|
||
│ │
|
||
│ 返回示例: │
|
||
│ { │
|
||
│ currentIndex: 38, // 当前处理到第38个 │
|
||
│ totalRequests: 150, // 总共150个请求 │
|
||
│ pendingRequests: 112 // 还有112个待处理 │
|
||
│ } │
|
||
│ │
|
||
│ 衍生计算: │
|
||
│ • 已处理: 38个 │
|
||
│ • 处理进度: 38/150 = 25.3% │
|
||
│ • 待处理: 112个 │
|
||
│ │
|
||
│ 前端展示: │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ 🔄 提现处理进度 │ │
|
||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||
│ │ [████████░░░░░░░░░░░░░░░] 25.3% │ │
|
||
│ │ │ │
|
||
│ │ 已处理: 38 / 150 │ │
|
||
│ │ 待处理: 112个请求 │ │
|
||
│ │ 当前位置: 第38位 │ │
|
||
│ │ │ │
|
||
│ │ 💡 提示: │ │
|
||
│ │ 您的请求#42在第42位,前面还有4个请求 │ │
|
||
│ │ 预计等待时间: 约5分钟 │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 优势: │
|
||
│ ✓ 实时查看全局处理进度 │
|
||
│ ✓ 估算自己的等待时间 │
|
||
│ ✓ O(1)查询,gas友好 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 方式4: 查询待处理总数 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function getPendingRequestsCount() returns (uint256) │
|
||
│ │
|
||
│ 返回: 112 (还有112个待处理) │
|
||
│ │
|
||
│ 特点: │
|
||
│ • O(1)复杂度,实时维护的计数器 │
|
||
│ • 不需要循环,避免gas爆炸 │
|
||
│ • 可用于前端显示统计信息 │
|
||
│ │
|
||
│ 前端展示: │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ 📊 系统统计 │ │
|
||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||
│ │ 待处理提现: 112个 │ │
|
||
│ │ Vault余额: 50,000 USDC │ │
|
||
│ │ 预计可处理: 约45个请求 │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 附录:重要概念说明
|
||
|
||
### A. 价格精度和Chainlink集成
|
||
|
||
```
|
||
YT价格精度 (PRICE_PRECISION):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
精度: 1e30 (10^30)
|
||
|
||
示例:
|
||
• 价格 1.0 表示为: 1000000000000000000000000000000 (1e30)
|
||
• 价格 1.05 表示为: 1050000000000000000000000000000 (1.05e30)
|
||
• 价格 0.98 表示为: 980000000000000000000000000000 (0.98e30)
|
||
|
||
为什么使用1e30而不是1e18?
|
||
✓ 更高的精度,减少舍入误差
|
||
✓ 适合复杂的价格计算
|
||
✓ 支持更精确的价格波动
|
||
|
||
|
||
Chainlink USDC价格精度:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
精度: 1e8 (Chainlink标准)
|
||
|
||
示例:
|
||
• $1.00 表示为: 100000000
|
||
• $1.05 表示为: 105000000
|
||
• $0.98 表示为: 98000000
|
||
|
||
特点:
|
||
✓ 实时从Chainlink预言机获取
|
||
✓ 去中心化价格源,安全可靠
|
||
✓ 自动处理int256到uint256的转换
|
||
✓ 验证价格为正数(price > 0)
|
||
|
||
|
||
转换因子 (CONVERSION_FACTOR):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
动态计算: 10^ytDecimals × 10^30 / (10^usdcDecimals × 10^8)
|
||
|
||
对于BSC USDC (18位) 和 YT (18位):
|
||
转换因子 = 10^18 × 10^30 / (10^18 × 10^8) = 10^22
|
||
|
||
作用:
|
||
✓ 统一不同精度之间的计算
|
||
✓ 支持不同decimals的USDC实现
|
||
✓ 动态从代币合约读取decimals
|
||
✓ 避免硬编码,提高灵活性
|
||
```
|
||
|
||
### B. 兑换计算公式
|
||
|
||
```
|
||
重要说明:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
• USDC价格从Chainlink获取,精度1e8 (如 $1.00 = 100000000)
|
||
• YT价格存储在合约中,精度1e30
|
||
• USDC在BSC主网为18位小数 (1 USDC = 10^18)
|
||
• YT代币为18位小数 (1 YT = 10^18)
|
||
• 转换因子 = 10^22 (用于精度转换)
|
||
|
||
存款 (depositYT):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
ytAmount = (usdcAmount × usdcPrice × 10^22) ÷ ytPrice
|
||
|
||
其中:
|
||
• usdcAmount: USDC数量 (18位小数)
|
||
• usdcPrice: Chainlink价格 (8位精度)
|
||
• ytPrice: YT价格 (30位精度)
|
||
• 10^22: 转换因子
|
||
|
||
示例:
|
||
• 存入1,000 USDC (1000 × 10^18)
|
||
• usdcPrice = 100000000 ($1.00, Chainlink格式)
|
||
• ytPrice = 1.10e30
|
||
• ytAmount = (1000e18 × 100000000 × 10^22) ÷ 1.10e30
|
||
• = 909.09e18 YT
|
||
|
||
|
||
提款 (withdrawYT):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
usdcAmount = (ytAmount × ytPrice) ÷ (usdcPrice × 10^22)
|
||
|
||
示例:
|
||
• 提取1,000 YT (1000 × 10^18)
|
||
• ytPrice = 1.10e30
|
||
• usdcPrice = 100000000 ($1.00, Chainlink格式)
|
||
• usdcAmount = (1000e18 × 1.10e30) ÷ (100000000 × 10^22)
|
||
• = 1100e18 USDC
|
||
|
||
|
||
关键点:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
✓ USDC价格实时从Chainlink获取,确保准确性
|
||
✓ 转换因子自动处理不同精度之间的转换
|
||
✓ 支持USDC价格波动(稳定币微小波动)
|
||
✓ 计算在Solidity中使用整数运算,无浮点数
|
||
```
|
||
|
||
### C. 资产状态计算
|
||
|
||
```
|
||
Vault资产状态:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
totalAssets = idleAssets + managedAssets
|
||
|
||
• idleAssets: vault合约中实际持有的USDC
|
||
• managedAssets: manager提取、正在投资的USDC
|
||
• totalAssets: 用户可赎回的总价值
|
||
|
||
示例:
|
||
vault余额: 50,000 USDC
|
||
managedAssets: 50,000 USDC
|
||
totalAssets: 100,000 USDC (不变)
|
||
|
||
用户持有10,000 YT,价值:
|
||
(10,000 / 100,000) × 100,000 = 10,000 USDC
|
||
```
|
||
|
||
### D. 硬顶机制
|
||
|
||
```
|
||
硬顶 (Hard Cap):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
限制YT代币的最大供应量
|
||
|
||
作用:
|
||
✓ 控制vault规模
|
||
✓ 风险管理
|
||
✓ 防止过度铸造
|
||
|
||
检查时机:
|
||
• 每次depositYT时检查
|
||
• if (totalSupply + ytAmount > hardCap) revert
|
||
|
||
动态调整:
|
||
• Factory owner可以通过setHardCap调整
|
||
• 但不能低于当前totalSupply
|
||
```
|
||
|
||
### E. 统一赎回时间
|
||
|
||
```
|
||
赎回时间 (nextRedemptionTime):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
所有用户统一的赎回开放时间
|
||
|
||
特点:
|
||
✓ 类似基金的开放日
|
||
✓ 所有用户同时可赎回
|
||
✓ 不是个人锁定期
|
||
|
||
检查:
|
||
• block.timestamp >= nextRedemptionTime
|
||
• 未到时间调用withdrawYT会revert
|
||
|
||
管理:
|
||
• Factory owner可以设置
|
||
• 支持批量设置多个vault
|
||
```
|
||
|
||
### F. CEI模式
|
||
|
||
```
|
||
CEI模式 (Checks-Effects-Interactions):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
安全的合约编写模式,防止重入攻击
|
||
|
||
1. Checks (检查)
|
||
• 验证参数
|
||
• 检查权限
|
||
• 检查余额
|
||
|
||
2. Effects (状态更新)
|
||
• 更新合约状态
|
||
• 修改余额
|
||
• 记录变化
|
||
|
||
3. Interactions (外部交互)
|
||
• 转账代币
|
||
• 调用外部合约
|
||
• 触发事件
|
||
|
||
配合nonReentrant modifier,确保安全
|
||
```
|
||
|
||
### G. Chainlink价格预言机集成
|
||
|
||
```
|
||
Chainlink集成说明:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
系统使用Chainlink作为USDC价格数据源
|
||
|
||
初始化时设置:
|
||
• 合约初始化时传入 usdcPriceFeed 地址
|
||
• 该地址指向Chainlink的USDC/USD价格Feed
|
||
• 例如:Chainlink USDC/USD on BSC
|
||
|
||
价格获取流程:
|
||
┌──────────────────────────────────┐
|
||
│ 用户调用 depositYT() 或 │
|
||
│ withdrawYT() │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 合约调用 _getUSDCPrice() │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 调用 usdcPriceFeed │
|
||
│ .latestRoundData() │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 返回价格数据: │
|
||
│ • int256 price (如: 100000000) │
|
||
│ • roundId, timestamps等元数据 │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 价格验证: │
|
||
│ • if (price <= 0) revert │
|
||
│ • 确保价格为正 │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 类型转换: │
|
||
│ • int256 → uint256 │
|
||
│ • 返回 uint256(price) │
|
||
└──────────┬───────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────┐
|
||
│ 用于计算: │
|
||
│ • ytAmount = usdcAmount × │
|
||
│ usdcPrice × 10^22 / ytPrice │
|
||
└──────────────────────────────────┘
|
||
|
||
安全特性:
|
||
✓ 价格验证:拒绝负数或零价格
|
||
✓ 实时更新:每次交易都获取最新价格
|
||
✓ 去中心化:Chainlink多节点共识
|
||
✓ 类型安全:安全的int256→uint256转换
|
||
|
||
优势:
|
||
✓ 无需手动更新USDC价格
|
||
✓ 价格始终准确反映市场
|
||
✓ 减少管理员操作负担
|
||
✓ 提高系统自动化程度
|
||
|
||
错误处理:
|
||
• InvalidChainlinkPrice: 价格≤0时触发
|
||
• 交易自动revert,保护用户资金
|
||
```
|
||
|
||
### H. UUPS升级模式
|
||
|
||
```
|
||
UUPS (Universal Upgradeable Proxy Standard):
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
可升级合约的标准实现方式
|
||
|
||
结构:
|
||
┌─────────────┐
|
||
│ ERC1967Proxy│ ← 用户交互的地址(不变)
|
||
└──────┬──────┘
|
||
│ delegatecall
|
||
▼
|
||
┌─────────────┐
|
||
│ Implementation│ ← 逻辑合约(可升级)
|
||
└─────────────┘
|
||
|
||
优势:
|
||
✓ 合约地址不变
|
||
✓ 状态数据保留
|
||
✓ 可以修复bug和添加功能
|
||
✓ 升级权限由Factory控制
|
||
|
||
注意:
|
||
• 不能在状态变量声明时初始化
|
||
• 必须使用initialize函数
|
||
• 保留__gap数组用于未来扩展
|
||
```
|
||
|
||
### I. 两阶段提现机制(Withdraw Queue)
|
||
|
||
```
|
||
两阶段提现机制:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
解决资金分批到账的提现排队问题
|
||
|
||
设计目的:
|
||
• 基金赎回需要时间,资金不会一次性到账
|
||
• 按用户提现请求时间先后排队(FIFO)
|
||
• 资金到账后由后端统一批量发放
|
||
|
||
阶段一:用户提交请求
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
用户调用 withdrawYT(_ytAmount)
|
||
|
||
执行内容:
|
||
1. 验证参数和赎回时间
|
||
2. 立即销毁用户的YT代币
|
||
3. 计算应得USDC数量(锁定当前价格)
|
||
4. 创建WithdrawRequest记录
|
||
5. 返回requestId供用户查询
|
||
|
||
关键特点:
|
||
✓ YT立即销毁(防止重复提现)
|
||
✓ USDC暂不发放(等待批量处理)
|
||
✓ 金额已锁定(不受后续价格变化影响)
|
||
✓ 即使vault资金不足也可提交请求
|
||
|
||
阶段二:批量处理发放
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
Manager/Factory调用 processBatchWithdrawals(_batchSize)
|
||
|
||
执行内容:
|
||
1. 获取vault当前可用USDC
|
||
2. 按requestId顺序(FIFO)处理请求
|
||
3. 依次给用户转账USDC
|
||
4. 标记请求为已处理
|
||
5. 资金不足时自动停止
|
||
|
||
关键特点:
|
||
✓ FIFO严格保证(先提交先处理)
|
||
✓ 支持分批处理(避免gas超限)
|
||
✓ 断点续传(记录处理进度)
|
||
✓ 资金不足不会revert(优雅停止)
|
||
|
||
数据结构:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
struct WithdrawRequest {
|
||
address user; // 用户地址
|
||
uint256 ytAmount; // YT数量
|
||
uint256 usdcAmount; // 应得USDC数量(锁定)
|
||
uint256 requestTime; // 请求时间
|
||
uint256 queueIndex; // 队列位置
|
||
bool processed; // 是否已处理
|
||
}
|
||
|
||
状态变量:
|
||
• withdrawRequests[requestId] - 所有请求记录
|
||
• userRequestIds[user] - 用户的请求ID列表
|
||
• requestIdCounter - 请求ID计数器(递增)
|
||
• processedUpToIndex - 已处理到的位置
|
||
• pendingRequestsCount - 待处理请求数(O(1)查询)
|
||
|
||
查询功能:
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
• getUserRequestIds(user) - 用户的所有请求ID
|
||
• getRequestDetails(requestId) - 请求详情
|
||
• getUserPendingRequests(user) - 用户待处理请求
|
||
• getPendingRequestsCount() - 待处理总数
|
||
• getQueueProgress() - 队列处理进度
|
||
|
||
优势:
|
||
✓ 解决资金分批到账问题
|
||
✓ 公平的FIFO排队机制
|
||
✓ Gas优化(计数器避免循环)
|
||
✓ 用户体验好(可查询状态)
|
||
✓ 管理灵活(支持分批处理)
|
||
|
||
使用场景:
|
||
1. 基金赎回需要T+1或T+N到账
|
||
2. 资金分多批次回流
|
||
3. 避免流动性挤兑
|
||
4. 统一管理提现流程
|
||
|
||
风险控制:
|
||
⚠️ YT已销毁但USDC未到账的风险
|
||
→ 解决:Manager有责任及时处理请求
|
||
→ 解决:Factory可以代为处理
|
||
|
||
⚠️ 用户长时间等待的风险
|
||
→ 解决:可查询队列进度
|
||
→ 解决:前端显示预计等待时间
|
||
|
||
⚠️ 价格锁定可能错失市场波动
|
||
→ 解决:这是设计特性,确保公平性
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 暂停功能流程
|
||
|
||
### 9.1 暂停单个Vault
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Factory Owner (紧急情况) │
|
||
│ 检测到: YT-A Vault 存在安全问题 │
|
||
└────────────────────────────────┬────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 pauseVault(vaultAddress)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.pauseVault() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function pauseVault(address _vault) external onlyOwner │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ ✓ onlyOwner - 只有Factory owner可调用 │
|
||
│ ✓ isVault[_vault] - 验证vault存在 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 调用 vault.pause()
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.pause() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ internal _pause() │
|
||
│ • 设置 paused = true │
|
||
│ • 触发 Paused 事件 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 暂停生效
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Vault已暂停 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 被阻止的操作(revert EnforcedPause): │
|
||
│ ✗ depositYT() - 用户无法存款 │
|
||
│ ✗ withdrawYT() - 用户无法提款 │
|
||
│ ✗ withdrawForManagement() - Manager无法提取资产 │
|
||
│ ✗ depositManagedAssets() - Manager无法归还资产 │
|
||
│ │
|
||
│ 仍可用的操作: │
|
||
│ ✓ balanceOf() - 查询余额 │
|
||
│ ✓ totalSupply() - 查询总供应 │
|
||
│ ✓ totalAssets() - 查询总资产 │
|
||
│ ✓ getVaultInfo() - 查询详细信息 │
|
||
│ ✓ previewBuy() - 预览存款 │
|
||
│ ✓ previewSell() - 预览提款 │
|
||
│ ✓ canRedeemNow() - 检查赎回状态 │
|
||
│ │
|
||
│ 用户影响: │
|
||
│ • 所有资金操作暂停 │
|
||
│ • 资产安全锁定 │
|
||
│ • 可以查看但无法操作 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 9.2 恢复单个Vault
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Factory Owner (问题已解决) │
|
||
│ 安全问题已修复,可以恢复正常运行 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 unpauseVault(vaultAddress)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.unpauseVault() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function unpauseVault(address _vault) external onlyOwner │
|
||
│ │
|
||
│ 权限检查: │
|
||
│ ✓ onlyOwner - 只有Factory owner可调用 │
|
||
│ ✓ isVault[_vault] - 验证vault存在 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 2. 调用 vault.unpause()
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetVault.unpause() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ internal _unpause() │
|
||
│ • 设置 paused = false │
|
||
│ • 触发 Unpaused 事件 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 3. 恢复完成
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Vault恢复正常 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 所有功能恢复: │
|
||
│ ✓ depositYT() - 用户可以存款 │
|
||
│ ✓ withdrawYT() - 用户可以提款(如已过赎回时间) │
|
||
│ ✓ withdrawForManagement() - Manager可以提取资产 │
|
||
│ ✓ depositManagedAssets() - Manager可以归还资产 │
|
||
│ │
|
||
│ 系统状态: │
|
||
│ • 所有操作恢复正常 │
|
||
│ • 用户资产未受影响 │
|
||
│ • 暂停期间的价格更新仍然有效 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 9.3 批量暂停Vaults
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Factory Owner (系统级紧急) │
|
||
│ 检测到系统性风险,需要暂停多个Vault │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 pauseVaultBatch(vaultAddresses)
|
||
│ vaults: [0xVault001, 0xVault002, 0xVault003]
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.pauseVaultBatch() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ function pauseVaultBatch(address[] memory _vaults) │
|
||
│ │
|
||
│ 批量处理: │
|
||
│ for (i = 0; i < _vaults.length; i++) { │
|
||
│ require(isVault[_vaults[i]]) // 验证每个vault │
|
||
│ YTAssetVault(_vaults[i]).pause() │
|
||
│ } │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
├─────────┬─────────┐
|
||
│ │ │
|
||
Vault001 │ Vault002 │ Vault003
|
||
暂停 │ 暂停 │ 暂停
|
||
▼ │ ▼ │ ▼
|
||
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
|
||
│ YT-A Vault │ │ YT-B Vault │ │ YT-C Vault │
|
||
│ 状态: PAUSED │ │ 状态: PAUSED │ │ 状态: PAUSED │
|
||
│ 所有操作冻结 │ │ 所有操作冻结 │ │ 所有操作冻结 │
|
||
└───────────────────┘ └───────────────────┘ └───────────────────┘
|
||
│ │ │
|
||
└─────────┴─────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 批量暂停完成 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 优势: │
|
||
│ ✓ 一次交易暂停多个vault │
|
||
│ ✓ 节省gas费用 │
|
||
│ ✓ 原子操作,全部成功或全部失败 │
|
||
│ ✓ 快速响应系统性风险 │
|
||
│ │
|
||
│ 系统影响: │
|
||
│ • 所有指定vault的资金操作立即冻结 │
|
||
│ • 用户资产安全保护 │
|
||
│ • 管理员可以调查和修复问题 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 9.4 批量恢复Vaults
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ Factory Owner (风险已消除) │
|
||
│ 问题已解决,恢复所有暂停的Vault │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
│ 1. 调用 unpauseVaultBatch(vaultAddresses)
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ YTAssetFactory.unpauseVaultBatch() │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 批量恢复所有vault │
|
||
│ • 验证每个vault存在 │
|
||
│ • 调用每个vault的unpause() │
|
||
│ • 原子操作执行 │
|
||
└────────────────────────────┬────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 系统全面恢复 │
|
||
│ ───────────────────────────────────────────────────────────────── │
|
||
│ 所有vault恢复正常运行 │
|
||
│ 用户可以继续所有操作 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 暂停功能的应用场景:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 使用场景和最佳实践 │
|
||
│ │
|
||
│ 何时使用暂停功能: │
|
||
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
|
||
│ │
|
||
│ 1️⃣ 安全漏洞发现 │
|
||
│ • 发现合约安全问题 │
|
||
│ • 暂停受影响的vault │
|
||
│ • 保护用户资产 │
|
||
│ • 修复后恢复 │
|
||
│ │
|
||
│ 2️⃣ 价格异常 │
|
||
│ • 价格预言机故障 │
|
||
│ • 价格剧烈波动 │
|
||
│ • 暂停交易防止损失 │
|
||
│ • 价格稳定后恢复 │
|
||
│ │
|
||
│ 3️⃣ 系统升级 │
|
||
│ • 准备合约升级 │
|
||
│ • 暂停所有操作 │
|
||
│ • 执行升级 │
|
||
│ • 验证后恢复 │
|
||
│ │
|
||
│ 4️⃣ 流动性危机 │
|
||
│ • Manager提取资金后未及时归还 │
|
||
│ • 暂停提款防止挤兑 │
|
||
│ • 等待资金回流 │
|
||
│ • 流动性恢复后解除 │
|
||
│ │
|
||
│ 5️⃣ 监管要求 │
|
||
│ • 配合监管调查 │
|
||
│ • 临时冻结操作 │
|
||
│ • 保留完整记录 │
|
||
│ │
|
||
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
|
||
│ │
|
||
│ 最佳实践: │
|
||
│ ✓ 暂停前公告(如有时间) │
|
||
│ ✓ 记录暂停原因 │
|
||
│ ✓ 快速调查和修复 │
|
||
│ ✓ 恢复前全面测试 │
|
||
│ ✓ 恢复后公告说明 │
|
||
│ │
|
||
│ 注意事项: │
|
||
│ ⚠️ 暂停不影响已持有的资产价值 │
|
||
│ ⚠️ 暂停期间价格仍可更新(由Factory) │
|
||
│ ⚠️ Manager在暂停期间也无法操作 │
|
||
│ ⚠️ 查询功能不受影响 │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
``` |