In normal ERC-20:
flowchart LR
A[Wallet A] -->|transfer| T[ERC-20 Token]
T --> B[Wallet B]
In ERC-3643:
flowchart LR
A[Wallet A] -->|transfer request| T[T-REX Token]
T --> IR[Identity Registry]
T --> C[Compliance Contract]
IR --> IRS[Identity Registry Storage]
IR --> CTR[Claim Topics Registry]
IR --> TIR[Trusted Issuers Registry]
IRS --> ID[Investor ONCHAINID]
ID --> Claims[Signed Claims]
C --> Rules[Transfer Rules]
T -->|only if verified + compliant| B[Wallet B]
The token does not trust wallets as identities. A wallet is just a signing address. ERC-3643 links wallets to ONCHAINID identity contracts, then checks whether those identities carry valid claims such as KYC, AML, investor accreditation, jurisdiction, or token-specific eligibility. (docs.erc3643.org)
| Jargon | Plain meaning | Blockchain equivalent |
|---|---|---|
| Issuer | Entity creating the asset/token | Token owner / issuer admin |
| Investor | Person/company allowed to hold the token | Wallet mapped to ONCHAINID |
| KYC | “We know who this person/company is” | Claim on ONCHAINID |
| AML | “Not suspicious / not sanctioned / not laundering” | Claim on ONCHAINID |
| Accredited investor | Investor legally allowed to buy certain securities | Eligibility claim |
| Jurisdiction | Country/legal region rules | Country claim + compliance rule |
| Transfer restriction | Not everyone can receive/sell | canTransfer() + identity checks |
| Registrar / transfer agent | Party maintaining ownership records | Token + Identity Registry + agents |
| Custodian | Party holding assets for someone | Could be wallet/ONCHAINID owner or institution |
| Primary issuance | First sale/distribution | Mint to verified investors |
| Secondary transfer | Later investor-to-investor transfer | Permissioned transfer() |
| Redemption | Investor exits / burns token for off-chain asset/cash | Burn + off-chain settlement |
flowchart TB
subgraph Offchain["Off-chain real world"]
Asset[Real-world asset\nEquity, bond, fund, real estate, invoice]
Legal[Legal wrapper\nSPV, fund, issuer entity]
KYC[KYC/AML provider\nClaim issuer]
Regulator[Regulator / legal rules]
Docs[Subscription docs\nInvestor files\nPrivate data]
end
subgraph Onchain["On-chain ERC-3643 / T-REX system"]
Token[T-REX Token\nERC-20 compatible + permissioned]
Compliance[Compliance Contract\nRules engine]
IR[Identity Registry\nVerification gateway]
IRS[Identity Registry Storage\nwallet => ONCHAINID]
CTR[Claim Topics Registry\nrequired claim types]
TIR[Trusted Issuers Registry\nallowed claim issuers]
ONID[ONCHAINID\nidentity contract]
Claims[Claims\nsigned attestations]
end
subgraph Actors["Actors"]
Issuer[Issuer / Owner]
Agent[Agent\nmint, burn, freeze, forced transfer]
Investor[Investor wallet]
ClaimIssuer[Trusted Claim Issuer]
end
Asset --> Legal --> Token
Regulator --> Compliance
Regulator --> CTR
Issuer --> Token
Issuer --> Compliance
Issuer --> CTR
Issuer --> TIR
Agent --> Token
Investor --> ONID
ClaimIssuer --> Claims
KYC --> ClaimIssuer
Docs --> KYC
Claims --> ONID
Token --> IR
Token --> Compliance
IR --> IRS
IR --> CTR
IR --> TIR
IRS --> ONID
ONID --> Claims
ERC-3643 separates concerns: the Token handles balances and token lifecycle, the Identity Registry verifies participant eligibility, and the Compliance contract enforces transfer rules. (docs.erc3643.org)
The token is ERC-20-like, but every meaningful token operation is gated.
flowchart TD
Token[T-REX Token]
Token --> ERC20[ERC-20 surface\nbalanceOf, transfer, approve, allowance]
Token --> IdentityCheck[Identity check\nvia Identity Registry]
Token --> ComplianceCheck[Compliance check\nvia Compliance]
Token --> Admin[Admin controls\npause, freeze, recovery]
Token --> Lifecycle[Lifecycle\nmint, burn, forcedTransfer]
Token --> Metadata[Token info\nname, symbol, decimals, ONCHAINID]
Important capabilities: identity verification, compliance checks, pause, freeze, partial freeze, recovery from lost wallets, forced transfers, batch mint/burn/transfer/freeze. (docs.erc3643.org)
This is the main “is this wallet allowed?” contract.
flowchart TD
IR[Identity Registry]
IR --> IRS[Identity Registry Storage]
IR --> CTR[Claim Topics Registry]
IR --> TIR[Trusted Issuers Registry]
IRS --> Map[wallet => ONCHAINID]
CTR --> Topics[Required claimsKYC, AML, accreditation, country]
TIR --> Issuers[Allowed claim issuers]
IR --> Verify[isVerified(wallet)]
isVerified(wallet) roughly means:
sequenceDiagram
participant Token
participant IR as Identity Registry
participant IRS as Identity Registry Storage
participant CTR as Claim Topics Registry
participant TIR as Trusted Issuers Registry
participant ID as ONCHAINID
Token->>IR: isVerified(wallet)
IR->>IRS: get ONCHAINID for wallet
IRS-->>IR: ONCHAINID address
IR->>CTR: get required claim topics
CTR-->>IR: required topics
IR->>TIR: get trusted issuers
TIR-->>IR: trusted issuers
IR->>ID: read claims
ID-->>IR: signed claims
IR->>IR: verify topics + issuer signatures
IR-->>Token: true / false
The docs describe this exact pattern: fetch ONCHAINID, compare claims against required topics and trusted issuers, verify signatures, then return true or false. (docs.erc3643.org)
This is the address book.
erDiagram
WALLET ||--|| ONCHAINID : maps_to
IDENTITY_REGISTRY_STORAGE {
address wallet
address onchainid
uint16 country
}
Its job is simple but critical: map a wallet address to an ONCHAINID address so the system can treat a wallet as belonging to a verified identity. It can be shared by multiple Identity Registry contracts. (docs.erc3643.org)
ONCHAINID is an identity smart contract. It stores keys and claims, while private KYC data stays off-chain with the claim issuer; only signatures/hashes are on-chain. (docs.erc3643.org)
flowchart TD
ONID[ONCHAINID]
ONID --> Keys[Keys\nmanagement / permissions]
ONID --> Claims[Claims\nERC-735 style attestations]
ONID --> Exec[Can execute calls\nERC-734 style]
Claims --> KYC[KYC claim]
Claims --> AML[AML claim]
Claims --> Country[Country / residency claim]
Claims --> Accredited[Accredited investor claim]
Claims --> TokenSpecific[Token-specific eligibility claim]
Think of it as a reusable on-chain passport. It can be used across multiple tokens if the token trusts the same issuers/topics.
This says what claims are required.
flowchart LR
CTR[Claim Topics Registry] --> KYC[Topic 1: KYC]
CTR --> AML[Topic 2: AML]
CTR --> ACC[Topic 3: Accredited]
CTR --> COUNTRY[Topic 4: Country]
CTR --> SPECIAL[Topic N: Token-specific eligibility]
Each token can define its own required claim topics. For example, a private US fund token might require KYC + AML + accredited investor + not-US-sanctioned + specific subscription approval. (docs.erc3643.org)
This says who is allowed to issue claims.
flowchart TD
TIR[Trusted Issuers Registry]
TIR --> KYCProvider[KYC Provider A]
TIR --> LawFirm[Law Firm B]
TIR --> TransferAgent[Transfer Agent C]
TIR --> Bank[Bank / regulated entity D]
A claim is not valid just because it exists. It must be issued by an entity trusted for that claim topic. (docs.erc3643.org)
Identity answers: “Who are you, and are you eligible?”
Compliance answers: “Even if both parties are eligible, is this particular transfer allowed?”
flowchart TD
C[Compliance Contract]
C --> Can[canTransfer(from, to, amount)]
C --> Hooks[State hooks]
Hooks --> Transferred[transferred(from,to,amount)]
Hooks --> Created[created(to,amount)]
Hooks --> Destroyed[destroyed(from,amount)]
C --> Rules[Compliance modules / rules]
Rules --> MaxInvestors[Max number of investors]
Rules --> CountryCap[Country ownership limits]
Rules --> HoldingLimit[Per-investor holding cap]
Rules --> Lockup[Lockup period]
Rules --> SupplyLimit[Supply cap]
Rules --> AgentOnly[Agent-only operations]
The interface includes canTransfer, transferred, created, destroyed, bindToken, and unbindToken. canTransfer is read-only; state changes happen through hooks like transferred, created, and destroyed. (docs.erc3643.org)
sequenceDiagram
participant A as Sender Wallet
participant T as T-REX Token
participant IR as Identity Registry
participant C as Compliance
participant B as Receiver Wallet
A->>T: transfer(B, amount)
T->>T: check not paused
T->>T: check A not frozen
T->>T: check amount not frozen
T->>IR: isVerified(A)
IR-->>T: true / false
T->>IR: isVerified(B)
IR-->>T: true / false
T->>C: canTransfer(A, B, amount)
C-->>T: true / false
alt all checks pass
T->>T: update balances
T->>C: transferred(A, B, amount)
T-->>A: Transfer event
else any check fails
T-->>A: revert
end
A transfer can fail because:
flowchart TD
Fail[Transfer fails] --> NotRegistered[Wallet not registered]
Fail --> MissingClaim[ONCHAINID missing required claim]
Fail --> BadIssuer[Claim not from trusted issuer]
Fail --> ExpiredClaim[Claim invalid / expired / revoked]
Fail --> ComplianceRule[Compliance rule blocks transfer]
Fail --> Frozen[Address or amount frozen]
Fail --> Paused[Token paused]
Fail --> Balance[Insufficient transferable balance]
sequenceDiagram
participant Investor
participant KYC as KYC / Claim Issuer
participant ID as ONCHAINID
participant IRS as Identity Registry Storage
participant IR as Identity Registry
participant Issuer
Investor->>ID: create or provide ONCHAINID
Investor->>KYC: submit private documents off-chain
KYC->>KYC: verify identity / AML / eligibility
KYC->>ID: add signed claim
Issuer->>IRS: register wallet => ONCHAINID + country
Issuer->>IR: identity now eligible if claims match
Private documents normally stay off-chain. The chain stores attestations/signatures/hashes, not passport scans. (docs.erc3643.org)
sequenceDiagram
participant Issuer
participant Token
participant IR as Identity Registry
participant C as Compliance
participant Investor
Issuer->>Token: mint(Investor, amount)
Token->>IR: isVerified(Investor)
IR-->>Token: true
Token->>C: canTransfer(0x0, Investor, amount)
C-->>Token: true
Token->>Token: increase supply + investor balance
Token->>C: created(Investor, amount)
Token-->>Issuer: Transfer(0x0, Investor, amount)
Minting is not “free-for-all”; the recipient still needs to be verified and compliant.
This is one of the biggest differences from pure crypto assets.
sequenceDiagram
participant Investor
participant Agent
participant Old as Old Wallet
participant New as New Wallet
participant IRS as Identity Registry Storage
participant Token
Investor->>Agent: prove old wallet lost off-chain
Agent->>IRS: register New Wallet => same/new ONCHAINID
Agent->>Token: recoveryAddress(Old, New, investorIdentity)
Token->>Token: move balance Old -> New
Token->>Token: freeze/clear Old as needed
Token-->>Agent: RecoverySuccess
This supports the regulated-finance expectation that legal ownership can survive key loss. The docs explicitly mention token recovery from lost wallets. (docs.erc3643.org)
flowchart TD
Start[Regulatory / operational reason] --> Agent[Authorized agent acts]
Agent --> FullFreeze[Freeze address]
Agent --> PartialFreeze[Freeze part of balance]
Agent --> Forced[Forced transfer]
FullFreeze --> Audit[Event emitted]
PartialFreeze --> Audit
Forced --> Checks[Usually to compliant address]
Checks --> Audit
This is controversial from a crypto-native perspective, but normal for regulated assets. If a court order, fraud case, sanctions issue, or investor status change happens, the issuer/agent may need control functions.
classDiagram
class Token {
name
symbol
decimals
totalSupply
balances
identityRegistry
compliance
paused
frozenAddresses
frozenTokenAmounts
transfer()
mint()
burn()
forcedTransfer()
recoveryAddress()
freezePartialTokens()
}
class IdentityRegistry {
identityStorage
trustedIssuersRegistry
claimTopicsRegistry
isVerified(address)
registerIdentity()
deleteIdentity()
}
class IdentityRegistryStorage {
walletToIdentity
walletToCountry
addIdentityToStorage()
removeIdentityFromStorage()
}
class ONCHAINID {
keys
claims
addClaim()
removeClaim()
execute()
}
class ClaimTopicsRegistry {
requiredClaimTopics
addClaimTopic()
removeClaimTopic()
}
class TrustedIssuersRegistry {
trustedIssuers
addTrustedIssuer()
removeTrustedIssuer()
}
class Compliance {
boundToken
modules/rules
canTransfer()
transferred()
created()
destroyed()
}
Token --> IdentityRegistry
Token --> Compliance
IdentityRegistry --> IdentityRegistryStorage
IdentityRegistry --> ClaimTopicsRegistry
IdentityRegistry --> TrustedIssuersRegistry
IdentityRegistryStorage --> ONCHAINID
ONCHAINID --> TrustedIssuersRegistry : claims signed by
The key design pattern is:
function transfer(address to, uint256 amount) public override returns (bool) {
require(!paused, "token paused");
require(!frozen[msg.sender], "sender frozen");
require(availableBalance(msg.sender) >= amount, "insufficient unfrozen balance");
require(identityRegistry.isVerified(msg.sender), "sender not verified");
require(identityRegistry.isVerified(to), "receiver not verified");
require(compliance.canTransfer(msg.sender, to, amount), "not compliant");
_transfer(msg.sender, to, amount);
compliance.transferred(msg.sender, to, amount);
return true;
}That is not exact source code, but it is the mental shape.
ERC-3643 is modular because identity requirements and compliance rules change per jurisdiction, issuer, and asset type. The standard defines interfaces for Token, Identity Registry, Identity Registry Storage, Compliance, Trusted Issuers Registry, and Claim Topics Registry. (Ethereum Improvement Proposals)
ERC-3643/T-REX is a permissioned ERC-20 architecture where balances are still on-chain, but holding/transferring tokens requires: registered identity + valid claims + trusted claim issuers + token-specific compliance rules + issuer/agent lifecycle controls.