ERC721介绍

数字加密货币大致可以分为原生币(coin)和代币(token)两大类。前者如BTC、ETH等,拥有自己的区块链。后者如Tether、TRON、ONT等,依附于现有的区块链。市场上流通的基于以太坊的代币大都遵从ERC20协议。最近出现了一种被称为ERC721的数字加密资产,例如CryptoKitties。

ERC20可能是其中最广为人知的标准了。它诞生于2015年,到2017年9月被正式标准化。协议规定了具有可互换性(fungible)代币的一组基本接口,包括代币符号、发行量、转账、授权等。所谓可互换性(fungibility)指代币之间无差异,同等数量的两笔代币价值相等。交易所里流通的绝大部分代币都是可互换的,一单位的币无论在哪儿都价值一单位。

与之相对的则是非互换性(non-fungible)资产。比如CryptoKitties中的宠物猫就是典型的非互换性资产,因为每只猫各有千秋,而且由于不同辈分的稀缺性不同,市场价格也差异巨大。这种非标准化资产很长时间内都没有标准协议,直到2017年9月才出现ERC721提案,定义了一组常用的接口。ERC721至今仍旧处于草案阶段,但已经被不少dApp采用,甚至出现了专门的交易所。

ERC721标准

下面先给出ERC721标准的具体内容,后面会讲解。

