為什麼 EchoX NFT 專案 We are What We Eat 會偷跑與超賣?該如何避免?

NFT 專案持續火熱,由黃心健、江振誠與張逸軍共創之 NFT 專案 We are What We Eat 2022.1.10 11:00 優先釋出的 200 個 Seed NFTs 在 2 分鐘內全數鑄造完成,市場反應熱烈之下,項目方 EchoX 隔天(1/11)11:00 啟動第二波活動 Public Sale 預計再賣出 50 個。但第二波活動發生超賣和提前購買等問題。
項目方遭發現合約漏洞導致之超額鑄造,當時先行公告未經正常流程鑄造的 NFT 將不享有原本福利並要求退還,而後宣布於二級市場買賣之 NFT 皆可享有其原本福利補償購買客戶損失。

本次專案超賣原訂數量 200 個 NFT,項目方要求未經正常鑄造流程上架到 OpenSea 平台銷售之 NFT 應主動退回,造成已在平台搶購之粉絲錯愕與損失,智能合約在 NFT 專案中更顯重要,小型專案百萬起跳,大型專案 100 個 NFT 市值動輒超過 1 億,我們將從智能合約分析,再談該如何避免 NFT 超賣事件重演。


此次 3 位頂尖創作者與 ExchoX 的事件,我們先從項目方後續處理討論,再分析合約與討論解決方案。

一、EchoX 事件之後續處理

二、從智能合約角度分析為何會超賣與偷跑

  1. 找出合約 Mint Function
  2. 合約如何更新與設定?
  3. 為什麼會發生偷跑?(提早了 30 分鐘)
  4. 為什麼會發生超賣?(多賣了 200 個)
  5. 總結


一、EchoX 事件之後續處理

2022.1.11 放棄現有合約,原本透過官方渠道鑄造 Seed NFT 的買家,會重新空投原購買量的 Seed NFT 到你的錢包。在OpenSea 之二級市場買到「非官方 Seed NFT」的買家,EchoX 會直接空投新合約的 Seed NFT 至買家錢包,但需於 1/12 6pm(UTC+8)前 Email:service@echox.io 回報。需附上 (1.) 錢包地址 (2.) 你的 OpenSea NFT 連結。


二、從智能合約分析為何會超賣

1. 找出合約 Mint Function

在 etherscan 從合約地址去看交易紀錄

首先我們到 Transactions 看1/10, 1/11的交易紀錄,可以看到 Presale 這個 function被執行多次,Presale 需要傳送 ETH,且傳送的 ETH 也是 mint 的價格 0.095 ETH 的倍數,所以它就是 mint function。

透過 “Write Contract” 跟 “Transactions” 找出 mint function 是 presale

下面再去 “Code” 裡面仔細看 “presale” function 是怎麼作用的


presale function

presale 的功能為購買 NFT,這裡有 2 個條件 :

  • 截止時間之前才能購買(沒有規定開始時間)
  • 不能超過最大發行數量

接著我們來看一下合約要如何更新和設定。


2. 合約如何更新和設定

透過 setActivity function 來設定每一波活動
https://etherscan.io/address/0x52afa21bb061bb8a434102802c3d1625a86e9870#writeContract

setActivity 參數:

(1.) 第一波活動的合約設定
https://etherscan.io/tx/0x719ab9537f6d210f6308f22a0adf7ab78cbce11d93c0526b8f391a754162b2e4

把輸入資料(Input Data)放大來看:

從 etherscan 的活動紀錄我們可以明顯看出
第一次的設定是在 Jan-07-2022 10:54:28 AM +UTC (台北時間要 +8 小時)

setActivity 設定內容為 :
活動 ID(activityID) : 3
價格(charges.price) : 0.095 ETH
截止時間(period) : 1672272000 (Thursday, December 29, 2022 12:00:00 AM GMT)
最大發行數量(maxCirculation) : 200

(2.)第一波購買
第一波活動設定完成後就可以等人購買了,這裡 NFT 最大發行數量設定為 200 個,和官網宣布的一樣,這裡沒有問題。
但時間的設定會有點問題,因為 1672272000 的時間是 2022/12/29,這樣等同於沒有限制,但因為沒人發現,所以第一波沒有人提前購買。

訂單成立時間:2022-01-10 11:17:52 - 2022-01-10 11:21:09 (台北時間)
得到 19 eth,共賣出 200 個(每個 NFT 定價 0.095 ETH)

(3.)第二波活動的合約設定
https://etherscan.io/tx/0xf1a55b20727cbf7ee53bf18425e3cd64987337cc0239ed6e3a2982622c6eae03


我們把輸入資料(input data)放大來看:

