Skip to main contentA-REX Foundation

Livre blanc · 07

Hooks et modules de référence

Comment des fonctionnalités s'ajoutent à un jeton conforme sans toucher au standard : le contrat des hooks, les hooks de référence, les extensions compagnons, et la manière d'écrire, de tester et d'enregistrer les vôtres.

Les modules sont des démonstrations, non le standard

La relation entre A-REX Core et ses modules est celle qui existe entre ERC-3643 et les modules de conformité de T-REX : l'interface par laquelle les modules se branchent est standardisée ; les modules ne le sont pas. Un jeton conforme sans aucun hook est un jeton A-REX valide. Un hook écrit par n'importe qui est compatible avec tous les jetons conformes. C'est ce qui permet à l'écosystème de croître sans que le standard change.

graph LR
    T["ARexToken<br/>jeton conforme"] -->|"check / onExecuted / canSend / canReceive"| H1[EligibilityHook]
    T --> H2[ExpiryHook]
    T --> H3[AttestationHook]
    T --> H4["Votre hook"]
    H3 --> A[ARexAttestations]

Le contrat de hook

CallbackQuandDoit
checkavant la modification des soldes, par identifiant concerné, hooks dans l'ordre d'enregistrement, arrêt au premier code non nulêtre une fonction de lecture seule (view) ; ne jamais annuler la transaction pour des motifs de politique
onExecutedaprès la modification des soldes, par identifiant, dans l'ordrene pas appeler les fonctions du jeton qui modifient les soldes (le jeton est verrouillé)
canSend / canReceiveà chaque transfert et pour les vues ERC-7943 du jetonêtre des fonctions de lecture seule (view)

op vaut l'un des OP_MINT (1), OP_TRANSFER (2), OP_BURN (3), OP_FORCED_TRANSFER (4), OP_TRANSFORM (5). Dans une transformation, les entrées arrivent avec to == 0 et les sorties avec from == 0. data correspond aux données de transfert ERC-1155, abi.encode(processRef) pour les transformations, vide pour les transferts forcés.

Le jeton appelant est msg.sender. Un hook qui a besoin du lot lit IARexBatch(msg.sender).batchOf(id). Un hook lié à un seul jeton lors de son déploiement (ADR-025, Proposé) l'expose comme token() et refuse les appels de toute autre adresse.

Lorsque plusieurs règles lisent data, l'ADR-023 (Proposé) en fait une enveloppe étiquetée : jusqu'à 8 entrées (bytes32 key, bytes32 value), dont les clés suivent des espaces de noms comme les codes (keccak256("AREX:DELIVERY_ID"), keccak256("AREX:DOCUMENT_REF")), chaque règle ne lisant que sa propre clé. Des data de 32 octets gardent le sens unique qu'ils avaient auparavant pour chaque règle ; tout autre contenu ne donne aucune valeur, et la lecture n'annule jamais la transaction. Une règle écrite avant l'enveloppe la lit comme une absence de valeur : l'expéditeur ne construit donc une enveloppe que si toutes les règles du jeton qui lisent data lisent les enveloppes. Les DeliveryHook et TraceabilityHook de référence le font depuis la version 2.0.0-alpha.7.

Hooks de référence

EligibilityHook — autoriser, bloquer, sanctionner

Démontre HOOK_ELIGIBILITY. Maintient une liste d'autorisation facultative, une liste de blocage et une liste de sanctions ; canSend/canReceive renvoient leur conjonction ; check renvoie SANCTIONED, SENDER_INELIGIBLE ou RECEIVER_INELIGIBLE afin que les interfaces puissent expliquer le refus. Les transferts forcés sont toujours autorisés : saisir des biens sur un compte sanctionné est précisément l'objet de la mise en application. En production, les listes sont alimentées par un registre d'identité (ONCHAINID, EAS, justificatifs vérifiables) ou par un oracle de sanctions ; peu importe au hook lequel.

ExpiryHook — la périssabilité sans module

Sans état. Lit expiresAt et producedAt dans le lot. Bloque les émissions et les transferts de lots expirés (BATCH_EXPIRED), mais pas les destructions (passage en pertes) ni les transferts forcés (mise en application). Bloque facultativement les transferts de lots pas encore produits (BATCH_NOT_PRODUCED) — une plateforme qui finance l'avant-récolte positionne le drapeau pour les autoriser ; une place de marché au comptant le positionne pour les bloquer. Ce seul hook couvre la partie bloquante de la périssabilité ; les courbes de décroissance deviennent une fonction d'aide en lecture seule (view) ou une valorisation off-chain.

