Skip to main contentA-REX Core

Livre blanc · 16

Annexes

Sources faisant foi : contracts/standard/ .sol (CC0) et standard/AREX CORE.md. Identifiants d'interface reproduits par npm run interface ids.

Annexe A : référence des interfaces

Sources faisant foi : contracts/standard/*.sol (CC0) et standard/AREX-CORE.md. Identifiants d'interface reproduits par npm run interface-ids.

A.1 Récapitulatif de conformité

InterfaceIdentifiant ERC-165JetonHook
IERC11550xd9b67a26DOIT—
IERC7943MultiToken0x41c4fbadDOIT—
IARexBatch0xe22639e0DOIT—
IARexHookManager0x964f4861DOIT (getHooks)—
IARexAttest0xad603a6cDEVRAIT (jeton ou compagnon)—
IARexHook0x332afcbb—DOIT

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, repris tel quel)

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 et 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 Constantes (ARexCodes)

GroupeValeurs
OpérationsOP_MINT = 1, OP_TRANSFER = 2, OP_BURN = 3, OP_FORCED_TRANSFER = 4, OP_TRANSFORM = 5
Drapeaux de hookHOOK_CHECK = 1, HOOK_EXECUTED = 2, HOOK_ELIGIBILITY = 4
StatutSTATUS_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
Fonctions utilitairescommodity(scheme, code), unit(code), topic(name), code(namespace, name)

A.7 Rôles de l'implémentation de référence

ISSUER_ROLE, TRANSFORMER_ROLE, STATUS_ROLE, ENFORCER_ROLE, HOOK_ADMIN_ROLE, PAUSER_ROLE, UPGRADER_ROLE, DEFAULT_ADMIN_ROLE sur ARexToken (chacun étant keccak256("AREX_<NAME>")) ; ATTEST_ADMIN_ROLE sur ARexAttestations. Vues supplémentaires : isExpired(id), transferCheck(from, to, id, amount) ; fonction supplémentaire : burn(from, id, amount) ; emplacement ERC-7201 0x8ed599b6be05dec05297c009a1279a71df771ad996fe924d0b5a47326ff60900.

A.8 Hooks et extensions de référence

ContratTypeFonctions clés
PerishabilityHookhooksetCommodityDecay, setBatchDecay, valueBps, secondsRemaining, isExpired
SeasonalHookhookaddWindow, clearWindows, windowsOf, isOpen
DeliveryHookhookschedule, pickUp, markInTransit, recordReading, confirmDelivered, cancel, dispute, resolve, getDelivery, lockedUnits
TraceabilityHookhookrecordEvent, eventCount, getEvents ; drapeau de constructeur persist
CommodityPriceOracleextensionsubmit, finalizeRound, latestAnswer, getRound, currentRound, isStale, setParameters
CarbonImmobilizationWrapperextensionrecordImmobilization, linkToBatch, retire, release, attestBacking, backingOf, linksOf
ParametricInsuranceextensionfund, issue, claim, expire, getPolicy, freeCapacity

A.9 Schéma de métadonnées

standard/schema/batch-metadata.schema.json (JSON Schema 2020-12). Obligatoires : schemaVersion, commodity{scheme, code}, unit, quantity. Groupes facultatifs notables : 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[]. Exemple dans standard/examples/batch-metadata.example.json.

Annexe B : glossaire

TermeSignification
LotUn identifiant de jeton ERC-1155 doté d'un enregistrement Batch : un lot d'une denrée dans une unité, avec une origine et une date de production communes.
Réorganisation de lotsUn transform dont les sorties ont la même denrée et la même unité que les entrées et dont les quantités sont conservées (fractionnement, fusion). Ouvert aux détenteurs dans l'implémentation de référence.
TraitementUn transform qui modifie la denrée, l'unité ou la quantité. Exige TRANSFORMER_ROLE dans l'implémentation de référence.
FiliationLe graphe formé par les événements BatchTransformed et par parentsOf.
HookUn contrat implémentant IARexHook, enregistré sur un jeton, évalué dans l'ordre à chaque opération.
Code de rejetUn bytes32 renvoyé par le check d'un hook ; 0 signifie autorisé ; convention keccak256("NAMESPACE:NAME").
ÉligibilitéAutorisation, au niveau du compte, d'envoyer ou de recevoir, à laquelle répondent les hooks marqués HOOK_ELIGIBILITY ; exposée sous forme de canSend/canReceive d'ERC-7943.
Solde geléUnités qu'un compte détient mais ne peut pas déplacer (setFrozenTokens) ; peut dépasser le solde.
Transfert forcéDéplacement d'unités par ENFORCER_ROLE sans le consentement du détenteur (ERC-7943).
Attestation(batch, topic) → (issuer, reference, validity) enregistré par un émetteur de confiance pour ce thème.
ThèmeUn bytes32 identifiant l'objet d'une attestation ; ouvert ; correspond aux thèmes d'attestation d'ERC-735 et aux identifiants de schéma d'EAS.
Référence d'origineoriginRef : un hash ou une référence vers des preuves d'origine ; jamais des coordonnées.
Engagement sur les métadonnéesmetadataHash, keccak256 du document canonique off-chain situé à uri.
StatutValeur uint8 de cycle de vie ; 0 actif, 255 retiré (terminal) ; 1..254 défini par l'émetteur.
CTE / KDEÉvénement de suivi critique / élément de données clé (FSMA 204).
DDSDéclaration de diligence raisonnée (EUDR).
EPCISGS1 Electronic Product Code Information Services, le vocabulaire d'événements pour la traçabilité (version 2.0).
CPR / CPR-eCédula de Produto Rural, créance sur récolte brésilienne ; forme électronique enregistrée auprès d'entités autorisées.
EWRRécépissé d'entrepôt électronique au titre du U.S. Warehouse Act.
MLETRLoi type de la CNUDCI sur les documents transférables électroniques.
ERC-7943 (uRWA)Interface universelle d'actifs du monde réel : gel, transfert forcé, éligibilité ; Final en mai 2026.
ERC-3643 (T-REX)Standard de jetons à accès restreint pour les valeurs mobilières sur ERC-20 ; Final en décembre 2023.
ERC-7201Disposition de stockage à espace de noms pour les contrats pouvant être mis à niveau.

Annexe C : bibliographie

Standards et spécifications

  • 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 décembre 2023. https://eips.ethereum.org/EIPS/eip-3643
  • « ERC-7943: uRWA — Universal Real World Asset Interface. » Final, 27 mai 2026. https://eips.ethereum.org/EIPS/eip-7943
  • « ERC-7201: Namespaced Storage Layout. » 2023.
  • « ERC-735: Claim Holder. » 2017 (brouillon).
  • Documentation d'Ethereum Attestation Service.
  • 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.
  • Documentation d'OpenZeppelin Contracts 5.x ; annonce du partenariat entre OpenZeppelin et T-REX Network, juillet 2026.

Réglementation et droit

  • FDA. « Requirements for Additional Traceability Records for Certain Foods. » Règle finale, Federal Register 87(219), 2022 ; « Compliance Date Extension », Federal Register, 7 août 2025.
  • Règlement (UE) 2023/1115 (déforestation) ; règlement (UE) 2025/2650 (modification) ; communiqué de presse du Conseil de l'UE, 18 décembre 2025.
  • Règlement (UE) 2023/1114 (MiCA) ; orientations de l'ESMA sur la qualification des crypto-actifs en instruments financiers, décembre 2024.
  • Comité européen de la protection des données. « Guidelines 02/2025 on processing of personal data through blockchain technologies », version 2.0, 7 juillet 2026.
  • SEC. Release No. 33-11412, 17 mars 2026. SEC v. W.J. Howey Co., 328 U.S. 293 (1946).
  • GENIUS Act, Public Law 119-27 (2025) ; règlements d'application, Federal Register, 18 août 2026.
  • Uniform Commercial Code, modifications de 2022, Article 12 (Controllable Electronic Records).
  • U.S. Warehouse Act ; 7 CFR Part 869 (Electronic Warehouse Receipts).
  • CNUDCI. « Model Law on Electronic Transferable Records. » 2017. Royaume-Uni, Electronic Trade Documents Act 2023.
  • Comisión Nacional de Valores (Argentine). Resolución General 1150/2026. Ley 9.643 (warrants).
  • Brésil. Lei 8.929/1994, Lei 13.986/2020 (CPR) ; Lei 11.076/2004 (CDA/WA) ; CVM Resolução 88 et Consulta Pública SDM 05/2025.
  • Verra. « Verra Addresses Crypto Instruments and Tokens. » 2022 ; VCS Program Guide.
  • Directive (UE) 2024/825 (autonomisation des consommateurs en faveur de la transition écologique).

Recherche et industrie

  • 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.
  • Banque mondiale. « Future of Food: Harnessing Digital Technologies to Improve Food System Outcomes. » 2022.
  • ERC3643 Association. « History of ERC-3643 » ; annonce de l'initiative de standardisation ISO TC 307.
  • Chainlink. « Automated Compliance Engine (ACE): Technical Overview. » 2025–2026.

Annexe D : modèles

D.1 Hook minimal

Source : contracts/examples/MyHook.sol (importe ../reference/hooks/ARexHookBase.sol et ../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 Déploiement (plugin de mises à niveau)

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 Squelette de métadonnées

{ "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": "…" } }

Annexe E : FAQ

A-REX est-il un ERC ? Pas encore. La spécification est rédigée au format ERC et sera soumise après un déploiement en production, des implémentations indépendantes et un audit. Aucun numéro n'a été attribué ; les noms dans le code n'utilisent pas le préfixe ERC.

Dois-je utiliser ARexToken ? Non. Implémentez les interfaces comme vous le souhaitez ; la référence n'est qu'une manière de faire.

Dois-je utiliser les hooks de référence ? Non. Ce sont des démonstrations. Copiez-les, remplacez-les ou écrivez les vôtres.

Un hook peut-il bloquer un transfert forcé ? Il peut renvoyer un code pour OP_FORCED_TRANSFER, et le jeton annulera alors la transaction. Les hooks de référence ne le font pas ; un hook qui régit la mise en application (par exemple en exigeant une référence d'ordonnance) le peut.

Où vont les coordonnées ? Dans un stockage off-chain restreint référencé depuis les métadonnées, jamais on-chain.

Comment représenter une récolte future ? producedAt = 0 ; conditionnez les transferts avec ExpiryHook(allowPreHarvestTransfers).

La quantité est-elle conservée dans transform ? Pas par le standard ; la référence autorise n'importe quel détenteur à réorganiser des lots lorsqu'elle est conservée et exige TRANSFORMER_ROLE dans le cas contraire.

Le jeton est-il une valeur mobilière ? Le standard ne tranche pas. C'est l'offre qui le fait. Consultez un conseil juridique ; la surface de mise en application est là quelle que soit la réponse.