Livre blanc · 13
Analyse des performances
Gaz mesuré de l'implémentation de référence avec zéro, un et deux hooks ; ce qui détermine le coût ; et recommandations de déploiement.
Méthode
Les chiffres ci-dessous proviennent de scripts/gas-report-standard.js exécuté sur le réseau en processus de Hardhat contre l'implémentation de référence compilée (solc 0.8.22, viaIR, optimizer.runs = 1 pour ARexToken), septembre 2026. « À chaud » (warm) désigne la même paire expéditeur/destinataire/identifiant que lors du transfert précédent (emplacements de stockage déjà touchés dans le bloc). Hooks : EligibilityHook (CHECK + ELIGIBILITY) et ExpiryHook (CHECK). Pour reproduire :
npx hardhat run scripts/gas-report-standard.js
Résultats
xychart-beta
title "Gaz d'un transfert à chaud selon le nombre de hooks (milliers)"
x-axis ["aucun hook", "Éligibilité", "Éligibilité + Expiration"]
y-axis "gaz (k)" 0 --> 140
bar [66.8, 91.2, 119.6]Le coût croît linéairement avec le nombre de hooks : chacun représente un appel externe à check par identifiant, plus canSend et canReceive pour un hook d'éligibilité. Le tableau donne chaque opération.
| Opération | 0 hook | 1 hook | 2 hooks |
|---|---|---|---|
createBatch (nouvel identifiant, émission de 1000) | 264,096 | 283,831 | 299,396 |
safeTransferFrom (premier, à froid) | 80,687 | 108,266 | 136,682 |
safeTransferFrom (à chaud) | 66,790 | 91,166 | 119,582 |
transform fractionnement 1 → 2 (deux nouveaux identifiants) | 564,422 | 595,707 | 636,858 |
setFrozenTokens | 54,188 | 54,188 | 54,188 |
forcedTransfer | 80,152 | 89,909 | 99,569 |
burn | 66,621 | 83,001 | 93,395 |
Transfert à chaud avec exactement un hook de chaque type (coût marginal de la règle) :
xychart-beta horizontal
title "Gaz marginal d'un hook sur un transfert à chaud (milliers)"
x-axis ["DeliveryHook", "Traceability (émission)", "EligibilityHook", "ExpiryHook", "SeasonalHook", "PerishabilityHook"]
y-axis "gaz ajouté (k)" 0 --> 35
bar [12.3, 17.4, 24.4, 25.2, 27.5, 31.0]TraceabilityHook en mode persistant ajoute 184.5k et est exclu du graphique pour des raisons d'échelle.
| Hook | Gaz | Δ par rapport à l'absence de hook |
|---|---|---|
| EligibilityHook | 91,166 | +24,376 |
| ExpiryHook | 92,023 | +25,233 |
| SeasonalHook | 94,324 | +27,534 |
| PerishabilityHook | 97,813 | +31,023 |
| DeliveryHook (aucune livraison active) | 79,076 | +12,286 |
| TraceabilityHook, émission seule | 84,152 | +17,362 |
| TraceabilityHook, persistant | 251,273 | +184,483 |
Ce qui détermine le coût
- Un transfert sans hook coûte ~67k à chaud, c'est-à-dire ERC-1155 plus le suivi de l'offre plus les lectures d'existence, de statut et de gel du lot et la comptabilité du pipeline (mise de côté des données, verrou). C'est le plancher.
- Chaque hook ajoute environ 25–30k à un transfert : un appel à
check(view, inter-contrats) plus, pour les hooks d'éligibilité, des appels àcanSendetcanReceive. Le coût est linéaire en fonction du nombre de hooks et du nombre d'identifiants dans un transfert groupé. Sonder chaque contrat de règle pour chaque capacité avecsupportsInterfaceavant de l'appeler ajouterait plusieurs appels statiques par identifiant ; ce surcoût n'existe pas, car les drapeaux sont mis en cache à l'enregistrement. createBatchest dominé par le stockage : la structureBatch(six mots plus une chaîne) et les emplacements de solde et d'offre d'ERC-1155. C'est un coût unique par lot.transformcrée de nouveaux identifiants : un fractionnement en deux paie deux enregistrements de lot plus deux émissions plus une destruction, plus les appels de hooks sur chaque mouvement (OP_TRANSFORM). Un fractionnement en n coûte à peu prèsn × createBatchplus une destruction ; la fusion de n en un seul coûte à peu prèsndestructions plus un createBatch.- La mise en application est peu coûteuse : un gel occupe un seul emplacement ; un transfert forcé coûte ce que coûte un transfert plus l'écriture de dégel et l'événement.
transferCheck/canTransfersont des vues : gratuites off-chain, et suivent le même chemin de code que la transaction.
Ce que la conception apporte
| Conception par sondage de capacités | A-REX Core (ARexToken) | |
|---|---|---|
| Transfert avec n contrats de règles | identifiants × modules × (sondes supportsInterface + appel de hook) avant l'exécution de toute logique | identifiants × hooks × 1 appel (+2 pour les hooks d'éligibilité) ; drapeaux mis en cache à l'enregistrement |
| Rejet | revert avec chaîne (copiée en mémoire, non indexable) | erreur personnalisée avec l'adresse du hook et un code bytes32 |
| Filiation | indisponible | ~280k par lot de sortie |
| Gel / transfert forcé | indisponible | 54k / 80k |
La colonne de gauche décrit la conception qu'A-REX Core remplace (ADR-004, ADR-005) ; seule la colonne de droite est mesurée.
Recommandations de déploiement
- Le coût monétaire est
gas × gas price × token price, et les deux derniers facteurs varient de plusieurs ordres de grandeur selon les chaînes et les jours. À titre d'illustration seulement, à 0.01 gwei et 3,000 USD par ETH, un transfert à chaud avec deux hooks (119,582 gaz) coûte environ 0.0036 USD et uncreateBatch(264,096 gaz) environ 0.008 USD ; à 20 gwei sur le mainnet d'Ethereum, les mêmes opérations coûtent environ 7.2 et 15.8 USD. Mesurez sur la chaîne cible avant de vous engager dans un modèle d'économie unitaire. - Transferts groupés :
safeBatchTransferFromamortit les coûts fixes ; le coût des hooks reste proportionnel au nombre d'identifiants. - Ordre des hooks : placez en premier les hooks peu coûteux qui rejettent beaucoup ; un rejet interrompt le pipeline avant l'exécution des hooks plus coûteux.
- Nombre de hooks : trois à cinq suffisent à la plupart des émetteurs ; chaque hook supplémentaire représente un coût mesurable par transfert et une surface de gouvernance.
- Métadonnées : gardez
uricourte (un CID ou un Digital Link) ; la chaîne est stockée on-chain. - Lectures off-chain : utilisez
transferCheckavant de soumettre ; une transaction annulée coûte tout de même du gaz.
Débit
Le jeton lui-même n'est pas le goulet d'étranglement ; c'est la chaîne. Un transfert unique est une transaction ; une transformation avec n sorties est une transaction comportant n émissions. L'indexation de la filiation exige de lire les événements BatchTransformed, émis une fois par opération avec les listes complètes de quantités ; un indexeur n'a donc rien à reconstituer à partir des événements propres à chaque transfert.
Taille des contrats
ARexToken se déploie à 24,136 octets (limite 24,576), compilé avec optimizer.runs = 1. Les autres contrats sont petits : ARexAttestations 2,708 ; hooks entre 1,358 (ExpiryHook) et 6,215 (DeliveryHook), TraceabilityHook 4,076 ; extensions entre 3,716 et 4,588. Ajouter des fonctionnalités au jeton lui-même est limité par la taille, par conception — c'est à cela que servent les hooks et les contrats compagnons.