Security
Learning Corner
Advanced 20 min read

ONCHAINID and ERC-3643

How ONCHAINID brings identity, claims, and verification to permissioned ERC-3643 token systems.

Think of it as a

passport system for permissioned tokens

ONCHAINID stores identity keys and claims, while ERC-3643 asks, before minting or transferring, whether a wallet belongs to an identity that has the right attestations.

Why this exists

Plain ERC-20 tokens only know balances and allowances. Permissioned real-world-asset tokens usually need more: who the holder is, which claims they have, which issuers are trusted, and whether token rules should allow minting or transfer. ERC-3643 solves that by pairing a token with identity and compliance contracts. ONCHAINID is the identity layer inside that stack.

Without ONCHAINID + ERC-3643
// token only sees addresses
function mint(address to, uint256 amount) external onlyOwner 
  _mint(to, amount);
  • No built-in concept of verified investor identity
  • No standard place for KYC or accreditation attestations
  • No issuer trust list, claim topic list, or regulated transfer gate
With ONCHAINID + ERC-3643
// ERC-3643 token checks identity registry first
function mint(address to, uint256 amount) public onlyAgent 
  require(identityRegistry.isVerified(to), "Identity is not verified.");
  _mint(to, amount);
  • Every wallet can map to an ONCHAINID contract
  • Claims can prove facts like KYC passed or investor accredited
  • Only claims from trusted issuers on required topics count

The stack at a glance

ERC-3643 Token mint / transfer call isVerified() Identity Registry wallet → ONCHAINID country metadata Claim Topics Registry which claim topics are required Trusted Issuers Registry which issuers may certify which topics ONCHAINID ERC-734 keys + ERC-735 claims for one investor or token

Core components

1. Identity

A contract that implements ERC-734 key management and ERC-735 claims.

2. ClaimIssuer

A specialized identity that can validate and revoke claims signed by its claim keys.

3. IdFactory

Deploys user or token ONCHAINIDs via CREATE2 and tracks wallet bindings.

4. IdentityRegistry

Maps wallets to ONCHAINID contracts and answers whether a wallet is verified.

5. ClaimTopicsRegistry

Stores the claim topics a token requires, up to 15 topics.

6. TrustedIssuersRegistry

Stores which claim issuers are trusted for which topics.

How ONCHAINID itself works

1

Keys define who can control or use the identity

In the ONCHAINID Identity contract, keys are stored by purpose. The important built-in purposes are 1 = management, 2 = action, 3 = claim signer, 4 = encryption.

// example: Alice's hardware wallet controls her ONCHAINID
bytes32 managementKey = keccak256(abi.encode(aliceSafe));
identity.addKey(managementKey, 1, 1);

// example: a service wallet can perform actions
bytes32 actionKey = keccak256(abi.encode(aliceOpsWallet));
identity.addKey(actionKey, 2, 1);
2

Claims attach attestations to the identity

A claim has a topic, issuer, signature, data, and URI. The claim ID is keccak256(abi.encode(issuer, topic)), so there is effectively one stored claim per issuer-topic pair on a given identity.

// example: KYC provider attests topic 7 for Alice
uint256 topic = 7;
address issuer = address(kycClaimIssuer);
bytes memory data = abi.encode(
  "KYC passed on 2026-04-23",
  "country=AE"
);
bytes memory signature = sign(keccak256(abi.encode(aliceIdentity, topic, data)));

identity.addClaim(topic, 1, issuer, signature, data, "ipfs://...");
  • The issuer is usually a ClaimIssuer contract, not just a bare EOA
  • The signature must match the hash of identity address, topic, and data
  • For external issuers, addClaim checks validity by calling issuer.isClaimValid(...)
3

ClaimIssuer verifies or revokes those attestations

A ClaimIssuer contract extends Identity. It checks that the recovered signer address has purpose 3, meaning it is a valid claim signer key of the issuer identity. It also tracks revoked signatures.

// concrete example
// RegCorp has a ClaimIssuer contract with signer key signer1
bytes32 signerKey = keccak256(abi.encode(signer1));
claimIssuer.addKey(signerKey, 3, 1);

// if signer1 signed Alice's KYC claim, this returns true
bool ok = claimIssuer.isClaimValid(aliceIdentity, 7, signature, data);

// later, RegCorp can revoke the same signature
claimIssuer.revokeClaimBySignature(signature);

Does ONCHAINID mint claims?

Not really. It is more accurate to say ONCHAINID stores claims, while an issuer creates and signs the claim off-chain, and then someone with a claim key adds that signed claim on-chain to the identity.

Issuer org checks KYC docs Signer key signs topic + data ONCHAINID stores claim ERC-3643 IR validates claim

How IdFactory works

The IdFactory deploys IdentityProxy contracts using CREATE2. It keeps track of used salts, wallet-to-identity links, token-to-identity links, and linked wallets for each identity.

User identity example

// factory owner creates Alice's ONCHAINID
address aliceId = idFactory.createIdentity(
  aliceWallet,
  "alice-2026-04"
);

// internally, the factory prefixes the salt with "OID"
// and deploys IdentityProxy via CREATE2
  • The initial management key is Alice wallet by default
  • The factory records wallet → identity
  • Later, linked wallets can be added with linkWallet()

Token identity example

// TREXFactory can create a token ONCHAINID too
address tokenId = idFactory.createTokenIdentity(
  address(token),
  tokenOwner,
  "us-tbill-series-a"
);

