ERC721A
為什麼 ERC721 mint 很貴?
ERC721 mint 很貴,核心原因是它會在 mint 當下做多次鏈上狀態寫入,而 storage 寫入正是以太坊裡最花 gas 的操作之一。 如果合約還加上 ERC721Enumerable,每次 mint 還要同步維護額外索引,所以成本會再明顯上升。
Gas 來源
一般 ERC721 mint 至少要更新 token 的擁有者資料與持有者餘額,所以如果一次 mint 5 顆,通常就是對 5 個 tokenId 各自寫一次 _owners[tokenId] _balances[owner] 加一,mint N 顆就有 N 次 ownership 與 balances 寫入更新。也就是說,ERC721 如果是批量,用迴圈一次大量的 mint,這些更新會對每顆 token 重複發生一次,花費過多手續費,因此當批量 mimt 時我們要用 ERC721A 解決這個問題。
1 | _owners[tokenId] = owner |
ERC721A
設計目標
由於在 ERC721 下,批次 Mint 會消耗大量的 gas ,為了解決這個問題,我們就需要用到 ERC721A。ERC721A 的設計目標,是在符合 IERC721 的前提下,讓同一筆交易中批量 mint 多顆 NFT 時,gas 成本能大幅下降。 它由 Azuki ,一個 NFT 項目團隊提出,希望當 batch mint 時能將 gas 成本壓低。這個標準特別適合公開發售、同一地址一次買多顆,或大量地址在短時間內同時 mint 的場景。
基本原理
ERC721 在批量 Mint 時,通常每顆 token 都要各自寫入一次 tokenId -> owner 的 ownership 資料,因此 mint N 顆就接近要做 N 次的 storage 寫入。 ERC721A 的核心想法是 Ownership lazy Evaluation,當批量 mint 一段連續 tokenId 時,只先記錄這批第一顆的 ownership,後面的 token 先不逐顆寫入。
查詢方式
例如 Alice 一次 mint 3 顆時,ERC721A 只會把第一顆 token 的 owner 寫成 Alice,而後面兩顆保持未初始化狀態;當之後查詢這兩顆的 ownerOf 時,合約再往前找最近一個已記錄的 ownership,推得它們也屬於 Alice。 這樣就把原本 N 次 ownership 寫入,壓縮成 1 次寫入,從而降低 batch Mint 的 gas。
成本轉移
ERC721A 省下的是 mint 階段的大量寫入成本,但不是完全沒有代價。部分成本會被轉移到後續的transfer,因為那時合約可能要補寫 ownership 資料,避免後續 token 的所有權推導出錯。
Ownership lazy evaluation 概念
細講 Ownership,當一個 ERC721 的 TokenId 是連號且一次 mint 多顆時,我們這樣做
只在這一批的「第一顆 tokenId」寫入 ownership,後面幾顆暫時不寫。
例如一次 mint 5 顆給 Alice:ownership[startTokenId] = Alice.addressstartTokenId+1…startTokenId+4 這幾個 slot 先保持空白。
當有人之後呼叫 ownerOf(tokenId) 查某顆 NFT 時,如果發現這個 tokenId 的 ownership slot 是空的,就往前掃描,一直減一找前一個 tokenId 的 ownership,直到遇到第一個有紀錄的 slot,以那個 owner 為準。
延遲到什麼時候才會寫?
當發生 transfer,就會檢查有沒有需要補寫 owner 的欄位
ERC721A 把 ownership slot 的初始化延後到第一次 transfer,當第一次 transfer 某顆中間的 token 時,合約會順便「補寫」鄰近的 ownership,避免後面 token 的推導錯亂。以上面的例子,當 Alice將 startTokenId+3 轉給Bob時,由於 startTokenId+4 在 mint 時還沒被寫過,因此要將 startTokenId+4 的 owner 設為 Alice。