AttestationHook — filtrage réglementaire par denrée

Associe un code de denrée à un thème d'attestation requis. Avant un transfert, lit le lot, recherche l'exigence, interroge le registre d'attestations avec isAttested et renvoie ATTESTATION_MISSING dans le cas contraire. « Le café exige une référence de diligence raisonnée EUDR », « les lots étiquetés biologiques exigent un certificat biologique valide », « les bovins exigent un certificat sanitaire » correspondent chacun à un appel à setRequirement. Depuis la version de référence 2.0.0-alpha.7, son propriétaire peut activer checksTransform (désactivé par défaut) : les lots d'entrée d'un transform exigent alors eux aussi leur certificat, de sorte qu'un détenteur muni de TRANSFORMER_ROLE ne peut pas remettre à un autre compte un lot non certifié sous la forme d'un nouveau lot. Les sorties sont de nouveaux lots et ne sont pas vérifiées.

PerishabilityHook — modèles de décroissance

Configuration de la décroissance par code de denrée, avec dérogation par lot ; modèles NONE, LINEAR (jusqu'à un plancher à l'expiration), EXPONENTIAL (demi-vie) et STEP (baisse à chaque intervalle). Vues valueBps, secondsRemaining, isExpired. Bloque les émissions et les transferts de lots expirés (BATCH_EXPIRED) ainsi que les transferts de lots dont la valeur restante est nulle (PERISH:NO_VALUE) ; ne bloque jamais les destructions ni la mise en application.

SeasonalHook — fenêtres de récolte et de négociation

Fenêtres absolues [start, end] par denrée et par opération (16 au plus par clé). Une denrée/opération sans fenêtre n'est soumise à aucune restriction. Usage typique : OP_MINT limité à la fenêtre de récolte, OP_TRANSFER à la fenêtre de négociation ; SEASON_CLOSED dans les autres cas. Depuis la version de référence 2.0.0-alpha.7, un gestionnaire retire une fenêtre par ses bornes (removeWindow), jamais par sa position, et les fenêtres terminées libèrent de la place : lorsqu'une clé est pleine, l'ajout d'une fenêtre supprime d'abord celles qui sont terminées. Chaque retrait émet WindowRemoved, si bien qu'un indexeur peut reconstruire les fenêtres à partir des événements.

DeliveryHook — garde et règlement

Un expéditeur planifie la livraison de amount unités à un destinataire par l'intermédiaire d'un transporteur ; les unités sont verrouillées (un compteur en O(1), de sorte que check ne parcourt jamais l'historique). Le transporteur et les capteurs consignent l'enlèvement, le transit et les relevés de température (indicateur de dépassement) ; le destinataire confirme la livraison ; les litiges sont portés devant un arbitre. Le règlement est le transfert ERC-1155 lui-même : expéditeur → destinataire, montant exact, avec le numéro de la livraison dans data (32 octets, abi.encode(deliveryId), ou depuis la version 2.0.0-alpha.7 l'entrée AREX:DELIVERY_ID d'une enveloppe) ; check ne l'autorise que lorsque la livraison est DELIVERED, et onExecuted la marque SETTLED et déverrouille. Les unités libres (non verrouillées) continuent de circuler. Les unités verrouillées ne peuvent être ni transférées, ni détruites, ni utilisées comme entrées d'un transform : check renvoie IN_TRANSIT pour toute opération qui ferait passer le solde du détenteur sous le montant verrouillé, à l'exception du transfert de règlement, des émissions et des transferts forcés. Après qu'un transfert forcé a saisi des unités verrouillées, check renvoie toujours un code au lieu d'annuler la transaction. Depuis la version de référence 2.0.0-alpha.7, les unités gelées par le jeton (getFrozenTokens d'ERC-7943) ne sont pas libres pour planifier une livraison (freeUnits indique combien le sont) ; une livraison dont un transfert forcé a pris les unités ne peut être ni confirmée ni acceptée comme livrée (LockedUnitsMoved), puisque son règlement ne pourrait jamais avoir lieu, mais elle peut encore être contestée et retournée ; et une plage de température dont le minimum n'est pas inférieur au maximum est refusée (InvalidRange).