token.setOnchainID(tokenId);
  • The token identity is separate from investor identities
  • ERC-3643 token metadata can point to this ONCHAINID
  • The token owner becomes the initial management key

How ERC-3643 uses ONCHAINID

1

Register the wallet and ONCHAINID

The Identity Registry stores the investor wallet, its ONCHAINID contract, and a country code. In the ERC-3643 implementation, registerIdentity delegates storage to IdentityRegistryStorage.

identityRegistry.registerIdentity(
  aliceWallet,
  IIdentity(aliceId),
  784 // UAE for example, using ISO numeric-style metadata in project conventions
);
2

Define which claim topics matter

The Claim Topics Registry tells the token which topics must be present. The registry itself does not know semantics, only topic numbers.

// example semantics chosen by your deployment
uint256 TOPIC_KYC = 7;
uint256 TOPIC_ACCREDITED = 42;

claimTopicsRegistry.addClaimTopic(TOPIC_KYC);
claimTopicsRegistry.addClaimTopic(TOPIC_ACCREDITED);
3

Define which issuers are trusted for which topics

The Trusted Issuers Registry binds claim issuers to allowed topics. For example, one issuer may be trusted for KYC, another for accredited-investor status.

trustedIssuersRegistry.addTrustedIssuer(
  IClaimIssuer(address(regCorpIssuer)),
  [TOPIC_KYC]
);

trustedIssuersRegistry.addTrustedIssuer(
  IClaimIssuer(address(brokerDealerIssuer)),
  [TOPIC_ACCREDITED]
);
4

Token checks verification during mint and transfer

The ERC-3643 token calls identityRegistry.isVerified(to) in mint, transfer, and transferFrom. If verification fails, the action reverts.

function mint(address to, uint256 amount) public onlyAgent 
  require(identityRegistry.isVerified(to), "Identity is not verified.");
  require(compliance.canTransfer(address(0), to, amount), "Compliance not followed");
  _mint(to, amount);

What exactly does isVerified() do?

This is the key ERC-3643 check. For each required topic, the Identity Registry gets all trusted issuers allowed for that topic, computes the expected claim IDs, loads the claims from the user’s ONCHAINID, and asks the issuer whether the signature is still valid.

  • If the wallet has no identity registered, verification fails immediately
  • If no claim topics are configured, verification passes trivially
  • For each required topic, there must be at least one trusted issuer for that topic
  • For each required topic, at least one matching stored claim must exist and validate
  • If a claim is missing, signed by the wrong issuer key, or revoked, verification fails

Concrete example for each component

1

Identity

Alice has ONCHAINID 0xAliceId. Her Safe is a management key, and her backend signer is an action key.

2

ClaimIssuer

RegCorp has issuer contract 0xRegIssuer. It trusts signer 0xSigner1 as a claim key for topic 7, KYC passed.

3

IdFactory

Issuer admin deploys Alice ONCHAINID with salt alice-2026-04. Factory remembers that wallet 0xAliceWallet maps to 0xAliceId.

4

ClaimTopicsRegistry

The token requires topic 7 for KYC and topic 42 for accreditation.

5

TrustedIssuersRegistry

RegCorp is trusted for topic 7. BrokerDealerCo is trusted for topic 42.

6

IdentityRegistry

Wallet 0xAliceWallet is registered to 0xAliceId with country metadata. The token queries this registry whenever Alice receives tokens.

End-to-end example

Example: Alice buys tokenized treasury shares KYC + Accredited Investor topics required 1. IdFactory deploys Alice ONCHAINID wallet 0xAlice → identity 0xAliceId 2. Issuers sign claims topic 7 KYC, topic 42 accredited 3. Claims stored on 0xAliceId issuer-topic claim IDs now exist 4. IdentityRegistry registers wallet 0xAliceWallet → 0xAliceId 5. Token agent calls mint() mint to 0xAliceWallet 6. isVerified() returns true all required topics valid, so mint succeeds
  • If Alice later loses her wallet, a new wallet can be linked to the same ONCHAINID, preserving identity continuity
  • If RegCorp revokes the KYC claim signature, future transfers or mints to Alice can fail verification
  • If the token changes its required topics, the same ONCHAINID may become insufficient until new claims are added

Trade-offs and gotchas

Pros

  • Reusable identity across multiple permissioned tokens
  • Clear issuer trust model instead of hard-coding one verifier
  • Revocable claims, not permanent one-time approvals
  • Wallet continuity via linked wallets and identity mapping

Cons

  • Topic numbers are deployment conventions, not self-describing semantics
  • Claim creation still depends on an off-chain attestation workflow
  • More contracts and governance complexity than a plain token
  • Verification can fail if issuer keys rotate or claims are revoked without careful ops

Key takeaways

1

ONCHAINID is an on-chain identity contract, not just a whitelist row

It combines ERC-734 keys and ERC-735 claims so identities can be controlled, updated, and attested over time.

2

Claims are signed by issuers, then stored on the identity

The identity does not invent facts. It stores attestations signed by claim issuer keys and can later prove or revoke them.

3

ERC-3643 uses ONCHAINID through registries

IdentityRegistry, ClaimTopicsRegistry, and TrustedIssuersRegistry together decide whether a wallet is verified for minting or transfers.

4

The real power is reusable identity + revocable attestations

That is what makes permissioned tokens feel more like regulated systems and less like static whitelists.