Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
什么是ERC-721?现在我们看到的各种加密猫猫狗狗都是基于ERC-721创造出来的,每只都是一个独一无二的ERC-721代币,不过ERC-721在区块链世界远不止猫猫狗狗,它更大的想象空间在于将物理世界的资产映射到区块链上。本文就来剖析下什么是ERC721.
: T( n, S. n& {3 a& g$ n/ d4 OERC721是什么& @: i8 L- X9 d8 @# \
在创建代币一篇,我们讲到过ERC20代币,
# D. G+ X" _8 m$ U8 I% \6 U和ERC20一样,ERC721同样是一个代币标准,ERC721官方简要解释是Non-Fungible Tokens,简写为NFTs,多翻译为非同质代币。
+ b, y, I6 W9 r" x6 s7 _. X. ?* F5 L6 _( w! O
ERC721 是由Dieter Shirley 在2017年9月提出。Dieter Shirley 正是谜恋猫CryptoKitties背后的公司Axiom Zen的技术总监。因此谜恋猫也是第一个实现了ERC721 标准的去中心化应用。ERC721号提议已经被以太坊作为标准接受,但该标准仍处于草稿阶段。本文介绍的ERC721标准基于最新(2018/03/23官方提议。
! l# O' i' D8 Q, u9 J

; O9 }5 ?6 }* q: G) m那怎么理解非同质代币呢?: ]  C" P' ]# v) O% ?5 y, `7 l4 P
非同质代表独一无二,谜恋猫为例,每只猫都被赋予拥有基因,是独一无二的(一只猫就是一个NFTs),猫之间是不能置换的。这种独特性使得某些稀有猫具有收藏价值,也因此受到追捧。
! l+ G( c5 ]8 I$ s  g# JERC20代币是可置换的,且可细分为N份(1 = 10 * 0.1), 而ERC721的Token最小的单位为1,无法再分割。( V9 ~1 m8 f4 Q# ~0 s0 E$ X3 Y

( m' b# q. f. j/ b5 V如果同一个集合的两个物品具有不同的特征,这两个物品是非同质的,而同质是某个部分或数量可以被另一个同等部分或数量所代替。- w% H. H1 h9 \

2 s2 j3 m- R8 z# ~/ H非同质性其实广泛存在于我们的生活中,如图书馆的每一本,宠物商店的每一只宠物,歌手所演唱的歌曲,花店里不同的花等等,因此ERC721合约必定有广泛的应用场景。通过这样一个标准,也可建立跨功能的NFTs管理和销售平台(就像有支持ERC20的交易所和钱包一样),使生态更加强大。9 b! L2 a& I% I' C. T9 m( V. L' j* v
ERC721标准% l/ L* P' m6 c$ A4 b8 Z, ~
ERC721最为一个合约标准,提供了在实现ERC721代币时必须要遵守的协议,要求每个ERC721标准合约需要实现ERC721及ERC165接口,接口定义如下:9 p& B5 s$ T; M% n" k- [) R7 o
pragma solidity ^0.4.20;
$ k4 n5 ^+ y* x$ u* N, hinterface ERC721 /* is ERC165 */ {
$ |) |. W& U) B+ p    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
0 Y, W2 z8 `: x' {- {5 z    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);+ x# Z0 P: `3 n+ D! E: @% S1 G
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
7 S; N6 q2 G, r: R4 J" s    function balanceOf(address _owner) external view returns (uint256);
( u4 [) I5 v5 r! h, ?, |    function ownerOf(uint256 _tokenId) external view returns (address);- M% }. W5 r# {+ e" w1 i' c
   
3 f3 D4 r- B$ m' p/ ~9 a6 M    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;3 E1 m/ V! `0 k- ?
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;. q0 E8 o& w! g5 A. h' u. J9 ?3 ~0 ^
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;! j# z' n9 n/ o3 x
   
