Most EU compliance writing is organised one regulation at a time. That is the right shape for a lawyer and the wrong shape for a build, because the contracts do not divide that way. The document-anchoring contract answers the Prospectus Regulation, the fund regime and the market-abuse regime at once. The identity layer answers anti-money-laundering, digital-identity and investor-classification duties simultaneously. Read regulation by regulation, you write the same module down four times and still cannot tell how many contracts you are building.
So this article follows the way the system’s shape — organized by architecture layer, with regimes attaching to whichever layer governs them. A layer exists because something has to be built, not because a Regulation has a name.
Scope: the issuer lane. The entity issuing and administering a tokenized security — including the moment it has the token admitted to trading on someone else’s venue, which is when the market-integrity layer switches on and not before. Venue operators and own-account dealers carry a larger obligation set not covered here.
1. The rule that decides what goes on-chain
Before any module, one test. It removes more work than it creates.
An on-chain record earns its place only when an on-chain function gates on it. Some require, revert or branch has to read it and decide something. Holding every input needed to compute an answer is not a reason to compute it on-chain — only permission to, if something reads the result.
The rule of thumb that “a rule goes on-chain when the contract holds every input” is necessary and not sufficient, and the gap is where over-building lives. A notification threshold is the clean example: give a contract a price feed and it can aggregate a running total perfectly. It still does not belong on-chain, because crossing the threshold makes a transaction notifiable, never unlawful. Nothing gates. The contract could only emit an alert an indexer would raise anyway — pricing worse, unable to count business days, unable to correct an immutable total after a bad feed.
“The contract could decide this” and “a contract must decide this” are different claims. Only the second buys on-chain state.
The carve-out: emitting an event is not storing state.
An event surface no contract reads is how off-chain surveillance and regulatory reporting receive ledger facts; market-abuse monitoring is unbuildable without it. The test bars state nothing reads, not events nothing reads. The carve-out inverts for personal data. Storage can be deleted; an event log cannot. So where an event describes a natural person it carries the wallet and an opaque hash and nothing else — tier, jurisdiction, person type, claim outcomes and declared covenants stay in storage, where deletion actually works.
The sharpest case is the internal person identifier that ties an investor’s wallets together: in storage, one erasure call removes every wallet under it; in a log, it states permanently that those addresses are one human. An event says that something happened to a wallet; storage says what. And the indexer loses nothing, because the operator minted that identifier and holds the wallet-to-person table in its own database — the one copy of the linkage the operator can delete, which is why it is the copy that holds it.
That gives three honest categories, and naming the third is part of the design:
| What it Means | Example | |
| On-chain | The contract holds every input and a function reverts on it | Transfer eligibility; subscription ceilings; the denominator, timers and breach-state machine of a fund limit |
| Partial | The decision is on-chain, an input is fed in | Valuation figures and what the fund holds — the numerator of the same limit; working-day calendars; per-jurisdiction thresholds |
| Off-chain | Procedural, human, or addressed to the firm rather than the transfer | Customer due diligence itself; regulator filings; policy documents |
A design that claims everything is on-chain is not more compliant. It is less honest about where the failure modes are.
2. Seven capabilities, before any token standard
Whether to build on the ERC-1400 family or ERC-3643 (T-REX) is the wrong question to start with, and it is not a compliance question. Every obligation here is satisfiable under either. The choice turns on the operator’s existing stack, vendor relationships, auditor familiarity and interoperability commitments — it changes which capabilities arrive pre-built and which are custom, and therefore the audit surface. It does not change the rulebook.
So this section specifies the architecture is specified as a required capability set, then binds it to whichever standard you chosen:
| # | Capability | What forces it |
|---|---|---|
| 1 | Pre-validation transfer gate — every movement checked before it executes, with an opaque refusal reason, and every reason a wallet may not move held in one store under one flag | Eligibility rules across every regime. Disclosing that a block was AML-driven is a criminal offence, so the revert stays generic — and a generic revert is decoration if a sanctions listing, a lapsed record and a suspicion block sit in three readable storage slots. One store makes the classes indistinguishable by construction |
| 2 | Investor identity and classification record — wallet resolved to a person, and the person to a verified record carrying tier and jurisdiction | Investor classification, customer due diligence, digital-identity claims. Two hops, not one, and that is regulation talking: the prospectus exemptions count people per Member State and the right to erasure erases a person, so attributes stored per wallet let one human hold two jurisdictions and two classifications — and let an “erased” investor keep trading through a wallet the delete never reached |
| 3 | Trusted attestation issuers, with revocable claims — third-party attestations revocable with immediate effect on transferability | Qualified trust-service and electronic-attestation regimes; periodic AML re-screening |
| 4 | Rule modularity — rules added, removed and upgraded individually, each mappable to one Article | Fund limits change on their own schedule; the audit needs a one-to-one Article-to-function map |
| 5 | Freeze, forced transfer and recovery — parcel-level freezes, forced transfers, lost-key recovery | Circuit-breakers, regulator-ordered remediation, seizure and transfer-to-estate orders. Wallet-level stops are not here — sanctions, suspicion, probate and court attachments live in the single store from capability 1, because a stop distinguishable by where it is stored discloses its class |
| 6 | Partition and tranche segmentation — sub-balances with independent transfer rules | Side pockets, per-tranche lock-ups, the pending state a subscription sits in before it settles |
| 7 | Investor covenants — what the investor themselves stated or acknowledged, bound to the hash of the document version it was given against, checkable at mint, send or receive independently | Key-information delivery, long-life fund warnings, declared-person registers, retail-access acknowledgements |
Capabilities 3 and 7 look like one capability and are not.
The third runs one direction: a third party attests something about the investor. The seventh runs the other: the investor attests something themselves — I received this document, I am a declared person. The third is time-based and expires. The seventh binds to a document version hash, so revising the document invalidates every outstanding acknowledgement the moment the new version is anchored — no sweep, no configuration, no chance to forget.
3. The layers, and what lives in each
| Layer | Modules | Principal regimes |
|---|---|---|
| Token and identity base | SecurityToken · IdentityRegistry · TrustedIssuersRegistry / ClaimTopicsRegistry | Investor classification · anti-money-laundering · digital identity |
| Identity and eligibility | ModularCompliance and its rule modules · RestrictedPartyRegistry / RestrictedPartyGate — the single wallet-stop store, read by the token and the payout path directly as well as through the gate · CovenantRegistry | Anti-money-laundering · targeted sanctions · key-information delivery · declared-person registers |
| Fund-structure enforcement | EltifConcentration · UcitsFiveTenForty · NavBorrowingCap · LmtGate · HoldingPeriodLock · ValuationOracle | Alternative-fund, UCITS and long-term-fund regimes |
| Investor economics | DistributionAgent · CouponSchedule · DistributionWaterfall · BuybackAgent | Market-abuse safe harbours · fund distribution rules |
| Market integrity | PdmrClosedPeriodFreeze · PdmrRegister · MarketEventSchema (the event surface, not the reporting bridge) | Market Abuse Regulation |
| Disclosure and document registry | DocumentRegistry · SubscriptionEscrow | Prospectus Regulation · fund prospectus regimes · key information documents · market-abuse disclosure |
| Governance and upgrade control | Stock multisig → TimelockController → ProxyAdmin → proxy, deployed unmodified, the disclosure document’s hash carried in the timelock salt so change and document are bound on-chain · DoraGovernor — a protocol pause, an incident log and a key-rotation register, and nothing else. No custom contract sits on the upgrade path. The pause is read where it has to bite — the token’s holder-initiated transfers and mints, the fund modules’ acquisition paths, payouts and buy-back purchases — and deliberately not by forced transfer, recovery, repayments, disposals or refunds. A pause nothing reads is an event with a different name | Prospectus supplement discipline — see § 4 |
| Data protection | Almost no module. The constraint runs through all of them — minimise personal data on-chain, justify every field that remains, keep it out of event logs entirely — plus one contract: a PersonErasure coordinator that answers an erasure request in a single call, fanning out to every store holding residue about a person and erasing the identity registry last. Complete as to storage, silent as to history | General Data Protection Regulation |
Two properties of that table are where the page count goes when you organise by regulation instead.
One module usually answers several regimes.
DocumentRegistry anchors an offer prospectus, a fund prospectus and annual report, market-abuse disclosures and a retail key information document. Scoped from any one regime it is under-built for the other three. IdentityRegistry is the same story.
One regime usually spans several modules.
A retail key-information duty touches DocumentRegistry for anchoring, CovenantRegistry for delivery acknowledgement, and is a fund-regime line item as well. There is no single place to read it.
Every obligation here is removable except one, and how it is removed is a design rule.
Which obligations an issuer owes is a scoping decision: anti-money-laundering rules bind obliged entities — investment firms, fund managers, payment institutions — and a bare securities issuer is not one until it holds a licence. A client owing less does not unwire the compliance engine; the reference is mandatory at construction and never null. They empty the rule set — one removal per Article, each logged. A nullable reference cannot tell “nobody wired it” from “not owed”, and a half-finished deployment then waves every transfer through.
Targeted sanctions are the exception – they bind regardless of licence, which is why the token reads the wallet-stop store directly, above the removable module list, and not only through a module governance can drop with one call. That read runs on every path that moves units, the agent-operated forced transfer included. A control that binds irrespective of client type must not be reachable only through a list one removeModule call empties: with the module gone, an agent key would otherwise be able to place units on a listed person and call it a seizure.
4. How many of each — the question that decides your topology
The list above says which modules exist, not how many instances you deploy. For a platform running more than one asset that is the more expensive question. Some of it regulation decides; some is a genuine choice whose cost lands somewhere unexpected.
One instance, platform-wide — regulation decides this:
| Module | What forces it |
|---|---|
IdentityRegistry and its due-diligence claims | The anti-money-laundering trigger is the business relationship, not the product, and the refresh cadence is per-customer. Per-asset identity puts one investor on several refresh clocks and lets a lapse on one asset coexist with trading on another |
| Investor classification claim | Classification is per-client. One classification service, many regimes |
TrustedIssuersRegistry / ClaimTopicsRegistry | Revocation of a qualified attestation is final and must kill transferability everywhere at once |
RestrictedPartyRegistry | A listing is against a person. Per-asset, one list hit is several writes with a window between them in which the person is stopped on one asset and exiting through another. Probate holds and court attachments in the same store are person-scoped too: an estate is not per-asset |
DoraGovernor, the register of information, incident classification | Entity-level duties |
One instance per asset — because the parameters are that asset’s:
SecurityToken and its ModularCompliance instance · the fund limit set (EltifConcentration, UcitsFiveTenForty, NavBorrowingCap, LmtGate, HoldingPeriodLock) · SubscriptionEscrow, per offer including its validity date · prospectus, final terms and key-information entries · PdmrClosedPeriodFreeze, keyed to that issuer’s reporting calendar · the distribution modules.
Genuinely a choice — decide it, do not default into it:
DocumentRegistry (one namespaced registry, or one per asset) and the valuation feed. CovenantRegistry straddles by construction: each entry carries its own scope, and evaluating one reads a platform-wide investor tier and a per-asset offer configuration in the same check. It cannot sit on either side of the line.
Decide that middle bucket on upgrade cost, not on gas. While an offer is open — from prospectus approval to the later of the offer closing or trading starting — a material change to disclosed contract behaviour needs a supplement approved and published before deployment. A compliance module shared across several assets makes one upgrade a material change to several disclosed behaviours: several supplements, each with up to five working days of regulatory approval, each opening a three-working-day investor withdrawal window.
Upgrade windows already run in weeks for one asset. The duty does close — most upgrades in an instrument’s life fall after the offer and owe no supplement; market-abuse disclosure takes over once the venue admits the token to trading, and nothing does for a closed unlisted offer — but a multi-asset platform nearly always has some offer open, or a rolling base prospectus that re-enters the window each time it reopens, and a shared module ties every asset to whichever one is inside it.
Shared infrastructure is cheaper to build and materially more expensive to change.
Merging registries later is straightforward; splitting them after issuance is a re-issuance. And size the blast radius first: a shared identity layer means one lapsed due-diligence record freezes that investor across every asset — correct, but it has to fit your refresh workflow — while a per-asset layer produces exactly the lapse-on-one-live-on-another problem the rules exist to prevent. Neither is a safe default.
One constraint sits on top. A single identity registry readable by several compliance surfaces is a purpose-limitation question under data-protection law: do not treat a shared registry as neutral there because anti-money-laundering rules make it convenient.
5. What this architecture deliberately does not do
Three boundaries, each regularly assumed the other way.
It does not claim there is no personal data on-chain — because the claim is false and will not survive a data-protection authority. A wallet address bound to a verified investor is personal data, and so is every transfer it makes. The register is the product; it cannot be made anonymous. So: direct identifiers — names, addresses, dates of birth — never touch the chain, in storage or in an event. Every field beside the address is justified individually, because address plus jurisdiction plus identifier hash is a profile, and each addition moves re-identification closer to possible without the off-chain record.
And erasure is approximated, not achieved — the off-chain record is deleted, its key destroyed, an on-chain coordinator sweeps every store that holds residue about the person, and the anchor becomes an orphan that resolves to no one. That coordinator is complete as to storage and silent as to history: it reaches every deletable field and no event and no calldata, ever, which is why the rules about what may go in a log are worth obeying before the first emit rather than after. The erasure plan says “approximation” in those words, because an authority that reads “erased” and finds an immutable identifier treats the document as the problem.
It does not compute business days. Statutory windows run in working days, and no contract knows that a given Thursday is a national holiday where it matters. Window timestamps are fed in against a real calendar, never derived from block time.
It does not treat a compliance obligation as sufficient reason to build a contract. An indexer, an archive, or a person with a name and a runbook discharges several genuine obligations here. Saying so is what makes the rest credible.

Leave feedback about this