RWA 代币化 —— 结算与领取
本文介绍 RWA 认购的后半程流程:项目结算、超额认购处理、代币领取与退款。
1. 概述
认购期结束后,进入结算阶段:
1 | ┌─────────────────────────────────────────────────────────┐ |
2. 超额认购处理
2.1 什么是超额认购
当募集金额超过目标金额时,即发生超额认购:
1 | 项目目标:募集 1,000,000 USDC,发售 10,000 代币 |
2.2 分配算法
超额认购时,按比例分配代币:
1 | function _calculateUserAllocation( |
2.3 分配示例
1 | 项目参数: |
3. 项目结算
3.1 settleProject
项目方调用结算函数,转入代币并收取募集资金。
1 | function settleProject( |
3.2 结算流程图
1 | ┌─────────────────────────────────────────────────────────┐ |
3.3 保证金说明
保证金(Deposit)用于:
- 约束项目方履约
- 可用于后续分红或赔偿
- 比例在创建项目时设定(最高 50%)
1 | 保证金比例(基点): |
4. 用户领取
4.1 claim
用户在项目结算后领取代币和退款。
1 | function claim( |
4.2 领取流程
1 | 用户调用 claim(projectId) |
4.3 查询可领取金额
1 | function getClaimableAmounts( |
5. 完整流程示例
5.1 时间线
1 | Day 0: 项目创建 |
5.2 代码示例
1 | // ===== 认购期结束后 ===== |
6. 边界情况处理
6.1 未满额认购
募集金额低于目标时:
- 用户获得全部请求的代币
- 无退款
- 项目方收到实际募集金额(扣除保证金)
1 | 目标:1,000,000 USDC |
6.2 刚好满额
1 | 目标:1,000,000 USDC |
6.3 极端超额
1 | 目标:1,000,000 USDC |
7. 查询函数
7.1 分配计算
1 | // 计算指定金额可购买的代币数量 |
7.2 状态查询
1 | // 获取用户认购详情 |
8. 事件
1 | // 项目状态变更 |
9. 安全考虑
9.1 重复领取防护
1 | // 状态检查确保只能领取一次 |
9.2 精度处理
- 使用专门的 PriceCalculationLib 处理不同精度代币
- 乘法在除法之前,减少精度损失
- 向下取整保护合约资产
9.3 结算顺序
项目方必须在结算时转入足够的 RWA 代币:
1 | // 使用 safeTransferFrom 确保转账成功 |
9.4 资金安全
- 超额部分留在合约中直到用户领取
- 每个用户的分配动态计算,确保总量不超支
- 使用 nonReentrant 防止重入攻击
10. Gas 优化
10.1 动态计算 vs 预计算
当前实现采用动态计算分配:
- 优点:节省结算时的 Gas
- 缺点:每次 claim 需要计算
替代方案是结算时预计算:
- 优点:claim 时直接读取
- 缺点:结算 Gas 高,可能超限
对于用户数量较多的项目,动态计算更优。
10.2 批量领取
可考虑添加批量领取函数:
1 | function batchClaim(uint256[] calldata projectIds) external nonReentrant { |