Skip to main contentA-REX Foundation

سجلات القرارات · 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

**Proposed** (2026-10-23). Reference adapter available; informative, adds no requirement to AREX-CORE.md
معرّف المستند
ADR-020
التاريخ
2026-10-23
متوفر بالإنجليزية فقط
هذه الصفحة بالإنجليزية. فصول الورقة البيضاء والمخططات وصفحات المنصة مترجمة؛ وتتبع مقالات المساعدة لغات المساعدة في وحدة التحكم. يبقى المعيار المعياري في المستودع؛ استخدم طلب وصول مبكر لذلك النص. وتبقى أدلة تصميم النظام وسجلات القرارات بالإنجليزية.

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.

FieldValue
IDADR-020
Subject areaInteroperability
StatusProposed (2026-10-23). Reference adapter available; informative, adds no requirement to AREX-CORE.md
Date2026-10-23
OwnersA-REX Contributors; requested by the A-REX Platform (owner decision D5, 2026-10-23: build interop now)
Related requirementsAREX-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-20 decimals() 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_CHECK or HOOK_ELIGIBILITY can refuse operations; one with only HOOK_EXECUTED can only observe.
  • T-REX and ONCHAINID are GPL-3.0: no code of theirs may be copied into the MIT reference.

Alternatives considered

AlternativeForAgainstOutcome
Make ARexToken implement IERC3643one contractmodifies the core; an ERC-1155 cannot be one ERC-20 per id; EIP-170 sizeRejected
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 lotthe 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 implyDeferred (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 compliancethe reverse direction: it makes T-REX rules govern A-REX, not A-REX visible to T-REX; binds to one fungible tokenDeferred (kept in ERC-3643.md §A)
A compliance-module bridge: an ERC-3643 module that asks the A-REX tokenT-REX modular compliance would enforce A-REX rulesonly useful when a T-REX token exists; still no view of the lots themselvesRejected for this need
Read-through facade per lot, plus a notification-only hook that mirrors eventsno change to the token; every answer and movement is the token's own; T-REX tooling sees each lot with balances and historyone contract per lot (a minimal clone); holders approve the adapter once to move lots through ERC-20Proposed

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_EXECUTED only. onExecuted accepts calls only from its token. For a lot with an ERC-3643 view it makes that view emit the ERC-20 Transfer(from, to, amount) of the balance change (mints from address(0), burns to address(0), forced transfers and both legs of transform included). With autoCreate on, 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 salt bytes32(id)); expose(id) creates the view of an existing lot.
    • It is every lot's identity registry: isVerified(wallet) = the token's canReceive(wallet); identity(wallet) and investorCountry(wallet) come from an optional identity directory (the ONCHAINID claim issuer, ADR-021). Verification is A-REX eligibility, not claims, so issuersRegistry(), topicsRegistry() and identityStorage() are address(0).
    • move(from, to, id, amount) moves units for one of its own lot views only, through the token's safeTransferFrom, which checks that from approved 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.
  • ARexERC3643Lot, one per lot (IERC3643, ICompliance, IAgentRole):

    ERC-3643 / ERC-20Answer
    balanceOf(w), totalSupply()balanceOf(w, id), totalSupply(id) of the token
    decimals(), name(), symbol(), version()0, <prefix> <id>, <symbol>-<id>, arex-erc3643/1.0.0
    identityRegistry()the adapter
    compliance()the lot view itself; canTransfer(from, to, amount) = the token's ERC-7943 canTransfer(from, to, id, amount)
    isFrozen(w)!canSend(w) on the token
    getFrozenTokens(w)getFrozenTokens(w, id) on the token
    paused()the token's paused() when it has one, else false
    onchainID()the issuer's ONCHAINID set on the adapter, or address(0)
    transfer, transferFrom, approve, allowanceERC-20; movements through the adapter's move
    mint, burn, forcedTransfer, recoveryAddress, setAddressFrozen, freezePartialTokens, unfreezePartialTokens, pause, unpause, setName, setSymbol, setOnchainID, setIdentityRegistry, setCompliance, every batch*, addAgent, removeAgent, bindToken, unbindToken, transferred, created, destroyedrevert ARexERC3643UseARexRoles(): those powers are the A-REX token's roles (ERC-7943 forcedTransfer, 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 Transfer logs; explorers that rebuild balances from logs need autoCreate.
  • 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

WhatWhere
Contractsarex-contracts contracts/reference/interop/ARexERC3643Adapter.sol, ARexERC3643Lot.sol, interfaces/IERC3643Surface.sol
Testsarex-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 conformanceinterop/ERC-3643.md
First consumerA-REX Platform add-on "ERC-3643 compatibility" (docs/INTEROP.md there)
  • ADR-004: every rule is a hook; flags cached at registration
  • ADR-013: no position on legal classification
  • ADR-019: capabilities in the standard, policy in profiles
  • ADR-021: ONCHAINID claim issuer
  • ADR-022: EAS mirror