ERC721标准简析

ERC20是可替代型通证,ERC721则是不可替代型通证。这意味着每个通证是完全不同的, 并且每个通证对不同的用户都有不同的价值。 这种类型通证最具有代表性的应用就是CryptoKittes,每一个数字猫都是独立的,因为每只猫各有千秋,而且由于不同辈分的稀缺性不同,市场价格也差异巨大。。

如果说ERC20实现了“币”,那么ERC721就实现了“货”。如果说ERC20协议本身只能发行可替代性通证(fungible token),用其来代表各种可替代性事物(如钱,证劵,积分,代币等等)。那么现实生活中大部分的事物的不可替代性(任何一个物理商品,IP,版权以及身份)就可以通过ERC721来实现。

ERC721接口简介

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 事件。
transferFrom(): 用来转移NFTs, 方法成功后需触发Transfer事件。

这里需要注意的有以下几点:

1、由于每一个NFT都是独一无二的,所以与ERC20的代币不同,ERC721的每一个NFT都有其固定的拥有者,通过一个map(uint256=>address)储存起来,通过ownerOf()来获得持有者的地址。

2、safeTransferFrom()要转移NFT所有权,首先要做以下的检查:1)调用者msg.sender就是当前tokenId的所有者或者得到了授权的地址 2)_from必须是当前tokenId的所有者地址 3)_tokenId必须是当前合约所监测的NFTs中的一个 4)_to的地址不能为0 5)如果_to是一个合约,那么它必须实现ERC721TokenReceiver接口。

3、transferFrom()也要在实现的时候检查以上前四条,与safeTransferFrom()不同之处在于调用者必须自己确认_to地址能正常接收NFT,否则将丢失此NFT。

4、使用setApprovalForAll()函数来批准一个地址来传输和处理由特定地址拥有的所有令牌,因为我们有一个全局变量operatorApprovals ,其中所有者的地址映射到批准的支票地址,然后映射到布尔。 默认设置为0或false,但通过使用setApprovalForAll()我们可以将此映射设置为true,并允许地址处理所有ERC721的拥有。

ERC721TokenReceiver

interface ERC721TokenReceiver {
    /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
    function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);
}

一个可以接受NFT的合约,必须实现 ERC721TokenReceiver 接口,转让NFT的合约应该调用其onERC721Received方法,并检查其返回值。如果返回值不为bytes4(keccak256("onERC721Received(address,uint256,bytes)"))抛出异常。

ERC721Metadata

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); 
}

ERC721Metadata 接口用于提供合约的元数据:name , symbol 及 URI(NFT所对应的外部资源)。

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

上面的四个接口中,前两个是必须实现的,后面两个可以选择性的实现。

在标准的接口中,挖矿、销毁并不是标准的一部分,但是在实际使用中,还是要尽量实现。

同样,OpenZeppelin完成了完整的ERC721的实现,感兴趣的可以去看源码:https://openzeppelin.org/

猜你喜欢

转载自blog.csdn.net/lj900911/article/details/83244561