TraceabilityHook — journal d'événements calqué sur EPCIS

Observe chaque opération sur les jetons et la classe selon les étapes métier CBV (commissioning, shipping, destroying, transforming) et les dispositions (active, in_transit, destroyed, seized) ; RECORDER_ROLE consigne les événements de suivi critique hors jeton (refroidissement, emballage, réception) avec readPoint et bizLocation. Deux modes : émission seule (environ +17 k de gaz par transfert ; un indexeur reconstruit le journal) ou persistance (environ +184 k ; getEvents répond on-chain, avec pagination). La version 2 du hook, dans la version de référence 2.0.0-alpha.7, est liée à un seul jeton dès son déploiement : seul ce jeton signale des opérations, et recordEvent n'accepte que les lots qui existent sur lui, si bien que personne ne peut écrire d'entrées au nom du jeton. Son EPCISEvent porte tous les champs d'une entrée (opération, point de lecture, lieu et auteur de l'enregistrement), de sorte que le mode émission seule ne perd rien. La référence du document d'un mouvement vient de data de 32 octets ou de l'entrée AREX:DOCUMENT_REF d'une enveloppe, jamais de l'entrée d'une autre règle. Le hook ne peut pas être mis à niveau : les instances de la version 1 et leurs événements restent tels quels, et la version 2 est un nouveau déploiement.

CompanyFactsHook — les enregistrements propres d'une entreprise

Démontre uniquement HOOK_EXECUTED : il ne refuse jamais une opération, son onExecuted ne revert jamais et il est lié à un seul token. Il enregistre les enregistrements propres d'une entreprise tels que le descripteur de vocabulaire du standard les décrit (interop/VOCABULARY.md, « Records on the ledger ») : des faits sur un lot, un site ou l'entreprise (un recordHash plus au plus 8 valeurs publiques), des marques d'étape (références d'étape salées aux indices de bit 0–255, une ou jusqu'à 50 par transaction), des étapes reçues du token d'une autre entreprise, des ancrages quotidiens (une racine de Merkle et un compte) et des annulations. Chaque écriture porte un approvalHash, le hash de l'enregistrement de l'entreprise indiquant qui l'a approuvée. Le Safe de l'entreprise enregistre les définitions et les étapes ; une clé d'enregistrement, qui peut être déléguée, écrit les enregistrements. Lors d'un transform, il reporte sur les sorties les étapes par lesquelles chaque lot parent est passé. Il n'ajoute l'étape d'un type de procédé que pour un processRef engagé dans le même bloc (commitRun), et chaque engagement n'est honoré qu'une fois. Il reporte de la même façon le modèle de chaîne de contrôle (cocModel, le plus bas des parents) et la couverture EUDR (eudrCovered, le ET des parents). Événements : FactRecorded, StageRecorded, ReceivedStageRecorded, Anchored, FactVoided, RunCommitted, StagesCarried, CustodyDeclared. Version de référence 2.0.0-alpha.9.

RequireStageHook — pas de livraison sans les étapes requises

