user logout in the vault changed to queuing mechanism, and add function of batch sending WUSD
This commit is contained in:
@@ -3,7 +3,10 @@
|
||||
## 目录
|
||||
1. [创建Vault流程](#1-创建vault流程)
|
||||
2. [用户存款流程(depositYT)](#2-用户存款流程deposityt)
|
||||
3. [用户提款流程(withdrawYT)](#3-用户提款流程withdrawyt)
|
||||
3. [用户提款流程(withdrawYT - 两阶段提现)](#3-用户提款流程withdrawyt---两阶段提现)
|
||||
- 3.1 [第一阶段:提交提现请求](#31-第一阶段提交提现请求)
|
||||
- 3.2 [第二阶段:批量处理提现请求](#32-第二阶段批量处理提现请求)
|
||||
- 3.3 [资金不足时的处理](#33-资金不足时的处理)
|
||||
4. [价格更新流程](#4-价格更新流程)
|
||||
5. [资产管理流程 - 提取投资](#5-资产管理流程---提取投资)
|
||||
6. [资产管理流程 - 归还资产](#6-资产管理流程---归还资产)
|
||||
@@ -285,7 +288,9 @@
|
||||
|
||||
---
|
||||
|
||||
## 3. 用户提款流程(withdrawYT)
|
||||
## 3. 用户提款流程(withdrawYT - 两阶段提现)
|
||||
|
||||
### 3.1 第一阶段:提交提现请求
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
@@ -329,12 +334,15 @@
|
||||
│ 2. 调用 withdrawYT(5000e18)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ YTAssetVault.withdrawYT() │
|
||||
│ YTAssetVault.withdrawYT() - 提交请求 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ function withdrawYT(uint256 _ytAmount) │
|
||||
│ function withdrawYT(uint256 _ytAmount) returns (uint256 requestId) │
|
||||
│ • 非重入保护: nonReentrant │
|
||||
│ • 暂停检查: whenNotPaused │
|
||||
│ • 参数: 5,000 YT │
|
||||
│ │
|
||||
│ 🔴 重要变化:此函数不再立即发放WUSD! │
|
||||
│ 只创建提现请求,进入排队等待 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 3. 多重验证
|
||||
@@ -352,9 +360,11 @@
|
||||
│ ③ block.timestamp >= nextRedemptionTime │
|
||||
│ ✓ 2025-02-16 >= 2025-02-15 通过 │
|
||||
│ (已到赎回时间) │
|
||||
│ │
|
||||
│ ⚠️ 不再检查流动性!即使vault中WUSD不足也可以提交请求 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 4. 计算可获得的WUSD数量
|
||||
│ 4. 计算应得的WUSD数量
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 计算WUSD数量 │
|
||||
@@ -367,32 +377,13 @@
|
||||
│ │
|
||||
│ 计算过程: │
|
||||
│ wusdAmount = (5,000e18 × 1.10e30) ÷ 1.00e30 │
|
||||
│ = (5,000e18 × 1.10) ÷ 1.00 │
|
||||
│ = 5,500e18 │
|
||||
│ = 5,500 WUSD │
|
||||
│ │
|
||||
│ 用户获得收益: 5,500 - 5,000 = 500 WUSD (10%增值) │
|
||||
│ 💡 这个金额会锁定在请求中,不受后续价格变化影响 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 5. 检查Vault流动性
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 流动性检查 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ uint256 availableWUSD = IERC20(wusdAddress).balanceOf(vault) │
|
||||
│ if (wusdAmount > availableWUSD) revert InsufficientWUSD() │
|
||||
│ │
|
||||
│ 当前状态: │
|
||||
│ • Vault中WUSD余额: 10,000 WUSD │
|
||||
│ • 需要支付: 5,500 WUSD │
|
||||
│ • 5,500 ≤ 10,000 ✓ 流动性充足 │
|
||||
│ │
|
||||
│ 注意: │
|
||||
│ 如果manager已提取部分资金进行投资,availableWUSD可能不足 │
|
||||
│ 此时用户需要等待manager归还资金 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 6. 销毁用户的YT(CEI - Effects)
|
||||
│ 5. 立即销毁YT代币(CEI - Effects)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 销毁YT代币 │
|
||||
@@ -406,51 +397,295 @@
|
||||
│ 结果: │
|
||||
│ • 用户YT余额: 10,000 → 5,000 YT │
|
||||
│ • 总供应量: 10,000 → 5,000 YT │
|
||||
│ │
|
||||
│ ⚠️ 注意:YT已销毁,但WUSD还未发放! │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 7. 转出WUSD给用户
|
||||
│ 6. 创建提现请求记录
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 代币转移(Interactions) │
|
||||
│ 创建WithdrawRequest │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ IERC20(wusdAddress).safeTransfer( │
|
||||
│ msg.sender, // 用户地址 │
|
||||
│ 5500e18 // 转出5,500 WUSD │
|
||||
│ ) │
|
||||
│ requestId = requestIdCounter // 当前假设为 requestId = 42 │
|
||||
│ │
|
||||
│ 结果: │
|
||||
│ • Vault WUSD余额: 10,000 → 4,500 │
|
||||
│ • 用户WUSD余额: 0 → 5,500 │
|
||||
│ withdrawRequests[42] = WithdrawRequest({ │
|
||||
│ user: msg.sender, // 用户地址 │
|
||||
│ ytAmount: 5000e18, // 5,000 YT │
|
||||
│ wusdAmount: 5500e18, // 应得5,500 WUSD │
|
||||
│ requestTime: block.timestamp, // 当前时间戳 │
|
||||
│ queueIndex: 42, // 队列位置 │
|
||||
│ processed: false // 未处理 │
|
||||
│ }) │
|
||||
│ │
|
||||
│ userRequestIds[msg.sender].push(42) // 记录到用户请求列表 │
|
||||
│ requestIdCounter++ // 43 │
|
||||
│ pendingRequestsCount++ // 待处理计数+1 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 8. 触发事件
|
||||
│ 7. 触发事件
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 事件记录 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ emit Sell( │
|
||||
│ emit WithdrawRequestCreated( │
|
||||
│ 42, // requestId │
|
||||
│ msg.sender, // 用户地址 │
|
||||
│ 5000e18, // YT数量 │
|
||||
│ 5500e18 // WUSD数量 │
|
||||
│ 5500e18, // 应得WUSD数量 │
|
||||
│ 42 // queueIndex │
|
||||
│ ) │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 9. 返回WUSD数量
|
||||
│ 8. 返回请求ID
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 提款完成 │
|
||||
│ 请求提交完成 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ 用户最终状态: │
|
||||
│ • YT余额: 5,000 YT (剩余) │
|
||||
│ • WUSD余额: 5,500 WUSD (获得) │
|
||||
│ • 收益: 500 WUSD (10%增值) │
|
||||
│ 返回值: requestId = 42 │
|
||||
│ │
|
||||
│ Vault最终状态: │
|
||||
│ • totalSupply: 5,000 YT │
|
||||
│ • totalAssets: 4,500 WUSD (假设无managedAssets) │
|
||||
│ • idleAssets: 4,500 WUSD │
|
||||
│ 用户当前状态: │
|
||||
│ • YT余额: 5,000 YT (已减少) │
|
||||
│ • WUSD余额: 0 WUSD (尚未到账) ⏳ │
|
||||
│ • 提现请求: requestId = 42 (排队中) │
|
||||
│ │
|
||||
│ 返回值: 5,500 WUSD │
|
||||
│ Vault状态: │
|
||||
│ • totalSupply: 5,000 YT (已减少) │
|
||||
│ • pendingRequestsCount: +1 │
|
||||
│ • requestIdCounter: 43 │
|
||||
│ │
|
||||
│ 📍 下一步: │
|
||||
│ 用户需要等待Manager或Factory调用processBatchWithdrawals() │
|
||||
│ 批量处理提现请求后,WUSD才会到账 │
|
||||
│ │
|
||||
│ 查询请求状态: │
|
||||
│ • getRequestDetails(42) - 查看请求详情 │
|
||||
│ • getUserPendingRequests(user) - 查看所有待处理请求 │
|
||||
│ • getQueueProgress() - 查看队列处理进度 │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 第二阶段:批量处理提现请求
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Manager/Factory (资产管理方) │
|
||||
│ 当前状态: │
|
||||
│ • Vault中有足够的WUSD (基金赎回资金已到账) │
|
||||
│ • 待处理请求: 150个 │
|
||||
│ • 准备批量发放WUSD给用户 │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 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. 获取可用WUSD并开始循环处理
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 循环处理请求 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ uint256 availableWUSD = vault.balance(WUSD) // 假设: 100,000 WUSD │
|
||||
│ 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 (availableWUSD >= request.wusdAmount) { │
|
||||
│ // ✅ 可以处理此请求 │
|
||||
│ 处理逻辑 ▼ │
|
||||
│ } else { │
|
||||
│ // ❌ WUSD不足,停止处理 │
|
||||
│ break │
|
||||
│ } │
|
||||
│ } │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 5. 处理单个请求(循环内)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 处理请求详细步骤 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ 以 requestId = 42 为例: │
|
||||
│ │
|
||||
│ ① 转账WUSD给用户 │
|
||||
│ IERC20(wusd).safeTransfer(request.user, 5500e18) │
|
||||
│ • 用户WUSD余额: 0 → 5,500 WUSD ✅ │
|
||||
│ │
|
||||
│ ② 标记为已处理 │
|
||||
│ request.processed = true │
|
||||
│ │
|
||||
│ ③ 更新统计数据 │
|
||||
│ availableWUSD -= 5500e18 // 剩余可用WUSD减少 │
|
||||
│ 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 (总发放WUSD) │
|
||||
│ ) │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 8. 返回处理结果
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 批量处理完成 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ 返回值: │
|
||||
│ • processedCount: 50 (处理了50个请求) │
|
||||
│ • totalDistributed: 275,000 WUSD (总共发放) │
|
||||
│ │
|
||||
│ 更新后的状态: │
|
||||
│ • pendingRequestsCount: 150 → 100 (还剩100个待处理) │
|
||||
│ • processedUpToIndex: 100 → 150 │
|
||||
│ • Vault WUSD余额: 100,000 → (100,000 - 275,000) = -175,000 ❌ │
|
||||
│ (这里假设vault有足够资金,实际会提前检查) │
|
||||
│ │
|
||||
│ 用户影响(requestId = 42的用户): │
|
||||
│ ✅ YT余额: 5,000 YT (已销毁) │
|
||||
│ ✅ WUSD余额: 5,500 WUSD (已到账!) │
|
||||
│ ✅ 提现完成,可以自由使用WUSD │
|
||||
│ │
|
||||
│ 队列状态: │
|
||||
│ • 已处理: 150/250 = 60% │
|
||||
│ • 待处理: 100个 │
|
||||
│ • 可继续调用processBatchWithdrawals()处理剩余请求 │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.3 资金不足时的处理
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 场景:WUSD资金不足 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ 当前状态: │
|
||||
│ • Vault中WUSD: 50,000 │
|
||||
│ • 待处理请求: 100个 │
|
||||
│ • 前10个请求需要: 60,000 WUSD │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 调用 processBatchWithdrawals(100)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 处理过程 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ 循环处理: │
|
||||
│ • Request 1: 需要5,000 WUSD ✅ 处理成功 (剩余45,000) │
|
||||
│ • Request 2: 需要5,000 WUSD ✅ 处理成功 (剩余40,000) │
|
||||
│ • Request 3: 需要5,000 WUSD ✅ 处理成功 (剩余35,000) │
|
||||
│ • Request 4: 需要5,000 WUSD ✅ 处理成功 (剩余30,000) │
|
||||
│ • Request 5: 需要5,000 WUSD ✅ 处理成功 (剩余25,000) │
|
||||
│ • Request 6: 需要5,000 WUSD ✅ 处理成功 (剩余20,000) │
|
||||
│ • Request 7: 需要5,000 WUSD ✅ 处理成功 (剩余15,000) │
|
||||
│ • Request 8: 需要5,000 WUSD ✅ 处理成功 (剩余10,000) │
|
||||
│ • Request 9: 需要5,000 WUSD ✅ 处理成功 (剩余5,000) │
|
||||
│ • Request 10: 需要5,000 WUSD ✅ 处理成功 (剩余0) │
|
||||
│ • Request 11: 需要5,000 WUSD ❌ 资金不足,停止处理 │
|
||||
│ │
|
||||
│ 处理结果: │
|
||||
│ • processedCount: 10 (只处理了10个,而不是100个) │
|
||||
│ • totalDistributed: 50,000 WUSD │
|
||||
│ • 剩余90个请求继续排队 │
|
||||
│ │
|
||||
│ ⚠️ 不会revert,优雅地停止! │
|
||||
└────────────────────────────┬────────────────────────────────────────┘
|
||||
│
|
||||
│ 后续处理
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 等待资金到账 │
|
||||
│ ───────────────────────────────────────────────────────────────── │
|
||||
│ Manager操作: │
|
||||
│ ① 等待基金赎回下一批资金到账 │
|
||||
│ ② 调用 depositManagedAssets(100000e18) 充值 │
|
||||
│ ③ 再次调用 processBatchWithdrawals(100) 继续处理 │
|
||||
│ │
|
||||
│ 用户体验: │
|
||||
│ • Request 1-10的用户: ✅ WUSD已到账 │
|
||||
│ • Request 11+的用户: ⏳ 继续排队等待 │
|
||||
│ • 可通过getUserPendingRequests()查询状态 │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -988,6 +1223,11 @@
|
||||
|
||||
## 8. 查询信息流程
|
||||
|
||||
- 8.1 [查询单个Vault信息](#81-查询单个vault信息)
|
||||
- 8.2 [通过Factory查询Vault信息](#82-通过factory查询vault信息)
|
||||
- 8.3 [查询所有Vault列表](#83-查询所有vault列表)
|
||||
- 8.4 [查询提现请求信息(新增)](#84-查询提现请求信息新增)
|
||||
|
||||
### 8.1 查询单个Vault信息
|
||||
|
||||
```
|
||||
@@ -1147,6 +1387,165 @@
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 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数量 │
|
||||
│ wusdAmount: 5500e18, // 应得WUSD数量 │
|
||||
│ requestTime: 1739692800, // 请求时间戳 │
|
||||
│ queueIndex: 42, // 队列位置 │
|
||||
│ processed: false // 是否已处理 │
|
||||
│ } │
|
||||
│ │
|
||||
│ 前端展示: │
|
||||
│ ┌────────────────────────────────────────┐ │
|
||||
│ │ 📋 提现请求 #42 │ │
|
||||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||||
│ │ 状态: ⏳ 排队中 │ │
|
||||
│ │ YT数量: 5,000 YT │ │
|
||||
│ │ 应得WUSD: 5,500 WUSD │ │
|
||||
│ │ 提交时间: 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, │
|
||||
│ wusdAmount: 5500e18, │
|
||||
│ requestTime: 1739692800, │
|
||||
│ queueIndex: 42, │
|
||||
│ processed: false │
|
||||
│ } │
|
||||
│ ] │
|
||||
│ │
|
||||
│ 前端展示: │
|
||||
│ ┌────────────────────────────────────────┐ │
|
||||
│ │ 👤 我的提现请求 │ │
|
||||
│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │
|
||||
│ │ ✅ 请求#15 1,000 YT → 1,100 WUSD │ │
|
||||
│ │ 状态: 已完成 2025-02-10 │ │
|
||||
│ │ │ │
|
||||
│ │ ⏳ 请求#42 5,000 YT → 5,500 WUSD │ │
|
||||
│ │ 状态: 排队中 队列第42位 │ │
|
||||
│ │ 提交于: 2025-02-16 10:00 │ │
|
||||
│ │ │ │
|
||||
│ │ ⏳ 请求#68 3,000 YT → 3,300 WUSD │ │
|
||||
│ │ 状态: 排队中 队列第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 WUSD │ │
|
||||
│ │ 预计可处理: 约45个请求 │ │
|
||||
│ └────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录:重要概念说明
|
||||
@@ -1308,6 +1707,104 @@ UUPS (Universal Upgradeable Proxy Standard):
|
||||
• 保留__gap数组用于未来扩展
|
||||
```
|
||||
|
||||
### H. 两阶段提现机制(Withdraw Queue)
|
||||
|
||||
```
|
||||
两阶段提现机制:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
解决资金分批到账的提现排队问题
|
||||
|
||||
设计目的:
|
||||
• 基金赎回需要时间,资金不会一次性到账
|
||||
• 按用户提现请求时间先后排队(FIFO)
|
||||
• 资金到账后由后端统一批量发放
|
||||
|
||||
阶段一:用户提交请求
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
用户调用 withdrawYT(_ytAmount)
|
||||
|
||||
执行内容:
|
||||
1. 验证参数和赎回时间
|
||||
2. 立即销毁用户的YT代币
|
||||
3. 计算应得WUSD数量(锁定当前价格)
|
||||
4. 创建WithdrawRequest记录
|
||||
5. 返回requestId供用户查询
|
||||
|
||||
关键特点:
|
||||
✓ YT立即销毁(防止重复提现)
|
||||
✓ WUSD暂不发放(等待批量处理)
|
||||
✓ 金额已锁定(不受后续价格变化影响)
|
||||
✓ 即使vault资金不足也可提交请求
|
||||
|
||||
阶段二:批量处理发放
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Manager/Factory调用 processBatchWithdrawals(_batchSize)
|
||||
|
||||
执行内容:
|
||||
1. 获取vault当前可用WUSD
|
||||
2. 按requestId顺序(FIFO)处理请求
|
||||
3. 依次给用户转账WUSD
|
||||
4. 标记请求为已处理
|
||||
5. 资金不足时自动停止
|
||||
|
||||
关键特点:
|
||||
✓ FIFO严格保证(先提交先处理)
|
||||
✓ 支持分批处理(避免gas超限)
|
||||
✓ 断点续传(记录处理进度)
|
||||
✓ 资金不足不会revert(优雅停止)
|
||||
|
||||
数据结构:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
struct WithdrawRequest {
|
||||
address user; // 用户地址
|
||||
uint256 ytAmount; // YT数量
|
||||
uint256 wusdAmount; // 应得WUSD数量(锁定)
|
||||
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已销毁但WUSD未到账的风险
|
||||
→ 解决:Manager有责任及时处理请求
|
||||
→ 解决:Factory可以代为处理
|
||||
|
||||
⚠️ 用户长时间等待的风险
|
||||
→ 解决:可查询队列进度
|
||||
→ 解决:前端显示预计等待时间
|
||||
|
||||
⚠️ 价格锁定可能错失市场波动
|
||||
→ 解决:这是设计特性,确保公平性
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 暂停功能流程
|
||||
|
||||
Reference in New Issue
Block a user