user logout in the vault changed to queuing mechanism, and add function of batch sending WUSD

This commit is contained in:
2025-12-19 13:26:49 +08:00
parent 21674f86a9
commit 399354646a
27 changed files with 2057 additions and 2877 deletions

View File

@@ -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. 销毁用户的YTCEI - 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. 暂停功能流程