Learn what ERC-3643 (T-REX standard) means for regulated security tokens in DeFi. Explore its role in compliance, tokenization, and secure finance.
In the fast-changing world of blockchain, security tokens have emerged as one of the most promising bridges between traditional finance and decentralized ecosystems. Yet, bringing real world assets (RWAs) such as real estate, company shares, or fine art onto the blockchain has never been straightforward. Unlike cryptocurrencies, these assets must comply with strict legal frameworks involving KYC and AML checks, jurisdictional restrictions, and ownership eligibility. The absence of these mechanisms in standards like ERC-20 has limited the blockchain’s ability to serve as a credible foundation for regulated financial markets.
ERC-3643, also known as the T-REX (Token for Regulated EXchanges) standard, directly addresses this gap. It provides a set of interfaces and smart contracts specifically designed for regulated, institutional-grade security tokens, embedding compliance logic and identity verification directly at the token level. Originally developed by Tokeny, the T-REX protocol has become a formal Ethereum standard that allows the issuance, management, and transfer of security tokens while ensuring that every transaction complies with legal requirements.
ERC-3643 is a Standards Track ERC proposal that extends the ERC-20 framework to support permissioned and compliance-driven security tokens. Unlike unrestricted fungible tokens, which can move freely between wallets, ERC-3643 tokens are designed to enforce rules around identity, eligibility, and transfer restrictions at the smart contract level. This makes the standard particularly suited for tokenized securities and other regulated real-world assets.
By introducing identity registries, compliance modules, and agent roles, the T-REX standard enables issuers and regulators to maintain control over how security tokens are distributed and traded, while still leveraging the efficiency and transparency of blockchain technology.
The key challenges addressed by ERC-3643 include:
In short, ERC-3643 provides the compliance and governance layer that ERC-20 lacks, making it possible for institutions to issue, manage, and trade securities on-chain without sacrificing regulatory oversight.
ERC-3643 distinguishes itself from other token standards by focusing on identity-bound compliance and modular governance for security tokens. The table below highlights the key differences:
Standard | Purpose / Focus | Key Features | Limitations | How ERC-3643 Improves |
---|---|---|---|---|
ERC-7943 (uRWA) | General tokenization of RWAs (fungible, NFTs, multi-tokens) | Lightweight compliance hooks (isUserAllowed , canTransfer ), ERC-165 introspection, fungible + non-fungible support | Minimal compliance enforcement, no mandatory on-chain identity, unopinionated design | Introduces mandatory identity registries and claim verification, ensuring suitability for regulated securities |
ERC-1400 (Security Token) | Partitioned security tokens with tranche-based issuance | Partitioning, document attachment, transfer restriction hooks | High gas costs, bulky storage, complex user experience | Offers ERC-20 compatibility, modular compliance without partitioning, and broader asset flexibility |
ERC-1404 (Simple Restricted Token) | Lightweight restrictions on ERC-20 | Functions like detectTransferRestriction , messageForTransferRestriction | Too basic; no compliance ecosystem, no identity checks, no modular rules | Expands into full compliance framework with registries, agent roles, partial freezes, and forced transfers |
In essence, ERC-3643 builds on the lessons of these earlier proposals and delivers a comprehensive compliance-first architecture for regulated securities, while remaining efficient and ERC-20 compatible.
At its foundation, ERC-3643 extends ERC-20 with a compliance layer that validates identities and eligibility before any transfer occurs. Instead of permitting transfers by default, as in ERC-20, every operation in ERC-3643 is mediated by identity and compliance contracts. This design ensures that only verified and eligible participants can hold or move regulated tokens.
Key requirements include ERC-20 compatibility, on-chain identities, pre-transfer checks (canTransfer
), recovery mechanisms, freezes, pauses, mint/burn, agent/owner roles, forced transfers, and batching.
Transactions in ERC-3643 occur directly between peers but with built-in restrictions and controls, unlike unrestricted ERC-20 transfers. AML/KYC checks are enforced on-chain, preventing circumvention via unregulated exchanges.
Detailed Workflow:
ERC-3643 defines several interconnected contracts:
Additionally, IAgentRole manages privileged access.
Interactions: During a transfer, the Token calls IdentityRegistry's isVerified
and Compliance's canTransfer
. If passed, it executes and notifies Compliance via transferred
.
Tokenize real-world assets with ERC-3643 while staying compliant. We help ensure security, governance and regulatory alignment for your project.
The ERC describes interfaces in text below, I implement them as Solidity code blocks based on the specifications and reference designs.
This handles agent management for privileged operations.
1// SPDX-License-Identifier: GPL-3.0
2pragma solidity ^0.8.0;
3
4interface IAgentRole {
5 event AgentAdded(address indexed agent);
6 event AgentRemoved(address indexed agent);
7
8 function addAgent(address agent) external;
9 function removeAgent(address agent) external;
10 function isAgent(address agent) external view returns (bool);
11}
12
Implementation example in a contract:
1contract AgentRole {
2 address public owner;
3 mapping(address => bool) internal _agents;
4
5 modifier onlyOwner() {
6 require(msg.sender == owner, "Caller is not owner");
7 _;
8 }
9
10 constructor() {
11 owner = msg.sender;
12 }
13
14 function addAgent(address agent) external onlyOwner {
15 require(!_agents[agent], "Agent already added");
16 _agents[agent] = true;
17 emit AgentAdded(agent);
18 }
19
20 function removeAgent(address agent) external onlyOwner {
21 require(_agents[agent], "Agent not found");
22 _agents[agent] = false;
23 emit AgentRemoved(agent);
24 }
25
26 function isAgent(address agent) external view returns (bool) {
27 return _agents[agent];
28 }
29}
30
Extends IERC20 with compliance and freeze features.
1interface IToken is IERC20, IAgentRole {
2 event TokensFrozen(address indexed addr, uint256 amount);
3 event TokensUnfrozen(address indexed addr, uint256 amount);
4 event Paused(address account);
5 event Unpaused(address account);
6
7 function pause() external;
8 function unpause() external;
9 function isFrozen(address addr) external view returns (bool);
10 function getFrozenTokens(address addr) external view returns (uint256);
11 function setFrozen(address addr, bool freeze) external;
12 function freezePartialTokens(address addr, uint256 amount) external;
13 function unfreezePartialTokens(address addr, uint256 amount) external;
14 function recovery(address lostWallet, address newWallet, address investorOnchainID) external;
15 function forcedTransfer(address from, address to, uint256 amount) external returns (bool);
16 function mint(address to, uint256 amount) external;
17 function burn(address from, uint256 amount) external;
18 function batchMint(address[] calldata to, uint256[] calldata amounts) external;
19 // Additional batch functions for transfers, freezes, etc.
20}
21
Example transfer implementation with checks:
1contract Token is IToken, ERC20, Pausable {
2 IIdentityRegistry public identityRegistry;
3 IModularCompliance public compliance;
4 mapping(address => bool) private _frozen;
5 mapping(address => uint256) private _frozenTokens;
6
7 constructor(string memory name, string memory symbol, address _identityRegistry, address _compliance) ERC20(name, symbol) {
8 identityRegistry = IIdentityRegistry(_identityRegistry);
9 compliance = IModularCompliance(_compliance);
10 }
11
12 function transfer(address to, uint256 amount) public override whenNotPaused returns (bool) {
13 require(!_frozen[msg.sender], "Sender wallet frozen");
14 require(!_frozen[to], "Receiver wallet frozen");
15 require(amount <= balanceOf(msg.sender) - _frozenTokens[msg.sender], "Insufficient free balance");
16 require(identityRegistry.isVerified(to), "Receiver not verified");
17 require(compliance.canTransfer(msg.sender, to, amount), "Transfer not compliant");
18 _transfer(msg.sender, to, amount);
19 compliance.transferred(msg.sender, to, amount);
20 return true;
21 }
22
23 // Similar for transferFrom, with allowance checks
24
25 function forcedTransfer(address from, address to, uint256 amount) external onlyAgent returns (bool) {
26 require(identityRegistry.isVerified(to), "Receiver not verified");
27 uint256 freeBalance = balanceOf(from) - _frozenTokens[from];
28 if (amount > freeBalance) {
29 uint256 tokensToUnfreeze = amount - freeBalance;
30 _frozenTokens[from] -= tokensToUnfreeze;
31 emit TokensUnfrozen(from, tokensToUnfreeze);
32 }
33 _transfer(from, to, amount);
34 compliance.transferred(from, to, amount);
35 return true;
36 }
37
38 function mint(address to, uint256 amount) external onlyAgent {
39 require(identityRegistry.isVerified(to), "Receiver not verified");
40 _mint(to, amount);
41 compliance.created(to, amount);
42 }
43
44 // Additional functions like pause, freeze, etc., follow similar patterns
45}
46
Manages user verification.
1interface IIdentityRegistry {
2 event IdentityStored(address indexed investorAddress, IIdentity indexed investorIdentity);
3 event IdentityUnstored(address indexed investorAddress, IIdentity indexed investorIdentity);
4 event IdentityModified(IIdentity indexed oldIdentity, IIdentity indexed newIdentity);
5 event CountryUpdated(address indexed investorAddress, uint16 indexed country);
6
7 function isVerified(address addr) external view returns (bool);
8 function storeIdentity(address investorAddress, IIdentity investorIdentity, uint16 investorCountry) external;
9 function modifyStoredInvestorCountry(address investorAddress, uint16 investorCountry) external;
10 function modifyStoredIdentity(address investorAddress, IIdentity newInvestorIdentity) external;
11 function unstoreIdentity(address investorAddress) external;
12 function transferOwnershipOnIdentityRegistryContract(address newOwner) external;
13 function bindIdentityRegistry(address identityRegistry) external;
14 function unbindIdentityRegistry(address identityRegistry) external;
15}
16
Implementation snippet for isVerified :
1contract IdentityRegistry is IIdentityRegistry {
2 IClaimTopicsRegistry public topicsRegistry;
3 ITrustedIssuersRegistry public issuersRegistry;
4 mapping(address => IIdentity) private _identities;
5 mapping(address => uint16) private _investorCountries;
6
7 function isVerified(address addr) external view override returns (bool) {
8 IIdentity identity = _identities[addr];
9 if (address(identity) == address(0)) return false;
10 uint[] memory requiredTopics = topicsRegistry.getClaimTopics();
11 for (uint i = 0; i < requiredTopics.length; i++) {
12 IClaimIssuer issuer = issuersRegistry.getTrustedIssuerForClaimTopic(requiredTopics[i]);
13 if (issuer == IClaimIssuer(address(0))) return false;
14 // Verify claim signature and validity
15 // (Implementation would include keccak256 hashing and ecrecover for signature check)
16 }
17 return true;
18 }
19
20 // Other functions for storing/modifying identities
21}
22
For customizable rules.
1interface IModularCompliance {
2 event ModuleAdded(address indexed module);
3 event ModuleRemoved(address indexed module);
4
5 function bindToken(address token) external;
6 function unbindToken(address token) external;
7 function addModule(address module) external;
8 function removeModule(address module) external;
9 function canTransfer(address from, address to, uint256 amount) external view returns (bool);
10 function created(address to, uint256 amount) external;
11 function destroyed(address from, uint256 amount) external;
12 function transferred(address from, address to, uint256 amount) external;
13 function getModules() external view returns (address[] memory);
14 function getTokenBound() external view returns (address);
15}
16
Example module for max balance rule:
1contract MaxBalanceModule {
2 uint256 public maxBalance;
3
4 function canTransfer(address from, address to, uint256 amount) external view returns (bool) {
5 // Check if to's balance + amount <= maxBalance
6 return (IToken(msg.sender).balanceOf(to) + amount <= maxBalance);
7 }
8 // Other hooks if needed
9}
10
In a ModularCompliance contract, modules are called sequentially in canTransfer .
Over the last few years, ERC-3643 has moved beyond theory and become the backbone of several large-scale tokenization initiatives. Institutions, funds, and infrastructure providers are adopting the standard to enforce compliance, streamline issuance, and enable regulated secondary markets.
Below are some of the key players and how they are leveraging ERC-3643:
The security of ERC-3643 depends heavily on the integrity of its compliance architecture and the ecosystem of registries and issuers it interacts with. Because the standard directly governs regulated assets, its attack surface differs from generic ERC-20 contracts. The following are the most relevant vectors to consider in real-world deployments of ERC-3643:
ERC-3643, through its T-REX implementation, has solidified its position as a cornerstone for regulated tokenization on Ethereum and beyond. By addressing the gaps in compliance, efficiency, and lifecycle management for security tokens, it paves the way for trillions in real-world assets to enter the blockchain ecosystem securely and scalably. As of 2025, with billions already tokenized and growing adoption in multi-chain environments, ERC-3643 is not just a standard but a catalyst for the tokenized economy. Developers and institutions alike should leverage its open-source nature to build compliant, innovative financial products, ensuring blockchain's promise of decentralization aligns with real-world regulatory demands.
To strengthen your tokenized ecosystem with security and compliance, explore our expertise at QuillAudits. For those diving deeper into technical details, Tokeny’s GitHub repo remains an excellent entry point.
Contents
Get updates on our community, partners, events, and everything happening across the ecosystem — delivered straight to your inbox.
Subscribe Now!
Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654
Privacy PolicyAll Rights Reserved. © 2025. QuillAudits - LLC
Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654
hello@quillaudits.comAll Rights Reserved. © 2025. QuillAudits - LLC
Privacy Policy