
Un mot unique provoque un « drame » : 200 millions de fonds verrouillés à jamais dans l'NFT Akutar
TechFlow SélectionTechFlow Sélection

Un mot unique provoque un « drame » : 200 millions de fonds verrouillés à jamais dans l'NFT Akutar
Cet article vous a permis d'apprendre une nouvelle méthode de mint appelée l'enchère hollandaise ainsi que son principe, et vous a fait découvrir le terme « totalBids », qui vaut 200 millions.
L'auteur de cet article, Chen Jian Jason, provient du compte WeChat « Aujourd'hui, avons-nous un peu mieux compris le monde ? ». Vous pouvez suivre ce compte pour consulter les articles précédents et échanger plus en profondeur avec l'auteur. Vous pouvez également suivre son Twitter : jason_chen998 pour rester informé des dernières actualités.
Le précédent article sur la NBA m’a épuisé, j’avais besoin de faire une pause. Mais le monde web3 est tellement passionnant qu’il y a chaque jour trop d’actualités importantes. Même pendant le week-end, je suis contraint de reprendre du service.

Aujourd’hui, un projet NFT appelé Akutar a perdu à cause d’un bug dans son contrat intelligent 11 539 ETH, soit environ 34 millions de dollars américains, ou encore 200 millions de yuans chinois, définitivement bloqués. 200 millions !
Jetons un coup d'œil à l'adresse du contrat pour contempler ces 200 millions, et imaginons la douleur insoutenable de l'équipe Akutar face à cette somme inaccessible.

Présentons brièvement Akutar. D’après la description officielle du site web et leurs publications Twitter, ce n’est pas un projet improvisé. Bien au contraire, c’est un projet sérieux et de haute qualité, tant par le soin apporté aux illustrations que par la qualité de leur feuille de route.

Son initiateur est un joueur de baseball célèbre, Micha Johnson. L’idée lui est venue après avoir entendu par hasard la conversation entre un petit garçon noir et sa mère. Le garçon demandait si un astronaute pouvait être noir. C’est ainsi que Micha Johnson a décidé de lancer une série représentant des petits garçons noirs portant un casque spatial, rêvant de devenir astronautes – une belle histoire, somme toute.

Alors pourquoi un projet fondé sur une telle histoire touchante s’est-il effondré ? En partie parce que la volonté du projet de gagner de l’argent a surpassé ses intentions philanthropiques, se retournant contre lui-même. Ce projet utilisait une méthode particulière d’enchères néerlandaises.
La méthode traditionnelle consiste à fixer un prix minimum puis à enchérir à la hausse jusqu’à ce que le dernier enchérisseur remporte l’achat – c’est l’enchère anglaise. L’enchère néerlandaise, elle, part d’un prix élevé qui baisse progressivement. Le premier à accepter le prix à un moment donné remporte l’achat. Cette méthode met à l’épreuve la psychologie humaine : chacun veut attendre le prix le plus bas, mais craint que quelqu’un d’autre ne devance son achat.
Azuki a utilisé ce modèle néerlandais, mais Akutar a modifié la méthode d’Azuki. Dans Azuki, le prix diminue dynamiquement, donc plus on achète tard, moins on paie ; acheter tôt peut coûter plus cher. Akutar a ajouté une règle de « remboursement » : bien qu’apparemment plus favorable aux utilisateurs, je pense qu’elle visait en réalité à engranger encore plus de profits.
Comme illustré ci-dessous, le prix de départ est de 3,5 ETH, diminuant de 1 ETH toutes les 6 minutes. Le prix final d’achat devient le prix de référence. Tous ceux ayant payé un prix supérieur verront la différence leur être remboursée. Par exemple, si le prix d’achat le plus bas atteint 1,5 ETH, tous les acheteurs ayant payé plus que 1,5 ETH recevront un remboursement de l’écart. Cette règle encourage les utilisateurs à acheter sans hésiter, même s’ils risquent de payer cher, car ils seront remboursés.

Akutar possède donc un grand pool de fonds stockant l’argent versé par les utilisateurs, incluant à la fois les revenus destinés à l’équipe du projet et les montants devant être remboursés. Rappelons ici une notion importante déjà abordée : un contrat intelligent fonctionne comme une adresse de portefeuille personnelle. Il s’agit d’une adresse blockchain capable de recevoir et envoyer des cryptomonnaies. Lorsque vous mintez (frappez) un NFT, vous envoyez d’abord votre argent à l’adresse du contrat, puis celui-ci vous transfère l’NFT. Autrement dit, dans toute vente primaire d’NFT, l’argent va d’abord à l’adresse du contrat, avant que l’équipe du projet ne puisse retirer les fonds vers son propre portefeuille.
Les 200 millions ont été perdus lors de cette étape de retrait, car un bug dans le code du contrat intelligent l’a rendue impossible. Or, les contrats intelligents sont immuables : contrairement au logiciel traditionnel où un bogue peut être corrigé par mise à jour, dans le web3, un bug irréparable signifie que ces 200 millions resteront à jamais inaccessibles, observés seulement de loin.
Examinons maintenant quelques lignes clés du code pour comprendre le mécanisme et identifier précisément l’origine du problème.
D’abord, comprenons le principe de l’enchère néerlandaise. On commence par obtenir le prix actuel : on récupère le timestamp du dernier bloc (block.timestamp), on soustrait le temps de début (startAt), puis on divise par 6 (car le prix baisse toutes les 6 minutes). On obtient ainsi le nombre de baisses effectuées (timeElapsed). On multiplie ce nombre par le montant de chaque baisse pour avoir le total de réduction (discount), puis on soustrait cette réduction du prix initial (startingPrice) afin d’obtenir le prix courant à payer. Dans le code, ces paramètres monétaires ne sont pas codés en dur, mais sont des variables modifiables – ce qui signifie que l’équipe du projet s’est réservé une porte dérobée pour ajuster les prix selon les circonstances, maniant ainsi plus facilement sa faucille.

