什么是 ERC-3643?
本文介绍了ERC-3643,这是一个以太坊代币标准,专为受监管的资产设计,它通过链上身份、资格检查和模块化合规规则,在ERC-20模型的基础上,支持需要许可的代币。ERC-3643由ERC-3643协会管理,旨在标准化现实世界资产的许可代币化,适用于证券、房地产和基金等用例。
概述
ERC-3643 是以太坊许可型代币的标准,意味着代币只能由满足预定义的合规性规则(如 KYC/AML、投资者资格和管辖区要求)的身份持有和转移。它专为受监管的资产而设计,你必须知道谁持有该资产以及他们是否被允许持有或交易它。
最初被称为 T-REX (Token for Regulated EXchanges,受监管交易所代币),由 Tokeny 发起,现在正式成为 ERC-3643,并由 ERC-3643 协会管理,该协会专注于将现实世界资产 (RWA) 的许可型代币化进行标准化。
在实践中,ERC-3643 是智能合约套件,共同实现:
- 链上身份 & 声明(通过 ONCHAINID)
- 合格持有者的身份注册表
- 模块化合规性规则
- 代币合约,在转移时强制执行合规性,同时保持与 ERC-20 的兼容性
由于 ERC-3643 将身份和合规性规则直接集成到代币标准中,因此它是代币化 RWA(如证券、房地产、基金和其他受监管工具)的绝佳选择。
你将要做什么
- 了解与普通 ERC-20 相比,ERC-3643 正在解决什么问题
- 学习高级架构(核心合约、注册表和角色)
- 了解如何在链上强制执行身份和合规性
- 演练 ERC-3643 系统中转移如何运作
- 概述部署、角色和常见的 RWA 用例
你将需要什么
warning
本指南中的代码示例未经审计,仅用于概念理解。未经彻底审查、测试和独立安全审计,请勿在生产中使用它们。
ERC-3643 解决的问题
在深入研究之前,让我们设置背景。标准 ERC-20 代币是无需许可的。任何人都可以发送它,任何人都可以接收它,并且任何地址都可以持有它。对于像 DAI 或 UNI 这样的资产来说,这是一个特性。
但是,当处理现实世界的资产时,例如代币化的证券(公司股份)或 fractionalized 房地产,这就会成为一个问题。现实世界的法规要求你了解谁持有该资产,并根据以下内容限制转让:
- 身份:持有人是否通过了 KYC?
- 管辖权:接收者是否在受制裁国家?
- 认证:持有人是否是被允许购买此证券的“合格投资者”?
- 锁定期:资产是否处于无法出售的“锁定期”?
ERC-3643,最初被称为 T-REX (Token for Regulated EXchanges, 受监管交易所代币),旨在将这些规则引入链上。它是一个智能合约套件,使与 ERC-20 兼容的代币具有“合规性感知”。
标准要求
从高层次来看,ERC-3643 的实现应提供:
- 兼容性和接口
- 保持 ERC-20 的兼容性
- 公开用于转移的标准预检查 (
canTransfer) - 支持受监管流程所需的批量操作和管理功能
- 身份和合规性
- 集成链上身份系统(例如,ONCHAINID)
- 在转移、铸造和销毁时使用合规性层
- 控制和操作
- 支持暂停和冻结(全局、地址级别和部分冻结)
- 使用 EIP-173 所有权加上 Agent 角色来执行敏感操作(强制转移、恢复、铸造/销毁)
ERC-3643 架构
ERC-3643 是有意的模块化。它没有将所有内容都放在一个单体代币合约中,而是将职责分配给多个合约。
概括地说,核心组件是:
| 组件 | 摘要 |
|---|---|
| ONCHAINID | 一个单独的身份合约(基于 ERC-734/735),它持有用户可验证的 claim,由受信任的发行者发布。 |
| 受信任的发行者注册表 | 受信任的地址列表(例如,KYC 提供商),可以添加有关用户身份的 claim |
| Claim Topics 注册表 | 所需 claim 类型的目录(例如,KYC 验证、合格投资者)。 |
| 身份注册表 | 将钱包映射到 ONCHAINID 和国家/地区,公开 isVerified 等验证。 |
| 合规性合约 | 编码提供和转移规则,在转移之前/之后查询。 |
| 许可型代币 (T-REX) | 与 ERC-20 兼容的代币。它持有对身份注册表和合规性合约的引用,并在任何转移之前咨询它们。 |
ONCHAINID
ONCHAINID 是一个通用身份合约,用于记录密钥和可验证的 claim。
claim 示例包括:
- 地址 X 通过了提供商 Y 的 KYC
- 此投资者在管辖区 Z 中是合格的
受信任的发行者(如 KYC 提供商或受监管机构)会发布这些 claim。该合约不会直接存储个人身份信息 (PII),而是存储引用和哈希以保护隐私。
多个钱包可以链接到相同的底层身份,并且在代码中,此身份通常被称为 IIdentity。ONCHAINID 充当与合规性相关的事实的锚点。
受信任的发行者注册表
受信任的发行者注册表 跟踪哪些 claim 发行者对于给定的代币是受信任的,以及每个发行者可以签署哪些 claim 主题。
例如,你可能会信任:
- 用于
KYC_VALIDATED主题的特定 KYC 提供商。 - 用于
ACCREDITED_INVESTOR的受监管实体。
只有这些发行者的 claim 才被视为对该代币的合规性检查有效。
Claim Topics 注册表
Claim Topics 注册表 定义哪些 claim 类型对于持有代币很重要,例如:
KYC_VALIDATEDACCREDITED_INVESTORNOT_IN_RESTRICTED_COUNTRYNOT_ON_SANCTIONS_LIST
与 Trusted Issuers Registry 一起,它定义了需要哪些 claim 以及谁可以发布它们。
身份注册表
身份注册表 是代币持有者的看门人:
- 存储每个列入白名单的钱包的 ONCHAINID
- 公开
isVerified(address) - 强制只有经过验证的身份才能保留注册
它通常依赖于 IdentityRegistryStorage,因此多个代币可以共享一个白名单,同时保留特定于代币的注册表。在 KYC 之后,投资者链接或部署 ONCHAINID,从受信任的发行者收到所需的 claim,并且他们的钱包已注册国家/地区代码(ISO-3166 数字)。
合规性合约
合规性 合约编码提供规则和转移限制。例子:
- 每个国家/地区的投资者人数上限。
- 每个投资者的最大仓位规模。
- 管辖区允许/拒绝列表。
- 基于时间的规则,如锁定期和归属。
标准接口:
function canTransfer(address from, address to, uint256 amount) external view returns (bool);
function transferred(address from, address to, uint256 amount) external;
function created(address to, uint256 amount) external;
function destroyed(address from, uint256 amount) external;
代币合约使用合规性合约来:
- 预先检查是否允许转移 (
canTransfer)。 - 在转移、铸造和销毁后通知合规性逻辑 (
transferred、created、destroyed),以便它可以保持内部状态(上限、计数器等)同步。
许可型代币 (T-REX)
该代币实现标准 ERC-20 功能,并保存对 IdentityRegistry 和 Compliance 合约的引用。它不会盲目地发送代币,而是通过一些额外的检查来路由每个转移,以确保允许移动。它用以下内容包装转移:
- 暂停/冻结检查
- 合规性检查
- 转移后Hook (
transferred)
典型的扩展包括:
- 强制转移和代币恢复
- 暂停/冻结(全局和每个地址)
- 部分冻结(只有部分余额是可移动的)
- 批量操作
RWA 代币转账如何运作
现在,让我们逐步了解 ERC-3643 代币转账是如何运作的。
步骤 1:用户发起转移
用户(Alice)像往常一样调用代币的 transfer 或 transferFrom 函数,以将代币转账到新地址(Bob):
token.transfer(bob.address, amount);
token.transferFrom(from, bob.address, amount); // 如果使用 allowance
步骤 2:资格检查
Token 合约不会移动代币。它首先通过 Identity Registry 执行资格检查。该逻辑通常如下:
- 检查代币是否已暂停,或者两个地址是否都被冻结
- 通过调用
isVerified()函数,确保接收者已注册并在IdentityRegistry中具有所需的 claim
在许多实现中,代币直接调用
identityRegistry.isVerified(...),然后调用compliance.canTransfer(...)。在其他实现中,资格检查捆绑在canTransfer本身中。重要的一点是,在任何余额移动之前,都会强制执行资格和合规性规则。
步骤 3:合规性评估
在资格检查之后,Token 合约继续进行第二次检查:compliance.canTransfer(alice.address, bob.address, amount)。
Compliance 合约检查其模块化逻辑,以确定是否允许转移,并且未违反任何规则。
合规性合约可以评估以下规则:
- 全局上限(例如,每个管辖区的持有人数量)
- 每个投资者和每个国家/地区的仓位限制
- 时间窗口、锁定期和归属
- 为该代币配置的任何自定义模块
如果违反任何规则,canTransfer 将返回 false,并且代币应该回滚。
步骤 4:转移
如果所有检查都通过,则转移像正常的 ERC-20 转移一样执行。然后,Token 调用 compliance.transferred(from, to, amount) 以更新合规性状态,以供将来检查。
在铸造时,Token 调用 compliance.created(to, amount),在销毁时,它调用 compliance.destroyed(from, amount),以便合规性引擎也跟踪供应变化。
可审计性
由于 claim 由受信任的发行者签名并通过 ONCHAINID 存储,因此你可以维护资格的可验证审计跟踪。
你有一个可审计的跟踪:
- 谁在何时持有什么
- 哪些 claim 和规则允许转移
- 随着时间的推移,注册表和合规性模块的治理变更
角色和权限
ERC-3643 将 Owner(根据 EIP-173)与可以操作敏感功能的 Agent 地址分开。Agent 角色是标准化的:
interface IAgentRole {
event AgentAdded(address indexed agent);
event AgentRemoved(address indexed agent);
function addAgent(address agent) external;
function removeAgent(address agent) external;
function isAgent(address agent) external view returns (bool);
}
Owner 管理代理和高级配置。Agent 执行诸如冻结、强制转移、铸造/销毁和批量操作之类的操作,具体取决于实现。
开发者的核心接口
ERC-3643 实现公开的关键标准化接口:
- ERC3643 代币
- 身份注册表
- 身份注册表存储
- 合规性
- 受信任的发行者
- Claim Topics
interface IERC3643 is IERC20 {
// getters
function onchainID() external view returns (address);
function identityRegistry() external view returns (IIdentityRegistry);
function compliance() external view returns (ICompliance);
function paused() external view returns (bool);
function isFrozen(address user) external view returns (bool);
function getFrozenTokens(address user) external view returns (uint256);
// admin
function pause() external;
function unpause() external;
function setAddressFrozen(address user, bool freeze) external;
function freezePartialTokens(address user, uint256 amount) external;
function unfreezePartialTokens(address user, uint256 amount) external;
function setIdentityRegistry(address identityRegistry) external;
function setCompliance(address compliance) external;
// lifecycle
function forcedTransfer(address from, address to, uint256 amount) external returns (bool);
function mint(address to, uint256 amount) external;
function burn(address user, uint256 amount) external;
function recoveryAddress(address lostWallet, address newWallet, address investorOnchainID) external returns (bool);
// batch helpers
function batchTransfer(address[] calldata toList, uint256[] calldata amounts) external;
}
interface IIdentityRegistry {
// wiring
function setIdentityRegistryStorage(address storageAddr) external;
function setClaimTopicsRegistry(address topics) external;
function setTrustedIssuersRegistry(address issuers) external;
// actions
function registerIdentity(address user, IIdentity id, uint16 country) external;
function deleteIdentity(address user) external;
function updateCountry(address user, uint16 country) external;
function updateIdentity(address user, IIdentity id) external;
// reads
function isVerified(address user) external view returns (bool);
function identity(address user) external view returns (IIdentity);
function investorCountry(address user) external view returns (uint16);
}
interface IIdentityRegistryStorage {
function storedIdentity(address user) external view returns (IIdentity);
function storedInvestorCountry(address user) external view returns (uint16);
function addIdentityToStorage(address user, IIdentity id, uint16 country) external;
function removeIdentityFromStorage(address user) external;
function modifyStoredInvestorCountry(address user, uint16 country) external;
function modifyStoredIdentity(address user, IIdentity id) external;
function bindIdentityRegistry(address identityRegistry) external;
function unbindIdentityRegistry(address identityRegistry) external;
function linkedIdentityRegistries() external view returns (address[] memory);
}
interface ICompliance {
function canTransfer(address from, address to, uint256 amount) external view returns (bool);
function transferred(address from, address to, uint256 amount) external;
function created(address to, uint256 amount) external;
function destroyed(address from, uint256 amount) external;
}
interface ITrustedIssuersRegistry {
function addTrustedIssuer(IClaimIssuer issuer, uint[] calldata claimTopics) external;
function removeTrustedIssuer(IClaimIssuer issuer) external;
function updateIssuerClaimTopics(IClaimIssuer issuer, uint[] calldata claimTopics) external;
function getTrustedIssuers() external view returns (IClaimIssuer[] memory);
function isTrustedIssuer(address issuer) external view returns (bool);
function getTrustedIssuerClaimTopics(IClaimIssuer issuer) external view returns (uint[] memory);
function getTrustedIssuersForClaimTopic(uint256 claimTopic) external view returns (IClaimIssuer[] memory);
function hasClaimTopic(address issuer, uint claimTopic) external view returns (bool);
}
interface IClaimTopicsRegistry {
function addClaimTopic(uint256 claimTopic) external;
function removeClaimTopic(uint256 claimTopic) external;
function getClaimTopics() external view returns (uint256[] memory);
}
设计回顾
至少,ERC-3643 代币部署涉及:
- 部署注册表:
ClaimTopicsRegistry、TrustedIssuersRegistry、IdentityRegistryStorage、IdentityRegistry。 - 配置主题和发行者:添加 claim 主题和受信任的发行者及其支持的主题。
- 将存储绑定到身份注册表,并在身份注册表上设置注册表。
- 部署
Compliance,并在部署后将其绑定到代币。 - 部署代币,并引用
IdentityRegistry和Compliance。 - 设置 Owner 和 Agent 角色,并将敏感功能限制为代理。
- 在身份注册表中注册投资者身份 (
address、ONCHAINID、country)。 - 使用
mint分配供应,并确保铸造/销毁调用created/destroyed。
常见用例
- 代币化的私募股权基金/风险投资基金/私募股权: 仅限于合格或机构投资者
- 证券代币发行 (STO): 强制执行管辖权限制、最大持有人、锁定期等。
- 代币化的房地产: 确保只有符合条件的投资者才能持有财产的部分所有权
- 受监管的交易场所: 构建合规的二级市场,在其中链上验证每个买卖订单
由于它仍然与 ERC-20 兼容,因此 ERC-3643 代币可以与钱包、托管人、交易所(中心化或分散式,在允许的情况下)以及投资组合和分析工具集成,只要这些平台准备好处理资产的许可性质(例如,处理由于合规性导致的转移回滚)。
接下来是什么
从这里,你可以:
- 阅读完整的 ERC-3643 白皮书 和规范
深入研究诸如交割与支付 (DvD)、交易所集成和可升级性模式之类的极端情况,这些模式超出了本概述的范围。
- 探索参考实现
克隆 ERC-3643 / T-REX 存储库,将注册表和代币部署到本地或测试网环境,并尝试符合合规性和不合规性的转移。
- 制作一个简单的 RWA 用例原型
例如:
- 一个代币化的私募股权基金,其中只有来自特定辖区的合格投资者才能持有该代币
- 一种具有锁定期和转移窗口的代币化房地产资产
使用 ERC-3643 将这些规则直接编码到代币中。
- 构建监控和合规性工具
使用 Quicknode Streams 订阅到:
-
来自你的 ERC-3643 代币的
Transfer事件 -
来自你的合规性模块的自定义事件(例如,违反规则、强制转移)
然后将该数据馈送到仪表板、警报系统或内部合规性工具中。
当你探索这些后续步骤时,你将更加清楚地了解 ERC-3643 如何融入你自己的 RWA 或证券代币路线图。
结论
在本指南中,你学习了 ERC-3643 如何在熟悉的 ERC-20 模型之上分层链上身份、资格检查和模块化合规性规则,以支持受监管的许可资产。
如果你正在以太坊或其他 EVM 链上构建 RWA 或证券代币基础设施,ERC-3643 提供了一个开源基础 (T-REX),而不是从头开始重新发明合规性。结合 Quicknode 的可靠基础设施,你可以设计、部署和监控符合现实世界监管框架的许可代币。
订阅我们的新闻通讯,了解更多文章和指南。通过 Twitter 分享反馈或加入我们的 Discord 社区服务器。
我们 ❤️ 反馈!
如果你有任何反馈或对新主题的请求,请告诉我们。我们很乐意听到你的来信。
- 原文链接: quicknode.com/guides/rea...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~