Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2478 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
! b# ~! N: K, m) `7 {7 W
: S2 j% {( J& n, `5 h: F8 {9 g    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
2 ]5 ], \/ P! _. g2 }
2 l$ U7 V# t. J5 E: `4 N8 D    ERC721Basic.sol
. f/ v: u3 V0 C5 t& Y
: [- C' e% ~8 h8 z7 G5 x! ^    pragmasolidity^0.4.23;2 F2 J# D- N5 E6 N3 }
) D: z9 ^) G, M5 s2 I
    /**; C  j9 a, ^' @
0 O; M( H8 J6 c) {6 x5 v
    *@titleERC721标准的基本接口5 U% x6 b3 p( n: P4 @. j

+ Z/ @/ }3 B4 W    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md' P% F2 Y0 A- J0 @6 N+ k7 l5 ^  q

4 X' d( _  h: y3 j* ~* @+ `    */' E8 _+ }) j  S  A# H, O

& O+ E0 z. k8 w    contractERC721Basic{' w4 v0 U% Q% u% z

4 a% e8 L% h; r9 d    eventTransfer(
; \8 `2 h# ?* B8 U$ p: I) ~: U, `: l8 M  C
    addressindexed_from,
: D$ l* h! }; a" d' v5 k) q1 G, G& h7 B0 s4 w' |/ Y1 W
    addressindexed_to,+ O/ f5 D# k" @1 `
' P) {5 J6 ~: h5 i; ^
    uint256_tokenId
" Y& K% t2 ?2 Z/ f+ P  }! S* {+ T
    );  d6 X! K" h# r
( }+ n# |1 p2 |6 y$ V
    eventApproval(7 F3 v6 ]/ k% l" z: N$ J6 g

4 C- H: @9 A4 d, t    addressindexed_owner,% T- N, L+ _. R& ?

+ k0 J" N/ x, F- r6 y6 A    addressindexed_approved,
5 t5 ?3 L% ]+ r1 [( b7 R; E
( v& P; N8 O* S9 l! }    uint256_tokenId
% D  K6 v- C# ]2 Q: S, X& Z' {1 U( d9 Q, a7 c
    );
2 j  g  [9 P- ?3 ]9 T; e8 q
5 q; m8 U4 t1 O0 Y# g    eventApprovalForAll(9 Z( r: u& I* A( {! M* A& ]3 L& n

2 j* f. ?3 m  h3 }    addressindexed_owner,3 g3 Y, C# i. \5 b4 p

& b0 I0 C2 @4 J" G% h$ q3 A4 N    addressindexed_operator,1 F- F- Q! P. _5 m4 f* P

# B# L: n, d1 L0 T, R  r0 K    bool_approved
5 W% T# ~  J0 x) _( _' `% N
6 {) K5 ~2 _; M# K9 H$ I1 X    );1 I  ^3 A0 E' i4 c

; s" ]7 e; ~# f    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);# c% R( f" I, |1 D( V
# p; ?" S8 \& K$ U, {- }
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
/ f8 s7 }. G. R" _5 x1 a' b: p' f0 F( b; }( ^$ p
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);
* E1 Z) \1 X+ }: T
$ o. i) D$ G4 d3 [) c    functionapprove(address_to,uint256_tokenId)public;
. i* q) m/ K9 v' Q
& p  z' _8 V/ a% c3 e5 s    functiongetApproved(uint256_tokenId)5 m2 I! L4 \' o, B
5 [! u) P/ o% [) `
    publicviewreturns(address_operator);$ f0 \; e: f" [6 f7 Z

7 J/ o# I1 W2 D/ u3 `/ l    functionsetApprovalForAll(address_operator,bool_approved)public;3 W4 o( S1 w: {3 e

% C& I( Z" U/ f& L    functionisApprovedForAll(address_owner,address_operator)
' y/ E4 `* K/ J( ~) _3 w" r8 H! u' m% g
    publicviewreturns(bool);
" t# n; @5 ?0 i2 h9 N4 D4 }: h
0 `' {: e' }* D5 e, A& {    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
( b" J! j& w% z* m- B4 o) M5 y& d1 q
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)1 r9 D1 M: q$ _* W, \

) \. f. ^0 d* d8 [7 C; r    public;- `: P9 Z3 e6 c+ D7 S, f
( F- }8 L, B" Y: K. [4 [" z7 g) r$ Q
    functionsafeTransferFrom(9 G5 C$ x8 x" a# B8 ]+ Q, b" i

; _) ~* ~# |* a$ f5 ]! M    address_from,
& n% n) \0 ]7 s3 z: @, l3 m8 L+ w! F! I) a; Y0 U
    address_to,6 ^( B, S- r" }; @- M% T$ d& s+ e
' j) w8 }$ ]1 }# p0 P' U
    uint256_tokenId,
2 _7 N4 X9 D0 C* P1 b5 b" v% N
6 X8 Y) W0 `8 T' y; S4 Z    bytes_data3 m! G  Y4 }5 ^9 K3 X
* @- M7 g7 L% E8 j, G
    )
5 i( i4 w; s! s0 w* r: K8 P+ O8 z4 E) w6 B/ S: d
    public;1 F; t, p* A# b
/ c! Q9 o9 K, t4 P5 y
    }
; m  D2 o; ]8 o. V  U
/ j# z4 o: D% d" ^4 D2 _8 d* f    ERC721Basic合约定义了基本的接口方法:
) K' W/ \/ p  f8 |+ i+ H( X' _1 R# Z* Y: S
    balanceOf返回_owner的代币数量
+ r/ c( V" X- k% G) Z1 A, h- z7 S$ }
. ~5 s' N8 e; s- N    ownerOf根据_tokenId返回代币持有者address
" R( Q, S; O6 h5 A/ R7 k# `+ x
5 u/ F$ I( h* S    exists_tokenId是否存在* y+ g" n5 o& P, {

" ~" m( u5 L7 L% D# v' u; _) P4 l    approve授权_tokenId给地址to
- \; ^  E- ]6 c, s5 p7 U8 ?/ {  n9 h  U
    getApproved查询_tokenId的授权人_operatoraddress
" Y" g. z& O9 K* V3 ]( u, Z2 r# i: `' C: A7 {
    setApprovalForAll授权_operator具有所有代币的控制权
$ G& @2 ~' w9 Y& _% a+ r
% J0 S! M; z3 V4 j# T- v$ f    isApprovedForAll9 \" y- p  u5 |" }- |8 |

8 q2 M# C/ E( g* q( P( w$ W    transferFrom转移代币所有权
0 y- l  m) D0 H$ f1 [/ e+ A
2 G) H2 r$ a# u6 s    safeTransferFrom转移代币所有权
3 }' Y& z7 b* u
6 j( |6 k& l9 m. r7 ^7 ?' c% n    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
# ~. p1 X6 L+ L( n, R0 K' ~' |3 _* Z$ m; x- E
    ERC721.sol
& C8 r+ y* P+ ~+ V# K
5 D2 ~& _+ N8 X# l/ x8 E7 R    pragmasolidity^0.4.23;) e4 l7 W0 p. @0 g! W4 x6 Z
) k+ u% T5 f/ z' `$ D$ Y
    import"./ERC721Basic.sol";
