Whitepaper · 04
Solution Overview
Architecture of A-REX Core: three tiers with one direction of dependency, the transfer pipeline, the actors, and how the pieces are deployed.
Three tiers, one direction of dependency
A-REX separates what must be standardized from what must merely work:
The four layers of the standard
flowchart TB
L3["Layer 3 · IARexAttest<br/>attest · revokeAttestation · isAttested · trusted issuers per topic"]
L2["Layer 2 · IARexHook + IARexHookManager<br/>hookFlags · check → bytes32 · onExecuted · getHooks"]
L1["Layer 1 · IARexBatch<br/>createBatch · batchOf · setBatchStatus · setBatchMetadata · transform · parentsOf"]
L0["Layer 0 · ERC-1155 + ERC-165 + IERC7943MultiToken<br/>freeze · forcedTransfer · canSend · canReceive · canTransfer"]
L3 --- L2 --- L1 --- L0
classDef l3 fill:#edf5ff,stroke:#0f62fe,color:#161616
classDef l2 fill:#d0e2ff,stroke:#0f62fe,color:#161616
classDef l1 fill:#a6c8ff,stroke:#0f62fe,color:#161616
classDef l0 fill:#78a9ff,stroke:#0043ce,color:#161616
class L3 l3
class L2 l2
class L1 l1
class L0 l0The two tiers of the repository and the direction of dependency
flowchart LR
STD["<b>The standard</b><br/>standard/ · contracts/standard/<br/>normative · CC0"]
REF["<b>Reference implementation</b><br/>ARexToken · ARexAttestations<br/>MIT"]
DEMO["<b>Demonstrations</b><br/>7 hooks · 3 extensions<br/>MIT · not normative"]
STD -->|implemented by| REF -->|demonstrated by| DEMO
DEMO -.->|depend only on the interfaces| STDThe standard never depends on the reference; the token never depends on the hooks. Remove every hook and every extension and a conformant token still exists. This is the property that lets a third party implement A-REX without adopting anything from this repository except six interface files.
What a batch is
A batch is an ERC-1155 token id with a record:
struct Batch {
address issuer; // who created it (or performed the transformation)
uint64 createdAt;
uint8 status; // 0 ACTIVE · 255 RETIRED (terminal) · 1..254 issuer-defined
bytes32 commodity; // keccak256("HS:100199"), keccak256("FAO:0111"), keccak256("GTIN:0779…")
bytes32 unit; // UN/CEFACT Rec. 20: "KGM", "TNE", "LTR", "BX"
uint64 producedAt; // 0 = not yet produced (pre-harvest)
uint64 expiresAt; // 0 = none
bytes32 originRef; // hash / reference to origin evidence — never coordinates
bytes32 metadataHash; // keccak256 of the off-chain document
string uri; // where the document is
}
Everything richer — grade, moisture, protein, packaging, GS1 identifiers, the traceability lot code, the EUDR declaration reference, lab reports, the issuer's status table — lives in the metadata document whose hash is committed on-chain. The document follows a published JSON Schema aligned with EPCIS 2.0 and the FSMA 204 key data elements.
The transfer pipeline
Every balance change — mint, transfer, burn, forced transfer, transformation — passes through one choke point in the reference token. The order is fixed and auditable:
flowchart TD
A[safeTransferFrom / createBatch / burn / forcedTransfer / transform] --> B[reentrancy lock]
B --> C{paused?}
C -- yes, not forced --> X1[EnforcedPause]
C -- no --> D{canSend from / canReceive to<br/>conjunction of ELIGIBILITY hooks}
D -- false --> X2[ERC7943CannotSend / CannotReceive]
D -- true --> E{per id: exists? not retired?<br/>amount ≤ balance − frozen?}
E -- fail --> X3[ARexBatchNotFound / ARexBatchRetired /<br/>ERC7943InsufficientUnfrozenBalance]
E -- ok --> F{per id, per CHECK hook in order:<br/>check → code}
F -- code ≠ 0 --> X4["ARexHookRejected(hook, code)"]
F -- all 0 --> G[balances updated · supply tracked]
G --> H[per id, per EXECUTED hook: onExecuted]
H --> I[unlock]Two views replay the same logic without changing state: canTransfer (boolean, as ERC-7943 requires) and transferCheck (the first rejection code, so an interface can tell the user why).
Forced transfers skip the pause and the eligibility checks — enforcement must work when everything else is frozen — but still run the hooks with OP_FORCED_TRANSFER, so a hook can insist, for example, on a court-order reference in the transfer data.
Lineage
transform is the single operation for splitting, merging and processing:
graph LR
W1["wheat #1<br/>250 t · farmer"] -- "transform (re-batch)" --> W2["wheat #2<br/>100 t · buyer A"]
W1 -- "transform (re-batch)" --> W3["wheat #3<br/>150 t · buyer B"]
W2 -- "transform (processing, TRANSFORMER_ROLE)" --> F4["flour #4<br/>75 t · mill"]- Re-batching (same commodity, same unit, conserved quantity) is open to any holder or approved operator: a cooperative splitting a silo lot among members, an exporter merging deliveries.
- Processing (anything else) additionally requires
TRANSFORMER_ROLE. parentsOf(4) == [2],parentsOf(2) == [1]; oneBatchTransformedevent per operation, which is an EPCISTransformationEventby construction.
Enforcement
ENFORCER_ROLE can freeze any amount for any account (setFrozenTokens, may exceed the balance, as ERC-7943 specifies) and move tokens without the holder's consent (forcedTransfer). This is what makes a batch token usable outside a demo: a lender executing a warrant, a court ordering the seizure of stored grain, a warehouse recovering a lot after a customer loses keys. Every enforcement action is an event.
Hooks
A hook is a contract with five functions and a constant flags bitmap. The token caches the flags at registration, so a transfer costs one external call per interested hook, not one interface probe per capability per module. A hook learns which token is calling from msg.sender; one deployment can serve many tokens.
Reference hooks demonstrate the three capabilities:
| Hook | Capability | What it proves |
|---|---|---|
EligibilityHook | CHECK + ELIGIBILITY | allow/block lists and sanctions feed canSend / canReceive and produce precise codes |
ExpiryHook | CHECK | perishability and pre-harvest gating derived purely from the batch record |
AttestationHook | CHECK | "coffee needs an EUDR declaration attested before it can be sold" |
PerishabilityHook | CHECK | decay models and value views; expired or valueless lots do not move |
SeasonalHook | CHECK | harvest and trading windows per commodity |
DeliveryHook | CHECK + EXECUTED | custody lock during delivery; settlement is the transfer itself, identified by data |
TraceabilityHook | EXECUTED | EPCIS-shaped event log of every operation plus manual critical tracking events |
Companion extensions (not hooks): CommodityPriceOracle, CarbonImmobilizationWrapper, ParametricInsurance.
Attestations
A companion contract records (batch, topic) → (issuer, reference, validity). Only issuers trusted for a topic can attest; revocation, expiry and loss of trust all make isAttested false. Topics are bytes32, so ERC-735 claim topics, Ethereum Attestation Service schema ids and hashes of certification names all work without a table in the standard.
Actors and roles
| Actor | Typical role in the reference token | Typical action |
|---|---|---|
| Originator platform, cooperative, elevator | ISSUER_ROLE | createBatch |
| Farmer / holder | none | transfer, re-batch, burn |
| Mill, packer, processor | TRANSFORMER_ROLE | processing transform |
| Warehouse, inspector, platform | STATUS_ROLE | setBatchStatus, setBatchMetadata |
| Certifier, laboratory, authority | trusted issuer for a topic | attest |
| Lender, court-appointed custodian, compliance | ENFORCER_ROLE | setFrozenTokens, forcedTransfer |
| Governance (multisig, timelock) | DEFAULT_ADMIN_ROLE, HOOK_ADMIN_ROLE, UPGRADER_ROLE, PAUSER_ROLE | roles, hooks, upgrades, pause |
Nothing in the standard fixes these roles; they are how the reference implementation exercises the MUSTs ("restricted to an authorized role").
Deployment shapes
- Public L2 (Polygon, Arbitrum, Base, Optimism): cheapest, most composable; suited to commodity trading and financing where counterparties are businesses.
- Permissioned EVM chain: where data-protection authorities or the anchor institution require it; the EDPB expressly encourages permissioned designs. The standard is chain-agnostic.
- Hybrid: batches on a public chain, restricted data (plot polygons, producer identity) behind access-controlled storage referenced from metadata.
The reference stack deploys with one Ignition module or one script: token proxy, attestation registry, eligibility and expiry hooks.
Design decisions and the alternatives they replace
| Alternative considered | A-REX Core | Reason |
|---|---|---|
| a wide core interface with enums for commodity, grade, state | 8-function IARexBatch with open codes | nothing to redeploy for a new crop, scheme or lifecycle |
| capability interfaces probed on every transfer | one hook interface, flags cached | gas linear in hooks, not in ids × modules × probes |
| string reasons | bytes32 codes and typed errors | machine-readable, indexable |
| lifecycle state changeable by any holder | role only; RETIRED terminal | security |
| harvest date required in the past | producedAt == 0 allowed | pre-harvest financing |
| no split / merge / processing | transform + parentsOf | traceability, recalls, EPCIS |
| no freeze or forced transfer | ERC-7943 | enforceability |
| coordinates stored on-chain | origin reference only | GDPR / EDPB 02/2025 |
| registry and identity contracts required | nothing required | no imposed identity stack |