协议说明

VRC-721合约标准

VRC-721是在波场公链上发行非同质化代币(non-fungible token, NFT)一套标准接口,与ERC-721完全兼容。由于 VRC-721 中的每个代币都是唯一的,因此 VRC-20 标准不足以处理 NFT。

必须实现的接口

每个符合VRC-721标准的智能合约都必须实现VRC721与VRC165接口。

pragma solidity ^0.4.20;

  interface VRC721 {
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _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);
  }
  interface VRC165 {
      function supportsInterface(bytes4 interfaceID) external view returns (bool);
  }

balanceOf(address _owner)
返回指定账户拥有的 NFT 数量

ownerOf(uint256 _tokenId)
返回指定 NFT 的所有者

safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data)
转让 NFT 的所有权

safeTransferFrom(address _from, address _to, uint256 _tokenId)
转让 NFT 的所有权

transferFrom(address _from, address _to, uint256 _tokenId)
转让一个NFT的所有权(调用者必须确认_to地址是否可以正常接收NFT,否则NFT会丢失)

approve(address _approved, uint256 _tokenId)
授予其他人 NFT 的控制权

setApprovalForAll(address _operator, bool _approved)
由第三方 (_operator) 授予/恢复对所有 NFT 的控制权

getApproved(uint256 _tokenId)
查询某个 NFT 的授权

isApprovedForAll(address _owner, address _operator)
查询operator是否为业主授权地址

supportsInterface(bytes4 interfaceID)
查询是否支持某个接口(interfaceID)

event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId)
Approve 成功后会触发 Approval 事件

event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId)
成功的 transferFrom 和 safeTransferFrom 将触发 Transfer 事件

event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved)
setApprovalForAll 成功后会触发 ApprovalForAll 事件

合约如果需要接受安全转账,必须实现VRC721TokenReceiver接口:

   interface VRC721TokenReceiver {
     //This method will be triggered when the ‘_to’ is the contract address during the ‘safeTransferFrom’ execution, and the return value must be checked, If the return value is not  bytes4(keccak256("onVRC721Received(address,address,uint256,bytes)")) throws an exception. The smart contract which can receive NFT must implement the VRC721TokenReceiver interface.
       function onVRC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external                returns(bytes4);
   }

onVRC721Received(address _operator, address _from, uint256 _tokenId, bytes _data)

safeTransferFrom方法配合使用,当_to为合约地址时,需要调用该方法并检查返回值。 如果返回值不是 bytes4(keccak256("onVRC721Received(address,address,uint256,bytes)")) 将抛出异常。 可以接收 NFT 的智能合约必须实现 VRC721TokenReceiver 接口。

📘

注意

bytes4(keccak256("onVRC721Received(address,address,uint256,bytes))) 的哈希值与以太坊版本 bytes4(keccak256("onERC721Received(address,address,uint256,bytes))) 不同。 对于函数onTRC721Received的返回值,请使用0x47f3171e而不是0x150b7a02。

metadata extension接口(可选)

metadata extension接口对于TRC-721智能合约来说是可选的,用户可以查询智能合约的名称以及NFT代表的资产的详细信息。

 interface VRC721Metadata {
     function name() external view returns (string _name);
     function symbol() external view returns (string _symbol);
     function tokenURI(uint256 _tokenId) external view returns (string);
  }

name()
返回合约名称

symbol()
返回合约代码

tokenURI(uint256 _tokenId)
返回 _tokenId 对应的外部文件的 URI。 外部资源文件需要包括名称、描述和图片。

enumeration extension接口(可选)

enumeration extension对于VRC-721智能合约是可选的,允许用户的智能合约发布其NFT的完整列表并使其可见。

interface VRC721Enumerable  {
    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(uint256 _index)
通过_index返回对应的tokenId

tokenOfOwnerByIndex(address _owner, uint256 _index)
返回所有者拥有的 NFT 列表中索引对应的 tokenId