Записи о решениях · ADR-020
ADR-020: ERC-3643 compatibility as a read-through facade and a notification-only hook
ERC 3643 is a Final ERC for permissioned tokens, run in production by issuers, transfer agents, wallets, explorers and compliance vendors (the ERC3643 Association reports more than 140 members). Their tooling reads a sma
- Идентификатор документа
- ADR-020
- Дата
- 2026-10-23
- Источник
- docs/adr/ADR-020.md
Each lot is visible to the ERC-3643 (T-REX) ecosystem as an ERC-3643 token whose every answer is read live from the A-REX token and whose every movement goes through the A-REX token's own transfer; the adapter joins the pipeline only to be told about balance changes, so it can neither refuse nor allow anything and the token is not modified.
| Field | Value |
|---|---|
| ID | ADR-020 |
| Subject area | Interoperability |
| Status | Proposed (2026-10-23). Reference adapter available; informative, adds no requirement to AREX-CORE.md |
| Date | 2026-10-23 |
| Owners | A-REX Contributors; requested by the A-REX Platform (owner decision D5, 2026-10-23: build interop now) |
| Related requirements | AREX-CORE §4 (enforcement, ERC-7943), §5 (hooks), ADR-001, ADR-004, ADR-013, ADR-019 |
| Supersedes / superseded by | — |
Context
ERC-3643 is a Final ERC for permissioned tokens, run in production by issuers, transfer agents, wallets,
explorers and compliance vendors (the ERC3643 Association reports more than 140 members). Their tooling reads a
small surface: identityRegistry(), compliance(), isVerified(wallet), canTransfer(from, to, amount),
isFrozen, getFrozenTokens, paused, onchainID, and the ERC-20 balances and Transfer events beneath them.
An A-REX token is an ERC-1155 with one id per lot, enforced by ERC-7943 and an ordered hook pipeline. Nothing in that tooling can see a lot today. interop/ERC-3643.md sketched two directions in 2026-10: ERC-3643 identity and compliance used as A-REX rules (A), and a lot wrapped in an ERC-3643 token for investors (B). Neither was built. The owner of the reference platform decided on 2026-10-23 (D5) to build interoperability now so that companies already using ERC-3643 tooling can adopt A-REX without changing it.
Two rules bind any solution. The token and the attestation registry are never modified for an integration (ADR-001, the platform owner's "core never modified"). And an integration must never weaken an A-REX rule: a lot that the token would refuse to move must not move because a different interface was used.
Issue
How can the ERC-3643 ecosystem read, and where allowed move, A-REX lots without changing the token and without any path that bypasses or weakens the hook pipeline?
Assumptions
- ERC-3643 tooling reads the interfaces of the Final ERC-3643 text; T-REX 4.1.6 is the most deployed implementation of them. Tooling that needs T-REX internals (its factory, modular compliance modules) is out of reach of any adapter.
- Lots are integer quantities of a unit (
batchOf(id).unit), so ERC-20decimals()is 0. - A-REX lots are goods. The ERC-3643 interfaces are used for tooling compatibility; nothing here classifies a lot as a security (ADR-013).
Constraints
- ARexToken and ARexAttestations are unchanged (ADR-001; the platform's hooks decisions of 2026-10-22).
- The only extension point of a conformant token is the hook pipeline (ADR-004). A hook with
HOOK_CHECKorHOOK_ELIGIBILITYcan refuse operations; one with onlyHOOK_EXECUTEDcan only observe. - T-REX and ONCHAINID are GPL-3.0: no code of theirs may be copied into the MIT reference.
Alternatives considered
| Alternative | For | Against | Outcome |
|---|---|---|---|
Make ARexToken implement IERC3643 | one contract | modifies the core; an ERC-1155 cannot be one ERC-20 per id; EIP-170 size | Rejected |
| Wrapper that holds lot units and issues an ERC-3643 token (direction B of ERC-3643.md) | full T-REX semantics, investors never touch the lot | the wrapper becomes the holder of the goods; forced transfers and transforms of the lot need reconciliation; it is the securities use case the platform must not imply | Deferred (kept in ERC-3643.md §B for issuers who need it) |
| ERC-3643 compliance contract used as an A-REX rule (direction A) | reuses existing compliance | the reverse direction: it makes T-REX rules govern A-REX, not A-REX visible to T-REX; binds to one fungible token | Deferred (kept in ERC-3643.md §A) |
| A compliance-module bridge: an ERC-3643 module that asks the A-REX token | T-REX modular compliance would enforce A-REX rules | only useful when a T-REX token exists; still no view of the lots themselves | Rejected for this need |
| Read-through facade per lot, plus a notification-only hook that mirrors events | no change to the token; every answer and movement is the token's own; T-REX tooling sees each lot with balances and history | one contract per lot (a minimal clone); holders approve the adapter once to move lots through ERC-20 | Proposed |
Decision (proposed)
The reference adapter is two contracts in contracts/reference/interop/ of arex-contracts:
-
ARexERC3643Adapter, one per A-REX token:- It is a hook with flags
HOOK_EXECUTEDonly.onExecutedaccepts calls only from its token. For a lot with an ERC-3643 view it makes that view emit the ERC-20Transfer(from, to, amount)of the balance change (mints fromaddress(0), burns toaddress(0), forced transfers and both legs oftransformincluded). WithautoCreateon, it creates the view of a lot when the lot is created, so the view's log history is complete. - It deploys each lot's view as a minimal clone at a predictable address
(
lotAddress(id)= CREATE2 with saltbytes32(id));expose(id)creates the view of an existing lot. - It is every lot's identity registry:
isVerified(wallet)= the token'scanReceive(wallet);identity(wallet)andinvestorCountry(wallet)come from an optional identity directory (the ONCHAINID claim issuer, ADR-021). Verification is A-REX eligibility, not claims, soissuersRegistry(),topicsRegistry()andidentityStorage()areaddress(0). move(from, to, id, amount)moves units for one of its own lot views only, through the token'ssafeTransferFrom, which checks thatfromapproved the adapter and runs the full pipeline.- Its settings (name and symbol prefixes, the issuer's ONCHAINID, the identity directory,
autoCreate) change what tooling displays, never what the token allows.
- It is a hook with flags
-
ARexERC3643Lot, one per lot (IERC3643,ICompliance,IAgentRole):ERC-3643 / ERC-20 Answer balanceOf(w),totalSupply()balanceOf(w, id),totalSupply(id)of the tokendecimals(),name(),symbol(),version()0,<prefix> <id>,<symbol>-<id>,arex-erc3643/1.0.0identityRegistry()the adapter compliance()the lot view itself; canTransfer(from, to, amount)= the token's ERC-7943canTransfer(from, to, id, amount)isFrozen(w)!canSend(w)on the tokengetFrozenTokens(w)getFrozenTokens(w, id)on the tokenpaused()the token's paused()when it has one, elsefalseonchainID()the issuer's ONCHAINID set on the adapter, or address(0)transfer,transferFrom,approve,allowanceERC-20; movements through the adapter's movemint,burn,forcedTransfer,recoveryAddress,setAddressFrozen,freezePartialTokens,unfreezePartialTokens,pause,unpause,setName,setSymbol,setOnchainID,setIdentityRegistry,setCompliance, everybatch*,addAgent,removeAgent,bindToken,unbindToken,transferred,created,destroyedrevert ARexERC3643UseARexRoles(): those powers are the A-REX token's roles (ERC-7943forcedTransfer,setFrozenTokens, pause)isAgent(w),owner()false,address(0)underlying()(token, id)
The interfaces are transcribed from the CC0 ERC-3643 text (interfaces/IERC3643Surface.sol), so their selectors
are those of T-REX 4.1.6.
Whether the adapter is deployed for a token, and whether autoCreate is on, is policy (ADR-019): the
implementation's profile and the company's settings decide; the standard only describes the capability.
Argument
The facade answers exactly what the token answers, so there is nothing to keep in sync and nothing that can drift.
The hook is the only way to see balance changes that do not pass through the facade (direct transfers, forced
transfers, transforms), and by taking only HOOK_EXECUTED it gets that view without any power over the
operation: the token never asks it whether an operation may happen. Moving units through ERC-20 calls the token's
public transfer, so the pipeline, ERC-1155 approval and acceptance checks run as they do for any other caller. The
wrapper of direction B would make T-REX semantics fully native, but it would also make the wrapper the holder of
the goods and present a lot as an investment, which is neither needed for visibility nor consistent with ADR-013.
Consequences
Positive
- T-REX wallets, explorers and compliance dashboards see every exposed lot with its balances, supply, frozen amounts, pause and eligibility, without any change on their side or on the token.
- The adapter can be added to or removed from a live token through the normal hook lifecycle. Removing it stops the mirrored events and leaves every rule as it was.
- Holders who approve the adapter can move lots from tooling that only speaks ERC-20, under the same rules.
Negative
- One clone per exposed lot (about 134,000 gas when created together with the lot) and about 3,000 to 12,000 gas per balance change of an exposed lot for the mirrored event.
- A view created after its lot already moved has correct balances but no earlier
Transferlogs; explorers that rebuild balances from logs needautoCreate. setApprovalForAll(adapter, true)is per token. The adapter can move any lot of an approving holder, but only when the holder (or an ERC-20 allowance the holder gave) asks through that lot's view.- ERC-3643 tooling that requires T-REX internals (modular compliance modules, the T-REX factory, recovery) does not work against the facade.
Obligations it creates
- Implementations that expose lots this way say so in their profile and in the lot's metadata or passport (the view's address), and never describe the lot as a security.
- The conformance clauses IC-1 to IC-4 and IC-6 of interop/ERC-3643.md hold for any implementation of this adapter.
Implementation and evidence
| What | Where |
|---|---|
| Contracts | arex-contracts contracts/reference/interop/ARexERC3643Adapter.sol, ARexERC3643Lot.sol, interfaces/IERC3643Surface.sol |
| Tests | arex-contracts test/foundry/ERC3643Adapter.t.sol (18 tests), test/foundry/InteropConformance.t.sol (IC-1 to IC-6, fuzzing and an invariant run) |
| Mapping and conformance | interop/ERC-3643.md |
| First consumer | A-REX Platform add-on "ERC-3643 compatibility" (docs/INTEROP.md there) |