Transfert groupé : deux règles pour détecter le bug
Un batch est passé alors que le contrôle du token le refusait. Quelles deux règles l’auraient détecté avant que quiconque repère le bug ?

EN 30 SECONDES
Un invariant est une règle qui doit rester vraie après chaque appel. Deux détectent ce bug : l’exécution n’autorise jamais ce que canTransfer a refusé, et les transferts d’un détenteur n’entament jamais ses tokens gelés.
À RETENIR · 3
- Première règle : si un transfert s’exécute, canTransfer a dit oui pour le total de chaque token id, pas pour chaque élément.
- Deuxième règle : les transferts d’un détenteur ne font jamais passer un solde sous le montant gelé, s’il n’y était pas déjà.
- Appliquez les deux règles à tout chemin qui déplace plusieurs montants : batchs, opérateurs, transferts vers soi, routeurs et burns sans privilège.
Sur cette page
PR n° 2045 des ERC, ouverte au 7 oct. 2026 : voyez son état actuel.
L’invariant qui prouve que le contrôle colle au transfert
EN BREF Deux règles, vérifiées après chaque appel : l’exécution n’autorise jamais ce que canTransfer a refusé, et les transferts d’un détenteur n’entament jamais ses tokens gelés.
LES MOTS À CONNAÎTRE
- Invariant
- Une règle qui doit rester vraie après chaque appel à un contrat, quel que soit l’ordre des appels.
- canTransfer
- Une fonction en lecture seule, une « vue », qui répond oui ou non : ce transfert serait-il autorisé ?
- Opérateur
- Un compte que le détenteur a autorisé à déplacer ses tokens à sa place.
- Transfert forcé
- Un transfert fait par un rôle autorisé sans l’accord du détenteur.
EN CLAIR
La première règle est générale, et ERC-7943 l’énonce noir sur blanc pour les transferts publics, en nommant la vue canTransfer Une fonction en lecture seule, une « vue », qui répond oui ou non : ce transfert serait-il autorisé ? Voir le glossaire :
MUST NOT succeed in cases where canTransfer would return false.
OBJET OBTENU
La vue est une promesse
La seconde règle est celle pour laquelle le gel existe : un détenteur ne peut envoyer que ce qui dépasse le montant gelé. La première dépend du total par id : interrogez la vue élément par élément, et cette règle passe sur le code défectueux.
Où la vue et l’exécution peuvent encore diverger
EN BREF Dès qu’un token sépare la vue de contrôle et le chemin de transfert, les deux peuvent diverger : interrogez chaque fonction qui déplace plusieurs montants.
ÉTAPE PAR ÉTAPE
Étape 1. La question. Lisez le chemin batch et demandez-vous : chaque élément voit-il le débit du précédent ?
- La question Lisez le chemin batch et demandez-vous : chaque élément voit-il le débit du précédent ?
- Oui Protégés par construction, mais lancez quand même le test : un transfert vers soi peut contredire la vue.
- Non Additionnez par id. Un contrôle après débit, placé avant l’appel au destinataire, peut compléter, mais il rate les transferts vers soi. Vérifiez aussi les burns dans la même boucle.
- Pas sûr Écrivez d’abord le handler de test (niveau 4) et laissez-le trancher.
Le schéma n’est pas propre à ERC-1155. À titre de comparaison, l’implémentation T-REX d’ERC-3643 fait boucler batchTransfer sur transfer() : chaque élément est comparé à un solde déjà débité par le précédent.
ATTENTION
Le canTransfer d’ERC-3643 se trouve sur son contrat de conformité, un contrat distinct qui vérifie les règles, directement ou via des modules. Ce n’est pas la même fonction que celle d’ERC-7943.
Au-delà des batchs, j’appliquerais les deux mêmes règles aux transferts d’Opérateur Un compte que le détenteur a autorisé à déplacer ses tokens à sa place. Voir le glossaire (autorisés via setApprovalForAll), aux transferts vers soi-même et à tout wrapper ou routeur qui appelle le token en boucle. Ajoutez les burns sans privilège : le standard exige (MUST NOT) qu’ils ne brûlent pas plus que le montant non gelé.
ATTENTION
Les constats annexes de l’issue, comme un transfert forcé où from est égal à to, relèvent de ce cas. Vous recrutez pour ce type de contrat ? Exigez ce test dans le brief avant l’audit.
Sources : ERC-7943 (Final), issue n° 1814 des ERC, Token.sol de T-REX, ERC-3643.
FAQ
Deux règles : si un batch passe, canTransfer a dit oui pour le total de chaque token id avant l’appel. Et les transferts d’un détenteur ne font jamais passer son solde sous le montant gelé, s’il n’y était pas déjà. Transferts forcés et burns privilégiés ont leur propre règle.
Non. Le bug se trouve dans l’implémentation de référence, dans assets/erc-7943, au sein du dépôt des ERC. Le texte normatif dit déjà que les tokens gelés ne peuvent pas être transférés par le compte, et que canTransfer doit comparer le montant à la part non gelée.
NIVEAU TERMINÉ
Ce que vous savez maintenant
- Les deux règles : rien de ce que la vue a refusé ne s’exécute, et aucun transfert du détenteur n’entame ses tokens gelés.
- Pourquoi la première règle doit porter sur le total de chaque id, pas sur chaque élément.
- Quels autres chemins vérifier, et pourquoi les chemins privilégiés ont leur règle.
Vérifiez par vous-même
Touchez ou cliquez une question pour voir la réponse.
Un routeur déplace les tokens d’un détenteur en appelant le token dans une boucle. Les deux règles s’appliquent-elles encore ?
Oui. Tout chemin qui déplace les tokens du détenteur doit respecter les deux, et une boucle est justement l’endroit où la vue et l’exécution peuvent diverger.
Ancien CTO d’Integra. Auteur nommé (1 sur 5) d’ERC-3643, premier auteur d’ERC-6960, co-auteur d’ERC-7410 et co-auteur d’ERC-8203, encore à l’état de brouillon. Conçoit des systèmes d’IA en production et des systèmes Web3 régulés.
Un projet à livrer ou un poste à pourvoir ?
Parlons de votre besoinSuivre les notes techniques
Recevez les nouveaux articles sur l’IA en production et les smart contracts par email.