Verify once with Didit. Get admitted on five EVM chains at the same time. Every transfer on any of them is enforced on-chain.
The default story of on-chain identity is not a good one. You verify on chain A. You want to use chain B, so you verify again. Sometimes with a different provider. Sometimes with a different set of documents. Each verification is its own record, each record has its own expiry, and none of them talk to each other. The user's actual identity, the thing being checked, is the same across all of them.
What follows is how we replace that with a single credential that five EVM chains all accept. It is not a full self-sovereign identity stack (that is a longer road). It is the useful, shippable subset: one KYC verification, one on-chain credential per chain, and one compliance layer that enforces both the credential and the allowlist on every transfer.
The five chains, and the ones we do not include
Today the portable-KYC path covers Sepolia, Shibuya, Amoy, Minato, and Plume. Five EVM chains, one Didit verification, one credential-issuance flow. The credential validator is attached to the policy engine on each of the five, which is a fact you can read off the chains rather than take from us. Non-EVM chains (Solana, Stellar Soroban, Stacks Clarity) are deliberately not in this credential path; they run their own native identity primitive, and we wrote about why in a separate post.
Five is a workable number to think in. It is enough that the portability is real (a user actually saves work), and it is small enough that the guarantees can be stated precisely for each chain without hand-waving. As more EVM chains onboard, the pattern extends without change; the on-chain surface is the same.
Step 1: Didit runs the verification once
The verification itself lives off-chain, with a KYC provider we chose specifically because they do the boring parts well: document capture, liveness, sanctions and PEP checks, jurisdiction handling. The user starts the flow inside our app, is redirected into Didit's interface, submits the required documents, and comes back to our app when Didit has produced a signed result. The user never gives us their documents; we receive the pass/fail result and the metadata we need to record the check.
Once we have that result, one thing happens on our side: our credential-issuance service prepares an issuance for each of the five chains. Nothing about the identity moves on-chain; only an attestation that a valid check took place.
Step 2: The credential is issued on each EVM chain
Each chain has an on-chain credential contract. When the issuance service posts to a chain, that chain's credential contract records: the user's wallet address, the credential type (KYC), the expiry, and a reference back to our attestation that can be verified but not de-anonymized. The credential is per-address; the user's identity is not on-chain, and cannot be reconstructed from what is on-chain.
The five issuances happen in parallel, so from the user's perspective there is one "you are verified" moment that resolves the admission on all five chains at once. The issuance is signed by our issuer key, and each chain's credential contract accepts only signatures from our issuer or the specific set of issuers whitelisted by governance. If the issuer key is rotated, existing credentials remain valid until expiry; new credentials are signed by the new key.
The user verifies once. The credential is issued on five chains. Every transfer on any of them runs the check.
Step 3: Every transfer runs the check
This is the part that is easy to miss. Having a credential is not the same as having enforcement. Enforcement is what happens when a transfer runs, not when the credential is issued. Our token contracts are attached to a Chainlink ACE ComplianceCheck contract, and every transfer runs a modular policy set on-chain. The policy set for OB-issued tokens says, precisely: the sender must be on the allowlist, AND the sender must hold a valid credential, AND the transfer must not exceed the max-balance cap for the recipient. It is the "AND" that makes the credential a load-bearing part of the enforcement instead of a nice-to-have.
This runs on every transfer, on every one of the five chains, whether the caller is a human wallet or an agent operating under mandate. The identity check is not "we looked at your credential at admission time"; it is "we look at your credential every time you touch a regulated asset." That is what portable actually means: not one credential in one place, but one credential enforceable in every place the user might touch the asset.
What "portable" is not
Portability across five EVM chains is not the same as portability across every chain we support. The credential contract on the EVM side does not exist on Solana, Soroban, or Clarity. Those chains have their own native identity modules that we sync from the same off-chain verification, but they are not the same on-chain artifact. This is a deliberate design decision, not an omission.
Portability is also not indefinite. Every credential has an expiry, defined by the same policy that governs any regulated identity check. When the credential expires, the user re-verifies once, and the five chains re-issue in parallel. The pattern holds; the check is fresh.
Revocation, expiry, and the honest bit about admin control
The issuer can revoke a credential, on all five chains, in a single administrative action. This is not something the operator does casually; the same governance that authorizes new issuers authorizes revocation. When a credential is revoked, transfers involving that address begin to revert at the ACE policy check on every chain that credential covered. There is no admission grace period. This is the correct behavior for regulated assets, and it is what an issuer needs to be able to point to when a regulator asks how they enforce.
The single-admin risk is real, and we do not hide it. The mitigation is that the admin key that authorizes issuance and revocation lives inside a multisig, not on any relay or credential-issuance server. The issuance service can post credentials that the on-chain contract already accepts; it cannot elevate itself into an admin, and it cannot revoke credentials on its own.
What this buys the user
From the user's perspective, the entire mechanism collapses to: verify once, and any transfer of a regulated asset on any of the five supported EVM chains simply works. From an issuer's perspective: every holder of a regulated token is provably KYC-checked, at the moment of every transfer, on-chain, without the issuer having to build any of it. From an auditor's perspective: the check is deterministic, the credential is inspectable, the enforcement is a specific contract call visible in the block explorer.
This is not a marketing pitch. It is the specific behavior of the specific contracts you can see on our five EVM testnet chains today. When mainnet arrives, Chainlink's cross-chain identity infrastructure will let a single credential replicate across CCIP-connected chains natively, and our five-chain issuance flow collapses into that native model. The user experience does not change; the plumbing gets shorter and the trust model gets stronger.
Try the demo
The full loop is live on testnet. Connect a wallet, complete the Didit flow once, and watch the credential land on all five EVM chains. Every subsequent transfer of an OB-issued token, on any of the five, runs the check on-chain, in front of you.
Testnet, unaudited. Not a solicitation. Not an offer of securities. Every transaction you make on this site is signed by your own wallet on a public testnet. No real money moves.
Testnet, unaudited. Not a solicitation. Not an offer of securities. Every transaction you make on this site is signed by your own wallet on a public testnet. No real money moves.