Livre blanc · 08
Cadre de sécurité
Modèle de menaces, invariants, contrôle d'accès, frontière de confiance des hooks, gestion des clés de mise en application, sûreté des mises à niveau et posture d'audit de l'implémentation de référence d'A-REX Core.
La posture de sécurité en un paragraphe
Le jeton de référence possède un seul point de passage obligé (_update), un ordre d'évaluation fixe, un verrou de réentrance autour de toute la séquence de hooks, une autorité fondée sur les rôles qui n'est jamais dérivée des soldes, un stockage ERC-7201 et une surface réduite : huit fonctions externes modifiant l'état en plus d'ERC-1155. Les capacités les plus puissantes — gel, transfert forcé, administration des hooks, mises à niveau — sont des rôles distincts destinés à des multisigs et à des timelocks, et chacun de leurs usages est un événement.
Invariants
| Invariant | Garanti par | Testé par |
|---|---|---|
totalSupply(id) est égal à la somme des soldes pour id | OpenZeppelin ERC1155Supply ; transform détruit puis émet via _update | tests de filiation (fractionnement, fusion, traitement) |
status == 255 est terminal | setBatchStatus annule la transaction avec ARexInvalidStatusTransition | tests de statut |
| Un lot retiré ne peut être ni émis ni transféré, seulement détruit | _update | test du lot retiré |
amount ≤ balance − frozen pour les mouvements initiés par le détenteur | _update ; forcedTransfer abaisse frozen à balance − amount | tests de gel et de transfert forcé |
| Aucun hook ne peut ré-entrer dans une fonction modifiant les soldes | verrou de stockage posé avant les vérifications, levé après les notifications | test ReentrantHook |
| Les hooks sont évalués dans l'ordre d'enregistrement ; la suppression préserve l'ordre | décalage du tableau dans removeHook | test d'ordre |
| Une opération rejetée ne modifie aucun solde et n'émet aucun transfert | les vérifications s'exécutent avant super._update | test de rejet (compteur d'exécutions inchangé) |
| L'autorité ne dérive jamais du solde | chaque fonction modifiant l'état est conditionnée à un rôle ou à une approbation ERC-1155 | tests « détenir des jetons ne confère rien » |
canTransfer == (transferCheck == 0) | canTransfer est défini ainsi | tests de conformité |
Modèle de menaces
Acteurs et capacités
| Acteur | Peut | Ne peut pas |
|---|---|---|
| Détenteur | transférer des unités non gelées à des destinataires éligibles ; détruire ; réorganiser des lots de même denrée et de même unité avec quantité conservée | modifier le statut, émettre, traiter pour obtenir une autre denrée, déplacer des unités gelées |
| Opérateur approuvé | comme le détenteur, pour le compte qui l'approuve | tout ce qu'un détenteur ne peut pas faire |
ISSUER_ROLE | créer des lots | déplacer les jetons d'autrui |
TRANSFORMER_ROLE | effectuer des transformations de traitement sur les jetons qu'il détient ou pour lesquels il est approuvé | transformer des jetons sans approbation |
STATUS_ROLE | modifier le statut (y compris retirer), mettre à jour les métadonnées | déplacer des jetons |
ENFORCER_ROLE | geler n'importe quel montant ; forcer n'importe quel transfert | contourner les hooks (ils s'exécutent avec OP_FORCED_TRANSFER) |
HOOK_ADMIN_ROLE | ajouter/retirer des hooks | modifier directement les soldes |
PAUSER_ROLE | tout interrompre sauf les transferts forcés | — |
UPGRADER_ROLE | remplacer l'implémentation | — (c'est un pouvoir total ; voir la gestion des clés) |
| Contrat de hook | rejeter des opérations ; les observer ; répondre sur l'éligibilité | ré-entrer ; modifier les soldes |
Scénarios
Hook malveillant ou défectueux (déni de service). Un hook qui rejette toujours bloque tous les transferts du jeton ; un hook qui annule la transaction dans check produit le même effet. Atténuation : HOOK_ADMIN_ROLE peut retirer n'importe quel hook à tout moment (ordre préservé) ; PAUSER_ROLE peut tout interrompre pendant l'enquête ; les transferts forcés s'exécutent toujours, de sorte que la mise en application n'est pas perdue. L'enregistrement vérifie la prise en charge d'ERC-165 et des drapeaux non nuls, et rejette les EOA. Recommandation : auditer les hooks avant de les enregistrer ; en garder un petit nombre ; placer l'administrateur derrière un timelock afin que les changements de hooks soient visibles avant leur prise d'effet.
Réentrance d'un hook. Le onExecuted d'un hook rappelle safeTransferFrom. Atténuation : le verrou ; l'appel annule la transaction avec ARexReentrantCall. Notez que le callback de réception d'ERC-1155 (onERC1155Received) s'exécute après la levée du verrou, comme dans tout jeton ERC-1155 ; l'état du jeton est alors définitif.
Clé de mise en application compromise. Quiconque détient ENFORCER_ROLE peut déplacer n'importe quels jetons. Atténuation : multisig avec une procédure documentée (ordonnance judiciaire, contrat de nantissement, avis de sanctions) ; chaque action émet ForcedTransfer/Frozen ; les hooks peuvent exiger une référence d'ordonnance dans les données de transfert (OP_FORCED_TRANSFER n'est pas exempté des hooks). Envisager un timelock pour la mise en application non urgente.
Compromission du rôle de mise à niveau. Compromission totale. Atténuation : multisig plus timelock ; validations de mise à niveau d'OpenZeppelin en CI ; stockage ERC-7201 pour éviter les accidents de disposition.
Abus de statut. STATUS_ROLE peut retirer un lot détenu par d'autres. C'est intentionnel — un entrepôt, un inspecteur ou un régulateur déclarant un lot impropre — et cela doit être communiqué aux détenteurs. Atténuation : l'attribuer à une institution responsable ; chaque changement est un événement accompagné d'un motif.
Fraude de l'émetteur. ISSUER_ROLE peut créer un lot qui n'existe pas physiquement. Le jeton ne peut pas l'empêcher ; il le rend imputable (issuer, originRef, metadataHash) et permet d'exiger avant tout transfert, via AttestationHook, des attestations de parties indépendantes (entrepôt, inspecteur, registre).
Substitution de métadonnées. setBatchMetadata modifie le hash et l'URI. Atténuation : accès réservé à un rôle ; les événements BatchMetadataUpdated et URI conservent l'historique ; les documents antérieurs restent vérifiables par rapport aux hashes antérieurs.
Front-running de transferCheck. Une vérification préalable peut devenir obsolète avant l'exécution de la transaction (l'état d'un hook change). La transaction réévalue ; le pire cas est un revert avec un code précis.
Griefing de gaz via les hooks. Chaque hook ajoute un appel externe par identifiant concerné et par phase. Un hook avec des boucles non bornées rend les transferts inabordables. Atténuation : règles d'écriture des hooks (check borné), revue avant l'enregistrement.
Confiance envers les hooks pouvant être mis à niveau. Un hook déployé derrière un proxy peut modifier la politique de transfert sans aucun changement sur le jeton. Atténuation : traiter les clés d'administration des hooks avec le même soin que HOOK_ADMIN_ROLE ; privilégier des hooks immuables en production.
Modèle de contrôle d'accès
AccessControl d'OpenZeppelin avec huit rôles sur le jeton et un sur le registre d'attestations ; DEFAULT_ADMIN_ROLE les administre tous. Disposition recommandée en production :
| Rôle | Titulaire |
|---|---|
DEFAULT_ADMIN_ROLE, UPGRADER_ROLE, HOOK_ADMIN_ROLE | multisig de gouvernance derrière un timelock |
ENFORCER_ROLE | multisig de mise en application (conformité + juridique) |
PAUSER_ROLE | clé de réponse aux incidents (rapide) |
ISSUER_ROLE, STATUS_ROLE, TRANSFORMER_ROLE | services opérationnels au moindre privilège, avec rotation des clés |
ATTEST_ADMIN_ROLE | autorité de certification ou plateforme |
initialize accorde tout à un seul administrateur par commodité ; la liste de contrôle de déploiement exige une redistribution avant la production.
Sémantique de la mise en application et de la pause
- La pause bloque les émissions, les transferts, les destructions et les transformations ; elle ne bloque pas les transferts forcés, de sorte qu'un ordre légal peut être exécuté pendant un incident.
- Les transferts forcés ignorent
canSend/canReceiveet la vérification du solde gelé, abaissent le montant gelé à ce qui reste, et exécutent tout de même les hooks avecOP_FORCED_TRANSFER. Les hooks de référence renvoientOKpour cette opération ; un hook qui régit la mise en application peut exiger des références d'ordonnance dansdata. - Le gel peut dépasser le solde (ERC-7943), de sorte qu'une sûreté peut couvrir les dépôts futurs.
Sûreté des mises à niveau
- UUPS ;
_authorizeUpgradeconditionné parUPGRADER_ROLE. - Structure de stockage ERC-7201 à espace de noms ; ajouts uniquement.
- Les validations du plugin de mises à niveau d'OpenZeppelin s'exécutent dans les tests et devraient s'exécuter en CI avant toute transaction de mise à niveau.
- Le paramètre
optimizer.runs = 1par fichier maintient l'implémentation sous EIP-170 ; une modification qui la fait dépasser la limite échoue à la compilation avec un avertissement et au déploiement avec un revert.
Sécurité des dépendances et du build
- OpenZeppelin Contracts et Contracts-Upgradeable épinglés à 5.3.0 ; fichier de verrouillage versionné ; la CI utilise
npm ci. - Solidity 0.8.22, viaIR, EVM
paris(aucune dépendance au stockage transitoire, déployable sur des chaînes qui n'ont pas adopté Cancun). - Aucune bibliothèque externe liée ; aucun delegatecall en dehors du proxy UUPS.
Posture d'audit
- 46 tests sur l'implémentation de référence, les hooks et les extensions couvrent chaque invariant ci-dessus, y compris une exécution d'invariants aléatoire à graine fixée.
- Le gaz et la taille sont mesurés par des scripts du dépôt.
- Un audit par un tiers de
ARexToken,ARexAttestationset des hooks de référence est une condition préalable déclarée pour un participant d'ancrage en production et pour la soumission de l'ERC (voir Évolutions futures). - La vérification formelle des invariants du pipeline figure sur la feuille de route ; les invariants sont suffisamment petits pour être énoncés sous forme de propriétés.
Risques résiduels que le standard ne supprime pas
- L'existence physique et la qualité d'un lot sont attestées, non prouvées ; le jeton rend les affirmations imputables, non vraies.
- La disponibilité des métadonnées off-chain dépend du stockage choisi ; le hash garantit l'intégrité, non la disponibilité.
- La gouvernance des hooks et des modules ne vaut que ce que valent les clés qui la contrôlent.