% W2 u+ P4 ]5 {  a, [    function approve(address _approved, uint256 _tokenId) external payable;
, y) q. f6 A+ b6 s$ O    function setApprovalForAll(address _operator, bool _approved) external;
$ j% u$ Y3 `* T1 U0 ]! L6 {    function getApproved(uint256 _tokenId) external view returns (address);7 M  ?4 ^6 {" A
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);8 Q0 r/ Y, H" c0 S7 G8 ]
}5 R2 f0 ?& V: L% O8 N5 A( k' ]4 K
接口说明:
6 p9 |$ b6 M1 ?- P" j3 X& u
  r6 J! ~# {1 g7 FbalanceOf(): 返回由_owner 持有的NFTs的数量。8 T1 r( o4 d8 ?" B
) K7 ^! u0 A% j+ _2 }( [5 N6 _
ownerOf(): 返回tokenId代币持有者的地址。3 Q, w5 q9 V/ \; E; l& R

! }( l4 w- r( v7 f3 Sapprove(): 授予地址_to具有_tokenId的控制权,方法成功后需触发Approval 事件。
7 U- Y" K# D7 r0 n- s$ j. U3 ]* T: J8 e6 i% }6 j
setApprovalForAll(): 授予地址_operator具有所有NFTs的控制权,成功后需触发ApprovalForAll事件。& Y' n/ }. I7 r
' |! D/ Q3 t+ _% k
getApproved()、isApprovedForAll(): 用来查询授权。5 @/ G% M: y( a3 C% e$ ^

( K! ^4 }. E1 V& d- LsafeTransferFrom(): 转移NFT所有权,一次成功的转移操作必须发起 Transer 事件。函数的实现需要做一下几种检查:
# k: t  @) p, I2 i7 Y; u3 ~' r* o' o" p' h6 y5 K
) I" `7 `: s9 \4 `# Z# ]5 M! q1 Y

! @' \' i3 ]' E调用者msg.sender应该是当前tokenId的所有者或被授权的地址_from 必须是 _tokenId的所有者_tokenId 应该是当前合约正在监测的NFTs 中的任何一个_to 地址不应该为 0如果_to 是一个合约应该调用其onERC721Received方法, 并且检查其返回值,如果返回值不为bytes4(keccak256("onERC721Received(address,uint256,bytes)"))抛出异常。一个可接收NFT的合约必须实现ERC721TokenReceiver接口:5 B: j! w# r& @& u# p5 b
& p: U4 ^& Q( |, m3 W! A! g
interface ERC721TokenReceiver {4 z' r# [9 X5 o1 \1 b' v
    /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
7 Y& L' N4 ?4 [, p3 J0 g# q2 O  ~    function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);' A- ^( K1 f( w2 _7 O! n7 }( ]
}0 @8 _5 C$ O" L6 I, t( N! @
transferFrom(): 用来转移NFTs, 方法成功后需触发Transfer事件。调用者自己确认_to地址能正常接收NFT,否则将丢失此NFT。此函数实现时需要检查上面条件的前4条。
3 A- n" v/ E; i1 ~1 p3 k
' V: z. @4 R& d& H& _. M8 y7 |$ m6 n
ERC165 标准
3 Z& o0 W$ C" a9 O4 l8 HERC721标准同时要求必须符合ERC165标准 ,其接口如下:# p- _2 @+ X# g4 P& J% H
interface ERC165 {) d  l+ v/ u. ~, s4 m
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
# P. F" r( I* A4 c4 u& u0 m& Q}) o  ~. x, y: @9 M
ERC165同样是一个合约标准,这个标准要求合约提供其实现了哪些接口,这样再与合约进行交互的时候可以先调用此接口进行查询。
: U2 `# h$ c! Y. YinterfaceID为函数选择器,计算方式有两种,如:bytes4(keccak256('supportsInterface(bytes4)'));或ERC165.supportsInterface.selector,多个函数的接口ID为函数选择器的异或值。
6 O0 f; G' ^6 J: o4 s- a- J* j8 W关于ERC165,这里不深入介绍,有兴趣的同学可以阅读官方提案。4 `7 O% @# b; h; [: ]; B
可选实现接口:ERC721Metadata3 S- p7 `7 Z1 i/ g
ERC721Metadata 接口用于提供合约的元数据:name , symbol 及 URI(NFT所对应的资源)。5 Y' w0 q, i9 \. c# K$ l' I
其接口定义如下:
# d. I" ]4 q; ointerface ERC721Metadata /* is ERC721 */ {
, ~9 z/ x1 I3 j5 D3 X8 y$ x; S    function name() external pure returns (string _name);
" g' [* Q1 g# Q0 S    function symbol() external pure returns (string _symbol);
& z# {0 Q$ K$ a5 v, x' x    function tokenURI(uint256 _tokenId) external view returns (string);  X1 N, a' J7 C/ Z0 r
}
* c( r. v' D+ ~4 R6 A5 ^7 o接口说明:
$ D" N5 c* T- ]name(): 返回合约名字,尽管是可选,但强烈建议实现,即便是返回空字符串。symbol(): 返回合约代币符号,尽管是可选,但强烈建议实现,即便是返回空字符串。tokenURI(): 返回_tokenId所对应的外部资源文件的URI(通常是IPFS或HTTP(S)路径)。外部资源文件需要包含名字、描述、图片,其格式的要求如下:
" D8 n  k4 Q! q  B
% t4 T8 X% L' K% W, \
{) D: Y6 M$ f  l6 Y0 l% ~
    "title": "Asset Metadata",
, k& L& ]* M3 w: u, ?' t    "type": "object",4 M5 E: N2 y* q& F. D" n8 O4 x* p4 N
    "properties": {
+ V3 b) `8 K3 P+ ?  n        "name": {/ u  L) _7 {' f4 Q: a
            "type": "string",
5 b, P( K+ V3 }            "description": "Identifies the asset to which this NFT represents",1 i& F6 J* v. o1 A* a" f# l
        },
6 V3 x1 N$ p! v: \% p        "description": {
+ A& L! f3 b5 x& V/ `0 a8 T            "type": "string",
+ v+ J+ \# H- b. L: F! Y            "description": "Describes the asset to which this NFT represents",/ ^( u! F, z; b9 Z9 @; a
        },! o, a" Y: ?; U4 y* R
        "image": {$ Q- x: l8 o. X% G: k
            "type": "string",
. `, Z4 V* v& w& |7 i            "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.",8 ?& S( i- d$ B0 h7 a
        }% n( H$ j# X' V8 w$ l( z2 d4 A
    }
7 N& g9 T; D! c1 W. E) |9 D. ~8 _5 H}
8 D% Y+ A) t/ @) o: V5 [: N9 ~+ FtokenURI通常是被web3调用,以便在应用层做相应的查询和展示。# K+ Z9 p0 j; M# `: v
可选实现接口:ERC721Enumerable
3 \( ~0 H0 h& [4 f2 |ERC721Enumerable的主要目的是提高合约中NTF的可访问性,其接口定义如下:
3 m+ a3 i% c9 N1 ?' cinterface ERC721Enumerable /* is ERC721 */ {
. R1 S' N/ D; K4 Z    function totalSupply() external view returns (uint256);+ c% m5 D& K0 l0 u" ^* c/ m2 O
    function tokenByIndex(uint256 _index) external view returns (uint256);
; l$ A- L! Q2 [" w3 m; j( x    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
$ J3 \. j1 ?0 a0 o) g6 P; ?, W  F# N}
9 R7 T0 H7 \  k. `& A, W接口说明:, i! ]/ I; y1 d2 S2 h( d* V
totalSupply(): 返回NFT总量tokenByIndex(): 通过索引返回对应的tokenId。tokenOfOwnerByIndex(): 所有者可以一次拥有多个的NFT, 此函数返回_owner拥有的NFT列表中对应索引的tokenId。; B8 m0 @& e, ?! U" Y9 I5 x
" f! l/ j  Z0 v( g+ }5 o
补充说明! ~! @- r1 \  S
NTF IDs3 r! k+ a$ c, [9 l) _! J
NTF ID,即tokenId,在合约中用唯一的uint265进行标识,每个NFT的ID在智能合约的生命周期内不允许改变。推荐的实现方式有:
8 ~6 V9 R* r4 ^# c% N$ a3 h2 _" i' B+ Q) v: f) N' c+ T- z' X% h" [4 V
从0开始,每新加一个NFT,NTF ID加1使用sha3后uuid 转换为 NTF ID. I* m" b5 N, o+ k# S! m

' G" M1 x( X' {$ |与ERC-20的兼容性" `  p8 G  j1 E1 A
ERC721标准尽可能遵循 ERC-20 的语义,但由于同质代币与非同质代币之间的根本差异,并不能完全兼容ERC-20。6 G) w: C3 x/ r9 ?0 t' E# M5 D
交易、挖矿、销毁
; e  t- A$ X* @3 w# j" W! U在实现transter相关接口时除了满足上面的的条件外,我们可以根据需要添加自己的逻辑,如加入黑名单等。1 ]: `/ l  W3 Y' I; w- x" h1 ]7 K3 ]  y
同时挖矿、销毁尽管不是标准的一部分,我们可以根据需要实现。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

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

    0

  • 关注

    0

  • 主题

    10