5 f2 b" W4 d" }% d9 ^8 s! u, Y. S! F4 f
    /**0 ~& Y: a5 i8 R

+ o- a  Q4 T, }* T2 J! {    *@titleERC-721标准的基本接口,可选的枚举扩展+ k6 Y8 A1 p. [8 W4 k

3 A8 w* n9 K5 H+ P* i) X) e    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md* ^% m: b7 Z# u. f* q

" G1 c& m" u7 a+ d! Z' |! `' ?    */& e0 k8 S" J, `  V  n8 I" [6 i) q  D

" t5 q7 g6 W9 ?" a    contractERC721EnumerableisERC721Basic{
- X: i% Z; C/ s8 X4 ?6 ?
! k3 L1 p( S2 f9 A: _4 D    functiontotalSupply()publicviewreturns(uint256);
/ V! w' L1 i% n4 D/ A- ]; ^  Q. P# l% |! x- m& D1 V% s
    functiontokenOfOwnerByIndex(: C5 u. s0 q, i) l" Z4 B; D. h
9 b. \& y  c7 w1 s
    address_owner,+ ^. J0 E# _" \3 X$ y1 E  t

( n' B3 m# L/ E6 {; f4 m    uint256_index
8 h' m& N: g& T! b. S3 t
% _& M' T2 z. E    )
5 J$ y2 j/ A5 W% T
2 |8 X8 x. H) S- S    public
8 ]9 L1 t( x1 x. F/ }# N+ J. \3 G) y' c& @3 l: t0 o9 c: Z
    view
8 B( x) X/ |6 i; L, n& E& o+ @. l+ F& h1 o
    returns(uint256_tokenId);
: n  t+ c0 E- M0 h6 X6 m
% I0 `# @6 X  v( i    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
7 }- ], T# n! p- M* `
8 g9 ~. c- i1 i: g    }
& y, l6 x- C8 j9 @+ Y6 D" d
. B0 o! g; `/ B; d6 J    /**
. n9 u! D. e* L2 H7 ^, |! n5 k" A7 s1 F
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展) J! g7 Z8 ?5 u1 U% L3 \1 Q; \

6 H+ C9 V  c. L$ C) m6 D    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
$ x, a' m: h9 C; @5 c# R. _+ R) N1 h8 X' s) w6 G0 {5 d
    */2 ]7 V) m4 d7 ]: h2 v& J2 h5 V  e. _

0 {* n6 h$ B5 @    contractERC721MetadataisERC721Basic{
0 t$ [; U8 [% h) K9 v* @! S
+ v9 W1 r+ K5 L9 B    functionname()publicviewreturns(string_name);
4 d7 o( e/ }1 ~" L# r5 q
0 O( u$ p0 x8 M5 {7 j2 g: y    functionsymbol()publicviewreturns(string_symbol);* C, Z. k# q; Y* Z6 f0 x  y; S3 J
2 @6 Z5 R, D- Z/ H" Z* L" L
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
. U" S: W  J7 b, ^3 G8 r/ G
( z5 O$ r" r' P/ _& c    }' K6 W! |6 z% `
% V+ j: Y, W& H7 Y
    /**1 F8 ]1 Z* K% B( Q
# t" E( ?2 i1 O
    *@titleERC-721标准的基本接口,完整实现接口$ \9 A+ {" G: |! G# x: J6 I: h
- r% Q  [/ H. b7 x# h1 Q
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
# b3 A- M3 b$ x9 l5 ]
0 `8 |, d+ r& s1 k    */
, p/ X7 s7 `) g/ ]8 z1 [! n) U, \: {7 ], E" S
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
# K( a/ K+ B3 V1 d' f8 T4 ?8 C* k* W
    }: k% y0 ^6 ]9 u; M

/ D# c; M! ], X! a6 _* h* u    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
6 p( o1 B+ p" u0 o5 E% N7 }4 [9 g8 t0 ]% u3 I7 W
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:0 D) q0 ?- y+ S+ N) s
$ L& e+ U. |4 q& J
    totalSupply返回代币总量
* k0 I1 I9 x! p/ x" e  o: F, S2 ^7 K6 _. T2 m
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
( Z- k$ T  o9 b2 w, J# ]5 L
$ d/ O) l4 K# J) k1 G4 Y$ \    tokenByIndex通过索引值返回tokenId2 \5 Z! y! `: V' V2 V! V
, e9 v0 ~6 O& v$ k# }2 B, N1 X
    ERC721Metadata元数据扩展哦用来描述合约元信息4 I- Q- f" e( M% i- E
) {  t( f" S- o9 I
    name返回合约名字# p( n  R& u. Y4 ^7 v( ]
: ^1 Z) y; k, ~9 N: h
    symbol返回代币符号8 f/ D/ j& v3 X& m

5 y+ r% N/ z7 e    tokenURI返回_tokenId对应的资源URI
) J7 K# R5 z5 [% s. w9 N: b" W% N9 W9 Q
    ERC721BasicToken
8 p( B. V/ ?. e! {+ m
7 f2 y* P  B3 R    ERC721BasicToken
9 @+ G) M7 U6 w% A7 g  l" j1 F! Q: Q7 V) u% x+ Q- ~
    pragmasolidity^0.4.23;% b. M( S8 x! ?0 U

' E/ ~! f6 I7 _3 k1 J$ q    import"./ERC721Basic.sol";  Y0 ^- R% T* H

2 n8 n: b% A+ j    import"./ERC721Receiver.sol";
5 f+ ^' r, H- p& Z7 _& J' S$ w0 r! E" G
    import"../../math/SafeMath.sol";
3 z; W7 D" {. f# t6 a; R+ J
; l; T  ^1 O  M' W    import"../../AddressUtils.sol";
* r5 L; n) k# i4 E' g% u% v2 h( t  \  V8 q  I( `2 M
    /**
9 h6 x6 n0 z2 v1 q7 L9 P  v" B( i. G5 Z( g, w$ l+ W
    *@titleERC721标准基本实现9 Z; e1 U  u. z, z1 e& }
) v, g; X3 o6 I1 m9 J% c  g& W/ W
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md6 {0 _, T! \4 p5 m
: c' b* {! u+ v! q
    */
" f, x; @/ h; s+ E) ?# v( [/ T
    contractERC721BasicTokenisERC721Basic{2 l4 S& j! n8 ~/ G& _" E8 e
: `0 n' u& s2 l0 a1 @. d$ f" X
    usingSafeMathforuint256;3 }3 T' K; c" V7 |7 o
5 ?8 {, Y+ b8 `: n1 v: H) ]
    usingAddressUtilsforaddress;
7 L# @$ z" ?2 r/ O! a- s# @% O) T7 l; D$ s2 U& _) Z. f3 u
    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
% ^' T" d, v- z- {' L* J4 X, m& F( M' ]
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
' }" k8 [  S$ n: Z) X
# M: \/ A* s% T0 X    bytes4constantERC721_RECEIVED=0xf0b9e5ba;
9 T$ a9 z$ b+ c- `* f" }: j5 R* C/ C
9 |$ e( }0 \7 R2 a4 s0 \% F    //tokenID到持有人owner的映射/ l; h- r- I9 b) w7 O* M  s

6 `$ U2 k2 j1 J! ]$ u    mapping(uint256=>address)internaltokenOwner;( b2 |9 l' u; i/ W3 V+ v

/ A% S$ m) p4 n. y4 n/ O! m. _/ C    //tokenID到授权地址address的映射
+ l6 Y/ k  }* @' d2 R4 n8 `  I- |: i/ D# A1 E$ N( k
    mapping(uint256=>address)internaltokenApprovals;