每个符合ERC721标准的合约必须实现ERC721ERC165接口。

  1. pragma solidity ^0.4.20;
  2. /// @title ERC-721 Non-Fungible Token Standard
  3. /// @dev See https://eips.ethereum.org/EIPS/eip-721
  4. /// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
  5. interface ERC721 /* is ERC165 */ {
  6. /// @dev This emits when ownership of any NFT changes by any mechanism.
  7. /// This event emits when NFTs are created (`from` == 0) and destroyed
  8. /// (`to` == 0). Exception: during contract creation, any number of NFTs
  9. /// may be created and assigned without emitting Transfer. At the time of
  10. /// any transfer, the approved address for that NFT (if any) is reset to none.
  11. event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
  12. /// @dev This emits when the approved address for an NFT is changed or
  13. /// reaffirmed. The zero address indicates there is no approved address.
  14. /// When a Transfer event emits, this also indicates that the approved
  15. /// address for that NFT (if any) is reset to none.
  16. event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
  17. /// @dev This emits when an operator is enabled or disabled for an owner.
  18. /// The operator can manage all NFTs of the owner.
  19. event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
  20. /// @notice Count all NFTs assigned to an owner
  21. /// @dev NFTs assigned to the zero address are considered invalid, and this
  22. /// function throws for queries about the zero address.
  23. /// @param _owner An address for whom to query the balance
  24. /// @return The number of NFTs owned by `_owner`, possibly zero
  25. function balanceOf(address _owner) external view returns (uint256);
  26. /// @notice Find the owner of an NFT
  27. /// @dev NFTs assigned to zero address are considered invalid, and queries
  28. /// about them do throw.
  29. /// @param _tokenId The identifier for an NFT
  30. /// @return The address of the owner of the NFT
  31. function ownerOf(uint256 _tokenId) external view returns (address);
  32. /// @notice Transfers the ownership of an NFT from one address to another address
  33. /// @dev Throws unless `msg.sender` is the current owner, an authorized
  34. /// operator, or the approved address for this NFT. Throws if `_from` is
  35. /// not the current owner. Throws if `_to` is the zero address. Throws if
  36. /// `_tokenId` is not a valid NFT. When transfer is complete, this function
  37. /// checks if `_to` is a smart contract (code size > 0). If so, it calls
  38. /// `onERC721Received` on `_to` and throws if the return value is not
  39. /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  40. /// @param _from The current owner of the NFT
  41. /// @param _to The new owner
  42. /// @param _tokenId The NFT to transfer
  43. /// @param data Additional data with no specified format, sent in call to `_to`
  44. function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
  45. /// @notice Transfers the ownership of an NFT from one address to another address
  46. /// @dev This works identically to the other function with an extra data parameter,
  47. /// except this function just sets data to "".
  48. /// @param _from The current owner of the NFT
  49. /// @param _to The new owner
  50. /// @param _tokenId The NFT to transfer
  51. function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
  52. /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  53. /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
  54. /// THEY MAY BE PERMANENTLY LOST
  55. /// @dev Throws unless `msg.sender` is the current owner, an authorized
  56. /// operator, or the approved address for this NFT. Throws if `_from` is
  57. /// not the current owner. Throws if `_to` is the zero address. Throws if
  58. /// `_tokenId` is not a valid NFT.
  59. /// @param _from The current owner of the NFT
  60. /// @param _to The new owner
  61. /// @param _tokenId The NFT to transfer
  62. function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
  63. /// @notice Change or reaffirm the approved address for an NFT
  64. /// @dev The zero address indicates there is no approved address.
  65. /// Throws unless `msg.sender` is the current NFT owner, or an authorized
  66. /// operator of the current owner.
  67. /// @param _approved The new approved NFT controller
  68. /// @param _tokenId The NFT to approve
  69. function approve(address _approved, uint256 _tokenId) external payable;
  70. /// @notice Enable or disable approval for a third party ("operator") to manage
  71. /// all of `msg.sender`'s assets
  72. /// @dev Emits the ApprovalForAll event. The contract MUST allow
  73. /// multiple operators per owner.
  74. /// @param _operator Address to add to the set of authorized operators
  75. /// @param _approved True if the operator is approved, false to revoke approval
  76. function setApprovalForAll(address _operator, bool _approved) external;
  77. /// @notice Get the approved address for a single NFT
  78. /// @dev Throws if `_tokenId` is not a valid NFT.
  79. /// @param _tokenId The NFT to find the approved address for
  80. /// @return The approved address for this NFT, or the zero address if there is none
  81. function getApproved(uint256 _tokenId) external view returns (address);
  82. /// @notice Query if an address is an authorized operator for another address
  83. /// @param _owner The address that owns the NFTs
  84. /// @param _operator The address that acts on behalf of the owner
  85. /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
  86. function isApprovedForAll(address _owner, address _operator) external view returns (bool);
  87. }
  88. interface ERC165 {
  89. /// @notice Query if a contract implements an interface
  90. /// @param interfaceID The interface identifier, as specified in ERC-165
  91. /// @dev Interface identification is specified in ERC-165. This function
  92. /// uses less than 30,000 gas.
  93. /// @return `true` if the contract implements `interfaceID` and
  94. /// `interfaceID` is not 0xffffffff, `false` otherwise
  95. function supportsInterface(bytes4 interfaceID) external view returns (bool);
  96. }

如果钱包程序接受安全转账,它必须实现钱包接口。

  1. /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
  2. interface ERC721TokenReceiver {
  3. /// @notice Handle the receipt of an NFT
  4. /// @dev The ERC721 smart contract calls this function on the recipient
  5. /// after a `transfer`. This function MAY throw to revert and reject the
  6. /// transfer. Return of other than the magic value MUST result in the
  7. /// transaction being reverted.
  8. /// Note: the contract address is always the message sender.
  9. /// @param _operator The address which called `safeTransferFrom` function
  10. /// @param _from The address which previously owned the token
  11. /// @param _tokenId The NFT identifier which is being transferred
  12. /// @param _data Additional data with no specified format
  13. /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  14. /// unless throwing
  15. function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
  16. }

ERC721接口解析

先来一波名词解释:

  • NFT: 非互换性资产(non-fungible token)
  • tokenId: NFT的id,类型为uint256
  • owner: NFT的拥有者,类型为address
  • balance: 用户拥有的NFT数量,类型为uint256
  • approved: NFT的管理者,只有NFT的owner和approved可以对NFT进行操作,类型为address
  • operator:operator拥有一个用户所有NFT的管理权限,类型为address

接下来解释下接口内的事件和方法:

