
1語から生じた「悲劇」:Akutar NFTの2億ドルが永久にロックされてしまう
TechFlow厳選深潮セレクト

1語から生じた「悲劇」:Akutar NFTの2億ドルが永久にロックされてしまう
この記事を通じて、皆様に新しいミント方式であるダッチオークションとその原理を学んでいただき、また「totalBids」という2億の単語についてもご紹介しました。
本記事の著者は陳剣jasonで、微信公式アカウント「今日はこの世界をもう少し理解できたかな」として公開されています。皆さんは公式アカウントをフォローして過去の記事をご覧になり、著者とより深くコミュニケーションを取ることもできますし、著者のTwitter:jason_chen998をフォローして最新情報を入手することもできます。
前回のNBAの記事を書いた後はあまりに疲れ果て、しばらく休むつもりでしたが、web3の世界はあまりに刺激的で毎日多くの大ニュースが発生しており、週末にもかかわらずまた強制的に仕事モードに戻ってしまいました。

本日、あるNFTプロジェクト「Akutar」がコントラクトのバグにより、11,539ETH(約3,400万ドル、2億人民元)が永久に引き出せなくなり、ロックされてしまいました。なんと2億人民元です!
まず、この2億円を見て羨ましく思いながら、コントラクトのアドレスを開き、Akutarチームがこの数字を前に抱えて号泣している様子を想像してみましょう。

まずAkutarについて紹介します。公式サイトや彼らのTwitterからわかるように、これはいわゆる「土臭い」プロジェクトではなく、非常に丁寧に作られた高品質なプロジェクトです。精緻な画風やロードマップの記述の質の高さからもそれがうかがえます。

このプロジェクトの発起人は有名な野球選手Micha Johnsonで、彼がある黒人少年と母親の会話を偶然耳にしたことがきっかけでした。少年が「宇宙飛行士って黒人でもなれるの?」と尋ねたことから、Micha Johnsonは宇宙飛行士を目指すヘルメットを被った黒人少年の一連のイラストを発行しようと決意しました。なかなか素敵な物語です。

しかし、こういった心温まる背景を持つNFTプロジェクトがなぜ失敗してしまったのでしょうか?ある意味では、プロジェクト側の利益追求が「心温まる慈善活動」よりも勝り、結果として自ら石を投げて自分の足を打ってしまったのです。彼らは比較的珍しい「オランダ式オークション」方式を採用していたためです。
従来のオークション方式は最低価格を設定し、参加者が徐々に価格を上げていき、最終的に最高入札者が購入するという「イギリス式オークション」ですが、「オランダ式オークション」は逆に最高価格からスタートし、時間とともに価格が下がっていき、誰かがその価格で買うまで続けられます。オランダ式オークションは人間心理を試されるもので、誰もが最も安い価格を待っている一方で、他の人が先に買ってしまうことを恐れます。
Azukiもオランダ式オークションを使用していますが、Akutarはさらに独自の変更を加えています。Azukiの価格は動的に下がっていくため、遅く買うほど安く、早く買うと損をする可能性があります。一方、Akutarは「返金」ルールを追加しました。一見するとユーザーに優しい仕組みに見えますが、実際にはより多くのお金を集めるための策略だと私は考えます。
下図のように、オークション開始価格は3.5ETHで、6分ごとに1ETHずつ下がります。最終的に最も低い価格で購入した価格が基準価格となり、それより高い価格で購入したユーザーには差額が返金されます。例えば、最終的な最低販売価格が1.5ETHの場合、1.5ETHを超える価格で購入したすべてのユーザーに差額が返金されます。これにより、ユーザーは安心して早期購入でき、「安く買えたかどうか」を気にする必要がなくなります。

そのため、Akutarには巨大な資金プールがあり、ユーザーが支払ったすべてのお金がここに蓄えられます。この中にはプロジェクト側が得るべき収益だけでなく、ユーザーに返金すべき金額も含まれます。ここで一つ知識として補足します。以前の記事でも触れたように、スマートコントラクトは個人のウォレットアドレスと同じ性質を持ち、どちらもブロックチェーン上のアドレスであり、仮想通貨の受取・送金が可能です。mint(新規購入)を行う際、ユーザーはまずお金をプロジェクトのコントラクトアドレスに送金し、その後コントラクトがNFTをユーザーに送ります。つまり、NFTの一次市場販売では、まずお金がコントラクトアドレスに入り、その後プロジェクト側がそれを自分のウォレットに引き出すという流れになります。
今回2億円がロックされたのは、この「引き出し」のステップにバグがあったためです。ブロックチェーンのスマートコントラクトは改ざん不可のため、一度バグが発生すると修正できません。従来のインターネットサービスであれば「お金が引き出せない」というバグがあっても、アップデートで修復可能ですが、web3の世界では、この2億円とは永遠に隔たり、ただ眺めるしかありません。
原理を理解するために、いくつかの重要なコードが何をしているのかを見ていきましょう。そして、どこに問題があったのかを分析します。
まずオランダ式オークションの原理を学びます。現在価格を取得する処理からです。まず最新ブロックのタイムスタンプblock.timestampを取得し、現在時刻から開始時刻startAtを引き、6で割ります(6分ごとに価格が下がるため)。これにより何回価格が下がったかtimeElapsedがわかります。次に、この回数に値下げ幅を掛け、合計の割引額discountを算出します。最後に開始価格startingPriceから割引額を引いて、現在の支払い価格を決定します。コード内で言及されている金額関連のパラメータは、あらかじめコントラクトに書き込まれているわけではなく、変更可能な変数です。つまり、プロジェクト側が状況に応じて金額を調整できるように、裏口を残しているということです。