Démontre HOOK_CHECK au-dessus de CompanyFactsHook. Jusqu'à 16 exigences, chacune indiquant les opérations qu'elle couvre (les livraisons et, en option, les entrées d'un transform), les produits et les étapes par lesquelles un lot doit être passé. Un lot auquel il en manque une est refusé avec REQUIRE_STAGE:MISSING ; un lot ou un module d'étapes qu'il ne peut pas lire est refusé avec REQUIRE_STAGE:UNREADABLE, jamais par un revert. Les émissions, les destructions et les mouvements sur ordre légal ne sont jamais refusés. Chaque exigence porte son propre appliesFrom : les lots créés avant ne sont pas vérifiés. Le Safe de l'entreprise fixe les exigences avec configure, de sorte que le point de départ peut changer lorsque les exigences sont remplacées ; chaque changement émet Configured. Version de référence 2.0.0-alpha.9.

Extensions compagnons

Trois préoccupations n'ont jamais eu besoin d'être des règles de transfert ; ce sont de simples contrats qui lisent ou écrivent des attestations :

ExtensionCe qu'elle fait
CommodityPriceOracledes déclarants soumettent des prix par denrée ; les tours sont numérotés et finalisés par quorum avec la médiane, ou manuellement une fois un minimum atteint ; latestAnswer, isStale
CarbonImmobilizationWrapperenregistre les crédits immobilisés dans un registre (registre, plage de numéros de série, millésime, tonnes, preuve), relie des tonnes à des lots, reflète le retrait et la libération, écrit l'attestation AREX:CARBON:IMMOBILIZED ; n'émet jamais de crédits
ParametricInsurancepool ERC-20 ; police par lot avec un thème déclencheur ; la réclamation est payée lorsque le déclencheur est attesté avant l'expiration

Lots anciens et lots nouveaux

Une règle activée pour un jeton qui détient déjà des lots régit soit tous les lots, soit uniquement les lots créés à partir d'un moment donné. Les ExpiryHook, AttestationHook, SeasonalHook et PerishabilityHook de référence reçoivent ce moment (appliesFrom, 0 pour tous les lots) lors de leur déploiement. Il ne peut plus être modifié ensuite, de sorte que personne ne peut exempter davantage de lots par la suite ; faire un autre choix exige un nouveau déploiement de la règle. RequireStageHook fait exception : chacune de ses exigences porte son propre appliesFrom, et le Safe de l'entreprise peut remplacer les exigences avec configure.

Décrire une règle aux systèmes qui l'utilisent

Une règle ou un module complémentaire peut publier un descripteur arex.module/1 à côté de son code. C'est un document JSON versionné qui nomme les paramètres et les réglages du contrat, les champs du lot qu'il lit, les types de certificats qu'il attend, ses événements et ses codes de rejet, ainsi que la manière dont son état est repris par une nouvelle version. Une plateforme, un portefeuille, un indexeur ou un auditeur le lit pour afficher la règle, la configurer et expliquer un refus sans code écrit spécialement pour cette règle. Depuis la révision 1.1, le descripteur peut aussi indiquer les opérations que la règle gouverne (ops : mint, transfer, burn, forced_transfer, transform). Le champ est informatif : absent, les opérations sont inconnues, et aucun consommateur ne peut s'appuyer sur lui pour appliquer un contrôle, car ce sont les vérifications du hook lui-même qui décident. La révision 1.2 ajoute deux choses. Un réglage peut désigner un lieu (ref:site) : il est enregistré comme l'originRef que portent les lots créés à cet endroit, ou comme la référence à la preuve d'origine hors chaîne qu'ils portent à la place (une déclaration de diligence raisonnée EUDR, par exemple), jamais comme une adresse ou des coordonnées. Et le gaz déclaré de check et onExecuted est mesuré avec les réglages remplis : avant de mesurer, un validateur appelle chaque opération qui fixe ou ajoute une valeur setup fois par clé avec des valeurs de test (8 sauf indication contraire du descripteur, 32 au plus), si bien qu'une règle qui parcourt une liste configurable déclare ce qu'elle coûte avec cette liste pleine. La révision 1.3 consigne ce que le premier consommateur du descripteur utilise déjà, afin que ses descripteurs passent la validation du schéma publié : les actions que des personnes enregistrent par une approbation (les enregistrements d'un module complémentaire, chacun avec le rôle qui peut l'appeler), les erreurs propres du contrat en mots, des mesures sur ses enregistrements, la donnée par livraison qu'une règle lit, une forme complète de ses événements avec leurs champs et leurs textes, et d'autres types de valeur (un lot, un enregistrement du module, un texte court, un texte conservé seulement par son empreinte). Chaque champ qu'elle ajoute est facultatif : tout descripteur antérieur reste valide. La révision 1.4 décrit chaque valeur assez précisément pour qu'un formulaire en soit construit : de nouveaux types de valeur (un montant avec sa devise, une date et une heure, un document conservé par son empreinte, un code au format défini comme un GTIN, un pays ou une région, une unité, une personne ou une partie de l'annuaire), ce qui atteint le registre (la valeur, seulement son empreinte, ou rien ; jamais de données personnelles), le titre, l'aide, l'exemple, la section et les conditions de chaque champ, des contrôles entre champs tirés d'une liste fermée, des valeurs calculées, des détails gardés hors du registre, des vues en lecture seule à côté d'un lot, et la façon d'afficher un enregistrement : toujours comme déclaré par l'organisation qui l'a enregistré, jamais comme vérifié. La révision 1.5 sale chaque empreinte : un descripteur qui déclare fingerprint: { "scheme": "salted-jcs/1" } enregistre le hachage de chaque valeur avec son propre sel de 32 octets, de sorte que des textes courts, des nombres ou des contours de parcelles ne peuvent pas être retrouvés en essayant des candidats. La révision 1.6 ajoute des mesures qui ne sont pas des totaux : outre count et sum, une mesure peut être la valeur moyenne, la plus basse ou la plus haute (avg, min, max) d'un champ numérique des enregistrements. Elles exigent ce champ numérique et ne sont jamais additionnées entre groupes ni entre entreprises : la moyenne de deux entreprises est la moyenne de leurs enregistrements, pas la moyenne de leurs moyennes. Les mesures peuvent aussi être regroupées par la partie qui a créé le lot (party) et par son site (site). Le modèle de module complémentaire d'humidité de la version de référence 2.0.0-alpha.10 en déclare une : l'humidité moyenne à la réception par produit et par site. Une mesure portant sur une valeur enregistrée en points de base déclare unit: "bp", et un consommateur l'affiche divisée par 100, sous forme de pourcentage. La révision 1.7 permet au visibleWhen d'un champ de prendre l'arbre de conditions du descripteur de vocabulaire sur les autres champs du même formulaire : des feuilles { field, op, value } combinées par all, any et not, au plus 3 niveaux et 12 feuilles, jamais une expression ni le contexte de l'enregistrement. La condition unique de la révision 1.4 reste valide, dépréciée, et se lit comme la feuille équivalente.