從 etherscan 的活動紀錄我們可以明顯看出
第二次的設定是在 Jan-11-2022 02:24:32 AM +UTC (台北時間要 +8 小時)

setActivity 設定內容為 :
活動 ID(activityID) : 3
價格(charges.price) : 0.095 ETH
截止時間(period) : 1672272000 (Thursday, December 29, 2022 12:00:00 AM GMT)
最大發行數量(maxCirculation) : 250

(4.) 第二波購買
訂單成立時間:2022-01-11 10:25:32 - 2022-01-11 10:30:55 (台北時間)
得到 23.75 eth,共賣出 250個(每個 NFT 定價 0.095 ETH)

以上是兩波發行的數據,至於為什麼會發生超賣和提前購買的問題,需要從程式碼去解析。

3. 為什麼會發生偷跑? (提早了 30 分鐘)

NFT 合約的部署設定會在銷售活動開始前,通常程式碼會寫出一個未來的開啟時間,等到區塊鏈時間大於開啟時間才能購買。
通常我們會這麼寫:

require(block.timestamp >= activity.period,
        "MSActivityCenter: This activity is out of date")

意思是活動會在設定的時間後才開啟。

註:
block.timestamp 為區塊鏈時間,activity.period 為設定的開始時間


但這份合約的邏輯是相反的

時間條件(畫紅線處):

activity.period >= block.timestamp

變成在指定的時間前才能購買,也就是這份合約只設定截止時間

所以第二波偷跑是怎麼造成的?

第二波項目方設定活動時,區塊鏈時間(block.timestamp)是 2022/1/11 10:24 (換算秒數:1641896672)

activity.period 被設定為 1672272000
presale函式可以看到時間條件:

activity.period >= block.timestamp 

1672272000 >= 1641896672 # 時間條件通過

所以項目方早上 10:24 設定活動,(下圖綠框)時間條件有通過,加上最大發行量(maxCirculation)跟本次發行量(circulation) 被設定為 250 跟 0 個,所以數量限制(下圖紅框)也通過了。才造成原本預計販售時間 11 點,卻在合約一設定就立刻變成可以購買,提早了 36 分鐘。

合約優化建議:

  • 合約的時間條件可以改成

block.timestamp >= activity.startTime

將原本的 period 命名改成 startTime(開賣時間),這樣程式碼的可讀性會更高。


4.為什麼會發生超賣?(多賣了200個)

超賣

主要是人為操作的問題。因為每一波活動都需設定 setActivity 函式(上圖),這個函式會設定 NFT價格,活動截止時間,最大發行量,並將此次活動目前發行量設置為 0

在第一波結束後,已售出量為 200。設定第二波活動時,第二波活動初始發行量被設定為 0(下圖 172 行),所以最大發行量(maxCirculation) 應該設定 50,但是第二波設定時把最大發行量設定成 250,多了 200 個。

此合約設計每次活動是獨立的,最大發行量是每次活動的發行量。但是設定活動的人,把第二波的最大發行量當作本項目預計釋出的總發行量,才會有 200 落差。

第一波活動鏈上設定

第二波活動鏈上設定

最大發行量的優化建議

如果只有兩波發行活動,且已確定最大發行量,可以在一開始就設定好 maxSupply,並讓總發行量(totalSupply)不要超過這個數值。
例如 seed NFT如果一開始就打算賣 250 個,可以在 constructor 階段就設定

uint public maxSupply = 250;


總結

整起 EchoX 事件中我們發現到,合約的設計以及人為操作,確實都需要很謹慎。畢竟合約就是法律條文,從部署上鏈以後,就不能夠輕易的更改。因此合約部署之前,團隊成員彼此間及活動的執行者,都需要進行充分的溝通以及討論。如此一來,才能避免兵荒馬亂,讓團隊在應對不管是好的突發狀況,又或者是壞的突發狀況,都可以很從容地去應對,也可以降低人為操作發生問題的可能性,就像是這次 EchoX 設定數量與官網公告的有 3 倍以上的差距。

另外也很值得探討的一點是 NFT 項目方與去中心化平台之間的關係,這次 EchoX 過程中不願意承認在二級市場 Opensea 上買到的 NFT。

從中我們可以了解到去中心化世界的運作是否真的去中心,同時對於 NFT 的擁有權及 NFT 項目方給予社群回饋,中間是存在著不確定性的,原本 EchoX 所承諾的 RAW 優先訂位權以及加購享用專屬的沉浸式「We Are What We Eat」VR 與料理體驗,EchoX 如果拒絕承認,就算持有NFT,到時候也沒辦法在 RAW 使用優先訂位權的。