Skip to main contentA-REX Core

Whitepaper · 16

Appendices

Authoritative sources: contracts/standard/ .sol (CC0) and standard/AREX CORE.md. Interface ids reproduced by npm run interface ids.

uint8 lifecycle value; 0 active, 255 retired (terminal); 1..254 issuer-defined.

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

InterfaceERC-165 idTokenHook
IERC11550xd9b67a26MUST—
IERC7943MultiToken0x41c4fbadMUST—
IARexBatch0xe22639e0MUST—
IARexHookManager0x964f4861MUST (getHooks)—
IARexAttest0xad603a6cSHOULD (token or companion)—
IARexHook0x332afcbb—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)

GroupValues
OperationsOP_MINT = 1, OP_TRANSFER = 2, OP_BURN = 3, OP_FORCED_TRANSFER = 4, OP_TRANSFORM = 5
Hook flagsHOOK_CHECK = 1, HOOK_EXECUTED = 2, HOOK_ELIGIBILITY = 4
StatusSTATUS_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
Helperscommodity(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

ContractKindKey functions
PerishabilityHookhooksetCommodityDecay, setBatchDecay, valueBps, secondsRemaining, isExpired
SeasonalHookhookaddWindow, clearWindows, windowsOf, isOpen
DeliveryHookhookschedule, pickUp, markInTransit, recordReading, confirmDelivered, cancel, dispute, resolve, getDelivery, lockedUnits
TraceabilityHookhookrecordEvent, eventCount, getEvents; constructor flag persist
CommodityPriceOracleextensionsubmit, finalizeRound, latestAnswer, getRound, currentRound, isStale, setParameters
CarbonImmobilizationWrapperextensionrecordImmobilization, linkToBatch, retire, release, attestBacking, backingOf, linksOf
ParametricInsuranceextensionfund, 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

TermMeaning
BatchAn ERC-1155 token id with a Batch record: a lot of one commodity in one unit with shared origin and production time.
Re-batchA 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.
ProcessingA transform that changes commodity, unit or quantity. Requires TRANSFORMER_ROLE in the reference implementation.
LineageThe graph formed by BatchTransformed events and parentsOf.
HookA contract implementing IARexHook, registered on a token, evaluated in order on every operation.
Rejection codeA bytes32 returned by a hook's check; 0 means allowed; convention keccak256("NAMESPACE:NAME").
EligibilityAccount-level permission to send or receive, answered by hooks flagged HOOK_ELIGIBILITY; exposed as ERC-7943 canSend/canReceive.
Frozen balanceUnits an account holds but cannot move (setFrozenTokens); may exceed the balance.
Forced transferMovement 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.
TopicA bytes32 identifying the subject of an attestation; open; maps to ERC-735 claim topics and EAS schema ids.
Origin referenceoriginRef: a hash or reference to origin evidence; never coordinates.
Metadata commitmentmetadataHash, keccak256 of the canonical off-chain document at uri.
Statusuint8 lifecycle value; 0 active, 255 retired (terminal); 1..254 issuer-defined.
CTE / KDECritical tracking event / key data element (FSMA 204).
DDSDue-diligence statement (EUDR).
EPCISGS1 Electronic Product Code Information Services, the event vocabulary for traceability (version 2.0).
CPR / CPR-eCédula de Produto Rural, Brazil's crop receivable; electronic form registered with authorized entities.
EWRElectronic warehouse receipt under the U.S. Warehouse Act.
MLETRUNCITRAL 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-7201Namespaced 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.