Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
什么是ERC-721?现在我们看到的各种加密猫猫狗狗都是基于ERC-721创造出来的,每只都是一个独一无二的ERC-721代币,不过ERC-721在区块链世界远不止猫猫狗狗,它更大的想象空间在于将物理世界的资产映射到区块链上。本文就来剖析下什么是ERC721.
4 A3 r7 p3 M3 G/ TERC721是什么
% Y$ I- `0 S+ R5 L0 d" ]/ x9 ?在创建代币一篇,我们讲到过ERC20代币,2 z5 ^; Q! f5 J! T# Z" ~
和ERC20一样,ERC721同样是一个代币标准,ERC721官方简要解释是Non-Fungible Tokens,简写为NFTs,多翻译为非同质代币。; E9 }- h! o& A  U

5 N9 i2 M$ _- }6 M5 f3 D7 hERC721 是由Dieter Shirley 在2017年9月提出。Dieter Shirley 正是谜恋猫CryptoKitties背后的公司Axiom Zen的技术总监。因此谜恋猫也是第一个实现了ERC721 标准的去中心化应用。ERC721号提议已经被以太坊作为标准接受,但该标准仍处于草稿阶段。本文介绍的ERC721标准基于最新(2018/03/23官方提议。5 X2 `; U5 y5 R: R, k
4 `# d0 P. {2 H' C& X
那怎么理解非同质代币呢?; \7 K8 ]/ _0 S: l
非同质代表独一无二,谜恋猫为例,每只猫都被赋予拥有基因,是独一无二的(一只猫就是一个NFTs),猫之间是不能置换的。这种独特性使得某些稀有猫具有收藏价值,也因此受到追捧。# k  t9 L/ O( y( G8 i6 B
ERC20代币是可置换的,且可细分为N份(1 = 10 * 0.1), 而ERC721的Token最小的单位为1,无法再分割。, E/ s( h" K% }5 j9 U7 F) D( }& ]+ e
' w. v8 @! R9 S8 H: n! ~
如果同一个集合的两个物品具有不同的特征,这两个物品是非同质的,而同质是某个部分或数量可以被另一个同等部分或数量所代替。
: V/ C* M; Y2 O; B
- Y# E0 d# T; D* J! W; @% u' O/ g
非同质性其实广泛存在于我们的生活中,如图书馆的每一本,宠物商店的每一只宠物,歌手所演唱的歌曲,花店里不同的花等等,因此ERC721合约必定有广泛的应用场景。通过这样一个标准,也可建立跨功能的NFTs管理和销售平台(就像有支持ERC20的交易所和钱包一样),使生态更加强大。
" c6 e! n; w) H- R& ~" lERC721标准, r3 s& I5 s& b3 w/ o. ~3 `/ e; I
ERC721最为一个合约标准,提供了在实现ERC721代币时必须要遵守的协议,要求每个ERC721标准合约需要实现ERC721及ERC165接口,接口定义如下:
3 P3 q( k- ]( }  Y4 d7 j' u4 L, lpragma solidity ^0.4.20;
/ `! W. e7 `1 j  D$ w: r! J4 O. ointerface ERC721 /* is ERC165 */ {
$ f( ^% {& _" h1 D  h    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
1 z9 S( w: a$ Z# C    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
. m4 s& s7 X9 U: h8 o9 d    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);* q3 G5 W( Q  C* ~* ~% u: l' q/ Q" \
    function balanceOf(address _owner) external view returns (uint256);
& `0 t# D1 D' m$ s+ C    function ownerOf(uint256 _tokenId) external view returns (address);
3 C  o. t3 ]4 \- n    1 p1 h5 w1 z8 q+ Y1 N
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
7 W. }" D. d5 i$ t$ S& ~( s1 ]    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
, u5 P9 M; y) b$ a    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
( b" ?# o0 ^+ d) [( J9 u   
3 ]3 c; e) _: }2 e4 F* F! R: n    function approve(address _approved, uint256 _tokenId) external payable;- d$ ^9 x9 h- A$ O# l" n
    function setApprovalForAll(address _operator, bool _approved) external;
: s6 h8 [5 T/ R2 ], H    function getApproved(uint256 _tokenId) external view returns (address);
/ ?  o5 z& y1 }& I( l/ |    function isApprovedForAll(address _owner, address _operator) external view returns (bool);1 N# R' @6 S$ w4 Q/ _
}
/ \' [  U! k5 R% @接口说明:2 ~6 [6 b. a3 v5 J

3 W3 S1 i% C$ B$ UbalanceOf(): 返回由_owner 持有的NFTs的数量。
6 m1 y3 p3 u9 L/ p# ^. i% C" n* h9 Y2 P0 o: W
ownerOf(): 返回tokenId代币持有者的地址。
$ Q0 Z. X) ?* y" G0 p4 m2 v
" }! x( d- ^" K% Iapprove(): 授予地址_to具有_tokenId的控制权,方法成功后需触发Approval 事件。  l; C: Q1 m' _# D% J

/ z% J& z  n% @5 ?" X9 ]: i3 D6 k6 PsetApprovalForAll(): 授予地址_operator具有所有NFTs的控制权,成功后需触发ApprovalForAll事件。
8 j: F8 H4 i& w0 x& X/ g0 k8 M/ O" C. d- X
getApproved()、isApprovedForAll(): 用来查询授权。
1 j3 f( d& D8 G1 o

0 l4 W! y  u" Q5 Y& C, ?safeTransferFrom(): 转移NFT所有权,一次成功的转移操作必须发起 Transer 事件。函数的实现需要做一下几种检查:
. k" G  V3 q% p. u& c* G/ z( s* _( X% F7 ^% A4 N

" e$ z# P) O1 ~, S; T  A( w3 O( v+ ?% `% d
调用者msg.sender应该是当前tokenId的所有者或被授权的地址_from 必须是 _tokenId的所有者_tokenId 应该是当前合约正在监测的NFTs 中的任何一个_to 地址不应该为 0如果_to 是一个合约应该调用其onERC721Received方法, 并且检查其返回值,如果返回值不为bytes4(keccak256("onERC721Received(address,uint256,bytes)"))抛出异常。一个可接收NFT的合约必须实现ERC721TokenReceiver接口:
  D' n  A  N* p; S7 ]8 k* a: L4 F& K* A6 _
interface ERC721TokenReceiver {, ^( B" j1 k, }% {  y
    /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`5 O8 f* a5 w9 R7 g
    function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);, M; X; N6 f/ m3 |/ x! S8 _% l
}
3 F' b1 b) l" s1 t% h: `# F5 T& vtransferFrom(): 用来转移NFTs, 方法成功后需触发Transfer事件。调用者自己确认_to地址能正常接收NFT,否则将丢失此NFT。此函数实现时需要检查上面条件的前4条。- J4 C* X3 _8 H& J  O( C" ~) ]: k

8 `$ P9 t6 A7 T: PERC165 标准
) ?, b( [8 J0 d3 e# `" A) S' j8 lERC721标准同时要求必须符合ERC165标准 ,其接口如下:
; z5 f* J+ x) C8 u+ \+ J) ainterface ERC165 {4 f& G8 U: s1 Y3 Q1 `
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
9 Q2 x# ^0 J2 f1 @}4 e7 ]3 Q. `) P5 i5 l
ERC165同样是一个合约标准,这个标准要求合约提供其实现了哪些接口,这样再与合约进行交互的时候可以先调用此接口进行查询。
/ @& {5 C1 ^1 _interfaceID为函数选择器,计算方式有两种,如:bytes4(keccak256('supportsInterface(bytes4)'));或ERC165.supportsInterface.selector,多个函数的接口ID为函数选择器的异或值。3 K( D5 c0 O- I( G% c
关于ERC165,这里不深入介绍,有兴趣的同学可以阅读官方提案。$ p9 }: @( g3 q0 i4 p$ G. ]
可选实现接口:ERC721Metadata6 ?: z+ l, P4 S) d% O& c
ERC721Metadata 接口用于提供合约的元数据:name , symbol 及 URI(NFT所对应的资源)。
8 u1 C- ^. b9 E4 C. t! |其接口定义如下:
7 V% Z( G0 m( V6 _! Zinterface ERC721Metadata /* is ERC721 */ {
9 R0 Q! C! p  K/ b5 {$ c, ]    function name() external pure returns (string _name);
) \, N9 ]/ C& S: G    function symbol() external pure returns (string _symbol);
& w; N0 B6 _+ F    function tokenURI(uint256 _tokenId) external view returns (string);
! a" R+ c+ `, V}) d+ C, h% d4 s, [, @- Y2 X
接口说明:
' S3 z) J8 G7 O% G  s. bname(): 返回合约名字,尽管是可选,但强烈建议实现,即便是返回空字符串。symbol(): 返回合约代币符号,尽管是可选,但强烈建议实现,即便是返回空字符串。tokenURI(): 返回_tokenId所对应的外部资源文件的URI(通常是IPFS或HTTP(S)路径)。外部资源文件需要包含名字、描述、图片,其格式的要求如下:. [0 ?/ I' j+ @9 U8 |
" ]& g$ b3 Q- \9 A
{2 B) d' ]# c: I2 W
    "title": "Asset Metadata",
" ^- @& C: E1 n6 M3 b    "type": "object",# A7 s  ]  @6 h3 U4 q/ N
    "properties": {/ I+ x1 ?' I$ K4 S5 m
        "name": {, f; ?+ s: r1 u+ e
            "type": "string",
+ l* p: _" @  e) N" N. j) b            "description": "Identifies the asset to which this NFT represents",
+ ?( @7 B" n2 n1 }* v        },; t* `% d' _5 j; F3 t5 q
        "description": {8 a9 M& t  l4 J7 G9 G" z4 O, b
            "type": "string",
. C5 Q" ^/ q. }$ S% S: I) i            "description": "Describes the asset to which this NFT represents",
$ s2 n! m" [* J        },6 r( n5 F- ^5 H% {# f
        "image": {
% l1 d$ G0 R" m" y5 X            "type": "string",2 W2 u7 p: A* ^' J
            "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."," @! B+ x2 W+ C/ x) u7 P+ W- K
        }# n! O- ^! R- Y, [# _3 X; ?; J$ n
    }2 i$ ^# S) N- c6 [/ m. B7 f
}' ^) a  O5 p2 S/ n  Q3 T
tokenURI通常是被web3调用,以便在应用层做相应的查询和展示。
& H% q! U7 T/ I可选实现接口:ERC721Enumerable2 e8 j( j+ x6 L6 D% F! _
ERC721Enumerable的主要目的是提高合约中NTF的可访问性,其接口定义如下:, C: t4 d2 |- ?
interface ERC721Enumerable /* is ERC721 */ {
6 ~4 V3 b# L! {2 [0 R, V! H    function totalSupply() external view returns (uint256);
2 _% o4 U( v$ X$ n; u/ {$ p    function tokenByIndex(uint256 _index) external view returns (uint256);
5 t" U: J4 c0 M4 Y: I9 h0 u    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
8 @  ~, w0 a* E1 ]}0 U, ^( }+ p  V
接口说明:1 I" s. g# K9 t) Q# L% H
totalSupply(): 返回NFT总量tokenByIndex(): 通过索引返回对应的tokenId。tokenOfOwnerByIndex(): 所有者可以一次拥有多个的NFT, 此函数返回_owner拥有的NFT列表中对应索引的tokenId。
2 Q# K0 R9 r. I

) k" @- l+ W2 j' q补充说明5 ~/ c, b3 c  ~0 F7 A' m" d
NTF IDs
$ S  w& m8 n$ A5 p% a& K' ANTF ID,即tokenId,在合约中用唯一的uint265进行标识,每个NFT的ID在智能合约的生命周期内不允许改变。推荐的实现方式有:$ A) Q9 b' e4 O: p

7 y/ c) K/ O' J+ R6 |) Q& ~从0开始,每新加一个NFT,NTF ID加1使用sha3后uuid 转换为 NTF ID
/ z4 L# h+ a9 K$ _( d& G! [2 j9 y/ J3 N  G5 @& N/ }( s
与ERC-20的兼容性
: |+ s/ _& R( Z1 a2 I" nERC721标准尽可能遵循 ERC-20 的语义,但由于同质代币与非同质代币之间的根本差异,并不能完全兼容ERC-20。. U  W. s0 `9 _5 ?/ ?& x1 b' z
交易、挖矿、销毁( ]# [0 a+ c. i" u3 r7 E% |
在实现transter相关接口时除了满足上面的的条件外,我们可以根据需要添加自己的逻辑,如加入黑名单等。8 s6 P; L# q& _; [9 S4 L0 w3 h% l
同时挖矿、销毁尽管不是标准的一部分,我们可以根据需要实现。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

有个胖子他姓杨 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    10