Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
什么是ERC-721?现在我们看到的各种加密猫猫狗狗都是基于ERC-721创造出来的,每只都是一个独一无二的ERC-721代币,不过ERC-721在区块链世界远不止猫猫狗狗,它更大的想象空间在于将物理世界的资产映射到区块链上。本文就来剖析下什么是ERC721.
9 V, K) s. U1 U  @, ]ERC721是什么
1 n, s  J  I/ _* B+ e在创建代币一篇,我们讲到过ERC20代币,
9 {$ z( D) g  t# D* h* T和ERC20一样,ERC721同样是一个代币标准,ERC721官方简要解释是Non-Fungible Tokens,简写为NFTs,多翻译为非同质代币。% @, A3 m9 m" W" ~+ P# {

. B' r. j  `- Z2 o4 K* u& aERC721 是由Dieter Shirley 在2017年9月提出。Dieter Shirley 正是谜恋猫CryptoKitties背后的公司Axiom Zen的技术总监。因此谜恋猫也是第一个实现了ERC721 标准的去中心化应用。ERC721号提议已经被以太坊作为标准接受,但该标准仍处于草稿阶段。本文介绍的ERC721标准基于最新(2018/03/23官方提议。
- M* b/ i7 y2 a8 ?

# C7 g/ U0 q1 |那怎么理解非同质代币呢?; i0 {( k- f* \
非同质代表独一无二,谜恋猫为例,每只猫都被赋予拥有基因,是独一无二的(一只猫就是一个NFTs),猫之间是不能置换的。这种独特性使得某些稀有猫具有收藏价值,也因此受到追捧。
* s4 N$ t0 c5 I( Y: oERC20代币是可置换的,且可细分为N份(1 = 10 * 0.1), 而ERC721的Token最小的单位为1,无法再分割。2 X3 ]" U1 o, G2 e; K& _

9 B9 O: m; \6 ~+ m6 r如果同一个集合的两个物品具有不同的特征,这两个物品是非同质的,而同质是某个部分或数量可以被另一个同等部分或数量所代替。, l0 u. `/ E8 _3 g1 W  ~' S
& F" Y% L' X+ o6 v7 D8 S" n6 g. q
非同质性其实广泛存在于我们的生活中,如图书馆的每一本,宠物商店的每一只宠物,歌手所演唱的歌曲,花店里不同的花等等,因此ERC721合约必定有广泛的应用场景。通过这样一个标准,也可建立跨功能的NFTs管理和销售平台(就像有支持ERC20的交易所和钱包一样),使生态更加强大。
% T4 s0 }9 f, [+ D  W' r' k; @ERC721标准' g" x+ U4 `; R% S) d
ERC721最为一个合约标准,提供了在实现ERC721代币时必须要遵守的协议,要求每个ERC721标准合约需要实现ERC721及ERC165接口,接口定义如下:
! D: W/ I+ Y" b6 Mpragma solidity ^0.4.20;
) _; A# U3 S3 Z* U  U, W) ainterface ERC721 /* is ERC165 */ {
& B, X: i% i2 {' @3 d+ S7 z    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);7 q2 _) F9 q6 M; W" l  k( }
    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
9 q! h7 `1 S, G8 _/ G( p( x    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
3 C) y) g0 C0 i6 N0 {! A+ C% ]( s% B# M    function balanceOf(address _owner) external view returns (uint256);; t* a. g* `- Z
    function ownerOf(uint256 _tokenId) external view returns (address);
& I4 n; E5 Y& a' t& r1 ^% w: b    ' K6 n  d# e* e1 j
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;1 @6 _6 R$ N6 E0 r7 E
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
8 G: G+ \9 w( V3 n, O3 H5 {    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;5 Q! v3 D. a6 O; ~2 g
    2 k# g+ P/ p6 j, ^) R
    function approve(address _approved, uint256 _tokenId) external payable;
6 J$ g4 B7 d! }' x    function setApprovalForAll(address _operator, bool _approved) external;% F# @& d7 e) }- a2 f+ L
    function getApproved(uint256 _tokenId) external view returns (address);
* j- c. y0 b( c# G    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
/ w( k( n8 A5 V! H, _. F( P}% _7 d! o9 G2 e; R
接口说明:5 i) s) m* {) C) S

1 L" t" H1 P9 }5 x, `2 K" CbalanceOf(): 返回由_owner 持有的NFTs的数量。
$ K0 k7 `7 K9 M; P/ j0 r& N! v7 A3 k
ownerOf(): 返回tokenId代币持有者的地址。# x2 N7 k  B# u' E

8 x1 O: B3 o& g; u( m% Dapprove(): 授予地址_to具有_tokenId的控制权,方法成功后需触发Approval 事件。9 ]/ b1 p0 V1 X

* Q! O' D6 ]# a/ HsetApprovalForAll(): 授予地址_operator具有所有NFTs的控制权,成功后需触发ApprovalForAll事件。
3 D8 E, V9 k; s5 H$ u5 B6 B
( }6 T) o2 h9 `* p: C4 q% ?& XgetApproved()、isApprovedForAll(): 用来查询授权。
" ^( s. J3 r7 S7 z3 B$ N. O$ ~, q
6 e$ ]9 Q) p* X& z; U
safeTransferFrom(): 转移NFT所有权,一次成功的转移操作必须发起 Transer 事件。函数的实现需要做一下几种检查:8 |, c1 h$ l* R% f# z2 M4 ~

3 Y: @2 J* X! M4 M+ ]1 G

( y3 j  E! G! j! C
3 _- v% ^& r5 s0 o' L& C( a: o调用者msg.sender应该是当前tokenId的所有者或被授权的地址_from 必须是 _tokenId的所有者_tokenId 应该是当前合约正在监测的NFTs 中的任何一个_to 地址不应该为 0如果_to 是一个合约应该调用其onERC721Received方法, 并且检查其返回值,如果返回值不为bytes4(keccak256("onERC721Received(address,uint256,bytes)"))抛出异常。一个可接收NFT的合约必须实现ERC721TokenReceiver接口:+ _8 V9 O* Z0 l% s1 f

9 l& s3 `7 F, g5 u( N- n6 Qinterface ERC721TokenReceiver {; b6 S0 u3 N4 x- r& U7 k: i. a
    /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
) L" u& d. J& b$ S# I    function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);% E) y6 g) S2 p. j( a( K  |
}4 W( c+ _8 b& x; d
transferFrom(): 用来转移NFTs, 方法成功后需触发Transfer事件。调用者自己确认_to地址能正常接收NFT,否则将丢失此NFT。此函数实现时需要检查上面条件的前4条。
; I. W0 A: v$ H; ?+ [  g  g- Y/ w- o

. K% n. R! R. v" h" {7 H  d8 [& J1 p% k' SERC165 标准
1 t* Z( W. }, _/ t7 z+ ?ERC721标准同时要求必须符合ERC165标准 ,其接口如下:
2 B! I- P# s2 Q0 j* ~interface ERC165 {
* k/ a! f6 f5 o+ y% q* l    function supportsInterface(bytes4 interfaceID) external view returns (bool);4 y4 h. M" e4 Z+ ?& b
}! D: A9 Y3 t0 q
ERC165同样是一个合约标准,这个标准要求合约提供其实现了哪些接口,这样再与合约进行交互的时候可以先调用此接口进行查询。
3 c5 M7 R! s. r& b# P# O# V: m' a9 h, FinterfaceID为函数选择器,计算方式有两种,如:bytes4(keccak256('supportsInterface(bytes4)'));或ERC165.supportsInterface.selector,多个函数的接口ID为函数选择器的异或值。
% v) J9 a9 U: E* D关于ERC165,这里不深入介绍,有兴趣的同学可以阅读官方提案。
; v: h5 Y6 F" q: f可选实现接口:ERC721Metadata
. x5 v8 J0 B; q6 x! P1 i  w, ZERC721Metadata 接口用于提供合约的元数据:name , symbol 及 URI(NFT所对应的资源)。' w# e$ Y1 N& ?$ R+ H
其接口定义如下:4 F6 P- W& r. L8 ~4 t! d3 T
interface ERC721Metadata /* is ERC721 */ {8 u7 q9 X% x* K/ k* Q. n
    function name() external pure returns (string _name);
- j* P( {1 v- G) w    function symbol() external pure returns (string _symbol);8 q, ?& `6 X3 c/ V4 s
    function tokenURI(uint256 _tokenId) external view returns (string);# Z( Z8 ]% d- h$ E1 s3 B
}& b; j# A+ W2 N! N" k& N. n% C
接口说明:' L" x0 R( I' I4 I( `7 J- }6 E
name(): 返回合约名字,尽管是可选,但强烈建议实现,即便是返回空字符串。symbol(): 返回合约代币符号,尽管是可选,但强烈建议实现,即便是返回空字符串。tokenURI(): 返回_tokenId所对应的外部资源文件的URI(通常是IPFS或HTTP(S)路径)。外部资源文件需要包含名字、描述、图片,其格式的要求如下:8 }$ X7 V  K4 _
) E. U% l3 @9 ^3 Y2 d
{' E5 D, c1 D: J% N! V* Q& `" _
    "title": "Asset Metadata",8 {) p- k( L6 H* a+ o4 y9 S
    "type": "object",
/ `6 V- b" h0 p* x    "properties": {+ _# U' M  O. h2 j% W* ]
        "name": {+ m4 w7 I4 b4 F
            "type": "string",8 H# W0 n1 G& z+ G- v9 l7 q
            "description": "Identifies the asset to which this NFT represents"," {- ~4 ?+ U0 ^, b, J
        },
; U  J# ?. ^7 O" v* n) y5 v        "description": {
( x9 v( Z/ D% X8 C3 a) q3 I5 j            "type": "string",2 H9 D4 {' M; T4 O" K6 ?
            "description": "Describes the asset to which this NFT represents",$ x/ v% F! d) _9 ]
        }," [3 E6 y' E  v( K& E* v  a
        "image": {
8 [' `0 G" N# l7 E) x( i: j& ]            "type": "string",
# y% K9 d4 N4 X$ \( K0 l$ D            "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.",
' J0 S5 l( b1 I# k, d        }0 Q8 f! u$ [+ T8 y$ ~. w7 K
    }4 P* G: U# q, z# t
}
! E5 O7 i2 P: {8 G+ N: G& ttokenURI通常是被web3调用,以便在应用层做相应的查询和展示。
% \4 I2 ~& S; G- h可选实现接口:ERC721Enumerable
5 ^+ _3 E- c: d. lERC721Enumerable的主要目的是提高合约中NTF的可访问性,其接口定义如下:
6 R; d1 d9 |, {  e1 hinterface ERC721Enumerable /* is ERC721 */ {
" m* R0 E2 Q+ [# g* i( y" W    function totalSupply() external view returns (uint256);) \/ p  i# r$ ]& W9 T* S' r: }: t; Y5 J3 B
    function tokenByIndex(uint256 _index) external view returns (uint256);& f! w: o9 \; X) L- h' K
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);* j: l, i! x( s4 V. B" k
}
. R, W  K( S, S6 W/ `$ j- [  K* y6 l接口说明:) S1 y, @: k+ }. I0 c" l
totalSupply(): 返回NFT总量tokenByIndex(): 通过索引返回对应的tokenId。tokenOfOwnerByIndex(): 所有者可以一次拥有多个的NFT, 此函数返回_owner拥有的NFT列表中对应索引的tokenId。3 j5 R  I5 O; Y, J0 z& E+ L

9 ?) t1 Y9 C4 h& ^补充说明  ]1 r) x( L( }. e9 U6 l
NTF IDs
/ f, [4 O1 W$ x2 n9 uNTF ID,即tokenId,在合约中用唯一的uint265进行标识,每个NFT的ID在智能合约的生命周期内不允许改变。推荐的实现方式有:  p6 u) m9 x/ s/ q

" _8 R4 I( E9 U6 b- x4 h$ _从0开始,每新加一个NFT,NTF ID加1使用sha3后uuid 转换为 NTF ID4 z& [; |' |: X* x6 U

: e/ [( Z6 ]! x/ ~) s! K5 J' u- U* j与ERC-20的兼容性- o) R( h6 M! s- ]
ERC721标准尽可能遵循 ERC-20 的语义,但由于同质代币与非同质代币之间的根本差异,并不能完全兼容ERC-20。, ~. O) E: r" h
交易、挖矿、销毁
4 @( d* ~# @/ i8 g2 T7 ~% w在实现transter相关接口时除了满足上面的的条件外,我们可以根据需要添加自己的逻辑,如加入黑名单等。0 M# U; Q! o  q2 ]. m6 l) W$ m
同时挖矿、销毁尽管不是标准的一部分,我们可以根据需要实现。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    10