# 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在暂停期间也无法操作 │ │ ⚠️ 查询功能不受影响 │ └─────────────────────────────────────────────────────────────────────┘ ```