event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

当NFT被转移时会触发Transfer事件,在NFT被创建和销毁时也会触发此事件。在NFT被转移时,他的approved会被重置为零地址。

event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

当NFT的管理者,也就是approved被改变的时候,会触发Approval事件。如果approved是零地址,说明NFT没有管理者。

event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

当NFT的owner指定一个用户拥有他所有NFT的管理权限时,会触发ApprovalForAll事件。operator拥有owner所有NFT的管理权限。

function function balanceOf(address _owner) external view returns (uint256);

查询一个用户拥有的NFT数量。

function ownerOf(uint256 _tokenId) external view returns (address);

查询一个NFT的拥有者。

function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

NFT的拥有者或管理者把一个NFT转移给别人,当to是一个合约的地址时,这个方法会调用onERC721Received方法。

function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;

NFT的拥有者或管理者把一个NFT转移给别人,这个方法有一个额外的data参数,上面那个safeTransferFrom方法会调用这个方法,然后把data置为""。

function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

NFT的拥有者或管理者把一个NFT转移给别人,可以看到,这个方法比起上面两个要少了个safe,说明是不安全的转移,转移者要自己验证to是不是一个正确的地址,如果不是的话,NFT可能会永久丢失。

function approve(address _approved, uint256 _tokenId) external payable;

NFT的拥有者把NFT的管理权限授予一个用户。

function setApprovalForAll(address _operator, bool _approved) external;

NFT的拥有者授权一个用户是否拥有自己所有NFT的管理权限。合约必须允许一个用户有多个operator。

function getApproved(uint256 _tokenId) external view returns (address);

查询一个NFT的管理者

function isApprovedForAll(address _owner, address _operator) external view returns (bool);

查询指定的operator是否拥有owner所有NFT的管理权限。

function supportsInterface(bytes4 interfaceID) external view returns (bool);

查询一个合约是否实现了一个接口。

function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);

这个方法处理NFT的转移,当一笔转移被发起时,这个方法可能会被调用,目的是拒绝这次转移。

ERC721的实现

Github上已经有ERC721的实现了,地址:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol

不过这是solidity的实现,并且基于公链,如果要基于联盟链,可以看一下我的这篇文章基于Hyperledger Fabric实现ERC721

参考

https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol

https://zhuanlan.zhihu.com/p/112275276

初探区块链数字加密资产标准ERC721的更多相关文章

  1. Panda Global获悉,美国承诺4年内明确区块链数字资产监管方式!

    近日,美国商品期货交易委员会(CFTC)宣布,在4年内将会全面把加密货币监管列为优先事项.Panda Global从7月8日公布的新战略中获悉,此次CFTC公布了自己接下来的新框架,并且在框架中承诺: ...

  2. 为什么区块链和加密行业需要 Web 3?

    为什么区块链和加密行业需要 Web 3? “由于人们都想从互联网上获得好处,互联网已经演变成了一个导致不公平和分裂的引擎,它被强大的力量所支配,并且任由其摆布.“——万维网之父.互联网先驱 Tim B ...

  3. 沪苏浙皖共同打造区块链数字经济发展高地,Panda Global表示区块链真的来了!

    近日,在长三角一体化发展重大合作事项签约仪式上,沪苏浙皖经信部门共同签约,推进长三角区块链数字经济一体化发展,共同打造数字经济发展高地.从此次签约活动也能看出来,区块链数字现金的发展已经得到了认可,早 ...

  4. NGK公链如何构建区块链数字经济商业帝国?

    2020年对于区块链市场来说,重大的利好消息莫过于NGK公链的上线了.NGK公链其广泛的市场前景.顶尖的技术,一直备受众多大型机构以及投资者所看好.同时,NGK公链也不负众望,在上线以后,就开始落地到 ...

  5. [币严BIZZAN区块链]数字货币交易所钱包对接之比特币(BTC)

    在币严BIZZAN开发数字货币交易所的过程中,一共有两大难点,一个是高速撮合交易引擎,另一个是钱包对接,这两者是我们团队以前没有接触过的.这个系列的文章主要介绍数字货币交易所钱包对接实现技术.第一个要 ...

  6. 重磅!Panda Global获悉立陶宛下周将发行区块链数字货币!

    近日,Panda Global从路透社获悉,立陶宛将在下周开始预售2.4万枚由央行发行的数字货币.该名为LBCoin的数字货币基于区块链技术生产,也是该国试点具有国家支持背景的数字货币和区块链技术的项 ...

  7. [区块链|非对称加密] 对数字证书(CA认证)原理的回顾

    摘要:文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用.接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的 ...

  8. [币严区块链]数字货币交易所之比特币(BTC)钱包对接 | 自建节点JSON-RPC访问

    BTC钱包对接流程 一.   部署BTC钱包节点 二.   分析BTC钱包的API 三.   通过JSON-RPC访问BTC钱包API 四.   部署测试 一.部署钱包节点 交易平台对接BTC之前,要 ...

  9. [币严区块链]数字货币交易所之以太坊(ETH)钱包对接(四) 使用web3j对接以太坊钱包

    本文给大家介绍了 Web3j Java 版本的框架的基本使用,大家可根据本文的内容进行扩展性的练习,对其他 API 的使用进行尝试. 使用web3j对接以太坊钱包 一.开发准备事项 启动 Geth 此 ...

