合规模块是 RWA 代币化平台的基础设施,负责投资者身份验证(KYC)、国家/地区合规检查以及投资者等级管理。
1. 概述 RWA(Real World Assets)代币化涉及真实资产,需要满足证券法规要求。合规模块确保只有经过验证的投资者才能参与。
合约
功能
IdentityRegistry
身份注册中心,管理 KYC 状态和投资者信息
ComplianceUpgradeable
合规检查,验证转账是否符合规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌─────────────────────────────────────────────────────────┐ │ 投资者 │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ IdentityRegistry │ │ (KYC 验证 + 身份存储) │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ RWA 业务模块 │ │ (Subscription / Token Transfer / etc.) │ └─────────────────────────────────────────────────────────┘
2. IdentityRegistry 合约解析 IdentityRegistry 是身份注册中心,存储投资者的 KYC 状态、国家代码和投资者等级。
2.1 角色定义 1 2 bytes32 public constant IDENTITY_REGISTRAR_ROLE = keccak256("IDENTITY_REGISTRAR_ROLE"); bytes32 public constant AGENT_ROLE = keccak256("AGENT_ROLE");
角色
权限
DEFAULT_ADMIN_ROLE
管理所有角色
IDENTITY_REGISTRAR_ROLE
注册商角色(预留)
AGENT_ROLE
执行身份注册、更新、删除操作
2.2 核心数据结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 用户地址 → 身份合约地址 mapping(address => address) private _identities; // 用户地址 → 国家代码(ISO 3166-1 数字代码) mapping(address => uint16) private _countries; // 身份合约 → 用户地址(反向映射) mapping(address => address) private _investorAddresses; // 用户地址 → KYC 验证状态 mapping(address => bool) private _verified; // 投资者等级 enum InvestorTier { None, // 未分级 Standard, // 标准投资者 Priority, // 优先投资者 VIP, // VIP 投资者 Strategic // 战略投资者 } // 用户地址 → 投资者等级 mapping(address => InvestorTier) private _investorTiers;
2.3 身份注册 registerIdentity 为投资者注册身份,设置 KYC 状态为已验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function registerIdentity( address _userAddress, // 投资者钱包地址 address _identity, // 身份合约地址(链上身份凭证) uint16 _country // 国家代码 ) external onlyAgent nonReentrant { require(_userAddress != address(0), "IdentityRegistry: invalid user address"); require(_identity != address(0), "IdentityRegistry: invalid identity address"); require(_identities[_userAddress] == address(0), "IdentityRegistry: identity already registered"); _identities[_userAddress] = _identity; _countries[_userAddress] = _country; _investorAddresses[_identity] = _userAddress; _verified[_userAddress] = true; emit IdentityStored(_userAddress, _identity); }
使用场景 :
1 2 3 4 5 用户完成链下 KYC 后: 1. KYC 服务商验证用户身份 2. 创建链上身份合约(可选) 3. Agent 调用 registerIdentity 记录验证状态 4. 用户获得参与 RWA 项目的资格
batchRegisterIdentity 批量注册多个投资者身份,适用于大规模 KYC 导入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function batchRegisterIdentity( address[] calldata _userAddresses, address[] calldata _identitiesArray, uint16[] calldata _countriesArray ) external onlyAgent { require( _userAddresses.length == _identitiesArray.length && _userAddresses.length == _countriesArray.length, "IdentityRegistry: arrays length mismatch" ); for (uint256 i = 0; i < _userAddresses.length; i++) { // ... 验证并注册每个身份 _identities[_userAddresses[i]] = _identitiesArray[i]; _countries[_userAddresses[i]] = _countriesArray[i]; _investorAddresses[_identitiesArray[i]] = _userAddresses[i]; _verified[_userAddresses[i]] = true; emit IdentityStored(_userAddresses[i], _identitiesArray[i]); } }
2.4 身份更新与删除 updateIdentity 更新用户的身份合约地址(如身份合约升级)。
1 2 3 4 5 6 7 8 9 10 11 12 function updateIdentity(address _userAddress, address _identity) external onlyAgent { require(_identities[_userAddress] != address(0), "IdentityRegistry: identity not found"); address oldIdentity = _identities[_userAddress]; _identities[_userAddress] = _identity; _investorAddresses[_identity] = _userAddress; // 清除旧映射 delete _investorAddresses[oldIdentity]; emit IdentityUpdated(_identity, _userAddress); }
updateCountry 更新用户的国家代码(如用户迁移)。
1 2 3 4 5 6 function updateCountry(address _userAddress, uint16 _country) external onlyAgent { require(_identities[_userAddress] != address(0), "IdentityRegistry: identity not found"); _countries[_userAddress] = _country; emit CountryUpdated(_userAddress, _country); }
deleteIdentity 删除用户身份(如 KYC 过期或用户请求注销)。
1 2 3 4 5 6 7 8 9 10 11 12 function deleteIdentity(address _userAddress) external onlyAgent { require(_identities[_userAddress] != address(0), "IdentityRegistry: identity not found"); address identityToRemove = _identities[_userAddress]; delete _identities[_userAddress]; delete _countries[_userAddress]; delete _investorAddresses[identityToRemove]; delete _verified[_userAddress]; emit IdentityUnstored(_userAddress, identityToRemove); }
2.5 投资者等级管理 投资者等级用于差异化服务,如认购优先权、额度上限等。
setInvestorTier 设置单个用户的投资者等级。
1 2 3 4 5 6 7 function setInvestorTier(address _userAddress, InvestorTier _tier) external onlyAgent { require(_userAddress != address(0), "IdentityRegistry: invalid user address"); require(_verified[_userAddress], "IdentityRegistry: user not verified"); _investorTiers[_userAddress] = _tier; emit InvestorTierUpdated(_userAddress, _tier); }
batchSetInvestorTier 批量设置投资者等级。
1 2 3 4 5 6 7 8 9 10 11 function batchSetInvestorTier( address[] calldata _userAddresses, InvestorTier _tier ) external onlyAgent { for (uint256 i = 0; i < _userAddresses.length; i++) { require(_verified[_userAddresses[i]], "IdentityRegistry: user not verified"); _investorTiers[_userAddresses[i]] = _tier; } emit InvestorTierBatchUpdated(_userAddresses, _tier); }
hasMinimumTier 检查用户是否达到最低等级要求。
1 2 3 function hasMinimumTier(address _userAddress, InvestorTier _minimumTier) external view returns (bool) { return uint(_investorTiers[_userAddress]) >= uint(_minimumTier); }
等级应用场景 :
1 2 3 项目 A:仅限 VIP 及以上投资者参与 项目 B:Standard 以上即可,但 VIP 享受 2 倍额度 项目 C:Strategic 投资者享有优先认购窗口
2.6 查询函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 获取用户身份合约地址 function identity(address _userAddress) external view returns (address); // 获取用户国家代码 function investorCountry(address _userAddress) external view returns (uint16); // 检查用户是否已验证 function isVerified(address _userAddress) external view returns (bool); // 通过身份合约获取用户地址 function investorAddress(address _identity) external view returns (address); // 获取用户投资者等级 function getInvestorTier(address _userAddress) external view returns (InvestorTier);
3. 与其他模块的集成 3.1 RWASubscription 集成 认购模块在用户认购时检查 KYC 状态:
1 2 3 4 5 6 7 8 9 10 11 // RWASubscription.sol function _validateSubscriptionPrerequisites(...) internal view { SubscriptionProject storage project = _projects[projectId]; // 如果项目要求 KYC if (project.requiresKYC) { require(identityRegistry.isVerified(msg.sender), "KYC not verified"); } // ... 其他验证 }
3.2 RWACompliantToken 集成 合规代币在转账时检查发送方和接收方的身份:
1 2 3 4 5 6 7 8 9 10 // RWACompliantToken.sol function _update(address from, address to, uint256 value) internal override { // 检查转账双方是否都已通过 KYC require( compliance.canTransfer(from, to, value), "Transfer not compliant" ); super._update(from, to, value); }
4. 国家代码说明 使用 ISO 3166-1 数字代码表示国家/地区:
代码
国家/地区
156
中国
344
中国香港
446
中国澳门
158
中国台湾
840
美国
826
英国
392
日本
702
新加坡
合规用途 :
某些 RWA 项目可能限制特定国家投资者
不同国家可能有不同的投资额度上限
满足跨境证券法规要求
5. 安全考虑 5.1 权限控制
仅 AGENT_ROLE 可执行身份操作
管理员应谨慎授予 Agent 角色
建议使用多签钱包作为 Admin
5.2 重入防护 registerIdentity 使用 nonReentrant 修饰器防止重入攻击。
5.3 数据一致性
注册时同时更新正向和反向映射
删除时清理所有相关映射
更新时先清理旧映射再设置新映射
6. 事件 1 2 3 4 5 6 event IdentityStored(address indexed userAddress, address indexed identity); event IdentityUpdated(address indexed identity, address indexed userAddress); event IdentityUnstored(address indexed userAddress, address indexed identity); event CountryUpdated(address indexed userAddress, uint16 country); event InvestorTierUpdated(address indexed user, InvestorTier tier); event InvestorTierBatchUpdated(address[] users, InvestorTier tier);
通过监听这些事件,可以构建链下索引服务,实现高效的身份查询和统计。