Try   HackMD

NFT 合約 ERC721A 介紹

contributed by < steven1lung >

ERC721A 可以做到什麼

  • ERC721A 是一個實做的 IERC721,可以達到在單次鑄造多顆 NFT 時省下可觀的 gas fee。
  • 這個合約讓我們可以用鑄造一顆 NFT 的價格來鑄造多顆 NFT。
  • ERC721A 在開發的時候有跟外部的安全顧問合作來確認這個合約是可行的。
  • ERC721A 鼓勵大家使用他們的合約來省下 gas fee。

先瞭解一下 Gas Fee

Gas fee 是一個價格,在要建立或是執行一個在 Ethereum 區塊鏈上的動作時會被要求給付。通常價格都是在小數點位的 ETH,常常會被稱作 gwei 或是 nanoeth,這個 gas fee 會被用來分配 EVM 的資源來讓去中心話的應用程式像是智能合約可以在一個安全且去中心化的狀況下自主運行。

Gas fee 的價格很簡單地會被定義在 network's miners 跟 network's users的供給需求上,network's miners 在 gas fee 沒有達到要求的前提下是有權力拒絕一個 transaction,而 network's users 就是需要這些礦工的運算能力。

What changes have ERC721A done

這邊只列出三個比較主要的改變

  • 移除 IERC721Enumerable 多餘的儲存空間
    被廣泛使用的 OZ IERC732Enumerable 使用了許多多餘的空間來存每個 token 的資料,這個會讓讀取的成本降低,但是相對地寫入的時候會成本會變非常高,這個不是使用者樂見的。

  • 每一次的鑄造完再更新使用者的 balance,而不是每鑄造一顆 NFT 更新。
    假設我們現在有 2 個 tokens 而且我們想要再買 5 個。在 solidity 中,我們每更新一次 stored value 就會需要一筆 gas fee,所以如果我們每次買了一顆 token 就更新一次我們擁有的數量(2, 3, 4, 5, 6, 7),那我們所要付出的 gas fee 一定比一次把 2 更新成 7 要付的 gas fee 多許多。

  • 每一次的鑄造完再更新使用者的資料,而不是每鑄造一顆 NFT 更新
    這邊跟第二點非常相似,假如我們想要買 3 個 token,每次買一顆就更新這個 token 裡的使用者資料會浪費許多 gas fee,但是如果再買完 3 個 token,再使用 ERC721A 的儲存方式會在寫入資料時省下非常多 gas fee。

    下面會有舉例

Difference Between ERC721 and ERC721A

When you mint a token

ERC721 紀錄每個 token 被哪個位址持有的方式是將每個 token 紀錄一個位址,就算是同一個位址挖了許多 token,還是會把同一個位址記錄在每個 token 上。

而 ERC721A 只會將你的錢包位址存在你挖的第一個 token,而後面你再挖的 token,就會留白。當要查詢這個 token 被誰持有時,就可以往上找第一個不是空白的位址就可以找到持有者了。

所以 ERC721A 會在你「每次的鑄造」紀錄你的位址,而不是 ERC721 的「每鑄造一顆 NFT」就紀錄你的位址。

透過 ERC721A 的這個方式可以達到 less gas fee 跟 energy efficient。

When you sell a token


比如說我們想要將 2 號 token 賣給其他錢包位址,那 ERC721 會將持有 2 號錢包位址的改成要賣給的錢包位址,非常直覺。

而在 ERC721A 會有些不同,因為我們使用了特別的儲存錢包位址,所以在轉移 token 的時候要做一些額外的事。比如說一樣 2 號要賣掉,那 2 號的位址要被改成新的錢包位址,3 號的位址要還原成原本的 1234

但是這樣就會想說我們這樣不就在 ERC721A 要改兩次位址嗎,所以在選擇要賣出的 token 時,盡量選擇 ID 最大的來賣,理論上就可以省下一次的修改。

function ownerOf(uint256 tokenId) public view virtual override returns (address){ require(_exists(tokenId),"ERC721A: owner query for nonexistent token"); uint256 lowestTokenToCheck; if(tokenId >= maxBatchSize){ lowestTokenToCheck = tokenId - maxBatchSize + 1; } for(uint256 curr = tokenId; cur >= lowestTokenToCheck; cur--){ address owner = _owners[curr]; if(owner != address(0)){ return owner; } } revert("ERC721A: unable to determine the owner of token"); }

Example

我們來看一個使用 ERC721A 的 NFT,點這裡

Conclusion

ERC721A 在鑄造 NFT 時是可以明顯地降低 gas fee,Azuki 覺得所有的 projects 都應該努力地進步,透過改良來降低 gas fee 並且達到 O(1)。Azuki 也非常歡迎大家將 ERC721A 使用在自己的 project 中。

參考資料

Azuki
ERC721A explained
ERC721A source code