1 v0 f1 B- N3 v6 H8 q. l1 a; T& ]. A# f9 I3 `
    //持有人到持有的token数量的映射) B9 e) X& S7 P9 P+ {
# M0 J  N; ]+ ?) o' q' Z9 G$ [9 ~
    mapping(address=>uint256)internalownedTokensCount;
8 B* D1 B; w& M# b7 m8 g" S* B* m0 H8 v; j, A$ m0 H5 a
    //持有人到操作人授权的映射( Y* f1 I7 k% H

& s2 @8 Y) ~! ]2 G6 Y    mapping(address=>mapping(address=>bool))internaloperatorApprovals;8 J0 S3 @: ^; F2 [* T
! g5 W$ A3 I% Y- m& k3 t. c
    /**
8 b  E- }/ E/ n$ q& n* h
0 }# A8 ?0 v! `    *@dev确保msg.sender是tokenId的持有人
% Z0 S: U3 E: h' O  S4 O4 V, }" B) s( A
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender/ _0 b% y2 x' m& I' A& ~
2 Z  A7 _( \% b7 E- M
    *// \8 p8 a! q) z) z  c/ Q/ ^
! W4 h5 }9 a  m3 a. T. W+ T7 ]
    modifieronlyOwnerOf(uint256_tokenId){
! r- w( V9 _; `" f5 ~' Q5 D
& v8 A, o8 V  H. Z) e0 y    require(ownerOf(_tokenId)==msg.sender);' L5 c' s$ R/ h% _4 y2 M) n
$ G% Q* {1 B7 G8 w: d" s6 \7 s
    _;
- i  W, E: L" t9 H0 W, `: v
, W% F% a9 `; M$ U1 d    }8 }" `; v; w, l! n" y2 B
8 b: }) w9 T3 ^, l0 g/ Z3 o  e5 K
    /**: r1 P9 n% ^! G: N
8 }0 y) y( M4 N& I+ K! c
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token3 Q2 y5 O& D- [  m
, ?7 R2 f: u( _3 ~) {. n! X
    *@param_tokenIduint256IDofthetokentovalidate0 a- H/ {  _4 `. L. w* r

2 _- e- r- n3 {+ z    */8 g( [8 ]7 r4 Y3 J
; O7 l8 }3 R: R& r
    modifiercanTransfer(uint256_tokenId){, P: X! z5 e# ~1 G
- t/ K4 m, j) |7 L
    require(isApprovedOrOwner(msg.sender,_tokenId));5 w' n  p3 e* W$ A- v. n

# M  u+ Z2 r# y$ t; X& F* D    _;
/ T3 I2 S7 T6 j
( }- H2 @! s+ q+ D2 C3 ~4 \# A7 a    }
5 m# @$ n% ^5 k5 j8 ]! z- w1 B1 q' T) M" g' Z- s- G2 @
    /**
7 }# }- y- E5 Y; ]# t& Z& U$ f/ a' N0 G8 c% V) W  z( o3 m2 O
    *@dev获取持有者的代币总数
( k; a. X5 M+ V! U* _' d2 }) f: m! {
    *@param_owneraddresstoquerythebalanceof0 T- Y4 S9 ^/ Q% p" h. q) o/ y

( A% Q/ L8 q) T    *@returnuint256representingtheamountownedbythepassedaddress
0 t) [" `- A/ O
, K( F0 q6 O7 Q) ?& w% F! X: O    */8 X9 ^) c8 p- ~( a0 ^7 K7 _

: ?! |3 a4 G, Z% B    functionbalanceOf(address_owner)publicviewreturns(uint256){. O) |* u$ l7 U9 N

# ~; a; j/ J4 D$ S/ f2 M    require(_owner!=address(0));
/ |4 h% b0 E/ }  Z5 \# p
+ ^, G3 s1 g* e    returnownedTokensCount[_owner];
4 n. b3 x# o: T# A! l4 p9 i/ V7 m7 T% Z' y
    }- ]+ y9 A/ {( `$ [9 T! p8 S
& r0 w; x  |, v" }! l: N- q
    /**
" V1 e* n; B& I! ]5 @, z- @$ H5 W  p
    *@dev根据tokenID获取持有者" \7 f: `; M( f* T" E4 E

  S- f: Q: V5 W4 R5 E8 Q' I! F' e    *@param_tokenIduint256IDofthetokentoquerytheownerof& |' l/ x: p+ T1 E5 r3 t; L" B
% k3 j" h; B: S# G
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
. y3 ~3 W) B  V' [2 @" C1 J2 Y5 n& m. ^" \, ~3 Y; D
    */
% r6 `" j- b8 c8 I" s8 Q( L8 B% i( _" C  I7 n- L
    functionownerOf(uint256_tokenId)publicviewreturns(address){
0 L1 a/ F/ M# Z  r0 u8 S" d* G9 O# O6 c' c
    addressowner=tokenOwner[_tokenId];
& x9 N7 }' ~8 y, w. ?: u
; \6 D( u: f+ l5 k9 W    require(owner!=address(0));" }! d6 x3 W* _' u

# W7 t7 p$ T: O4 v% \# X3 W/ J    returnowner;
& c6 Z' t& v$ F8 Z/ ^! G& T
/ D, _2 Z3 k$ Z! h( O    }
* o! [0 O# |$ T0 L$ u6 ?. c3 [  O% o, k2 W3 o8 r9 E4 b
    /**3 l/ _7 T: X8 b
0 @7 C- ^! o, O6 T( ]% i
    *@dev指定的token是否存在
: M1 J& m, e- G
  P+ ^3 |: N6 b2 f3 H    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
( s7 ~8 D/ P$ v- d7 \) L3 A$ b" X2 r6 i  p
    *@returnwhetherthetokenexists* a, F9 _6 |: C! c' x  D

2 U3 U. B( O6 A7 f+ ?    */9 d# k3 A) ~* y: J
2 ?( ]/ i  C: a
    functionexists(uint256_tokenId)publicviewreturns(bool){8 g& U: d: n0 E  B  f6 M  b$ ]1 a
/ e  Z' C0 P' N
    addressowner=tokenOwner[_tokenId];+ M$ f: Z% G. c! @3 X& k- f/ R
5 k& s8 a" A" t& M
    returnowner!=address(0);/ r8 y: k0 i5 s" j
$ e. E& Z# A7 v- n
    }+ V7 @- @/ ^8 j; o
2 X5 j" j. n  g! O% M- K
    /**
: j1 g& i3 c! N! h/ p; g% M5 {: M6 ?% S- Z/ M( H: e1 p5 G+ {! j
    *@dev批准另一个人address来交易指定的代币4 n# v6 W7 j. G; ~' {4 F
  n: Q+ T8 ^2 d% E
    *@dev0address表示没有授权的地址
9 E3 v: [% k( J, B; ~
2 y7 ]: h) M$ h    *@dev给定的时间内,一个token只能有一个批准的地址. i# L* F# [, d) w, y4 G
; f, A$ f9 a. S$ m/ n9 S0 h4 \
    *@dev只有token的持有者或者授权的操作人才可以调用  N, ~: l! r! b3 o9 I
; v) j/ r$ J* D+ |; P1 R
    *@param_toaddresstobeapprovedforthegiventokenID9 z9 G4 B) Y3 z+ V7 B$ \
; V# g. c0 z- l
    *@param_tokenIduint256IDofthetokentobeapproved
2 k7 A6 I/ o9 H; _0 ]6 M- Q: p1 c$ t0 ^# y+ t$ a
    */7 S0 m1 b6 P$ s8 T' w- X$ N* x

% \+ @7 i: f- s" J    functionapprove(address_to,uint256_tokenId)public{
! R% J% H9 Q% l% T6 Z: ?7 z1 j* s, h0 a+ t+ O- `$ J, s# X
    addressowner=ownerOf(_tokenId);: v2 b4 n, C. Z3 E  m" m( T

( s  M5 s: ]4 ~0 s2 c3 \    require(_to!=owner);- |. B2 U2 ]6 o2 b

6 i7 u/ ^" T8 O/ F% d. n( ^: o    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));& L" \6 Z% J# I. z
% K( S  B$ B" t
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){; |5 F$ _' B8 ~0 J

( t/ ~4 F8 A' T) H- p7 {% m9 [    tokenApprovals[_tokenId]=_to;
0 e4 x; P6 B. I* E+ p4 P3 }2 x0 l# l+ y
    emitApproval(owner,_to,_tokenId);
3 D, A, G  q' j5 z& L! ]: k: p; p8 I: M7 e2 `. ^
    }
1 V1 d  q. v6 O7 @& D+ `
) ?" d" a% k+ k6 i8 W" M    }
( E! ^0 x  z- D/ [
3 a# q! B* V$ Y6 l' o" V    /**
+ |! q8 L/ v' W' Z
3 [$ e. E. W2 `) q. D    *@dev获取token被授权的地址,如果没有设置地址则为0+ n/ ?3 k/ q. Z3 J6 B
- N: S  L* S8 M3 ], ]
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
/ B3 Z& s: @+ C
2 X0 e# L7 [  S* p    *@returnaddresscurrentlyapprovedforthegiventokenID2 M$ S. \5 t' i- F  B) ~

