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é
| Interface | Identifiant ERC-165 | Jeton | Hook |
|---|---|---|---|
IERC1155 | 0xd9b67a26 | DOIT | — |
IERC7943MultiToken | 0x41c4fbad | DOIT | — |
IARexBatch | 0xe22639e0 | DOIT | — |
IARexHookManager | 0x964f4861 | DOIT (getHooks) | — |
IARexAttest | 0xad603a6c | DEVRAIT (jeton ou compagnon) | — |
IARexHook | 0x332afcbb | — | 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)
| Groupe | Valeurs |
|---|---|
| Opérations | OP_MINT = 1, OP_TRANSFER = 2, OP_BURN = 3, OP_FORCED_TRANSFER = 4, OP_TRANSFORM = 5 |
| Drapeaux de hook | HOOK_CHECK = 1, HOOK_EXECUTED = 2, HOOK_ELIGIBILITY = 4 |
| Statut | 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 |
| Fonctions utilitaires | commodity(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
| Contrat | Type | Fonctions clés |
|---|---|---|
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 ; drapeau de constructeur 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 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
| Terme | Signification |
|---|---|
| Lot | Un 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 lots | Un 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. |
| Traitement | Un transform qui modifie la denrée, l'unité ou la quantité. Exige TRANSFORMER_ROLE dans l'implémentation de référence. |
| Filiation | Le graphe formé par les événements BatchTransformed et par parentsOf. |
| Hook | Un contrat implémentant IARexHook, enregistré sur un jeton, évalué dans l'ordre à chaque opération. |
| Code de rejet | Un 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ème | Un 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'origine | originRef : un hash ou une référence vers des preuves d'origine ; jamais des coordonnées. |
| Engagement sur les métadonnées | metadataHash, keccak256 du document canonique off-chain situé à uri. |
| Statut | Valeur 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). |
| DDS | Déclaration de diligence raisonnée (EUDR). |
| EPCIS | GS1 Electronic Product Code Information Services, le vocabulaire d'événements pour la traçabilité (version 2.0). |
| CPR / CPR-e | Cédula de Produto Rural, créance sur récolte brésilienne ; forme électronique enregistrée auprès d'entités autorisées. |
| EWR | Récépissé d'entrepôt électronique au titre du U.S. Warehouse Act. |
| MLETR | Loi 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-7201 | Disposition 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.