RWA 代币化 —— 认购模块
认购模块是 RWA 平台的核心业务模块,管理投资项目的创建、白名单验证、用户认购等功能。
1. 概述
RWASubscription 实现了完整的代币认购流程:
1 | ┌─────────────────────────────────────────────────────────┐ |
2. 角色与权限
1 | bytes32 public constant PROJECT_ADMIN_ROLE = keccak256("PROJECT_ADMIN_ROLE"); |
| 角色 | 权限 |
|---|---|
| DEFAULT_ADMIN_ROLE | 管理角色、设置财务参数、升级合约 |
| PROJECT_ADMIN_ROLE | 创建项目 |
| WHITELIST_SIGNER_ROLE | 签发白名单签名 |
| EMERGENCY_ROLE | 紧急暂停项目 |
3. 数据结构
3.1 认购项目
1 | struct SubscriptionProject { |
3.2 用户认购记录
1 | struct UserSubscription { |
3.3 状态枚举
1 | enum SubscriptionStatus { |
4. 项目创建
4.1 createProject
创建新的认购项目。
1 | function createProject( |
参数验证:
1 | require(rwaToken != address(0), "Invalid RWA token"); |
目标金额计算:
1 | // 使用辅助库计算目标募集金额 |
4.2 价格计算库
1 | library PriceCalculationLib { |
4.3 创建示例
1 | // 创建一个房产代币认购项目 |
5. 白名单签名验证
项目可以设置 requiresWhitelist = true,要求用户持有有效签名才能认购。
5.1 签名结构(EIP-712)
1 | bytes32 private constant WHITELIST_TYPEHASH = |
5.2 签名验证
1 | function _verifyWhitelistSignature( |
5.3 Nonce 管理
每个用户有独立的 nonce,每次成功认购后递增,防止签名重放。
1 | mapping(address => uint256) private _nonces; |
5.4 链下签名生成
1 | // 使用 ethers.js 生成白名单签名 |
6. 用户认购
6.1 带白名单签名认购
1 | function subscribe( |
6.2 无签名认购
用于不需要白名单的项目。
1 | function subscribe( |
6.3 前置条件验证
1 | function _validateSubscriptionPrerequisites( |
6.4 执行认购
1 | function _executeSubscription( |
7. 取消认购
在认购期内,用户可以取消认购并获得全额退款。
1 | function cancelSubscription( |
8. 查询函数
8.1 项目查询
1 | // 获取项目详情 |
8.2 用户查询
1 | // 获取用户认购记录 |
8.3 资格检查
1 | function canSubscribe(uint256 projectId, address user) external view returns (bool canSub, string memory reason) { |
8.4 项目统计
1 | function getProjectStatistics(uint256 projectId) external view returns ( |
9. 紧急控制
1 | // 紧急暂停单个项目 |
10. 事件
1 | event ProjectCreated(uint256 indexed projectId, address indexed rwaToken, uint256 tokenPrice, uint256 totalTokensOffered); |
11. 安全考虑
11.1 签名安全
- EIP-712 结构化签名防止跨合约/跨链重放
- Nonce 机制防止同一签名重复使用
- Deadline 限制签名有效期
11.2 金额安全
- 使用 SafeERC20 处理代币转账
- 先检查后转账,避免重入
- 精度计算使用专门的库函数
11.3 状态一致性
- 所有状态更新在单个交易中完成
- 使用 storage 指针避免数据不一致
- ReentrancyGuard 防止重入攻击