內容概要
二級標題
二級標題
二級標題
本文圍繞標準ERC721協議,描述了Mint、 safeMint、 transfer等是如何實現資產管理的,並通過解讀代碼來了解它的安全性設計和以太坊數據上鍊成本構成。
正文
正文
正文
正文
正文
二級標題
二級標題
二級標題
研發——可無障礙閱讀,理解精美的合約設計
一級標題
非研發——可能讀不懂列舉的代碼,但能體會標準協議的設計思路
在opensea上,可看到每個NFT都有個唯一的編號。
二級標題
比如azuki系列中第4132號,在頁面的Details欄目可以看到其合約地址,ID編號,部署所在公鍊等信息,而Properties欄目則是其設定的具備各種屬性,對應的稀有度(非azuki本身攜帶,而是opensea整合計算的)。
而咱們回顧到源代碼(此處取ERC721標準庫openzepplin代碼),會發現程序記錄了全局性的兩個字典類型的變量,通過_owners中用數字映射地址的方式記錄每一個ID 當前對應的所有者,同時也附帶用_balances 記錄了當前所有者總計持有的NFT數量
一級標題
並且由於ERC721創新性的賦予了一個ID對應地址的變量_owners,從而與ERC20僅_balances 進行地址與餘額的管理,區分出了FT(同質化)與NFT(非同質化)的差別。當奈飛的NFT忘記了web2的業務安全
2.1 Mint是如何進行的
當奈飛的NFT忘記了web2的業務安全
當奈飛的NFT忘記了web2的業務安全
Mint 意思為鑄造,即每個NFT的創造過程,例如之前的愛死機NFT
Mint 獲取到該NFT的資產證明。
從源代碼中可以看到,Mint 主要是進行了安全判斷:
判斷1:確保轉入的不是0x00地址(黑洞地址無法轉出,轉入則資產損失)
當奈飛的NFT忘記了web2的業務安全
判斷2:確保此交易所操作的NFTID是不存在的
最終代碼執行的操作是:
操作1:將轉入地址的_balances 所持有總數加1
操作2:將對應NFTID 的所有者修改為轉入的地址
操作3:完成交易則發出emit 事件,可以讓鏈下監聽到這次交易的數據https://eips.ethereum.org/EIPS/eip-165
中間有_beforeTokenTransfer和_afterTokenTransfer 屬於虛函數,作為標準,是讓項目方可以再不修改標準協議的情況下增加一些特定的邏輯代碼用的。
2.2 為何safeMint更安全
safeMint 意為安全的鑄造,從代碼實現中可以看到他本身也是調用了MInt 但是他額外增加了_checkOnERC721Received 的判斷,這點是屬於ERC165的標準,相當於在完成轉入操作後,則判斷對方地址,是否是黑洞地址(即無法發起交易NFT操作的地址)是防止轉入對象為合約地址時候,其合約沒有預設置好轉出的函數,導致資產在內無法被轉走,從而造成永久損失。
2.3 ERC165是如何防止資產轉入黑洞的?
是讓合約接口標準化的提案,在編程語法中interface 是接口的意思,在其中定義的函數可以不實現僅僅放上函數名字相關參數,在程序複雜的時候,相當於目錄一般告訴別人我都有什麼功能。
使用流程是:
但是接口的寫法各有千秋,名字定義參數類型,甚至是否存在都有不同,
(PS:讓合約具備NFT接收轉出功能,可通過引入IERC721Receiver.sol 拓展包來實現)
正文
正文
正文
類比一下:
transfer 轉移:由用戶調用,將本消息發送的錢包所持有的NFTID轉移到指定地址
類比一下:
類比一下:
transferFrom 從轉移:用某機構調用,需要用戶先授權某地址,讓其有權可轉移。
類比一下:
transfer 就是現金交易,從自己口袋裡拿錢支付
transferFrom 就是掃碼扣款,由店家申請扣款,受制於用戶是否開通小額代扣權限
接下來咱們從代碼來看看,其中可能有會意想不到的細節。
3.1 transfer 是如何進行的
他會檢測當前交易的from 方是否是此NFTID的持有者,並且限制該NFT轉入0x00地址。其次進行from 轉出地址和to 轉入地址的餘額刷新,修改_balances全局變量並且重新設置_owners此NFTID的所有者地址修改為to。
這裡有個防護的細節會先執行_approve(address(0), tokenId); 清空歷史授權,如果沒有這一步,則資產完成了轉移,但是其NFTID的轉移授權依舊在,細思極恐:
3.2 transferFrom是如何進行的
這的一大細節是:_msgSender() 這是openzepplin的標準庫Context.sol 中的方法。
所以一些處於中間環節的,類似library的合約需要考慮這種特殊情況。
一級標題
一級標題
其餘部分判斷是確定是否有授權記錄,易於理解,不作贅述
一級標題
4.還有哪些數據可擴展存儲在鏈上?
交易的環節也看完後,其實很多新同學也頓感奇怪,原來我買的NFT只有一個ID的歸屬地址指向了我,從而達成了唯一性。那就算如此,稀有度信息放在哪裡?我的NFT圖像本身在那裡?
這就是涉及到ERC721的元數據拓展IERC721Metadata.sol
咱們可以通過之前Etherscan教程方法來看看一些項目數據有什麼?
而近期興起的Metaverse項目元宇宙土地sandbox和****Decentraland ,以及去年火熱的****Axie Infinity ,基本鏈上存儲元數據也只是ID+網址。
一級標題
一級標題
像mirror那些是專門設計低費用可進行高存儲,一個塊常規都是30M起步,大約是以太坊的1000倍。
一級標題
5.以太坊上存儲有多貴?
這裡是本文稍難的地方。咱們從源碼來分析鏈上存儲的成本構成以及金額換算
成本產生將有2個方面,按執行流程來看
用戶發起一筆交易,將要寫鏈上數據作為參數傳入,其大小是一筆成本
交易執行合約代碼,依據修改和使用,EVM計算消耗的gas成本。
5.1 交易發起的成本
咱們可以核對下以太坊黃皮書,裡對交易數據大小所消耗gas有清晰的定義
可以看到交易所附帶的參數的價格:
每筆交易都有21000 GAS需要支付
為交易的每個非零字節數據或代碼支付68 GAS
為交易的每個零字節數據或代碼支付4 GAS
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64)(uint64, error)
所以如果是再Mint 的時候,登記上若干NFT屬性信息,交易的data部分會將abc等字符轉成2個十六進製表示,而每個字符為一個八位二進制,等於一個byte。所以可以約等於將data的長度除以2作為byte數。
而1kb的數據,如果都是非0的有信息量的文本信息,則等於增加是68*1000=6.8W 的gas消耗。按20gwei的gas價格和2000的eth兌換美元價格,可以估算出,每上鍊1kb數據在交易發起端就要:
20*(21000+68000)*1e9/1e18 * 2000 = 3.5美金
5.2合約存儲的成本
由於交易發起後,還有智能合約上存儲的邏輯,咱們從以太坊go源代碼中(EIP1283),來分析具體的消費量,代碼具體在函數內,太長了不全粘來:
歷史上GAS消耗的估算有經過若干迭代,如果是Petersburg或者Constantinople 未激活的話,則不按下面邏輯進行計算
gas消耗計算,依賴3個種數據的管理形式(增刪改)
EIP-5058 能否防止NFT項目方提桶跑路?