随机推荐

  1. 微信小程序 转盘抽奖 倒计时 整点

    xml: <view id="luckdraw_box"> <view id="luckdraw_back"> <image st ...

  2. Spring Boot +Vue 项目实战笔记(二):前后端结合测试(登录页面开发)

    前言:关于开发环境 每位 Coder 都有自己偏好的开发工具,从大的方面划分主要有文本编辑器流和 IDE 流两种,我有一段时间也喜欢用编辑器(Sublime Text.Vim),但对我来说开发效率确实 ...

  3. 阿里云服务器上部署java项目(安装jdk,tomcat)

    安装JDK a.执行下面的yum指令安装,无线配置环境变量. 1.yum -y update #首先更新一下YUM源2.yum list Java* ---------#列出所有的JDK 3.yum ...

  4. Linux常用命令(一)之文件处理命令

    分时的多用户.多任务的操作系统 多数的网络协议的支持(unix和tcp/ip协议是同时发展起来的),方便的远程管理(可以通过图形.命令行) 强大的内存管理和文件管理系统 大量的可用软件和免费软件(游戏 ...

  5. 性能测试工具JMeter 基础(九)—— 测试元件: 逻辑控制器之交替控制器

    交替控制器:根据被控制器触发执行次数,去依次执行控制器下的子节点(逻辑控制器.采样器),可以由线程组的线程数.循环次数.逻辑控制器触发. 交替控制器(lnterleave Controller) 简单 ...

  6. 为老的vueCli项目添加vite支持

    1.前言 接手公司的某个项目已经两年了,现在每次启动项目都接近1分钟,hmr也要好几秒的时间,but vite2发布之后就看到了曙光,但是一直没有动手进行升级,昨天终于忍不住了,升级之后几秒钟就完成了 ...

  7. MacOS开启PPTP协议

    ​ 开启PPTP协议: Mac OS X 系统默认开启了完整性保护(System Intregrity Protection,SIP),所以即使是root帐户也无法修改系统目录中的文件.如果需要修改受 ...

  8. Spring系列之集成MongoDB的2种方法

    MongoDB是最流行的NoSQL数据库,SpringBoot是使用Spring的最佳实践.今天带大家讲一讲SpringBoot集成MongoDB的两种方式,MongoDB的安装自行去官网查询,本地开 ...

  9. CodeForce-734C Anton and Making Potions(贪心+二分)

    CodeForce-734C Anton and Making Potions  C. Anton and Making Potions time limit per test 4 seconds m ...

  10. BZOJ_1008 越狱(快速幂)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1008 Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教 ...