Files
assetxContracts/doc/YT资产金库系统操作流程图.md
2025-12-24 16:41:26 +08:00

2189 lines
175 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# 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. 转入USDCCEI模式 - 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. 更新managedAssetsCEI - Effects
┌─────────────────────────────────────────────────────────────────────┐
│ 状态更新 │
│ ───────────────────────────────────────────────────────────────── │
│ managedAssets += _amount │
│ │
│ 更新: │
│ • managedAssets: 0 → 50,000 USDC │
│ │
│ 重要说明: │
│ managedAssets记录了被管理员提取、正在进行外部投资的USDC数量 │
│ 这部分资产不在vault合约中但仍计入totalAssets │
└────────────────────────────┬────────────────────────────────────────┘
│ 4. 转出USDCInteractions
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移 │
│ ───────────────────────────────────────────────────────────────── │
│ 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. 更新managedAssetsCEI - 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. 转入USDCInteractions
┌─────────────────────────────────────────────────────────────────────┐
│ 代币转移 │
│ ───────────────────────────────────────────────────────────────── │
│ 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在暂停期间也无法操作 │
│ ⚠️ 查询功能不受影响 │
└─────────────────────────────────────────────────────────────────────┘
```