Whitepaper · 16
Appendices
Authoritative sources: contracts/standard/ .sol (CC0) and standard/AREX CORE.md. Interface ids reproduced by npm run interface ids.
Appendix A: Interface Reference
Authoritative sources: contracts/standard/*.sol (CC0) and standard/AREX-CORE.md. Interface ids reproduced by npm run interface-ids.
A.1 Conformance summary
| Interface | ERC-165 id | Token | Hook |
|---|---|---|---|
IERC1155 | 0xd9b67a26 | MUST | — |
IERC7943MultiToken | 0x41c4fbad | MUST | — |
IARexBatch | 0xe22639e0 | MUST | — |
IARexHookManager | 0x964f4861 | MUST (getHooks) | — |
IARexAttest | 0xad603a6c | SHOULD (token or companion) | — |
IARexHook | 0x332afcbb | — | MUST |
A.2 IARexBatch
struct BatchInit { bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }
struct Batch { address issuer; uint64 createdAt; uint8 status; bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }
event BatchCreated(uint256 indexed id, address indexed issuer, bytes32 indexed commodity, bytes32 unit, uint256 quantity, address to);
event BatchStatusChanged(uint256 indexed id, uint8 previousStatus, uint8 newStatus, bytes32 reason);
event BatchMetadataUpdated(uint256 indexed id, bytes32 metadataHash, string uri);
event BatchTransformed(address indexed operator, uint256[] inputIds, uint256[] inputAmounts, uint256[] outputIds, uint256[] outputAmounts, bytes32 processRef);
error ARexBatchNotFound(uint256 id);
error ARexBatchRetired(uint256 id);
error ARexInvalidBatch(bytes32 reason);
error ARexInvalidStatusTransition(uint256 id, uint8 from, uint8 to);
error ARexLengthMismatch();
function createBatch(BatchInit calldata init, uint256 quantity, address to, bytes calldata data) external returns (uint256 id);
function batchOf(uint256 id) external view returns (Batch memory);
function batchExists(uint256 id) external view returns (bool);
function totalSupply(uint256 id) external view returns (uint256);
function setBatchStatus(uint256 id, uint8 status, bytes32 reason) external;
function setBatchMetadata(uint256 id, bytes32 metadataHash, string calldata uri) external;
function transform(address from, address to, uint256[] calldata inputIds, uint256[] calldata inputAmounts, BatchInit[] calldata outputs, uint256[] calldata outputAmounts, bytes32 processRef) external returns (uint256[] memory outputIds);
function parentsOf(uint256 id) external view returns (uint256[] memory);
A.3 IERC7943MultiToken (ERC-7943, verbatim)
event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
event Frozen(address indexed account, uint256 indexed tokenId, uint256 amount);
error ERC7943CannotSend(address account);
error ERC7943CannotReceive(address account);
error ERC7943CannotTransfer(address from, address to, uint256 tokenId, uint256 amount);
error ERC7943InsufficientUnfrozenBalance(address account, uint256 tokenId, uint256 amount, uint256 unfrozen);
function forcedTransfer(address from, address to, uint256 tokenId, uint256 amount) external returns (bool result);
function setFrozenTokens(address account, uint256 tokenId, uint256 amount) external returns (bool result);
function canSend(address account) external view returns (bool allowed);
function canReceive(address account) external view returns (bool allowed);
function getFrozenTokens(address account, uint256 tokenId) external view returns (uint256 amount);
function canTransfer(address from, address to, uint256 tokenId, uint256 amount) external view returns (bool allowed);
A.4 IARexHook and IARexHookManager
interface IARexHook is IERC165 {
error ARexHookRejected(address hook, bytes32 code);
function hookFlags() external view returns (uint8);
function check(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external view returns (bytes32 code);
function onExecuted(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function canSend(address account) external view returns (bool);
function canReceive(address account) external view returns (bool);
}
interface IARexHookManager {
event HookRegistered(address indexed hook, uint8 flags, uint256 position);
event HookRemoved(address indexed hook);
error ARexHookAlreadyRegistered(address hook);
error ARexHookNotRegistered(address hook);
error ARexInvalidHook(address hook);
function getHooks() external view returns (address[] memory);
function hookFlagsOf(address hook) external view returns (uint8);
function registerHook(address hook) external;
function removeHook(address hook) external;
}
A.5 IARexAttest
struct Attestation { address issuer; bytes32 ref; uint64 issuedAt; uint64 expiresAt; bool revoked; }
event Attested(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 ref, uint64 expiresAt);
event AttestationRevoked(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 reason);
event TrustedIssuerUpdated(bytes32 indexed topic, address indexed issuer, bool trusted);
error ARexUntrustedIssuer(bytes32 topic, address issuer);
error ARexAttestationNotFound(uint256 id, bytes32 topic);
function attest(uint256 id, bytes32 topic, bytes32 ref, uint64 expiresAt) external;
function revokeAttestation(uint256 id, bytes32 topic, bytes32 reason) external;
function getAttestation(uint256 id, bytes32 topic) external view returns (Attestation memory);
function isAttested(uint256 id, bytes32 topic) external view returns (bool);
function isTrustedIssuer(bytes32 topic, address issuer) external view returns (bool);
A.6 Constants (ARexCodes)
| Group | Values |
|---|---|
| Operations | OP_MINT = 1, OP_TRANSFER = 2, OP_BURN = 3, OP_FORCED_TRANSFER = 4, OP_TRANSFORM = 5 |
| Hook flags | HOOK_CHECK = 1, HOOK_EXECUTED = 2, HOOK_ELIGIBILITY = 4 |
| Status | STATUS_ACTIVE = 0, STATUS_RETIRED = 255 |
Codes (keccak256("AREX:…")) | PAUSED, FROZEN, SENDER_INELIGIBLE, RECEIVER_INELIGIBLE, SANCTIONED, BATCH_NOT_FOUND, BATCH_RETIRED, BATCH_INACTIVE, BATCH_EXPIRED, BATCH_NOT_PRODUCED, LIMIT_EXCEEDED, DOCUMENT_MISSING, SEASON_CLOSED, IN_TRANSIT, ATTESTATION_MISSING |
| Helpers | commodity(scheme, code), unit(code), topic(name), code(namespace, name) |
A.7 Reference implementation roles
ISSUER_ROLE, TRANSFORMER_ROLE, STATUS_ROLE, ENFORCER_ROLE, HOOK_ADMIN_ROLE, PAUSER_ROLE, UPGRADER_ROLE, DEFAULT_ADMIN_ROLE on ARexToken (each keccak256("AREX_<NAME>")); ATTEST_ADMIN_ROLE on ARexAttestations. Extra views: isExpired(id), transferCheck(from, to, id, amount); extra function: burn(from, id, amount); ERC-7201 slot 0x8ed599b6be05dec05297c009a1279a71df771ad996fe924d0b5a47326ff60900.
A.8 Reference hooks and extensions
| Contract | Kind | Key functions |
|---|---|---|
PerishabilityHook | hook | setCommodityDecay, setBatchDecay, valueBps, secondsRemaining, isExpired |
SeasonalHook | hook | addWindow, clearWindows, windowsOf, isOpen |
DeliveryHook | hook | schedule, pickUp, markInTransit, recordReading, confirmDelivered, cancel, dispute, resolve, getDelivery, lockedUnits |
TraceabilityHook | hook | recordEvent, eventCount, getEvents; constructor flag persist |
CommodityPriceOracle | extension | submit, finalizeRound, latestAnswer, getRound, currentRound, isStale, setParameters |
CarbonImmobilizationWrapper | extension | recordImmobilization, linkToBatch, retire, release, attestBacking, backingOf, linksOf |
ParametricInsurance | extension | fund, issue, claim, expire, getPolicy, freeCapacity |
A.9 Metadata schema
standard/schema/batch-metadata.schema.json (JSON Schema 2020-12). Required: schemaVersion, commodity{scheme, code}, unit, quantity. Notable optional groups: traceabilityLotCode, gs1{gtin, lgtin, sscc, glnProducer, digitalLink}, production, origin{country, originRef, eudr{ddsReference}, geohashPrecision, geohash}, quality{gradeScheme, grade, measurements[]}, status.table, attestations[], documents[]{type, hash, uri, registry, registryId}, epcis{bizStep, disposition, readPoint, bizLocation}, restricted{uri, hash, accessPolicy}, attributes[]. Example in standard/examples/batch-metadata.example.json.
Appendix B: Glossary
| Term | Meaning |
|---|---|
| Batch | An ERC-1155 token id with a Batch record: a lot of one commodity in one unit with shared origin and production time. |
| Re-batch | A transform whose outputs have the same commodity and unit as the inputs and whose quantities are conserved (split, merge). Open to holders in the reference implementation. |
| Processing | A transform that changes commodity, unit or quantity. Requires TRANSFORMER_ROLE in the reference implementation. |
| Lineage | The graph formed by BatchTransformed events and parentsOf. |
| Hook | A contract implementing IARexHook, registered on a token, evaluated in order on every operation. |
| Rejection code | A bytes32 returned by a hook's check; 0 means allowed; convention keccak256("NAMESPACE:NAME"). |
| Eligibility | Account-level permission to send or receive, answered by hooks flagged HOOK_ELIGIBILITY; exposed as ERC-7943 canSend/canReceive. |
| Frozen balance | Units an account holds but cannot move (setFrozenTokens); may exceed the balance. |
| Forced transfer | Movement of units by ENFORCER_ROLE without the holder's consent (ERC-7943). |
| Attestation | (batch, topic) → (issuer, reference, validity) recorded by a trusted issuer for that topic. |
| Topic | A bytes32 identifying the subject of an attestation; open; maps to ERC-735 claim topics and EAS schema ids. |
| Origin reference | originRef: a hash or reference to origin evidence; never coordinates. |
| Metadata commitment | metadataHash, keccak256 of the canonical off-chain document at uri. |
| Status | uint8 lifecycle value; 0 active, 255 retired (terminal); 1..254 issuer-defined. |
| CTE / KDE | Critical tracking event / key data element (FSMA 204). |
| DDS | Due-diligence statement (EUDR). |
| EPCIS | GS1 Electronic Product Code Information Services, the event vocabulary for traceability (version 2.0). |
| CPR / CPR-e | Cédula de Produto Rural, Brazil's crop receivable; electronic form registered with authorized entities. |
| EWR | Electronic warehouse receipt under the U.S. Warehouse Act. |
| MLETR | UNCITRAL Model Law on Electronic Transferable Records. |
| ERC-7943 (uRWA) | Universal Real World Asset interface: freeze, forced transfer, eligibility; Final May 2026. |
| ERC-3643 (T-REX) | Permissioned token standard for securities on ERC-20; Final December 2023. |
| ERC-7201 | Namespaced storage layout for upgradeable contracts. |
Appendix C: Bibliography
Standards and specifications
- Radomski, W. et al. "EIP-1155: Multi Token Standard." Ethereum Improvement Proposals, 2018.
- Vogelsteller, F., Buterin, V. "EIP-20: Token Standard." 2015.
- "ERC-165: Standard Interface Detection." 2018.
- "ERC-3643: T-REX — Token for Regulated EXchanges." Final, 15 December 2023. https://eips.ethereum.org/EIPS/eip-3643
- "ERC-7943: uRWA — Universal Real World Asset Interface." Final, 27 May 2026. https://eips.ethereum.org/EIPS/eip-7943
- "ERC-7201: Namespaced Storage Layout." 2023.
- "ERC-735: Claim Holder." 2017 (draft).
- Ethereum Attestation Service documentation.
- GS1. "EPCIS and CBV Standard 2.0." 2022. GS1 US. "EPCIS Recommendations for FSMA 204 Critical Tracking Events." 2024.
- UN/CEFACT. "Recommendation No. 20: Codes for Units of Measure Used in International Trade."
- IETF RFC 8785. "JSON Canonicalization Scheme (JCS)." 2020.
- OpenZeppelin Contracts 5.x documentation; OpenZeppelin and T-REX Network partnership announcement, July 2026.
Regulation and law
- FDA. "Requirements for Additional Traceability Records for Certain Foods." Final rule, Federal Register 87(219), 2022; "Compliance Date Extension," Federal Register, 7 August 2025.
- Regulation (EU) 2023/1115 (Deforestation); Regulation (EU) 2025/2650 (amendment); Council of the EU press release, 18 December 2025.
- Regulation (EU) 2023/1114 (MiCA); ESMA Guidelines on the qualification of crypto-assets as financial instruments, December 2024.
- European Data Protection Board. "Guidelines 02/2025 on processing of personal data through blockchain technologies," version 2.0, 7 July 2026.
- SEC. Release No. 33-11412, 17 March 2026. SEC v. W.J. Howey Co., 328 U.S. 293 (1946).
- GENIUS Act, Public Law 119-27 (2025); implementing regulations, Federal Register, 18 August 2026.
- Uniform Commercial Code, 2022 Amendments, Article 12 (Controllable Electronic Records).
- U.S. Warehouse Act; 7 CFR Part 869 (Electronic Warehouse Receipts).
- UNCITRAL. "Model Law on Electronic Transferable Records." 2017. United Kingdom, Electronic Trade Documents Act 2023.
- Comisión Nacional de Valores (Argentina). Resolución General 1150/2026. Ley 9.643 (warrants).
- Brazil. Lei 8.929/1994, Lei 13.986/2020 (CPR); Lei 11.076/2004 (CDA/WA); CVM Resolução 88 and Consulta Pública SDM 05/2025.
- Verra. "Verra Addresses Crypto Instruments and Tokens." 2022; VCS Program Guide.
- Directive (EU) 2024/825 (empowering consumers for the green transition).
Research and industry
- Zhang, P., Schmidt, D. C. "Blockchain Applications in Food Supply Chain Management: A Systematic Review." Journal of Food Engineering, 279, 2020.
- Caro, M. P. et al. "Blockchain-based Traceability in Agri-Food Supply Chain Management." IEEE, 2018.
- FAO. "The State of Food and Agriculture." 2023.
- World Bank. "Future of Food: Harnessing Digital Technologies to Improve Food System Outcomes." 2022.
- ERC3643 Association. "History of ERC-3643"; ISO TC 307 standardization initiative announcement.
- Chainlink. "Automated Compliance Engine (ACE): Technical Overview." 2025–2026.
Appendix D: Templates
D.1 Minimal hook
Source: contracts/examples/MyHook.sol (imports ../reference/hooks/ARexHookBase.sol and ../standard/IARexBatch.sol).
contract MyHook is ARexHookBase {
function hookFlags() public pure override returns (uint8) {
return ARexCodes.HOOK_CHECK;
}
function check(uint8 op, address, address, address, uint256 id, uint256, bytes calldata)
external
view
override
returns (bytes32)
{
if (op != ARexCodes.OP_TRANSFER) return ARexCodes.OK;
IARexBatch.Batch memory b = IARexBatch(msg.sender).batchOf(id);
b; // decide from b.commodity, b.producedAt, b.expiresAt, b.status ...
return ARexCodes.OK;
}
}
D.2 Deployment (upgrades plugin)
const token = await upgrades.deployProxy(await ethers.getContractFactory("ARexToken"), [admin, baseURI], { kind: "uups" });
const attestations = await (await ethers.getContractFactory("ARexAttestations")).deploy(admin, await token.getAddress());
await token.registerHook(await (await ethers.getContractFactory("EligibilityHook")).deploy(admin));
await token.registerHook(await (await ethers.getContractFactory("ExpiryHook")).deploy(true));
D.3 Metadata skeleton
{ "schemaVersion": "1.0.0", "commodity": { "scheme": "HS", "code": "100199" }, "unit": "KGM", "quantity": 250000,
"traceabilityLotCode": "…", "production": { "producedAt": "…" }, "origin": { "country": "AR", "originRef": "…" },
"status": { "table": { "1": "IN_STORAGE" } }, "documents": [ { "type": "warehouse_receipt", "hash": "…", "registryId": "…" } ],
"restricted": { "uri": "…", "hash": "…", "accessPolicy": "…" } }
Appendix E: FAQ
Is A-REX an ERC? Not yet. The specification is written in ERC format and will be submitted after a production deployment, independent implementations and an audit. No number has been assigned; names in the code do not use the ERC prefix.
Do I have to use ARexToken? No. Implement the interfaces any way you like; the reference is one way.
Do I have to use the reference hooks? No. They are demonstrations. Copy them, replace them, or write your own.
Can a hook block a forced transfer? It can return a code for OP_FORCED_TRANSFER, and the token will revert. Reference hooks do not; a hook that governs enforcement (e.g. requiring an order reference) may.
Where do coordinates go? In restricted off-chain storage referenced from metadata, never on-chain.
How do I represent a future harvest? producedAt = 0; gate transfers with ExpiryHook(allowPreHarvestTransfers).
Is quantity conserved in transform? Not by the standard; the reference allows any holder to re-batch when it is conserved and requires TRANSFORMER_ROLE otherwise.
Is the token a security? The standard does not decide. The offer does. Ask counsel; the enforcement surface is there whatever the answer.