The identity layer answers three regimes at once: the anti-money-laundering rules (Regulation (EU) 2024/1624 — "AMLR" — applying from 10 July 2027, and until then the prior directive as transposed), investor classification under MiFID II Annex II, and the digital-identity rules of eIDAS 2.0 (Regulation (EU) 910/2014 as amended by (EU) 2024/1183). Scoped from any one of them it is under-built for the other two. Written three times it is the same registry three times.
This article covers the record and the attestations behind it. IdentityRegistry, the TrustedIssuersRegistry and ClaimTopicsRegistry pair, and the store every wallet-level stop lives in, RestrictedPartyRegistry. The gate that reads the record on every transfer and the tipping-off rule that shapes its refusals — is in the transfer-restrictions article. The wider architecture is in the EU-Compliant Tokenized Securities: Smart Contract Architecture pillar.
No platform owes all of it. The first section is about which of the three regimes actually reaches you.
1. Which regime reaches you
Applies to every reader. Answer it against the operating entity's licence, not against the activity it performs.
The anti-money-laundering regime binds obliged entities, and Article 3 lists them. Investment firm, credit or financial institution, payment or e-money institution, fund manager, crypto-asset service provider, crowdfunding provider. An issuer of securities is not on the list. A genuinely unlicensed pure issuer is outside the regime and is caught only if it is independently one of the listed types. The moment any licence is held — venue, dealer, fund manager — it attaches in full.
Targeted financial sanctions bind everyone, irrespective of obliged-entity status. That is a separate regime with its own basis, and it is why the screening control in section 6 is built in every lane and cited differently depending on who you are.
Investor classification binds anyone distributing to EU clients. And the tier it produces retail, professional on request, per-se professional, eligible counterparty is read by more regimes than any other single fact about an investor. eIDAS 2.0 relying-party duties attach the moment you accept an EU Digital Identity Wallet attribute as identification.
So the registry is built regardless. What changes with the licence is the citation against each control, and an audit map that grounds a control in an anti-money-laundering Article for an entity outside Article 3 is a defect in the artefact the regulator reads.
2. One instance, platform-wide — regulation decides this, not preference
Applies to any operator running more than one tokenized asset. For a single asset the question does not arise yet; it will.
Every other layer in this architecture is one-per-asset. The identity layer is not, and it is not an engineering choice:
| Component | What forces one instance |
|---|---|
| The investor record and its due-diligence claims | Article 19(1)(a) makes the trigger the business relationship, not the product. Article 20's refresh cadence and Article 21's "do not carry out the transaction" are per customer. Per-asset identity puts one investor on several refresh clocks, and lets a lapse on one asset coexist with continued trading on another — the exact breach |
| The classification tier | Classification is per client. One classification, many regimes |
| Trusted issuers and claim topics | eIDAS Article 45d(4) makes revocation of a qualified attestation final. It has to kill transferability everywhere at once |
| The restriction store | A listing is against a person, not a product. Per asset, one list hit becomes several writes with a window between them, during which the person is stopped on one asset and exiting through another |
Two costs land on the choice, and both answers are wrong if left unstated.
With a shared registry, one lapsed due-diligence record freezes that investor across every asset simultaneously — correct, and a blast radius nobody has sized against the refresh-workflow commitment the gate article says expiry requires. With per-asset identity, the lapse freezes one asset while the investor keeps transacting on another, which is the breach. Pick deliberately.
"One per platform" is not "one per chain."
An operator whose issuance runs on a public chain and whose venue runs on a permissioned one has two deployments of every row above, and no atomic write across them. No contract closes that. What the design owes is a named sync mechanism, a stated worst-case propagation lag, and an owner, the restriction store anchors a list version and the version it swept to so the lag is at least measurable.
3. What the record holds, and what it must not
Applies to every registry. This section is a data-protection constraint before it is a design.
IdentityRegistry resolves in two hops, not one. a wallet holds a binding to a person, and the person holds the record — the classification tier, the jurisdiction, natural-or-legal, the reporting identifiers, the review horizon, and a set of claims each carrying an issuer and an expiry.
personIdOf()is the first hop and the join every other contract uses — the restriction store, the managers' register, wallet recovery.tierOf()andjurisdictionOf()are the second hop, done for you, and are what the covenant predicates and the subscription path read.
The second hop is a compliance requirement, not an implementation taste, and getting it wrong is a control failure before it is a privacy one. The registry shape most of this sector inherits keys by wallet, because the pattern it descends from parks the attributes in a per-investor identity contract and leaves the registry holding a pointer. Drop that per-person contract and there are good data-protection reasons to. Since a contract whose storage and address outlive an erasure request is exactly what the right to erasure cannot tolerate and the tempting move is to keep the wallet-keyed registry and push the attributes into the wallet row. Do not.
Attributes stored per wallet with no cross-wallet check mean one investor can hold two answers: wallet A registered as Germany/retail, wallet B as Ireland/professional, same human, nothing objecting. The prospectus exemptions count people — a per-Member-State money threshold and a 150-non-qualified-person headcount — so that is a subscriber choosing whichever Member State still has room, or the classification that skips the headcount entirely. Key the record by the person and the divergence is unrepresentable rather than merely checked: registering a second wallet against an existing person either matches the record or reverts.
Person-keyed storage does not cost you the standard's read surface, and conflating the two is why this looks like a harder choice than it is.
ERC-3643's identity registry is consulted by wallet — is this address verified, what identity and what country does it resolve to. That is the shape of the read, not a statement about where attributes live.
The wallet-keyed calls resolve wallet → person → attribute and write through to the person record, reverting on any divergence. So the standard's surface sits over the person key without weakening it. Where the standard asks for more than a read — typing the registry against a deployed per-investor identity contract, and carrying the investor's country on-chain as a numeric code — we record a declared deviation with its reason rather than leaving a reader to discover it.
A third falls out of the same reasoning: the standard offers an optional storage contract the registry can delegate to, explicitly shareable across several tokens, and we decline it. One person register shared across issuers is the cross-issuer correlation problem, not an efficiency. How you decline matters as much as declining. The functions are present and refuse: the setter reverts a named error, the getter answers zero. Omitting them would have been the tidier-looking choice and the worse one — a refusal leaves a readable trace a venue can act on, while a function that simply is not there fails inside the caller's tooling with nothing on-chain to explain why. The second of those is the same on-chain-attribute question the data-protection article puts to the data-protection officer, and the standard answers it in the direction that article treats as the one to justify.
The first of those is a substitution, and it is worth being precise about what replaces what.
The standard types its registry against IIdentity — a contract deployed per investor, holding that person's attestations at its own address. This design deploys no such contract. identity() answers a stable per-person handle: derived from the person identifier, comparable across calls, and never callable. The attestations it would have held are the claims on the person record, reached through the registry rather than through an address of their own.
The cost is an interoperability one, and it is deliberately loud.
A venue whose tooling takes the handle and calls it breaks against this design immediately and visibly, which is why a non-callable handle was preferred to returning a zero address, the same reasoning as the refusing setter above. It is a declared deviation and a disclosure item, not a silent narrowing. Why the registry holds the record rather than a per-investor contract is the erasure question, and the data-protection article is where it is worked through.
What is on-chain is a pointer, hashes and attestation references — never a direct identifier.
That is a minimization rule, not an exemption. The wallet key the claims hang off is itself personal data once bound to a verified record, so the registry is inside the data-protection regime whatever the claim payload looks like. Which further fields belong on the record and whether a gate could read a derived boolean instead of the attribute is a per-field decision for the data-protection officer, covered in the data-protection article.
Three rules are settled regardless. Events emit the wallet and an opaque hash and nothing else, because storage can be deleted and a log cannot. One wallet per investor per issuer — address reuse across issuers is the linkability problem no erasure measure reaches. And the eligibility check fails closed on a broken binding. A wallet whose person has gone leaves the required-claim set empty, and an empty required set passes everything. So the resolution failure has to be its own refusal rather than a silent one.
4. Onboarding — the due-diligence limbs that end up as claims
Applies in full to obliged entities. For an unlicensed issuer the screening survives on sanctions grounds and the rest is a commercial counterparty-risk control.
Article 19(1)(a) makes establishing a business relationship the trigger for full customer due diligence, with no value threshold. Every investor you onboard is a business relationship from the first subscription — which is why there is nothing to count on-chain, and why the value-based triggers elsewhere in Article 19 are not built.
Article 20 then sets the measures: identification and verification before the customer holds anything (20(1)(a)); the purpose and intended nature of the relationship; source of funds and source of wealth to risk; ongoing monitoring of transactions against the risk profile; and periodic refresh on a documented, risk-tiered cadence. Article 21 requires that where due diligence cannot be completed, the relationship is not established or continued, the transaction is not carried out, and a suspicious-transaction report is considered.
Enhanced due diligence is triggered by high-risk third countries, politically exposed persons — a status continuing for at least 12 months after leaving office — cross-border correspondent relationships with third-country crypto-asset service providers, and unusually complex or large transactions with no apparent purpose. Article 34 requires senior-management approval to establish or continue such a relationship. The correspondent-crypto-firm trigger is new in this Regulation and is the most-missed item in onboarding flows.
On-chain
All of the above is an off-chain determination written back as a claim. The identity service calls setClaim() with a topic, a value and an expiry; ClaimTopicsRegistry holds the set of topics required before a wallet is eligible, as a baseline plus per-jurisdiction additions through requiredTopics(). One design point does the compliance work:
- The refresh cadence becomes the claim's expiry, and the expiry is mandatory at the write. Articles 20 and 21 together mean the eligibility claim carries a validity window, and the gate treats an expired claim exactly as a missing one.
setClaim()therefore rejects a zero or past expiry and refuses anything further out than a governance-set maximum: a registry that accepts "never expires" has made the refresh cadence opt-in for whoever writes the claim, and one issuer passing zero turns the control off for every wallet it attests. Expiry then fails closed on a live position, which is what gives the refresh workflow a service-level commitment.
Partial. The determination behind each claim — tier, risk rating, beneficial ownership — is made off-chain and written back as the claim the gate reads.
Off-chain. The due diligence itself, all of it. The risk-tiered refresh policy, and senior-management approval on every enhanced case.
5. Trusted issuers, and a revocation with no undo
Applies to any platform accepting third-party attestations — a KYC provider, a qualified trust-service provider, or the EU Digital Identity Wallet.
The identity record does not attest anything itself. It holds claims signed by issuers the platform trusts, and TrustedIssuersRegistry is where that trust is recorded — registerIssuer() names an issuer against the claim topics it may attest, and nothing else. eIDAS 2.0 supplies most of the rules:
Article 5b makes attributes presented from the EU Digital Identity Wallet acceptable identification, and imposes relying-party duties. Registration, pre-declaring exactly which attributes you consume (Article 5b(3)), updating on change, identifying yourself at each interaction, and authenticating what is presented. The pre-declared set is also the data-minimization control.
Article 45d(4) is the one that shapes the contract: revocation of a qualified attestation is final and shall never be reversed.
What is verified on-chain, and what is not — state this before the revocation design, because it is routinely overclaimed.
No contract verifies an attestation signature or a selective-disclosure presentation. It cannot: verifying a presentation on-chain means writing the presented attribute where anyone can read it. It's permanent publication of personal data, which is the outcome the data-protection article treats as the one to design out. The claims service verifies the signature off-chain.
What the chain holds is the two things a contract can actually decide.
A write gate — a claim is only accepted from an issuer the trust registry currently names for that topic.
A revocation read, because issuer trust is re-checked on every read of the claim rather than at the write.
So a revocation invalidates outstanding claims without touching a single claim record, and the transfer that comes after it fails. An audit map that reads "signature verified on-chain" describes a control nothing implements.
On-chain
We build two revocation paths, because the Article does not say which the issuer meant.
revokeProspectively() stops the issuer attesting from now on but leaves claims issued earlier standing.
revokeRetroactively() invalidates everything the issuer ever attested.
isTrustedFor() takes the claim's issue time as an argument for exactly that reason.
There is no un-revoke. A holder re-verified after a revocation receives a new claim from a currently trusted issuer, not a restored one.
Two further eIDAS limbs constrain the shape rather than the data. Article 45h requires logical and functional separation for anyone issuing attestations. If the same entity both issues and consumes claims, that is a service-boundary requirement, and it argues against one investor record shared across an issuer entity and a venue entity. Article 5a(16) forbids the attestation issuer from being able to track or correlate a user's transactions. Which rules out any design where the claim issuer is called back on every transfer. Verification happens against what was presented and stored, never by pinging the issuer per movement.
6. The restriction store — every stop, one flag
Applies to every platform. Sanctions bind regardless of licence; this is the one control no client scopes out.
Article 20(1)(f) requires re-screening on every sanctions-list update, of the customer record and every beneficial-owner record, across the whole existing base. Article 75 requires refraining from executing a suspicious transaction where possible. Neither Article says where the resulting block lives, and the answer decides whether the tipping-off prohibition is real or cosmetic.
We build one store, RestrictedPartyRegistry, and it holds every reason a wallet may not move. A sanctions listing, a suspicion block, a probate hold, a court attachment, a lost-key hold, an operational hold pending investigation. All set the same flag and emit the same event shape. There is no class field and no reason code anywhere in the contract. Every entry carries a mandatory opaque case reference.
Four reasons it is not a flag on the identity record:
- Scope. A listing is against a person, so it is keyed by
personIdand follows them across every wallet and every asset. A second, wallet-keyed map covers addresses that were never onboarded — a counterparty flagged by chain analytics has no investor record to hang a flag on. - Removability. Every anti-money-laundering rule in this architecture is removable, because an unlicensed issuer correctly drops them. Sanctions are not removable. Bundle the sanctions block into the removable claim set and the issuer who correctly drops the AML modules silently drops sanctions with them. So the token and the distribution agent each take the store as a constructor argument that rejects a zero address, and read it above the module list.
- Lifecycle. A claim is revoked by its issuer on a cadence. A listing is list-driven, instant on the existing base, blocks receive as well as send, and never expires and only a delisting clears it.
- Observability — the decisive one. Contract storage is public. If a sanctions listing lived in one slot, a lapsed refresh in another, and a suspicion block in a third, an observer would read the three slots and know which class fired, whatever the revert code said. One store, one flag, and a population that also holds the boring majority is where the inference actually dies. A store named for sanctions would defeat that on its own — membership would be the disclosure.
Three operating properties follow
Two write roles, one flag
The screening vendor's key and the transfer agent's registrar key both write the same entry, because the vendor has no business recording a death and the registrar has no business running a list. Release is governance-only for both, since placing a restriction fails safe and lifting one releases a frozen position.
A permitted-destination carve-out is mandatory
The forced-transfer path reads the store too. Without it, the restriction meant to route value to a freezing order's own seizure destination, or to the heir who ends a probate hold, would block them instead — it relieves only the sender limb, and a restricted party may never be a recipient.
A stale sweep blocks entry, not exit
ScreeningIsStale() fails mints when the whole-base sweep has fallen behind the list, and leaves existing holders trading, because freezing the book over an operational lag is a self-inflicted outage on people who did nothing.
A screening hit is a restriction, never a claim and the claim catalogue enforces that by refusing to take the number back.
The tempting shortcut adds a "sanctions screened" claim topic recording pass or fail beside the record. But this rebuilds the two-slot leak exactly: anyone can publicly read the raw claim, and an eligibility check that reverts and names the missing topic reveals which question the wallet failed. So the design retires the topic that once held it — a retired number can never be required again, nothing un-retires it, and nothing reassigns it. Because a stale claim resolving to nothing fails closed while one resolving to some later topic fails open. A hit is written to the restriction store. A clear is written nowhere at all.
What the forced-transfer path actually runs, since the carve-out above depends on it.
It is not "the transfer gate" wholesale, reads the restriction store on both parties in the mandatory layer, checks the recipient's eligibility, and runs the rule modules. This deliberately does not re-check the sender's eligibility, a seizure ordered against a holder whose due-diligence record has lapsed is exactly the case the order exists for, and blocking it would make an administrative lapse a defence against a court.
Re-pointing the store is three calls, not one. The gate adapter, the token and the distribution agent each hold a reference. Do one and not the others and two stores are live with different contents, which is the observability failure the consolidation exists to end.
One thing the store does not answer. Its opacity answers the tipping-off prohibition. It does not answer whether data-protection law's criminal-offence-data rule permits a permanent public record that blocks a person — especially after someone corrects a false-positive match. The data-protection officer must make that decision before the first live screening run, and the data-protection article discusses it.
7. Fan-out — the question the diagram hides
Applies from the second asset onward. Decide it before the second asset deploys, not after.
The token calls the identity registry and the rule engine independently, and the rule engine holds no identity reference. Every module that needs an identity attribute wires its own. That is a star, not a chain, and it is a fan-out. A revoked claim, a lapsed record, or a new listing has to reach every module-held reference on every asset. On a single token, propagation is immediate by construction. Across several, it is several writes, and whether they must be atomic is a decision with a wrong default in both directions. A partial propagation leaves the same investor revoked on one asset and live on another, which is the Article 21 and Article 45d(4) failure in one. A fully atomic propagation across chains does not exist. State the mechanism, the worst-case lag, and the owner.
One fan-out in this design is atomic, and it is worth knowing which. An erasure request has the same shape as a revocation. One person can leave residue in many contracts, so a dedicated coordinator handles it: it reads the person's wallet list from this registry, calls every registered store, and erases the registry last, because the address-keyed stores cannot expand a person identifier themselves. Any store refusing stops the whole run. That is the opposite default from claim propagation, and deliberately. A stale claim on one asset is a window you can close, while a half-erased person is a state nobody can describe to a supervisor. Note the wiring risk it creates. A store that exists but was never registered as a target is silently skipped, so the target list belongs in the deployment checklist beside the module list.
8. Reporting — what the indexer has to be able to answer
Applies to obliged entities.
Article 69 requires a suspicious-transaction report for every suspicion including attempted transactions, filed personally by a named compliance officer (Article 69(6)). And requires requests from the financial intelligence unit to be answered within five working days, or under 24 hours where urgent. Nothing on-chain files a report. What the 24-hour limb does is set the query latency the event indexer has to support against historical transfer, block and restriction events, the structured record the response is answered from.
Article 77's five-year retention is the one limb that reaches back into §7. Someone can call the coordinator described above inside the retention window, and it must refuse. The legal-obligation basis documents the five years as a retention period, which is what makes refusal lawful rather than obstructive. The data-protection article works through the reconciliation.
InnBlockchain is an RWA tokenization development company building this architecture end to end. Scope your build.
At a glance
| Obligation | On-chain | Partial | Off-chain |
|---|---|---|---|
| Record shape | Wallet → person → record. Attributes on the person; the wallet holds only a binding. A second wallet either matches the person's record or reverts | — | The prospectus headcount and the money threshold both count people, so this is a control, not a preference |
| AMLR Art 3 — obliged entities | Decides the citation, not the build | — | Verify against the licence, not the activity |
| Art 19(1)(a) — business-relationship trigger | Claim must exist before any transfer; nothing to count | — | Full due diligence before any claim is written |
| Art 20; Art 21 — measures, refresh, inability to complete | setClaim() — expiry mandatory, capped at a governance maximum; expired = missing; fails closed | Purpose, source of funds and wealth, ongoing monitoring | Risk-tiered cadence with a service-level commitment |
| Art 34 — enhanced due diligence | Risk-tier claim | Determination | Senior-management approval |
| Arts 52, 53, 61 — beneficial ownership | — | Determination written back as a claim | Two-track determination, ownership and control |
| Art 20(1)(f); Art 75; sanctions | RestrictedPartyRegistry — one flag, every stop, opaque case ref; constructor-mandatory; read on the forced-transfer path too; stale sweep blocks mints only. A hit is never a claim topic | Whole-base re-screen on every list update | Owner and worst-case lag for the sweep |
| eIDAS Art 5b, 5b(3) | Trusted-issuer write gate; pre-declared claim set. The attestation signature is verified off-chain | Signature and presentation verification by the claims service; relying-party registration | — |
| Art 45d(4) | TrustedIssuersRegistry — prospective or retroactive revocation, no un-revoke | — | — |
| Art 45h; Art 5a(16) | No per-transfer callback to the issuer | — | Separate systems where you issue and consume; do not share one record across legal entities |
| Art 69 | Structured events as the historical record | Indexer latency sized to the 24-hour limb | Named officer files |
| Art 77 ↔ erasure | A single erasure coordinator: wallet list read from this registry, every store called, this registry erased last, atomic, timelocked | Retention store; deletion on day one of year six | Reconciliation agreed before build |
This is engineering commentary on regulatory requirements, not legal advice. Whether the anti-money-laundering regime reaches a specific entity, and on what date, needs sign-off from counsel.






