Akutar NFT的3400萬美金因為寫錯一個單詞被永久鎖死了?!

買賣虛擬貨幣
今天一個叫akutar 的nft 專案因為合約bug,導致11,539 個eth,價值3,400 萬美金、2 個億人民幣的錢永久取不出來被鎖死了,2 個億啊!




上篇寫nba 的文章寫的太累了大傷元氣,想休息一段時間再寫的,結果web3 的世界實在是太精彩,每天發生的大新聞太多,大週末的又被迫營業。

我們開啟合約地址看看這2 個億來眼饞眼饞,想像一下akutar 團隊望著這一串數字的抱頭痛哭的心情。



首先介紹一下akutar,從官網的描述和他們twitter 可以看出,這不是一個土狗專案,相反是一個很用心的高質量專案,不論是從精細的畫風還是roadmap 描述質量都很高。



它的發起人是一位知名的棒球運動員micah johnson,起源於他無意間聽到一位黑人小男孩與母親的對話,小男孩問母親宇航員能否是黑人,所以micah johnson 決定發行一系列夢想成為宇航員的戴著頭盔的黑人小男孩,一個還算美妙的故事。



那麼看著這麼暖心的故事背後的nft 這麼就砸了呢?從某種程度上還是專案方對於賺錢的渴望大過於所謂的暖心公益,從而搬起石頭砸了自己的腳,因為它使用了一種比較獨特的荷蘭拍方式。

傳統的拍賣方式是設定一個低價,然後大家向上叫價,最終出價最高者可購買,這是英式拍賣,荷蘭式拍賣則是先設定一個最高價,然後逐漸的降價,最終有人在某個價格點出手將其買下來,荷蘭拍更考驗人性,因為每個人都想等最低價,但是都怕別人先於自己購買。

azuki 就是用的是荷蘭拍,但是akutar 相比於azuki 的拍賣方式又做了改變,azuki 的價格是動態下降的,從而買的越晚價格越低,買的越早可能就吃了虧價格會高,akutar 則加了一個「退款」規則,該規則看起來好像對使用者更友好但是我認為實際上是想割更多的錢。

這如下圖所示,拍賣起始價格是3.5 eth,每過6 分鐘降低1eth,最終最低價格購買的人將成為標準價格,其他高於該價格購買的使用者將獲得退款,比如最後最低出售價格是1.5eth,那所有高於1.5eth出價的人均會獲得差價的退款,這種實際上是想讓使用者放心大膽的去買,不要蹲守最低價,即使買高了也能退款。



所以akutar 會有一個巨大的資金池用於儲存所有使用者交的錢,這部分錢包括專案方自己應得的,也包括需要退給使用者的,這裡先科普一個知識,之前的文章中也提到過,智慧合約的性質和你自己個人的錢包地址是一樣的,都是一個區塊鏈地址,可以接收、傳送虛擬貨幣,當你在mint 某個專案時,實際上是你先將錢打到專案合約地址,然後合約給你轉一個nft,即所有nft 的一級市場發售,錢都是先到了合約地址,再由專案方去進行提款操作,將合約裡面的錢提到自己的錢包中。

這次2 個億被鎖死就是因為在提款這個步驟出了bug,因為區塊鏈智慧合約不可篡改的特性使得出現了bug 是沒法修的,傳統網際網路如果有個bug 導致錢取不出來,修復迭代就可以,但是在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 表示尚未退款,如果為0 的話繼續向下執行,將使用者當時的報價減去最低成交價,再乘以購買數量,則等於要退給使用者的差價refund。

然後將該finalprocess 使用者退款從0 設定為1,表示已經完成退款,從而該使用者不能再去退了。

引數refundprogress 是記錄完成退款人數的,每退完一個使用者就會加1,因為是按照出價人數bidindex迴圈的,所以refundprogress 和bidindex 是一致的,這裡其實沒有毛病,本來出價的人和退款的人就應該是一樣的,但是!接著向下看!


專案方提款的邏輯是怎樣的,又有什麼漏洞導致其無法提款?


下圖為專案方進行提款的函式,即當專案方點選claimprojectfunds 按鈕後可以將錢提到自己錢包裡,這裡有三層校驗,第一層是先驗證當前是否已經結束了拍賣,如果結束進入第二層校驗退款人數是否大於報價人數,其實這裡專案方是好意,因為要確保每個人都退完了錢,專案方再提款,但就是這一層校驗出了問題,不知道你還記不記得totalbids 是什麼意思?是售出nft 數量呀,不是報價人數!



你會問那這又怎麼了呢?一個人在報價的時候是可以購買多個nft 的呀,退款人數實際上是購買人數,你要求購買人數超過賣出nft 數量,但是每人又可以買多個,那隻要有1 個人買了2 個,就意味著購買人數永遠不可能大於賣出數量,10 個人賣出了11 個,你怎麼要求10 大於11 呢?

我們上etherscan 看一下,refundprogess 的數量是3,699,說明共有3,699 人報價,但是totalbids 的數量是5,495,即共賣出了5,495 個,遠遠超過3,699,這輩子refundprogess 都不可能大於totalbids,這2 個億就永遠被鎖死在了合約中供後人觀摩。



所以是專案方寫錯單詞了,本來應該是想寫bidindex 購買人數,結果寫成了totalbids 賣出數量,一個單詞價值2 個億,這應該是全世界最貴的一個單詞了,大家給我狠狠的記住這個單詞totalbids,就是它值2 個億!

透過這篇文章帶著大家學習了一種新的mint 方式荷蘭拍以及其原理,另外帶大家認識了一個2 個億的單詞totalbids。


免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;