RWA 代币化 —— 合规与身份模块

合规模块是 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);

通过监听这些事件,可以构建链下索引服务,实现高效的身份查询和统计。