Maintenant que nous savons comment le prix est calculé, examinons ce qui se passe lorsqu’un utilisateur fait une offre. Le code complet étant trop long, je vais extraire les parties essentielles.
On récupère d’abord le prix actuel mentionné ci-dessus, puis on le multiplie par la quantité demandée (amount) pour obtenir le prix total (totalPrice). Ensuite, on vérifie si le montant envoyé par l’utilisateur (value) est supérieur ou égal au prix total. S’il est suffisant, l’exécution continue.

Ici, on définit ce qu’est une offre (bid) : elle contient l’adresse de l’offreur (bidder), le prix proposé (price), le nombre total d’achats effectués (bidsPlaced) et l’état du remboursement (finalProcess) : 0 = non remboursé, 1 = remboursé, 2 = remboursement annulé.

Nous arrivons maintenant au premier piège : totalBids indique le nombre total d’NFT vendus, initialisé à 0. À chaque nouvelle offre, on ajoute la quantité achetée (amount). Retenez bien cela, nous y reviendrons.

Puis vient le deuxième piège : un paramètre nommé bidIndex sert à compter le nombre d’utilisateurs ayant fait une offre. Retenez ces deux paramètres : totalBids indique le nombre total d’NFT vendus, tandis que bidIndex indique combien de personnes ont acheté.

Passons maintenant au processus de remboursement. L’équipe du projet doit cliquer sur un bouton « processRefunds », qui lance une boucle parcourant tous les utilisateurs ayant fait une offre. Le nombre d’itérations correspond à bidIndex (le nombre d’offreurs). Pour chaque utilisateur, on vérifie si son statut finalProcess est 0 (non remboursé). Si oui, on calcule le remboursement (refund) en soustrayant le prix minimal atteint du prix qu’il a payé, puis en multipliant par la quantité achetée.
Ensuite, on passe son statut finalProcess de 0 à 1, marquant ainsi le remboursement comme effectué, empêchant toute tentative ultérieure.
Le paramètre refundProgress compte le nombre d’utilisateurs ayant été remboursés. À chaque remboursement, il augmente de 1. Comme la boucle tourne autant de fois que bidIndex, refundProgress et bidIndex devraient être identiques. Jusqu’ici, tout semble correct : le nombre d’offreurs devrait égaler le nombre de remboursés. Mais ! Regardons la suite !

Quelle est la logique du retrait des fonds par l’équipe du projet, et quelle faille empêche ce retrait ?
Voici la fonction permettant à l’équipe du projet de retirer les fonds : en cliquant sur « claimProjectFunds », ils peuvent transférer l’argent vers leur portefeuille. Trois vérifications sont effectuées : premièrement, on vérifie si la vente aux enchères est terminée. Si oui, on passe à la deuxième vérification : le nombre de remboursements (refundProgress) doit être supérieur au nombre total d’unités vendues (totalBids). L’intention semble bonne – garantir que tous les remboursements soient faits avant que l’équipe retire les fonds. Mais justement, c’est ici que le bug apparaît. Souvenez-vous, totalBids signifie le nombre total d’NFT vendus, PAS le nombre de personnes ayant acheté !

Vous allez me dire : et alors ? Une personne peut acheter plusieurs NFTs à la fois. Le nombre de remboursements concerne donc le nombre d’acheteurs, pas le nombre d’objets vendus. Exiger que le nombre de remboursements dépasse le nombre total d’objets vendus est absurde, car une seule personne achetant 2 unités suffit à rendre cette condition impossible à remplir. Par exemple, 10 acheteurs pour 11 objets vendus : comment exiger que 10 > 11 ?
Consultons Etherscan : refundProgress vaut 3699, ce qui signifie que 3699 personnes ont fait une offre. Mais totalBids vaut 5495, soit 5495 objets vendus, largement supérieur à 3699. refundProgress ne pourra donc jamais dépasser totalBids. Ces 200 millions resteront à jamais prisonniers du contrat, exposés à la vue de tous comme une œuvre d’art tragique.


L’équipe du projet a donc mal écrit un mot. Elle voulait écrire bidIndex (nombre d’acheteurs), mais a écrit totalBids (nombre d’objets vendus). Un seul mot, valant 200 millions. C’est probablement le mot le plus cher du monde. Souvenez-vous bien de ce mot : totalBids. C’est lui qui vaut 200 millions !
À travers cet article, nous avons étudié une nouvelle méthode de minting : l’enchère néerlandaise, et découvert un mot unique valant 200 millions.
Bienvenue dans la communauté officielle TechFlow
Groupe Telegram :https://t.me/TechFlowDaily
Compte Twitter officiel :https://x.com/TechFlowPost
Compte Twitter anglais :https://x.com/BlockFlow_News