Le descripteur est informatif et au statut Proposé : il a été proposé par A-REX Platform, son premier consommateur, et deviendra un format recommandé lorsqu'un second implémenteur indépendant le consommera. Les champs qu'une règle ajoute au document de métadonnées d'un lot se trouveraient sous extensions.<key>, validés par le fragment de schéma du descripteur (ADR-017, Proposé, pour le schéma de métadonnées 1.3.0).

Une organisation peut aussi publier son propre vocabulaire sous forme de définitions arex.vocab/1 : types de travaux aux champs (taille, échantillonnage de sol), types de procédé (une fermentation de 72 heures, un tri par calibre) et listes d'étapes par produit (récolte, séchage, décorticage, classement, exportation). Ce sont des données, pas du code. Chacune utilise l'objet champ du descripteur, indique sa version et correspond à une classe d'étape de référence et à une étape métier GS1 CBV, afin qu'un lecteur qui ne connaît pas l'organisation la comprenne quand même. Un type de procédé est un transform avec un type, jamais une nouvelle opération : son processRef porte une étiquette de 4 octets du type et une empreinte des valeurs du procédé, de sorte qu'une règle peut agir selon le type et que chacun peut vérifier le procédé. Les enregistrements arrivent dans le registre un par un ou sous forme d'une racine de Merkle quotidienne, chaque valeur étant engagée avec son propre sel, ce qui permet à une organisation de divulguer certains champs et d'en garder d'autres. Une empreinte qui correspond montre qu'un enregistrement n'a pas changé depuis qu'il a été fait, jamais que le travail a été effectué comme déclaré. Le format est informatif et Proposé (révision 1.5 du descripteur de vocabulaire). La révision 1.1 ajoute un form facultatif qui répartit les champs en sections et en largeurs et fixe le comportement de chacun (conditions, valeurs par défaut, valeurs en lecture seule et calculées, masques et motifs) ; il ne fait que restreindre ce que les champs acceptent, si bien qu'un lecteur qui l'ignore lit chaque enregistrement comme avant. La révision 1.2 donne aux conditions un seul petit langage, partagé avec le descripteur de règle : not, jusqu'à 3 niveaux et 12 feuilles, et des feuilles qui lisent ce que la plateforme sait de l'enregistrement, dans des codes qui se lisent de la même façon dans toutes les langues (la culture en code OEPP, les jours depuis la plantation, le type de site, le pays, la position SH du produit du lot, sa dernière étape). Un contexte inconnu se lit comme vide, et toute condition de la révision 1.1 reste valide telle qu'elle est écrite. La révision 1.3 permet à une liste d'étapes d'indiquer son ordre (order) : avec strict, la valeur par défaut, un lot n'est pas enregistré à une étape tant qu'il lui manque une étape antérieure obligatoire, à compter de l'endroit où il est entré dans la liste ; avec flexible, les étapes s'enregistrent dans n'importe quel ordre et les manques sont laissés aux rapports. Une étape qui découle de l'histoire même du lot (son enregistrement, une transformation, une réception) n'est jamais refusée, et toute liste antérieure se lit comme strict. La révision 1.4 permet à un type de procédé d'indiquer la méthode de traitement du café que portent ses sorties (washed, natural, honey et ses variantes jaune, rouge et noire, pulped_natural, wet_hulled, anaerobic, other), tirée d'un champ de l'exécution ou fixée par le type, et les métadonnées process d'un lot peuvent porter la méthode (method ; mixed pour un lot seulement). C'est une déclaration de l'organisation, pas une certification, et elle voyage avec le lot même là où les valeurs des étapes restent privées. La révision 1.5 permet à une correspondance vers l'une des classes larges separating, conditioning, sorting_grading ou heat_treating d'ajouter une subclass tirée d'une liste fermée par classe (par exemple hulling, curing, screen, roasting), et un lecteur n'apparie l'étape d'une autre organisation d'une classe large que par sa sous-classe ou par une correspondance explicite par expéditeur. La révision 1.6 ajoute to_processor, une sous-classe de transporting : des marchandises envoyées à un transformateur qui les travaille pour leur propriétaire (travail à façon), si bien que la garde change mais pas la propriété.

