
ERC721-O: 全鏈 NFT的標準協議和實現
TechFlow Selected深潮精選

ERC721-O: 全鏈 NFT的標準協議和實現
Catddle NFT 將是第一個使用 ERC721-O 開發的 全鏈 NFT。
ERC721-O由Catddle NFT的開發團隊 Catddle Lab 設計。Catddle NFT 將是第一個使用 ERC721-O 開發的 全鏈 NFT。
*ERC721-O 是完全開源的項目;歡迎在GitHub 上參與貢獻!
概述
ERC721-O 是基於ERC721的 全鏈 NFT (Non-Fungible Token)的標準協議和實現。
ERC721-O 協議旨在協助第三方程式(例如錢包/交易所)與任何實現了該協議的NFT進行統一的驗證與交互 。
ERC721-O 新增了多種跨鏈功能,並提出了一系列解決跨鏈安全問題的方案。
背景
LayerZero 是一個新的區塊鏈基礎設施,能夠提供不同區塊鏈之間的消息傳遞服務。根據 LayerZero 的論文,這種消息傳遞服務保證了有效傳遞。當接收方收到來自有效傳遞服務的消息 m 時,該服務會確保關聯的交易 t 有效並且已在發送方側鏈上提交。
通過這個通用消息協議,全鏈 NFT的實現成為了可能。
ERC721-O 與現有全鏈NFT*的區別