4 E1 p+ [+ g7 a. G& C% f    */
$ O8 t# k4 B/ g: F/ @
' a. h5 ]2 }% A: X$ b    functiongetApproved(uint256_tokenId)publicviewreturns(address){
( A% ?# G0 A) }& E. i; A4 W  x1 v# `: {0 s. R& R, j- M
    returntokenApprovals[_tokenId];/ B9 c* G1 G. D+ m$ `
4 a2 R: A) L5 v9 M% H
    }6 D( c1 b6 @& O& o7 t

( d$ O; w7 b. `! {    /**
- B! S' a/ R2 `1 s: s$ m2 A+ |. T) g7 K5 f. s& P: u
    *@dev设置或者取消对操作人的授权4 A! n3 a. S! S" x

1 W5 }7 q1 O# I$ \0 n    *@dev一个操作人可以代表他们转让发送者的所有token
. y, \! [) x# k9 W( H: s! C6 r4 J4 q4 o. T: A
    *@param_tooperatoraddresstosettheapproval8 H# J$ }; `# |$ o) y+ l) K

2 j( _& m, s% Z% O5 D3 b# Z    *@param_approvedrepresentingthestatusoftheapprovaltobeset# h- V4 ?& q% H2 d  h6 j( ?  B5 t
& p6 r& R* S8 T7 C8 _
    */# z* y! A$ t. w! G$ r

+ u& J* X4 g; L    functionsetApprovalForAll(address_to,bool_approved)public{
: W* i, H. `6 q, s3 r3 f* s% [  B+ |& }- G
    require(_to!=msg.sender);
% X! R; G5 n! _* Y6 u/ l* V5 T5 d
5 d1 m% p$ g1 p. |    operatorApprovals[msg.sender][_to]=_approved;
2 |) S9 [  U" K! V3 Z& ?; M, Q4 L
    emitApprovalForAll(msg.sender,_to,_approved);
9 I2 R# h( X' c! R: Q; A( y+ H0 _" y
/ l; z% y! d  v  J    }
+ r  M8 Q6 n& i/ r
8 {) _* U0 A3 x    /**/ Z8 g+ i& ~4 j) Z) b7 M" m" h  d: a4 v

! t8 m/ D5 V  V9 t9 Z: _    *@dev查询是否操作人被指定的持有者授权& l# @# p3 h6 s% P' l

* S6 J# B; ~1 ~# S% E! z    *@param_owner要查询的授权人地址
  E! f% C% P. n
- R( b6 G" o! g0 U- W    *@param_operator要查询的授权操作人地址: o8 K, z$ d: q! i: t1 Q

# J& B- ^5 n) `' e+ w! m5 G8 L6 s    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
! J' O! I8 W* L$ k  Q* U3 a+ K
. F, _- j- W+ N9 G6 ?    */
4 ]# Q" m. o0 k* m8 |. ]% c9 R( R, K. [+ L: {
    functionisApprovedForAll(
9 q4 K+ A" L# y+ I, {
( X4 }* w4 |+ O9 w    address_owner,
/ ]" B& ~$ N, ~  m
* d' y- N) W; b    address_operator3 I; O3 B  x7 D. _" O/ ?- z( O

5 w1 W! g: D. a  e# F2 T    )
9 o; _/ t) H9 b+ a, T, }  C5 y  Z: J! v- d
    public  U& ?; X; m$ K
+ ^& B# R/ U0 ?
    view
  X0 w5 {' t! v) W, n8 M) n& y
' f6 o: _0 G1 J( |% f6 y    returns(bool)
9 @. y  M" R0 Z% \  ~
0 ^) j4 {/ V# {. D0 M    {7 D2 d. X4 b" Q; P
6 n& ~6 `+ w% m! Z4 v) t: q7 R$ d
    returnoperatorApprovals[_owner][_operator];
9 \/ C6 F, {- h8 e/ M$ F5 O6 H! D2 k9 _
    }, f+ S) n, v- F; s
/ Q9 \- d! h" T) v! x) c& l' K* r
    /**; M8 {2 O7 s' B% R' P
( r/ v1 a% C) a  m* |; `2 ~
    *@dev将指定的token所有权转移给另外一个地址7 _5 x9 P( W# E  J( k$ s' b8 f
) f  T. O6 [  {6 a4 R
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
9 H( d. G; y1 C. c2 g; ]+ b
. W+ f7 k* S# m    *@dev要求msg.sender必须为所有者,已授权或者操作人
7 u1 ~' u1 [8 E- ~( {3 V- [6 \# }; ]* H4 ^3 n8 y6 ^3 s5 u
    *@param_fromcurrentownerofthetoken3 p) X% A8 ?4 ^7 z' {9 h% w

% c  j. G! }7 X8 K    *@param_toaddresstoreceivetheownershipofthegiventokenID2 {6 L/ _, L0 T- s5 y3 b( g8 ]

7 m) b1 h! o2 L" s* b4 g    *@param_tokenIduint256IDofthetokentobetransferred
2 N5 A. a9 \5 @8 s6 p, d, e& y7 N/ N  Y: ~, |
    */3 h0 |" ~: q4 Y
5 C2 {& s' Z! W4 H, G' m8 a
    functiontransferFrom(
% a2 m' L, ?( J
& H, w% B. r& [2 i; |: {8 R- U' ?    address_from,
: [) G* X% E! n
; F# \9 N  E% u3 `" s9 E% u    address_to,: Z) [0 |0 f0 V$ Y. K' T

: h4 X; U2 V% l3 A    uint256_tokenId( M* ?  V  k6 |0 B
  o" _+ W& n% D( y; B
    )3 w- w0 [( X4 J& i

) {2 v2 m' o9 [/ ^    public
3 t2 t) M) |" ^2 t$ T
- O' P6 {3 L# Z2 [, V    canTransfer(_tokenId)
% ~% m* A- s# K! }$ \: r
' j0 K0 T/ C; w5 \, Y& L! T" Z* {    {
0 T# n: A% T$ J& f" J' z) c% G2 @, B. w+ @& ]! X) B) y
    require(_from!=address(0));
. i, D; B0 E( @: O9 O/ ^& R  u( i% w5 G; n( ?  X9 S8 {
    require(_to!=address(0));
9 @8 h; m" D7 H7 W; T, \5 m6 n5 }0 W0 w3 ?
    clearApproval(_from,_tokenId);
/ _6 G/ l1 _! Q7 [& s1 l# D/ w0 s3 E3 m/ a  ?2 \4 V
    removeTokenFrom(_from,_tokenId);
2 L0 P5 {2 W( w, r$ C& v# ?8 K7 D! o6 Z/ w& r7 [1 v7 Q
    addTokenTo(_to,_tokenId);$ x* K) [4 h' d& t0 _" m

% N; @1 s) Q* E8 n! Z    emitTransfer(_from,_to,_tokenId);
- F# |9 {/ |, C0 @$ `  d
+ h* X$ U2 ?7 j    }
/ ^. }; r9 z$ V! ^0 @: f
( w* P% r. T8 s0 C. @    /*** x9 y: o$ o3 a* g: H1 K  J
. a, E# `( I3 C# M2 J1 m2 s/ X9 R
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
' T" w9 Y6 z8 U
0 U- a: ]; @* ~, ]* Y    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值2 m  b% x3 Y: ?% C4 l. X# Z+ H
. @" m. \/ }* m1 M1 K
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
4 |/ {9 D, o+ ~8 e
( s- u* ~0 E' }# O) i. a    *@dev要求msg.sender必须为所有者,已授权或者操作人6 @+ V$ x3 l5 u: J6 J

' n) M) V2 ]2 a% ?# T    *@param_fromcurrentownerofthetoken
; }# E: `7 E# o/ \/ [
- B/ h& M, `, a& |/ W" P2 p    *@param_toaddresstoreceivetheownershipofthegiventokenID3 n2 v) {2 l$ H" j2 Z. W
2 u3 H) B' W; t- S8 `
    *@param_tokenIduint256IDofthetokentobetransferred
  j" X) @; m  d1 \/ m
1 S# p+ J! G, r    */8 z; R! V) d. e) u5 v
/ T8 ^* Y* l/ a8 D5 u
    functionsafeTransferFrom(0 |' L- E9 y# R! D
9 w! ^2 {4 z7 d# a; ]
    address_from,! K- F& M, C& e4 y! [
" a! K6 s" u' S; _! n( c% p
    address_to,
; y: ]$ i8 ~, F% M
7 n, A8 R! D0 M% x) T, b    uint256_tokenId
6 Y2 `8 D$ `/ M9 j1 Z3 O' ~. i% V3 E
    )
$ Y! f: F- l) f1 P! A# F8 L" ^6 T/ ]( x) t( t% F, g
    public( u$ r% l5 `* B: ^) S5 s

2 K% a  r; j6 E7 K; W! ^    canTransfer(_tokenId)
* Q/ ^+ k% ^2 E9 o4 Z, o- g$ B! j/ k5 H# G
    {, E# _3 l9 F& Q5 C+ \7 p

8 L8 @+ y7 Q  L9 s% Z    safeTransferFrom(_from,_to,_tokenId,"");$ X& I4 @$ J2 g* C6 M- ~* L

' T  A9 A" N$ ]    }! e* D( `6 A0 A0 H

' {# M- S4 ^, z  u0 I    /**
2 e+ ~, X! N0 o9 }& D, B. i, B4 o6 d1 k- F9 \. d+ `) O' {
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址4 x8 N5 [: [* u8 {) S! Z
0 ^/ n# _3 J8 u( E0 `, R6 \
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
) C8 E- g% w9 Z
1 V! p* ?0 ^" r1 J0 L& T8 r    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
4 ^9 ?( ?4 k! A$ Q% S( o( p) @& R) E: U* e3 C6 Z
    *@dev要求msg.sender必须为所有者,已授权或者操作人
* U  T0 W! G$ [' F+ O! ]( W8 }. j/ V& @
    *@param_fromcurrentownerofthetoken
7 n7 m) Q* {0 w/ b
' ?$ z; G" |& i' G: a& M    *@param_toaddresstoreceivetheownershipofthegiventokenID! X$ B' X7 M5 L3 X) U
7 X5 f) m6 C3 O. T4 E) i, ~) n
    *@param_tokenIduint256IDofthetokentobetransferred
0 [# ?) N* n6 j8 Z7 `% _9 D2 o5 R; x2 v
    *@param_databytesdatatosendalongwithasafetransfercheck7 I- h2 a+ N. g+ V/ C# {5 U
8 f: [1 l" ~0 f$ h3 r7 R
    */* ^- {( l8 W5 J2 P

, _  ?" J0 I$ f+ p1 l    functionsafeTransferFrom(
- i' M3 X0 T0 A" \2 d  t$ y/ U! D' V+ c. G! ]& p
    address_from,. E3 r( d" g" D1 b. T4 w, O. k

: u/ V7 N& y, z! O  Z    address_to,7 ?& P4 G  W' Q# M. T/ q. V  _* Q
8 @2 W$ {- F, o: y1 i
    uint256_tokenId,
0 u* S1 c7 \  W* R. f- y3 R
3 g1 L5 d9 E6 M. q8 f; p    bytes_data
6 i" v1 E6 k* [* C5 o
6 `) v3 L4 Q, m# Q( A/ Z    )
2 |- ]9 Q3 Z! g6 l0 I4 }' b6 D7 x* {% D
5 n) _, {% G  }& Y& {+ y) x1 k    public
# k+ {) M7 L4 ]) f1 r# J3 B. k8 \% f
    canTransfer(_tokenId)
. Y+ K& r1 x; }2 n' n" W2 i! w& m/ I  {: g) s
    {
: R- q5 q, }7 X& B' W$ {
7 n. O0 `7 p& N& d# i+ `9 j& G3 \    transferFrom(_from,_to,_tokenId);
- P, V1 z- A" v0 I! d: }$ E9 E- s& {3 t" h/ h( w6 c/ z3 C: I: e% X; x
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
6 t# V: C8 u2 X  b+ L$ W1 i. |: }) ]9 Q! B
    }
( E/ c6 l( D0 R, q# W' E& r# A+ c( ~2 Q: x% ~
    /**1 m- L8 `% ~% x' F" V' m
5 v4 _9 o* f1 L& R5 B+ X3 j
    *@dev返回给定的spender是否可以交易一个给定的token
" H" \; q' Y! m6 ~9 f, V
0 V. U$ S4 A$ b4 h* y, {    *@param_spenderaddressofthespendertoquery% A& {* N& ^, Z. R1 a% G3 L# q

7 [- X% c9 @1 ^! _5 k    *@param_tokenIduint256IDofthetokentobetransferred3 g6 `% n' Y& J+ j. ?4 x, O4 `
' q! a2 Y! v0 j
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,: T, _1 H& |9 H9 S: {
* G& E$ p1 v. @6 d7 n, _4 }
    *isanoperatoroftheowner,oristheownerofthetoken( n8 D5 l4 h" ^7 `7 c5 e

- b7 D% ?( ^$ W# s: O2 t, C; C    */' r% t1 M3 J7 Q+ b. n$ z
+ ?8 Z" }5 n& U; m  G
    functionisApprovedOrOwner(
% D. Z/ v+ E2 V- d/ I, Q( N7 J+ f& y, V# A! R. S6 ]
    address_spender,
6 G4 Z) z+ v$ g+ G9 |. L. ]9 b& J* S4 L+ c- N
    uint256_tokenId) {8 T6 P6 `, g* t

$ K, {  {( ^3 n% d- v+ K6 S' z    )
3 D' V* P) }1 i7 K. ^( H" _9 H6 m; n! ^2 ?7 y
    internal
& l. f- G" c2 N# c; Q1 Q. {$ V5 h  T$ a2 W" _
    view- W) M2 ]8 X, Q/ [( J9 {- L/ e
. [9 o, u" z2 W0 a- `3 _6 Y7 Z
    returns(bool)% p* e! z, O+ I* j% @! r' f5 x* v

, n6 W4 O/ U  K& k/ M    {
8 |% t0 q# y* c, K! \  |& @
' O8 n) z9 ^1 |6 s, l, S7 r    addressowner=ownerOf(_tokenId);
7 q' V& J/ K7 t* D  X
4 Y/ G/ a% e& a6 a8 \7 {    return(
2 [. Q  t7 J- E# o7 S; B8 H6 w8 L! y. B) t6 T7 T
    _spender==owner||
& h/ K  B, Y) N( d" l0 q
% I' F% X; B: F' x1 z    getApproved(_tokenId)==_spender||
+ c7 y! l- [7 i, N0 L4 B- P9 L2 `
5 ?7 \% b8 [1 r& T* \4 R    isApprovedForAll(owner,_spender)4 ^5 W! j3 \9 A; w
: d; j3 r8 h7 ^; ~" G
    );5 o, O9 f1 ~; E  @5 [  I
$ R! i5 ~, B5 {" b% M
    }
% Q" \. \/ O+ g3 [# J% u$ w6 g9 @8 I& v
    /**
! n0 }. C! m9 c* ?8 A6 ?& x5 l& m" B' h: Q' n
    *@dev增发一个新token的内部方法; f5 e, R* N% W2 a/ Y* n. q
' j" X7 G$ x) c2 x6 u0 X
    *@dev如果增发的token已经存在则撤销
9 K2 m6 N& S, H6 M1 n  X# Y8 ~7 q) w, g5 T2 m
    *@param_toTheaddressthatwillownthemintedtoken
: x/ ~, Z( L: Q  ~8 \6 ^3 `$ u' b+ K+ ]7 X  {7 o2 g: y* A3 H4 K' n' G
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender  ~$ d  j* y1 W0 z1 I
+ m" M7 P9 q% d$ [9 ?8 ]' h2 j
    */
' ?$ ~' V: M* q# {* h" O; H  T4 w: E
    function_mint(address_to,uint256_tokenId)internal{
: `' K3 J" }( f6 I) K# ]* K
, K* }9 _( D9 H5 b6 T' v* h    require(_to!=address(0));' P- Q8 r8 Y4 k% N/ ~# ]% M7 _
& {6 k! q( Z% ]
    addTokenTo(_to,_tokenId);) n9 X6 d+ A- q2 [* Z

1 u% K6 h+ E  H4 y    emitTransfer(address(0),_to,_tokenId);* \! f+ Y/ g3 f# C) X7 j- q3 q

' v9 p9 ]* w' H% a    }
" @7 Y0 Q- s- q; {9 k
* C0 k$ c8 v3 B( a8 G/ P    /**6 W$ _7 R: Y0 Y/ h! z
) y0 h4 B, ?1 g5 d1 t! m- B
    *@dev销毁一个token的内部方法  X# T( e; J9 c8 Z$ r$ j4 a/ B

! v! S: S  y3 G! Y. o6 `    *@dev如果token不存在则撤销
6 M, y$ K( e1 M6 l6 I" S. ?
& Z" g4 j  j1 Y1 c& `3 Q3 z    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender' _4 \& b* H% Q. i9 [
1 s( t/ d9 f1 A* F" n7 |, r
    */
) ^( U  i1 b+ S
& }! \+ F7 n5 P& X    function_burn(address_owner,uint256_tokenId)internal{. R1 Q* u0 w$ U: r

; f& Y) n3 I8 ?' H" M    clearApproval(_owner,_tokenId);9 T2 Q2 T; |$ e1 R

" M) u* x' E" V# z    removeTokenFrom(_owner,_tokenId);
# X# G/ ^6 E, w9 K5 K+ Z5 {
6 I" ?4 Q4 X" _! ~    emitTransfer(_owner,address(0),_tokenId);! `3 V: h0 Z1 }9 k" U: U

4 C9 h( o- K/ n5 |, K* K+ r    }0 H* Z, y6 h+ m% L  U, H; \9 ]. g

: x( r, S. h! T  J. Q    /**) m# ^3 m, p) R, u7 D
* y# Y3 V+ m2 b9 ^
    *@dev清除当前的给定token的授权,内部方法! V. n1 x9 Z" ^/ ~: ~9 B

- I& Y' z, }! @" U5 t" Z    *@dev如果给定地址不是token的持有者则撤销. W2 U) ~2 M5 t  K+ {3 ~  _, ]! \5 J
# Y$ A" S4 g$ [6 Q
    *@param_ownerownerofthetoken
3 ]! X0 F0 V7 B) Q& E5 r2 l- Y, P6 ~4 j3 D# W# o
    *@param_tokenIduint256IDofthetokentobetransferred
  ~# t, Y2 V4 }6 M( l$ [# x2 ?1 k  w; _
    */0 f! u% f/ G( }; G/ N

- ~* _0 Z6 I7 q% @1 L0 U    functionclearApproval(address_owner,uint256_tokenId)internal{  i3 ]' ?& E( f& m0 ~8 v% ~

+ I$ [2 O) y- V4 z    require(ownerOf(_tokenId)==_owner);+ N# y0 L" r' l  N4 R: H- d/ H

, [. w; `( U3 y9 W4 \) p, ?    if(tokenApprovals[_tokenId]!=address(0)){# b& X+ H) W: |4 W7 T: P2 C* t( }

) r1 l8 k, A5 T0 j    tokenApprovals[_tokenId]=address(0);
) J1 W% z$ g6 e0 _3 W
: V" L) X- b8 ~% z    emitApproval(_owner,address(0),_tokenId);: z9 [& f, I* ?- l  @$ P
% M( y# M1 A) v& P0 ]% o6 B% y
    }7 t! z# n+ M% _' I# t

! _" w. @: s5 V  c" T    }- N. J) Z0 r- `! l5 p
  J  R5 t& P9 F' D- N  i: }2 W
    /**
5 Z$ U" O# ?  P' A6 X6 K
: W7 r' y4 ^5 w    *@dev内部方法,将给定的token添加到给定地址列表中
& H; w: m9 M& |4 c3 l7 O: v% t% t% s$ J" W, O
    *@param_toaddress指定token的新所有者0 W; E$ K3 p( e' g1 m' R' h1 Q
& {1 j: y$ E. j+ w  ?4 U9 {' ^, W
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress
5 d$ W, I5 p9 m1 E3 }& u' M' W' V. P; F% X5 \" A8 z) }2 ^* z
    */
: P+ d& @. u+ c: w  J$ Y- `+ z$ s* O& K6 g/ C4 K
    functionaddTokenTo(address_to,uint256_tokenId)internal{  h, ]! X& {6 o0 p- @# F8 |

/ I: |, d( @' w, a$ b    require(tokenOwner[_tokenId]==address(0));/ H, m2 E+ S" L

; ~1 v+ X' _$ N9 g# P4 o' t    tokenOwner[_tokenId]=_to;
) U) ?5 @/ s* Y; l' L' F! i2 `7 T9 Q3 u0 q7 s- N* v
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);2 B6 A( \3 E2 y- H& g  m
/ Z# ?' u- b8 q" P  }3 \
    }5 I2 t/ _* D. H5 }' H4 R7 |3 O, }
( H, g* F' |  l. d
    /**
( ]& n4 L+ Y) X- h1 X) l0 w: M! I0 t7 w$ e
    *@dev内部方法,将给定的token从地址列表中移除& v1 i7 R, I% \% T
  f. _2 |' k: K( j
    *@param_fromaddress给定token的之前持有中地址
. e: o+ [8 K4 [0 K2 T# I/ ^+ X; `& `9 [3 Q
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress1 z. R5 I1 l% a7 I0 ^# \
6 Y8 X* |$ l1 o& G
    */
+ |* J5 Y! W% H: o7 }" y$ i2 b4 S5 W+ b' w. z) f" @+ ?' y
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{
7 b7 n' R# ~* _% a: a7 s' b2 R7 O) v; |& F: y
    require(ownerOf(_tokenId)==_from);, t. g5 r; K4 S# H5 _

$ c  {8 p7 z; y1 T: Z. D    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);+ T% O3 r  J' A
8 Z4 M# V4 p$ s$ J/ k5 \
    tokenOwner[_tokenId]=address(0);/ n1 o& K  e0 S" v* y4 t' m3 N7 t

3 ^1 v9 `/ o5 V' P! v    }
" Z' Z' z# X2 h) y8 Q9 x. E
) q1 B& `) V5 r- y    /**
9 r, v5 T4 N, e- O$ a2 s0 b
# o! p+ Q: V  r) d- R    *@dev内部函数,调用目标地址上的`onERC721Received`
) l' E( H% X1 o# l) d# S5 R# f6 V
7 z( p1 C7 P/ ?( A# X- W    *@dev如果目标地址不是合同则不执行调用
) }: u* U4 L- ?8 U* |- i4 h/ {% e# _: n* T
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID8 l$ j$ o8 ]  X) c8 V* ], \
& Q9 @- I! f: Y8 w2 q
    *@param_totargetaddressthatwillreceivethetokens
3 x: R3 n; T( p* U% H, y0 c
8 D7 F) c/ ?. e: s; x( l3 Y0 Q    *@param_tokenIduint256IDofthetokentobetransferred
3 k- [4 O- D1 Z6 a  c
' I! R/ Z7 B9 n/ f- n: F2 _" N- H3 z    *@param_databytesoptionaldatatosendalongwiththecall
$ b* e8 Y  ~* H% |/ e  x4 M& f( g
! m5 r5 i! R: E& w    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue- e. y$ `& S7 @

4 R3 {* [  }9 _& L( Q    */
* O( \6 E% [2 V# U2 C2 C- o% O/ X2 W/ L7 v+ h" ~
    functioncheckAndCallSafeTransfer(9 k; y. Q; ?: ]3 ]! n7 z
- l$ }3 j5 Z. Y7 x) b. |0 t
    address_from,
. n$ T( i, s% `4 B" F" H' S; c  ]+ o! X& S; `
    address_to,
" P9 v$ {/ `3 [: ?3 {
/ h( Z3 [& k7 j4 @    uint256_tokenId,! M& I. O( a7 k- O% G; E. t0 C
. q' H4 Q. C- s' ?6 b- T9 m% A
    bytes_data% o2 U4 {0 c; y2 r  p# n
8 |4 v9 {$ X( \) }* H. D$ D- c
    )
9 Q. A6 h# W! _- I( S' ^
6 h$ ?2 t, T4 A    internal# j5 v& Q# b% T1 M4 `/ q: q
$ z7 j: f7 T7 l& z3 Y4 x" \
    returns(bool)
9 |  a/ y$ D. y: e. \- \( O+ f, |
    {* F) X9 b; n) g/ H/ G
: Q- a" v9 n- Q, _
    if(!_to.isContract()){9 y) X8 M( u& ]8 k8 ?
# Q. e; q2 i- x4 E5 z
    returntrue;1 x! P; R9 E  C' \% E) z

" L/ R4 M+ m* E( t    }
  r9 R* u, O( V$ s7 Q, X9 U) A" t2 C# w& v6 [# [9 q
    bytes4retval=ERC721Receiver(_to).onERC721Received(
, Q; r. C' p+ X/ L  Y
1 {& S- W# j3 `. p  o$ u' n7 F  ~# E    _from,_tokenId,_data);
- Q* y3 z, G7 d: j! B2 {. d0 P# }/ Y) ~: G' g
    return(retval==ERC721_RECEIVED);" ]# K/ O, w* a" i8 I+ K3 F

, {- J* O9 e) @- K; t; B    }6 `% G3 b9 r4 d0 K% i

$ B1 `' d# p- }# t& [    }* y/ ]+ F* H, H  j
& ]% S! k6 j4 w; T7 K  V- o
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
+ S* M' A1 r+ Y4 x3 p, g
1 x# p& B0 s/ t# g; V    ERC721Token.sol7 r0 _0 y9 K$ S
. o: H. o1 i, {
    pragmasolidity^0.4.23;
* f/ W" S+ W# o6 G  N
4 k0 h. f  ?7 M9 s    import"./ERC721.sol";
+ z! g. c* J4 I, V; X. f# N7 {; G/ q# D, V2 T: L7 K( b
    import"./ERC721BasicToken.sol";
  P- |9 R, z% E; i4 B2 G* l- x# G7 y5 o4 i
    /**! ~( C" B/ S7 p, ^

! o* v- Y  \! x6 s) B- q% g5 v- S    *@title完整ERC721Token
/ n3 H$ Y5 O( o3 q2 o' V( `8 p6 H. b4 r, m% Z( {, Z* v  ]1 s
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
( `, Q7 A: U3 l& i. J7 [
5 B5 b# p$ c' _. g) K7 x1 ~1 E    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md1 o; M  m, M& @& c# _

* }( T" V4 `& f, l) {' w    */1 z7 U$ b' V8 ~# i9 X
% h  u- w4 J, \$ A, e( \; R2 |- W% R4 F
    contractERC721TokenisERC721,ERC721BasicToken{
& h+ z* z9 C" k! y0 P  M  Z: k8 }* p8 Y4 j8 F' S
    //代币名称$ X4 S7 n* [3 O9 X% P4 S
0 R7 a9 M5 O: i
    stringinternalname_;+ Z: [. W6 l; {3 ~4 G5 w
) z- f) I9 N$ O4 t6 l
    //代币符号
. {9 F$ z, E- U/ q# U/ f, n8 ]+ T2 b4 A, |! P
    stringinternalsymbol_;4 p3 M7 F; m9 B# t
3 }! E# Q7 c( `% E- u0 Q
    //所有者到所有者拥有的代币列表的映射
# v1 Q1 D% m$ Q. ~  o5 i- Q/ o1 g4 B) L1 L! I) ^* v0 y
    mapping(address=>uint256[])internalownedTokens;/ {2 a/ t2 L# Z4 _* l
9 B+ _1 _4 B' ]* X
    //所有者代币列表中代币ID到索引的映射, J2 U- o- a" c0 _
2 I  {$ ?8 p. A) J) o. G
    mapping(uint256=>uint256)internalownedTokensIndex;
8 T8 S' g' `5 p; [& J# l7 X2 S3 D5 Y8 n0 Y
    //保存所有代币ID的数组,用于枚举
: f# Z( E) r0 T- t7 l+ p7 I: ?+ ~- J+ j( E9 M; K0 w
    uint256[]internalallTokens;- L+ h2 s8 |3 v2 q' {3 o& L1 y
& D& }7 H( U* X( O
    //allTokens数组中代币ID到索引的映射+ o# O: v2 a% B% P
& t  x, w' Q- P5 X  @# s
    mapping(uint256=>uint256)internalallTokensIndex;
( P7 R, ~2 h# p8 L% }' I  R6 u) p+ w- w( n  ^, H6 y0 G- M
    //可选的代币资源URIs映射2 O$ V& g; r! K$ z% [
; \7 u7 I- H  c7 v
    mapping(uint256=>string)internaltokenURIs;
9 J$ ]( ^0 @, M  K1 {+ ]% z
. G7 ?6 i; ]9 F5 Z4 A5 W. s! `    /**
0 p1 G9 D+ a, {8 V9 F& w, v; `( W5 |" }& F
    *@devConstructorfunction
* a* m( x, m$ @/ c2 q, M; _- w7 E; B9 x3 d: X6 U5 K/ o
    */. E/ B  ~8 }+ j- r2 |# z6 p
& f3 z- ^" l; Z( g& U
    constructor(string_name,string_symbol)public{
* C# y8 s( |) P1 I8 H) ]1 ]
, s& p% a% O0 m( g    name_=_name;0 d' R: D; F+ J
/ }$ k, Y: A/ X- A0 d
    symbol_=_symbol;
* v& t3 X( C4 j+ E! J5 d# ?$ j/ A3 ^- o( N2 R5 F
    }# [- m' O; C2 W" P$ a: r- Y
5 |4 C! }0 @1 o( F
    /**
; l8 d4 a: ~+ B0 S6 d: A5 r: ]0 D, v3 P. S* r$ |
    *@dev获取代币名称
2 f  {8 a9 `6 D
' a/ w( C7 X  i+ d, v, @$ _7 h& W    *@returnstringrepresentingthetokenname
1 h- r  H' t# O! h4 P
& c1 r# u: p% l5 Q7 X$ H9 R    */6 a6 c* W* B. r' U% `/ }1 {) O

% o' ^( T5 v7 [    functionname()publicviewreturns(string){
3 N# G' {/ _* y' j3 `
9 R; J5 a* ^2 H. h5 Z- q5 T    returnname_;
6 P8 m# K! w& F/ _& K) {; Z; ?; W6 ~' P& L  e3 [2 ~2 Q, ~# X; j
    }# _) Y5 ?5 i3 u* P, V% _3 }/ |
* \' C% C! ~8 W) ^+ v" O
    /**
6 C  C' h) L$ P- _! B9 e% U
% M6 n4 E9 i0 z; K9 }    *@dev获取代币符号
* L7 B/ W5 l# C5 {2 ]) V
- \7 g) b* k. z( K& M3 P* Y5 W7 c    *@returnstringrepresentingthetokensymbol
4 Y: T6 R  \- A5 o, m, v, H
( J4 M5 Q$ v7 o; n    */
; n& R# ~) q4 |! H' f
( k+ l' M# R; U! m: a  e; @    functionsymbol()publicviewreturns(string){" ^1 _8 d2 P0 @, A
. M) X" A+ @8 K# r' T* Q8 P3 X
    returnsymbol_;
/ N1 x; l+ `, s
. p- m$ \# {; e! q+ l* e+ D    }
% x5 _- s5 c, ?- P7 z  W
+ w6 H7 \8 X4 t7 o    /**
. E" e! A1 H/ l& y& P; B
4 i) m% ]1 \( |- A, @* q0 f! F    *@dev根据_tokenId返回对应的资源URI
$ \1 U' }% `& f. A
# a4 I/ c' d' l    *@dev如果token不存在异常返回空字符串
% ]* V2 a$ z1 H2 d+ I9 z: L8 R
8 D+ I5 z! X4 V+ s    *@param_tokenIduint256IDofthetokentoquery
5 F8 F2 N0 H) }, H) g8 l
( f) r; L; z( M% x) `. s# @! B' s    */
% p$ {) a# d" b1 I( ?
. d6 p. Q0 q% n: `$ J& c  l    functiontokenURI(uint256_tokenId)publicviewreturns(string){  I7 S# g! H8 ]. [7 U5 D3 J
+ _3 r; T6 m, L# q) u
    require(exists(_tokenId));
' _' H8 V; z+ m  D2 n+ V
/ g# W1 z* e7 [8 u% y2 C    returntokenURIs[_tokenId];( x  J6 q1 o6 A

3 x3 a  A$ w8 |! b1 t    }# T- R, D$ c1 ]8 o' r' X
: W0 S; q6 N' g
    /**
! \0 L  f- u3 a$ Z0 `+ Q' [( L7 \- b! y  s
    *@dev获取tokenid通过给定的token列表中的索引( I' B# d" `1 D" y2 t
! t/ q* l1 ?/ E& B* H9 L9 G
    *@param_owneraddressowningthetokenslisttobeaccessed
4 |( R8 _- @% Z, T$ ?3 p# w* D, `
# S2 j' C) D& o6 z/ h9 p    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
% L, A  k1 }; @- U
8 m) O! u% `, C+ ~4 K; K" ?- T8 u    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress) {0 w  k+ l) y! c2 r0 \0 Q- E

# h# ^( G  ^) X8 x4 _- e: u0 i    */0 D8 G2 t/ e9 E7 q! T4 |

  s' u7 n6 l* g) O" J& _; k    functiontokenOfOwnerByIndex(
' s* [; _8 j0 K) u4 A
( I4 x  {. {; z. Z6 s* k" w7 r    address_owner,
+ Q' ~, X# ~0 P* _7 y; `, U( q( ~4 Y
    uint256_index- T4 P: k4 G5 k5 }: c. ^2 A) E
! ^7 o9 K0 m0 i
    )
" X3 S9 M8 W: p! Z  \! P( J7 A" S. B% f2 X4 `& Y
    public
* U1 z* `! R' q! N, U0 z( B# a. Q3 P2 |% d9 e) F$ R
    view
( c1 P  s( @! i4 D- ~
) o: U$ H7 x6 J  y    returns(uint256)
1 I' c* @& q5 t! N, `& @3 c3 U( X3 G; x6 |7 _: H$ j0 a
    {) ]9 n  c. h# f2 W" l, ~! S' C9 e
3 o/ T  d' p2 m& J) w/ l
    require(_index7 }* x; V0 K5 w/ f
  H- U# g8 G7 I3 a5 V
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。) a; r& F8 Q' [
; T, @* s- G  Z  O2 u
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2