Livre blanc · 04
Vue d'ensemble de la solution
Architecture d'A-REX Core : trois niveaux avec un seul sens de dépendance, le pipeline de transfert, les acteurs et la manière dont les éléments sont déployés.
Trois niveaux, un seul sens de dépendance
A-REX sépare ce qui doit être standardisé de ce qui doit simplement fonctionner :
Les quatre couches du standard
flowchart TB
L3["Couche 3 · IARexAttest<br/>attest · revokeAttestation · isAttested · émetteurs de confiance par thème"]
L2["Couche 2 · IARexHook + IARexHookManager<br/>hookFlags · check → bytes32 · onExecuted · getHooks"]
L1["Couche 1 · IARexBatch<br/>createBatch · batchOf · setBatchStatus · setBatchMetadata · transform · parentsOf"]
L0["Couche 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 l0Les deux niveaux du dépôt et le sens de la dépendance
flowchart LR
STD["<b>Le standard</b><br/>standard/ · contracts/standard/<br/>normatif · CC0"]
REF["<b>Implémentation de référence</b><br/>ARexToken · ARexAttestations<br/>MIT"]
DEMO["<b>Démonstrations</b><br/>7 hooks · 3 extensions<br/>MIT · non normatif"]
STD -->|implémenté par| REF -->|démontré par| DEMO
DEMO -.->|dépendent uniquement des interfaces| STDLe standard ne dépend jamais de la référence ; le jeton ne dépend jamais des hooks. Retirez tous les hooks et toutes les extensions, et un jeton conforme existe toujours. C'est la propriété qui permet à un tiers d'implémenter A-REX sans adopter quoi que ce soit de ce dépôt hormis six fichiers d'interface.
Ce qu'est un lot
Un lot est un identifiant de jeton ERC-1155 assorti d'un enregistrement :
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
}
Tout ce qui est plus riche — classe de qualité, humidité, protéines, conditionnement, identifiants GS1, code de lot de traçabilité, référence de déclaration EUDR, rapports de laboratoire, table des statuts de l'émetteur — vit dans le document de métadonnées dont le hash est engagé on-chain. Le document suit un JSON Schema publié, aligné sur EPCIS 2.0 et sur les éléments de données clés de FSMA 204.
Le pipeline de transfert
Toute modification de solde — émission, transfert, destruction, transfert forcé, transformation — passe par un point de passage obligé unique dans le jeton de référence. L'ordre est fixe et auditable :
flowchart TD
A[safeTransferFrom / createBatch / burn / forcedTransfer / transform] --> B["verrou de réentrance"]
B --> C{"en pause ?"}
C -- oui, hors transfert forcé --> X1[EnforcedPause]
C -- non --> D{"canSend from / canReceive to<br/>conjonction des hooks ELIGIBILITY"}
D -- false --> X2[ERC7943CannotSend / CannotReceive]
D -- true --> E{"par identifiant : existe ? non retiré ?<br/>montant ≤ solde − gelé ?"}
E -- échec --> X3[ARexBatchNotFound / ARexBatchRetired /<br/>ERC7943InsufficientUnfrozenBalance]
E -- ok --> F{"par identifiant, pour chaque hook CHECK dans l'ordre :<br/>check → code"}
F -- code ≠ 0 --> X4["ARexHookRejected(hook, code)"]
F -- tous à 0 --> G["soldes mis à jour · offre totale suivie"]
G --> H["par identifiant, pour chaque hook EXECUTED : onExecuted"]
H --> I["déverrouillage"]Deux vues rejouent la même logique sans modifier l'état : canTransfer (booléen, comme l'exige ERC-7943) et transferCheck (le premier code de rejet, afin qu'une interface puisse indiquer à l'utilisateur pourquoi).
Les transferts forcés contournent la pause et les vérifications d'éligibilité — la mise en application doit fonctionner quand tout le reste est gelé — mais exécutent tout de même les hooks avec OP_FORCED_TRANSFER, de sorte qu'un hook peut exiger, par exemple, une référence d'ordonnance judiciaire dans les données de transfert.
Filiation
transform est l'opération unique de fractionnement, de fusion et de traitement :
graph LR
W1["blé #1<br/>250 t · agriculteur"] -- "transform (réorganisation)" --> W2["blé #2<br/>100 t · acheteur A"]
W1 -- "transform (réorganisation)" --> W3["blé #3<br/>150 t · acheteur B"]
W2 -- "transform (traitement, TRANSFORMER_ROLE)" --> F4["farine #4<br/>75 t · minoterie"]- La réorganisation de lots (même denrée, même unité, quantité conservée) est ouverte à tout détenteur ou opérateur approuvé : une coopérative répartissant un lot de silo entre ses membres, un exportateur fusionnant des livraisons.
- Le traitement (tout le reste) exige en outre
TRANSFORMER_ROLE. parentsOf(4) == [2],parentsOf(2) == [1]; un événementBatchTransformedpar opération, ce qui constitue unTransformationEventd'EPCIS par construction.
Mise en application
ENFORCER_ROLE peut geler n'importe quel montant pour n'importe quel compte (setFrozenTokens, pouvant dépasser le solde, comme le précise ERC-7943) et déplacer des jetons sans le consentement du détenteur (forcedTransfer). C'est ce qui rend un jeton de lot utilisable hors d'une démonstration : un prêteur exécutant un warrant, un tribunal ordonnant la saisie de grains stockés, un entrepôt récupérant un lot après qu'un client a perdu ses clés. Chaque action de mise en application est un événement.
Hooks
Un hook est un contrat doté de cinq fonctions et d'un bitmap de drapeaux constant. Le jeton met les drapeaux en cache à l'enregistrement, de sorte qu'un transfert coûte un appel externe par hook concerné, et non une sonde d'interface par capacité et par module. Un hook apprend quel jeton l'appelle via msg.sender ; un même déploiement peut servir de nombreux jetons.
Les hooks de référence démontrent les trois capacités :
| Hook | Capacité | Ce qu'il démontre |
|---|---|---|
EligibilityHook | CHECK + ELIGIBILITY | les listes d'autorisation et de blocage ainsi que les sanctions alimentent canSend / canReceive et produisent des codes précis |
ExpiryHook | CHECK | le filtrage de la périssabilité et de l'avant-récolte, dérivé uniquement de l'enregistrement du lot |
AttestationHook | CHECK | « le café exige une déclaration EUDR attestée avant de pouvoir être vendu » |
PerishabilityHook | CHECK | modèles de décroissance et vues de valeur ; les lots expirés ou sans valeur ne circulent pas |
SeasonalHook | CHECK | fenêtres de récolte et de négociation par denrée |
DeliveryHook | CHECK + EXECUTED | verrou de garde pendant la livraison ; le règlement est le transfert lui-même, identifié par data |
TraceabilityHook | EXECUTED | journal d'événements calqué sur EPCIS pour chaque opération, plus des événements de suivi critique manuels |
Extensions compagnons (pas des hooks) : CommodityPriceOracle, CarbonImmobilizationWrapper, ParametricInsurance.
Attestations
Un contrat compagnon enregistre (batch, topic) → (issuer, reference, validity). Seuls les émetteurs de confiance pour un thème peuvent attester ; la révocation, l'expiration et la perte de confiance rendent toutes isAttested faux. Les thèmes sont des bytes32, de sorte que les thèmes d'attestation d'ERC-735, les identifiants de schéma d'Ethereum Attestation Service et les hashes de noms de certification fonctionnent tous sans table dans le standard.
Acteurs et rôles
| Acteur | Rôle typique dans le jeton de référence | Action typique |
|---|---|---|
| Plateforme d'origine, coopérative, silo collecteur | ISSUER_ROLE | createBatch |
| Agriculteur / détenteur | aucun | transfert, réorganisation de lots, destruction |
| Minoterie, conditionneur, transformateur | TRANSFORMER_ROLE | transform de traitement |
| Entrepôt, inspecteur, plateforme | STATUS_ROLE | setBatchStatus, setBatchMetadata |
| Certificateur, laboratoire, autorité | émetteur de confiance pour un thème | attest |
| Prêteur, dépositaire désigné par un tribunal, conformité | ENFORCER_ROLE | setFrozenTokens, forcedTransfer |
| Gouvernance (multisig, timelock) | DEFAULT_ADMIN_ROLE, HOOK_ADMIN_ROLE, UPGRADER_ROLE, PAUSER_ROLE | rôles, hooks, mises à niveau, pause |
Rien dans le standard ne fixe ces rôles ; ils constituent la manière dont l'implémentation de référence met en œuvre les exigences DOIT (« réservé à un rôle autorisé »).
Formes de déploiement
- L2 public (Polygon, Arbitrum, Base, Optimism) : le moins cher, le plus composable ; adapté au négoce et au financement de denrées lorsque les contreparties sont des entreprises.
- Chaîne EVM à accès restreint : lorsque les autorités de protection des données ou l'institution d'ancrage l'exigent ; l'EDPB encourage expressément les conceptions à accès restreint. Le standard est indépendant de la chaîne.
- Hybride : lots sur une chaîne publique, données restreintes (polygones de parcelles, identité du producteur) derrière un stockage à accès contrôlé référencé depuis les métadonnées.
La pile de référence se déploie avec un module Ignition ou un script : proxy du jeton, registre d'attestations, hooks d'éligibilité et d'expiration.
Décisions de conception et alternatives qu'elles remplacent
| Alternative envisagée | A-REX Core | Raison |
|---|---|---|
| une large interface de cœur avec des énumérations pour la denrée, le grade et l'état | IARexBatch à 8 fonctions avec codes ouverts | rien à redéployer pour une nouvelle culture, un nouveau schéma de classement ou un nouveau cycle de vie |
| des interfaces de capacité sondées à chaque transfert | une seule interface de hook, drapeaux mis en cache | gaz linéaire en nombre de hooks, et non en ids × modules × sondes |
| motifs sous forme de chaînes | codes bytes32 et erreurs typées | lisible par machine, indexable |
| état du cycle de vie modifiable par n'importe quel détenteur | rôle uniquement ; RETIRED terminal | sécurité |
| date de récolte obligatoirement passée | producedAt == 0 autorisé | financement avant récolte |
| ni fractionnement, ni fusion, ni traitement | transform + parentsOf | traçabilité, rappels, EPCIS |
| ni gel ni transfert forcé | ERC-7943 | possibilité de mise en application |
| coordonnées stockées on-chain | référence d'origine uniquement | GDPR / EDPB 02/2025 |
| contrats de registre et d'identité obligatoires | rien d'obligatoire | aucune pile d'identité imposée |