ERC721-O的改進
更安全
· 跨鏈燃料保護機制
儘管我們有非阻塞等一系列安全設計,但當跨鏈燃料限制(destination gas limit)設置比較低的時候,NFT仍然可能在跨鏈時被卡住。
為避免這種情況,我們引入了跨鏈燃料保護機制;合約所有者能夠通過設置合理的最低跨鏈燃料限制來保證所有NFT都能成功完成跨鏈,而不會出現燃料不足的現象,同時還能保證其他跨鏈能力不受影響。
· 遠程地址安全設置
更新使用中的全鏈 NFT 合約可能會導致資金永久損失。此外,當將全鏈NFT的合約部署到新鏈,且未按照特定的函數調用順序調用時,NFT可能會在跨鏈時被阻塞,甚至永久丟失。
為了解決這些問題,ERC721-O引入了安全的遠程地址設置機制。通過該機制合約所有者可以避免合約更新中的資金損失問題,且無需關心區塊鏈之間的函數調用順序。
· 固定三方庫版本
發送和接收消息依賴於 LayerZero 庫。在 LayerZero 更新時,必須有能力固定第三方庫的版本以避免升級帶來的潛在錯誤。這也是 LayerZero 官方推薦的最佳做法。
· 保留最後手段
即使引入了多種安全設計(例如,非阻塞,跨鏈燃料保護),仍然有可能出現消息路徑被阻塞並且無法成功重試的情況。
forceResumeReceive是我們可以使用的最後手段,否則鏈錯誤將被永久卡住。我們把它作為最後的手段保留在實現中。
更多功能
· 提供三方轉賬 (Approval) 模式
批准(Approve)第三方轉移你的Token是 ERC20 和 ERC721 中提供的一項關鍵能力。我們添加此功能是為了幫助第三方應用程序能夠更好地與全鏈NFT交互。
· 自由選擇跨鏈轉賬目標地址
用戶現在可以將NFT轉移到其他鏈上的任何地址,而不是隻將NFT轉移到另一條鏈上的同一地址。
· 發送NFT同時可以完成Gas空投
在用戶將 NFT 發送到另一條鏈後,如果用戶想使用它,則需要將額外的原生燃料(Ether、BNB、AVAX 等)發送到在目標鏈上的地址,這個額外的步驟很麻煩。
現在Gas跨鏈空投能夠直接與發送NFT同時完成, 在目標鏈上不再需要額外的操作。
· 允許使用token支付跨鏈手續費
當 LayerZero 推出其Token時,用戶可以通過設置特定的Token所有者來支付跨鏈費用。他們也許會提供一些折扣:)
更透明
· 關鍵部署信息公開
在ERC721-O協議設計中,發送端口地址(endpoint)和遠程合約地址(remote)都需要強制公開,所以任何用戶和第三方都可以檢查發送端口地址(endpoint)是否來自LayerZero官方,以及遠程合約地址(remote)是否正確設置。
因此,交易所和錢包等第三方可以輕鬆地為 ERC721-O Token實施檢查機制,以保護用戶免受潛在的資金損失。
· 重要鏈上活動披露
當重要的鏈上活動發生時,發送事件可以幫助用戶和第三方在第一時間瞭解在鏈上發生了什麼。
在 ERC721-O 接口設計中,向另一條鏈發送NFT和接收NFT都會強制發送事件。這可以幫助用戶和第三方清楚地瞭解鏈上發生的事情。
在 ERC721-O 實現中,其他關鍵的活動(例如暫停,設置遠程合約地址)也會發出事件以通知用戶發生重要變化。
· 允許進行Nonce跟蹤
Nonce標誌了某筆交易是從特定地址發送的第幾筆。LayerZero 提供Nonce跟蹤能力,ERC721-O將其納入合約的跨鏈事件中。通過發生的事件提供的信息,用戶和第三方可以輕鬆匹配源鏈和目標鏈上的交易。
減少Gas消耗
由於 LayerZero 已經為用戶做了 gas 預估檢查,所以發送消息前的 gas 預估檢查是多餘的。ERC721-O將其刪除以減少跨鏈時的燃料消耗。
代碼易於覆蓋和重用
所有函數和變量都設計為易於覆蓋和重用。
作為基類,virtual、override和internal被廣泛用於代碼中,並提供了良好的註釋,以便在開發者繼承合約代碼時給出更明確的提示與指引。
安全設計背後的原理
LayerZero 官方提供了很好的基本實現示例。此外,像Gh0stly Gh0sts這樣的NFT向所有人證明了跨鏈 NFT 的巨大潛力。
但是,如果 全鏈Token想要走得更遠,必須注意並解決一些嚴重的安全問題。為了解決這些問題,ERC721-O 引入了一系列特有的安全設計。
在我們深入介紹具體設計之前,這裡應該介紹一個重要的概念:跨鏈消息阻塞。跨鏈消息阻塞是一種無法從源合約向目標鏈送達消息的狀態。在這種狀態下,源合約能夠繼續發送消息,但它們都被卡在空中,不在源鏈上也不在目標鏈上,無法被接受和執行。
它不僅讓NFT用戶感到不愉快,而且是一種危險的狀態,因為:
所有阻塞消息都在鏈上消失,並在 LayerZero 維護的隊列中等待,這可能會存在風險。
如果失敗消息無法解析,被阻塞的消息隊列將永遠卡住。
如果合約所有者使用forceResumeReceive函數處理失敗的消息,而非retryPayload,則失敗的消息可能會永遠丟失。請注意,在全鏈NFT的實現中,丟失消息等同於丟失NFT。
因此,安全設計的主要目標就是儘量減少消息阻塞的可能性。
· 跨鏈燃料保護機制
需要注意的是,即使使用非阻塞機制,Token也可能由於跨鏈燃料限制(desination gas limit)較低的問題而被卡住。
在 ERC721-O 設計中,適配器參數向用戶完全開放以提供更多能力,例如可以在發送NFT的同時空投Gas Token (例如Ether, BNB, AVA等)。用戶還可以根據需要手動設置跨鏈燃料限制。如果用戶設置100為跨鏈燃料費限制,然後發起跨鏈請求,這對於 LayerZero 端點是合法的,但實際會造成交易阻塞。即使使用非阻塞模式也是如此。
這是因為當跨鏈燃料限制過低時,接收方鏈上的交易將在 try-catch 部分代碼運行之前失敗。換句話說,非阻塞模式在這種情況下無效。
為了解決這個問題,ERC721-O引入了燃料保護機制。這個機制將檢查用戶輸入適配器參數的有效性。如果適配器參數不合法或分配的燃料低於合約所有者指定的最小燃料限制,則交易將將無法發送。這個保護機制並不會限制用戶使用增強型適配器參數,用戶依然可以通過增強型參數來實現空投Gas等功能。
通過這個機制,合約所有者可以根據他們的接收函數的燃料消耗設置一個合理的最小燃料限制,以避免出現阻塞問題。
·遠程地址安全設置
任何人都可以通過 LayerZero 向任何人發送消息,因此必須設置遠程合約以避免執行來自他人的非法消息。在現有實現中,setTrustedRemote函數就能夠幫助限制消息發送方。合約所有者將調用setTrustRemote 設置遠程合約地址,然後該合約將只收到來自該遠程合約的消息。
這聽起來很合理,但這裡沒有考慮不同鏈上操作提交的時間總是存在間隔。
假設一個場景,A 鏈上的合約 a 和 B 鏈上的合約 b 已經相互設置對方為遠程合約,並都處於使用中。使用中意味著兩條鏈上都有已鑄造的NFT存在。而現在我們希望將 A 鏈上的合約 a 更新為同在 A 鏈上的新合約 c。
我們可以簡單地在 B 鏈上調用setTrustRemote函數,將 c 設置為合約 b 的新遠程合約地址。但這樣可能會發生糟糕的情況。此時 A 鏈上的用戶仍可以繼續向 B 鏈發送NFT,而由於 B 鏈上的遠程合約地址已改變,不再是 A 鏈,因此他們發送的所有NFT將永久丟失。請注意,非堵塞機制在這裡無濟於事,因為它僅在正確設置遠程合約地址後才會起作用。
相反的,即使我們先更改合約 a 的遠程合約地址,結果也是如此。 B 鏈上的NFT用戶可以在B 鏈也設置好之前發送NFT給合約 a。這也將導致NFT永久丟失,因為合約 a 上的遠程合約地址已經被更改,並且不再會設置到合約 b 的地址。
這裡需要注意的是,我們永遠無法確保不同鏈上的操作可以同時發生。那麼似乎我們無法在合約正在使用之後去更新合約?
其實是有辦法解決的,例如ERC721-O中的的遠程合約安全設置機制就可以解決這個問題。我們引入了一個pauseMove函數,它接受一個參數chainId。它會將move功能在chainId 鏈上加鎖。這意味著當前鏈上的用戶暫時無法向chainId鏈發送NFT。合約所有者可以在確認兩條鏈上的setRemote操作均已經確認後,再調用unPauseMove(chainId)以解鎖對chainId鏈進行move操作,以便用戶可以再次向chainId鏈發送NFT。
通過這樣的設計,合約所有者得以處理使用中合約的更新問題。回到我們的例子,合約所有者可以在 B 鏈上調用pauseMove(A),這樣 B 鏈上的用戶會無法向 A 鏈發送NFT,而 A 鏈上的用戶可以繼續向 B 鏈發送NFT。請注意,此時合約 b 仍然可以正確地接收來自合約 a 的NFT,因此在這段時間間隔內不會丟失任何NFT。然後合約所有者在 A 鏈的合約 a 上調用pauseMove(B),這樣 A 鏈上的用戶也無法向 B 鏈發送NFT。同樣的,還需要在A 鏈的合約 c 上調用pauseMove(B)。
這時候合約所有者就可以以任意的順序在合約 b 和 合約 c 上調用setRemote函數將對方設置為遠程合約地址。最後通過在合約 b 和合約 c 上調用unpause來恢復跨鏈發送,至此 A 鏈上的合約 a 就成功地被合約 c 替換了。
這種設計也適用於其他場景。例如,當一個部署在 A 鏈上並且已經在使用的NFT想要部署到 B 鏈上時,合約所有者必須首先在 B 鏈上設置遠程地址,否則NFT可能會被卡住。有了pauseMove功能,合約所有者就可以先pauseMove然後再在鏈 A 或鏈 B 上設置對方為遠程合約地址,而不必擔心函數調用順序帶來的影響。
事實上這種模式還可以擴展到其他類型的Token,例如 ERC20,這裡不再詳細展開。
討論
· 我們應該取消鏈上燃料估算嗎?
LayerZero 官方文檔建議進行鏈上燃料估算,以避免在目標鏈上發生交易失敗。
但事實上他們已經在 官方部署的智能合約中實施了這項檢查。另外,對於多種消息類型的情況,即使是進行鏈上燃料估計也無保證源鏈上燃料估計的正確性。此外,即使燃料估計錯誤,具有非阻塞設計的ERC721-O合約也可以完美地處理這個問題,而不會造成任何重大的損失。
因此,強制執行鏈上燃料估算似乎並沒有實質上的意義,我們將其從我們當前的協議版本中移除了。
· 我們應該移除forceResumeReceive函數嗎?
ForceResumeRecive功能很可能會導致資金損失。但是,如果某條意外的錯誤消息卡住了消息路徑並且無法成功重試,ForceResumeRecive是清除這樣的阻塞狀態的唯一方法。需要注意的是,非阻塞設計並不能始終確保消息路徑處於暢通狀態。為避免發生意料之外的阻塞,我們將其保留在當前實現中。當且僅當您的合約具有 IFG性質時(即時確定性)時,您才能覆蓋此函數並令其無效。即時確定性意味著如果交易在源鏈被接受,那麼它也將在目標鏈被接受。
阻塞對用戶體驗有害,甚至會帶來資金損失的風險的。因此,我們希望儘量減少阻塞發生可能性。鑑於交易的順序在 NFT 跨鏈操作中並不重要,我們可以利用 非阻塞機制來確保在發生一些意外錯誤/異常發送後,消息路徑仍然是暢通的。如果您的合約能夠確保在經過遠程地址檢查後總是正確執行,則可以移除非阻塞機制的部分。
ERC721-O 仍然是一個開放的需要社區共建的全新標準。我們相信,ERC721-O 將在社區的貢獻下,成為全鏈 NFT 的標準協議。
以上所有結論均來自 LayerZero 實驗室的開源文檔和開源代碼,以及在 LayerZero 官方節點上的實驗。如果您發現任何錯誤,非常感謝您可以發表評論或者在 Github 中或提出issue。感謝您的閱讀!
* 注: 我們在文中使用Gh0stly Gh0sts實現和官方示例作為對比的標準
歡迎加入深潮 TechFlow 官方社群
Telegram 訂閱群:https://t.me/TechFlowDaily
Twitter 官方帳號:https://x.com/TechFlowPost
Twitter 英文帳號:https://x.com/BlockFlow_News















