剖析非同質化代幣ERC721-全面解析ERC721標準

Tiny熊發表於2018-03-26

最新內容會更新在主站深入淺出區塊鏈社群
原文連結:剖析非同質化代幣ERC721-全面解析ERC721標準

什麼是ERC-721?現在我們看到的各種加密貓貓狗狗都是基於ERC-721創造出來的,每隻都是一個獨一無二的ERC-721代幣,不過ERC-721在區塊鏈世界遠不止貓貓狗狗,它更大的想象空間在於將物理世界的資產對映到區塊鏈上。本文就來剖析下什麼是ERC721.

ERC721是什麼

建立代幣一篇,我們講到過ERC20代幣,
和ERC20一樣,ERC721同樣是一個代幣標準,ERC721官方簡要解釋是Non-Fungible Tokens,簡寫為NFTs,多翻譯為非同質代幣。

ERC721 是由Dieter Shirley 在2017年9月提出。Dieter Shirley 正是謎戀貓CryptoKitties背後的公司Axiom Zen的技術總監。因此謎戀貓也是第一個實現了ERC721 標準的去中心化應用。ERC721號提議已經被以太坊作為標準接受,但該標準仍處於草稿階段。本文介紹的ERC721標準基於最新(2018/03/23官方提議。

那怎麼理解非同質代幣呢?

非同質代表獨一無二,謎戀貓為例,每隻貓都被賦予擁有基因,是獨一無二的(一隻貓就是一個NFTs),貓之間是不能置換的。這種獨特性使得某些稀有貓具有收藏價值,也因此受到追捧。

ERC20代幣是可置換的,且可細分為N份(1 = 10 * 0.1), 而ERC721的Token最小的單位為1,無法再分割。

如果同一個集合的兩個物品具有不同的特徵,這兩個物品是非同質的,而同質是某個部分或數量可以被另一個同等部分或數量所代替。

非同質性其實廣泛存在於我們的生活中,如圖書館的每一本,寵物商店的每一隻寵物,歌手所演唱的歌曲,花店裡不同的花等等,因此ERC721合約必定有廣泛的應用場景。通過這樣一個標準,也可建立跨功能的NFTs管理和銷售平臺(就像有支援ERC20的交易所和錢包一樣),使生態更加強大。

ERC721標準

ERC721最為一個合約標準,提供了在實現ERC721代幣時必須要遵守的協議,要求每個ERC721標準合約需要實現ERC721及ERC165介面,介面定義如下:

pragma solidity ^0.4.20;

interface ERC721 /* is ERC165 */ {

    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    function balanceOf(address _owner) external view returns (uint256);
    function ownerOf(uint256 _tokenId) external view returns (address);
    
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
    
    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

介面說明:

  • balanceOf(): 返回由_owner 持有的NFTs的數量。
  • ownerOf(): 返回tokenId代幣持有者的地址。
  • approve(): 授予地址_to具有_tokenId的控制權,方法成功後需觸發Approval 事件。
  • setApprovalForAll(): 授予地址_operator具有所有NFTs的控制權,成功後需觸發ApprovalForAll事件。
  • getApproved()、isApprovedForAll(): 用來查詢授權。

  • safeTransferFrom(): 轉移NFT所有權,一次成功的轉移操作必須發起 Transer 事件。函式的實現需要做一下幾種檢查:
  1. 呼叫者msg.sender應該是當前tokenId的所有者或被授權的地址
  2. _from 必須是 _tokenId的所有者
  3. _tokenId 應該是當前合約正在監測的NFTs 中的任何一個
  4. _to 地址不應該為 0
  5. 如果_to 是一個合約應該呼叫其onERC721Received方法, 並且檢查其返回值,如果返回值不為bytes4(keccak256("onERC721Received(address,uint256,bytes)"))丟擲異常。
    一個可接收NFT的合約必須實現ERC721TokenReceiver介面:
    interface ERC721TokenReceiver {
        /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
        function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);
    }
  • transferFrom(): 用來轉移NFTs, 方法成功後需觸發Transfer事件。呼叫者自己確認_to地址能正常接收NFT,否則將丟失此NFT。此函式實現時需要檢查上面條件的前4條。

ERC165 標準

ERC721標準同時要求必須符合ERC165標準 ,其介面如下:

interface ERC165 {
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

ERC165同樣是一個合約標準,這個標準要求合約提供其實現了哪些介面,這樣再與合約進行互動的時候可以先呼叫此介面進行查詢。
interfaceID為函式選擇器,計算方式有兩種,如:bytes4(keccak256('supportsInterface(bytes4)'));ERC165.supportsInterface.selector,多個函式的介面ID為函式選擇器的異或值。
關於ERC165,這裡不深入介紹,有興趣的同學可以閱讀官方提案

可選實現介面:ERC721Metadata

ERC721Metadata 介面用於提供合約的後設資料:name , symbol 及 URI(NFT所對應的資源)。
其介面定義如下:

interface ERC721Metadata /* is ERC721 */ {
    function name() external pure returns (string _name);
    function symbol() external pure returns (string _symbol);
    function tokenURI(uint256 _tokenId) external view returns (string);
}

介面說明:

  • name(): 返回合約名字,儘管是可選,但強烈建議實現,即便是返回空字串。
  • symbol(): 返回合約代幣符號,儘管是可選,但強烈建議實現,即便是返回空字串。
  • tokenURI(): 返回_tokenId所對應的外部資原始檔的URI(通常是IPFS或HTTP(S)路徑)。外部資原始檔需要包含名字、描述、圖片,其格式的要求如下:
{
    "title": "Asset Metadata",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "Identifies the asset to which this NFT represents",
        },
        "description": {
            "type": "string",
            "description": "Describes the asset to which this NFT represents",
        },
        "image": {
            "type": "string",
            "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive.",
        }
    }
}

tokenURI通常是被web3呼叫,以便在應用層做相應的查詢和展示。

可選實現介面:ERC721Enumerable

ERC721Enumerable的主要目的是提高合約中NTF的可訪問性,其介面定義如下:

interface ERC721Enumerable /* is ERC721 */ {
    function totalSupply() external view returns (uint256);
    function tokenByIndex(uint256 _index) external view returns (uint256);
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

介面說明:

  • totalSupply(): 返回NFT總量
  • tokenByIndex(): 通過索引返回對應的tokenId。
  • tokenOfOwnerByIndex(): 所有者可以一次擁有多個的NFT, 此函式返回_owner擁有的NFT列表中對應索引的tokenId。

補充說明

NTF IDs

NTF ID,即tokenId,在合約中用唯一的uint265進行標識,每個NFT的ID在智慧合約的生命週期內不允許改變。推薦的實現方式有:

  1. 從0開始,每新加一個NFT,NTF ID加1
  2. 使用sha3後uuid 轉換為 NTF ID

與ERC-20的相容性

ERC721標準儘可能遵循 ERC-20 的語義,但由於同質代幣與非同質代幣之間的根本差異,並不能完全相容ERC-20。

交易、挖礦、銷燬

在實現transter相關介面時除了滿足上面的的條件外,我們可以根據需要新增自己的邏輯,如加入黑名單等。
同時挖礦、銷燬儘管不是標準的一部分,我們可以根據需要實現。

參考實現

參考實現為訂閱使用者專有福利,請訂閱我的小專欄:區塊鏈技術檢視。

參考文獻

  1. EIPS-165
  2. EIPS-721

歡迎來我的知識星球深入淺出區塊鏈討論區塊鏈,作為星友福利,星友可加入區塊鏈技術付費交流群。
深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術部落格。

相關文章