価格の計算方法がわかったところで、次にユーザーの入札プロセスで何が起きているかを見ます。コードが長すぎるので全部は貼りませんが、重要な部分だけ説明します。
まず前述の現在価格を取得し、ユーザーが購入したい数量amountを掛け、総支払額totalPriceを求めます。その後、ユーザーが実際に支払った金額valueが総額以上かどうかを判定し、十分であれば次の処理に進みます。

ここでは、入札情報bidの構成要素を定義しています。つまり、bidder(入札者アドレス)、price(入札価格)、bidsPlaced(購入数量)、finalProcess(返金状態:0=未返金、1=返金済、2=返金キャンセル)です。

ここで最初の落とし穴が登場します:totalBidsは現在までに販売されたNFTの総数を表し、初期値は0です。ユーザーが入札するたびに、その購入数量amountが加算されます。この点をしっかり覚えておいてください。後で重要になります。

続いて二つ目の落とし穴:bidIndexというパラメータを使って、入札を行ったユーザーの人数を記録しています。この二つのパラメータを覚えておいてください。totalBidsは販売されたNFTの総数を、bidIndexはNFTを購入した人の総数を記録しています。

次に、プロジェクト側によるユーザーへの返金プロセスを説明します。プロジェクト側はまず「processRefunds」というボタンをクリックして返金を開始します。このボタンの背後にあるロジックは、すべての入札ユーザーを順に処理していくものです。繰り返し回数は前述のbidIndex(入札人数)です。処理内容としては、まず各ユーザーのfinalProcess(返金状態)が0(未返金)であるかを確認し、0であれば継続処理します。そのユーザーの入札価格から最低成立価格を引き、購入数量を掛けることで、返金すべき差額refundを算出します。
その後、そのユーザーのfinalProcessを0から1に変更し、返金済みであることを示します。これにより、同じユーザーが再び返金を受け取れないようになります。
パラメータrefundProgressは返金完了した人数を記録しており、一人返金するごとに1ずつ増加します。この処理はbidIndexに基づいてループするため、理論上refundProgressとbidIndexは一致するはずです。本来は入札者数と返金対象者数が一致するべきですが、しかし!ここからが肝心です!

プロジェクト側の資金引き出しロジックはどのようになっており、どこにバグがあるのか?
以下はプロジェクト側が資金を引き出すための関数です。プロジェクト側が「claimProjectFunds」ボタンを押すことで、自分のウォレットに資金を移動できます。この処理には三段階の検証があります。第一段階はオークションが終了しているかどうかを確認し、終了していれば第二段階へ進みます。第二段階では「返金完了人数refundProgressが入札人数bidIndexを超えているか」をチェックします。一見善意の仕様ですが、ここに重大なバグがあります。totalBidsが何を意味するか思い出してください。それは「販売されたNFTの数」であって、「入札人数」ではありません!

「それで何か問題でも?」と思うかもしれません。確かにユーザーは一度の入札で複数のNFTを購入できます。つまり返金対象となるのは「購入者数」であり、要求しているのは「購入者数>販売NFT数」という条件です。しかし、一人が複数購入できる以上、たとえば1人が2個買っただけで、購入者数が販売数を超えることは理論上不可能になります。10人が11個を買った場合、どうやって「10>11」を満たせるでしょうか?
etherscanで確認してみましょう。refundProgressの数値は3,699で、つまり3,699人が入札したことを意味します。一方、totalBidsは5,495で、つまり5,495個のNFTが販売されたということです。3,699人で5,495個を売るわけですから、refundProgressがtotalBidsを超えることは永遠にあり得ません。この2億円は永遠にコントラクト内にロックされ、後世の人々に見せられるだけの存在になってしまいました。


つまり、プロジェクト側が単語を間違えたのです。本来はbidIndex(購入者数)と書くべきところを、誤ってtotalBids(販売数)と書いてしまいました。たった一つの単語が2億円の価値を持つとは、おそらく世界で最も高価な単語でしょう。皆さん、この単語「totalBids」をしっかりと覚えてください。まさにこれが2億円の価値を持っているのです!
この記事を通じて、新しいmint方法であるオランダ式オークションの仕組みとその原理を学びました。また、「totalBids」という2億円の価値を持つ単語にも出会いました。
TechFlow公式コミュニティへようこそ
Telegram購読グループ:https://t.me/TechFlowDaily
Twitter公式アカウント:https://x.com/TechFlowPost
Twitter英語アカウント:https://x.com/BlockFlow_News