Écrire votre propre hook

L'exemple contracts/examples/SeasonHook.sol reste dans le dépôt. test/standard/ImplementationGuide.test.js l'exerce pour les lecteurs qui ont accès. SeasonalHook est le module de référence pour plusieurs fenêtres par denrée et par opération.

Règles pratiques :

  1. Les symboles OK et OP_FORCED_TRANSFER sont définis dans le texte normatif.
  2. Le comportement de la destruction est défini dans le texte normatif.
  3. Le rappel check est défini dans le texte normatif.
  4. Les noms de code tels que ARexCodes.code("MYNS", "NAME") sont définis dans le texte normatif.
  5. Les valeurs des drapeaux sont définies dans le texte normatif.
  6. Les rappels onExecuted et check sont définis dans le texte normatif.

Enregistrement et ordre

Placez en premier les règles peu coûteuses qui rejettent beaucoup. HOOK_ADMIN_ROLE devrait se trouver derrière un multisig ou un timelock : quiconque contrôle le pipeline contrôle quels transferts sont possibles.

Tests

test/standard/helpers.js déploie la pile de référence. RecordingHook enregistre chaque callback et peut recevoir l'instruction de rejeter avec n'importe quel code ; ReentrantHook tente de ré-entrer dans le jeton depuis onExecuted et prouve le verrou. DomainHooks.test.js et Extensions.test.js couvrent les hooks et les compagnons portés ; Invariants.test.js exécute une séquence aléatoire d'opérations à graine fixée et vérifie la conservation de l'offre, le statut terminal et le fait que canTransfer prédit chaque résultat. Depuis la version de référence 2.0.0-alpha.8, l'implémentation de référence fournit aussi un kit de hooks (conformance/hooks/), des suites Foundry que toute règle doit réussir, et un modèle de module (templates/module/). La version 2.0.0-alpha.9 ajoute un kit de modules complémentaires (conformance/addons/) et trois modèles de modules complémentaires testés avec lui : l'humidité à la réception (GrainMoisture), un certificat de commerce équitable enregistré comme fait déclaré par l'entreprise (FairTradeCertificate) et une prime versée à un producteur, dont le montant et le bénéficiaire ne sont enregistrés que sous forme d'empreintes salées (PremiumPayments).

Interopérer avec la conformité ERC-3643

Un module de conformité ERC-3643 expose moduleCheck(from, to, value, compliance). Un hook qui l'appelle pour OP_TRANSFER et fait correspondre false à un code rend réutilisables sur des jetons de lot les restrictions par pays, les plafonds de solde et les verrous temporels écrits pour des jetons de valeurs mobilières. L'inverse — exposer un hook A-REX à un jeton ERC-3643 — est tout aussi mécanique. L'Automated Compliance Engine de Chainlink s'intègre selon le même schéma : son moteur de politiques devient un hook. Ces deux directions sont des conceptions non implémentées. L'adaptateur de référence qui existe va dans l'autre sens et ne fait que lire : il permet aux portefeuilles et aux outils de conformité ERC-3643 de voir chaque lot comme un jeton ERC-3643 grâce à un hook de simple notification qui ne peut ni autoriser ni refuser un transfert (ADR-020, Proposé).