Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2426 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
- b0 \3 `  _# S+ M3 b) ~1 P" i
! d7 C( ^0 X: }6 F7 p5 ]    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
( U3 t- ^1 B% U- \! V% f
) |2 @& v" @1 p% F2 w6 Z/ X* \; s    ERC721Basic.sol  s! c' o: R. j0 C

9 [9 p7 u; L! ~# u; r    pragmasolidity^0.4.23;
6 ~* V/ n: R% T. z: N# X3 E
3 H" C4 P6 X' q( k% {& w2 _$ I    /**
' c( ?0 A- k/ y1 P8 i
% w8 D2 H7 _/ J% v' q    *@titleERC721标准的基本接口
. W5 o/ o3 W& q/ ?% e. I5 m8 l3 U) [& _1 O: ~) O2 n
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
  g- x& A  {+ G
8 u( w1 j' \* D7 e6 a8 B. l& c: Z    */
7 ^" b$ T# w8 ^- m3 n  w7 b/ p( p- O7 C6 K
    contractERC721Basic{5 {2 _/ Z2 X+ \" J* z- s

# P; Z  B0 u, ^    eventTransfer(, a# {# f5 _2 ]# ]
+ ~! `; h& j% Z+ j, p
    addressindexed_from,# n! c2 W& r4 |7 k% ?3 q6 n& u" |
0 k8 y* S% k* x' ^4 I3 M# }  ?  d& _
    addressindexed_to,
+ f! M% d, g2 H! K0 V1 f0 P. |( B$ `# E; |5 |
    uint256_tokenId
+ m& r  U$ [7 V; ]- o, h5 p  V
0 Y, H+ v" `. p, b/ V, |    );, j1 O& e$ h/ d: i* t) ^
+ {$ o! R$ Q6 a, [5 ?2 S' A
    eventApproval(
# v- X  w4 A* @6 m0 H0 z% ?3 K# B: E* x  @, D: _
    addressindexed_owner,: ^* l( p8 y3 `; {3 u* s
- W: e" F+ f$ Y; Y6 i$ G: R
    addressindexed_approved,
) f. K: l/ i" V7 l' d) I4 h; H# I  S
    uint256_tokenId
9 z5 C# e2 J9 ~/ G# `
% |# p% o8 P# s6 ]. E) |3 n/ Z; J: [    );
3 Q7 H- Z2 Z- x! d. B* w7 C
- M& N$ }: I( s    eventApprovalForAll(
7 `2 U9 y( f5 |% q) U: B
6 N" \+ z( m! O/ I- B4 ^4 A    addressindexed_owner," B, B7 D8 b3 g" h9 z6 Z
7 M; Y# O/ @1 u" c- r' Z; N
    addressindexed_operator,7 T( U: L& M9 f, X2 j0 m+ g- b; {

8 T, H  e7 n6 Q+ v8 Q4 g    bool_approved
# T" e4 S" c0 x
( @  }$ ?1 I" x6 m    );
% B; e% Q8 O( H' i- J# _# y9 m7 v! `4 s2 H* ?9 P
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
0 E# N( N4 _: E, ~3 c- u" g
# s0 J% a2 a9 o5 W* B0 d; u0 Y; Y    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
. g0 W! U+ v; p9 g) j- M7 n/ `: T/ K  z# m( C( [/ r5 o/ |; l
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);' U% z# Z% q( |. K
7 Q1 W) t+ ^' A, n; R, Y
    functionapprove(address_to,uint256_tokenId)public;5 o4 C1 p" E) E

1 u" H4 v, ^& |    functiongetApproved(uint256_tokenId)  f1 X9 n6 z3 d4 `
% Y4 `! i6 w5 k  z4 h
    publicviewreturns(address_operator);
1 W7 a' f/ \6 z3 Y0 ~) [. s  j/ Y4 {2 l4 A7 V0 b4 U0 c4 l
    functionsetApprovalForAll(address_operator,bool_approved)public;
( G8 _7 q, ^' }4 y- M+ }
2 M0 ]& E2 B& N: ~    functionisApprovedForAll(address_owner,address_operator)5 v) w( b3 e3 ~1 Q6 ]2 C
% u2 g6 U+ \2 l& @% C  [* Y! ]. y! U
    publicviewreturns(bool);
( H+ V1 Z. s8 W- m4 E0 y. v% O4 [6 K1 J9 I
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;0 x+ ^2 r( E5 l! B' w

6 i" o; ]( k2 [( M  H' \    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)) n& P2 K* w0 T/ `; d: Q( c$ N
6 _" l1 M! x  ~5 P7 o" D
    public;
4 W: |1 M* @+ h3 D7 R& p; u  t+ S  A/ r% _2 q% w' f
    functionsafeTransferFrom(0 b" o# Z0 k! q- d6 U+ E

; `7 K5 h- Y+ t+ M+ y2 u    address_from,
, }" N) g. o% ~% L0 p. o9 Z) ~3 F
7 s+ S) M' K/ @1 I" |/ {& }    address_to,
2 F( o, p, i: ~5 L' d- C% W) |+ ~# ?3 n$ d
    uint256_tokenId,
, u: w% ~$ B* ?4 q4 w( k5 [% X1 {$ X/ ?$ D: U
    bytes_data
6 \/ t3 y- k0 b1 A. E  N
0 \) d0 ], I$ @6 r- U    ): T' V! Y  p1 E$ L5 F4 Q: `
) |* G: X' w1 k! d6 h2 O1 k
    public;+ D$ S! b0 I# d% ~% P- |9 B1 u! j
: l! |% C1 D' n: J8 Y, c# v$ v
    }
6 }* G* |8 T! J9 g! R- t
- c8 P$ Z) S; Q2 w! Q& h    ERC721Basic合约定义了基本的接口方法:
  f6 M* N3 ], m8 f& G& U4 W$ k  L* T
    balanceOf返回_owner的代币数量
( F7 Y% N7 X; u5 X
* R; V3 S: Y+ L' a; l1 i    ownerOf根据_tokenId返回代币持有者address$ ^1 ?  j8 t- G; r( k' U
( j5 V7 r4 H( M4 a4 v) K% d
    exists_tokenId是否存在
+ u! w5 }, z& n0 v. J% P1 @
: g3 U" {& H. `5 ~$ C% I  ^2 [8 }3 g1 W    approve授权_tokenId给地址to
. X0 F% p& b# f* E! X- d- k' @+ I, v( r
    getApproved查询_tokenId的授权人_operatoraddress3 Y& \3 f' R' d, L8 q

6 n3 s8 f$ L/ V1 ^    setApprovalForAll授权_operator具有所有代币的控制权
1 [4 m. r; A9 T* g! T4 L$ i
) ~- C% G' q) x    isApprovedForAll# F; c" H5 a$ m  A4 ^  |$ u

( O7 `: C9 a$ x4 E2 T4 k$ y    transferFrom转移代币所有权2 X  R# d' w. T/ Y
$ i/ v4 u- o+ d# C' u+ e
    safeTransferFrom转移代币所有权( x7 g/ Z  ?" h3 i/ T$ x
) D% B" \5 b7 c( Q/ b# z
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
5 c4 m0 E: L6 w' _- M# E6 ~$ E6 X! {6 r" e- M
    ERC721.sol! ^6 I( I5 a2 d7 u/ S+ d4 f
  ~  \  f2 F0 }# b
    pragmasolidity^0.4.23;
; y3 o; n: L9 [# k- G$ A
5 R7 ^/ H/ b1 w. h  T    import"./ERC721Basic.sol";
/ a1 A; Y& v' X+ T8 |, Z. t$ g
( q0 {# M; ]# \: q; c! e9 Y1 i' A    /**+ F' |4 s) V' @4 }% F* }3 j

- U7 @! ]- T/ S1 L/ a, ]) m5 c    *@titleERC-721标准的基本接口,可选的枚举扩展$ Z6 z1 h0 X7 z' b8 }% s$ s
4 ^5 O1 A, Q3 i9 k; b/ I9 _+ v
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md7 J( I& e. Y# R, J
- f) z3 w8 M( w+ B$ H! \1 {
    */, s1 s4 s* H: d! S3 K+ S/ ~( }5 l5 l

) p  l. S3 R  q! [    contractERC721EnumerableisERC721Basic{# x7 r1 {: ^' e5 Y* K% G

+ v* G5 @7 b5 x( L4 D    functiontotalSupply()publicviewreturns(uint256);' Q  `( N7 n  d* ]. M

/ x+ X6 N, N. X    functiontokenOfOwnerByIndex(
4 d6 I. X5 w3 @
* Z$ m; ?$ Y- o; R6 n    address_owner,
4 w5 O1 Z" U3 K1 ?+ p  Y5 }' y6 H; V7 U
    uint256_index
. m/ S8 ~; l/ B7 ^$ Y! P. c
5 Y+ W% ~/ _# }    )* \+ F3 B/ m+ g; P

; B& }/ B3 k3 i5 g/ {8 x    public
9 g8 T. B$ G- u* y. ]9 G: V, e/ s, b* g2 Z0 F0 {0 L2 O
    view
- V, ~& \  @; m8 h+ `; o7 }0 U% S: Q* Y) Y* z% I5 A: N
    returns(uint256_tokenId);9 @; W0 N" E, B) d/ l( v" Z) T
, d0 |0 N5 x5 c. t7 f
    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
6 n5 j0 F/ t$ t$ s. O) [2 x5 h* g' W! c1 V
    }
+ l0 z. b8 u! ^4 @
3 j' t0 J( M/ z* N3 f9 Y) s    /**- V6 r0 j% g; ?2 O& k( ]/ O

9 @# Y! k! J# D, M( z5 A- |8 I7 I& N    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展  r4 u$ \- F! C+ q3 Y

' [; L. d8 c" y" b8 a  ]    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md6 R$ K  b1 j% T% x" f4 Z# e
6 i4 B) b* Z! ]
    */
1 d1 I- N2 W( z$ R; P
' K. g7 l* C; K% V8 ^& e; ^+ G! t    contractERC721MetadataisERC721Basic{
7 {4 |" a% A5 ]' z) W  P
8 b  A" F6 T2 M    functionname()publicviewreturns(string_name);/ d, r7 _) X7 g9 |
# D+ h% C" E& L6 K0 W
    functionsymbol()publicviewreturns(string_symbol);6 H: P) M; n, I, {- i
9 {6 h- [1 B/ S- T# W' w
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
/ j4 d( x- }; P1 V0 z$ V' I  M  n) \, E6 m9 N8 j  `: B
    }6 E' _3 X) }; |( q5 k* \
4 ?' ]% b0 R; W2 a  d; o
    /**) W8 G* b! O) {

0 p. U" f9 F% \' a, J( @+ I* r    *@titleERC-721标准的基本接口,完整实现接口& k/ @# y6 M& g/ g
3 A' A% W+ s; Y6 @7 _7 |
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
+ J' I6 H6 N9 ^2 p5 E% P9 Z$ A. _5 P7 j- \; E5 e
    */
+ A  }, P9 h0 {- P. k" g1 e7 W9 |+ V. a
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
9 P: |" i  |5 ]0 a
7 B9 T" J5 s- {% ?' \& z3 e, Z    }
$ c- u4 C' x" R2 m" ~
0 |- E  Q& \+ a$ m. o. Y7 f( n    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
# k+ |% `$ a% S9 Q3 K( m1 i, s8 }% ^' T
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:) `7 N0 M$ R8 ?: `
% V9 ~: d: _9 j7 c; u8 P" E6 s& A
    totalSupply返回代币总量0 A; r7 J, u( ^  a7 g$ g+ S+ Q

$ \( M9 T0 A2 H' v! f  S    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
9 v' z- X, y: o. d$ f
; H. \' S9 E! U, |& H  I    tokenByIndex通过索引值返回tokenId, o, c7 V! B% m' q' Z8 c1 [  j7 F

* v$ f7 e; \. ~9 R$ R4 }/ M6 k    ERC721Metadata元数据扩展哦用来描述合约元信息! u4 ?. R1 [( w5 ~& N, L! [
, [4 B8 ^+ K% U# l4 w
    name返回合约名字
0 D; `" G- a2 d! K' j5 j. h8 E4 X# ]
    symbol返回代币符号
8 g8 c9 o2 u3 |" A. v) V+ i1 T4 D4 _% ]0 @2 @' b
    tokenURI返回_tokenId对应的资源URI  ~1 |, I" \# t! @- t
1 E. `0 {. h5 ~; u& C/ d% T
    ERC721BasicToken
! k5 G, X: `% Q. b* d
$ W7 k; Q# r) `& _    ERC721BasicToken# }$ n% E" X6 p. g* d: M/ m# `

' `" F* [- n4 a+ P    pragmasolidity^0.4.23;
: I  ^4 n) n2 S" e$ F: u5 u
- v4 V9 |( P6 @! {4 R. w* |0 E    import"./ERC721Basic.sol";
. O3 r- R, S) z% L  V, f" \0 G; a3 o7 z6 ?
    import"./ERC721Receiver.sol";" ?/ h) a) _' }, {# |4 X
6 O- A9 V+ c  h3 q; j
    import"../../math/SafeMath.sol";1 Y! E" B8 R  H5 e' v

+ O; p  h4 _: b, G/ t3 O    import"../../AddressUtils.sol";" z1 b& p/ N) k& X

2 N* d9 l! E0 B' E    /**
9 m2 ?$ F- m! A$ F5 `% y+ _( A# v. {, Z! x
    *@titleERC721标准基本实现
. p, n3 ^+ |6 h7 u$ \' n) a- b9 _8 b/ K" q6 t
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md: Y& r, V' G; y/ {6 g$ Y8 o, a

7 W0 b; V6 H& l    */
$ {' g: h0 D; Z0 J* T6 s
  a; q* o$ P0 p8 j. q3 H0 B0 I2 q# u    contractERC721BasicTokenisERC721Basic{
5 r; T/ U; I* l$ N2 u/ l( F  y$ g0 Q! u3 f3 F
    usingSafeMathforuint256;
' _+ t: Z5 R* {2 I# F4 {) U, O8 T' G* T5 g9 @7 [- _
    usingAddressUtilsforaddress;
( x- n( R: o* R* g1 U1 n
) R. [3 k* W3 H5 h    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`6 F' Q# j) E. p$ C( N5 t" U
( |  u3 Y! d1 g
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
; @+ C2 {5 \! ]8 ]0 y
7 e5 }% q& q4 T: a% n    bytes4constantERC721_RECEIVED=0xf0b9e5ba;* A) F' C- f5 Q- t
% m6 F- {* c7 ~3 K7 @/ d; s
    //tokenID到持有人owner的映射
4 A* N7 L5 J2 i' k4 K0 N6 z+ i. n( E8 C
    mapping(uint256=>address)internaltokenOwner;
! a- V! y3 ^  N7 F' y
) c7 H2 T( Q9 U6 E" d1 w    //tokenID到授权地址address的映射
, M9 s2 O7 Z. l4 L: p) F5 t8 B" |& V
    mapping(uint256=>address)internaltokenApprovals;/ S! J+ B" X: i: U- n9 \( v
, t* M5 b9 @* J5 `3 I8 s! B
    //持有人到持有的token数量的映射' Q. ~( N3 [2 o

7 y# L! q5 _, H7 Y/ v5 r' O5 K8 c, l    mapping(address=>uint256)internalownedTokensCount;2 }0 u* [$ X8 C/ i' j
( Z# `) |/ f9 L
    //持有人到操作人授权的映射
" m9 ~& e8 [" K5 D' A" X
7 W4 J3 }. Z: h5 b1 g! L' ~    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
6 W1 _+ H/ Q# Z& ?0 T) _2 _3 }6 w
    /**5 U8 L1 r0 i1 o& u6 }' U
# B9 e# l% p% l2 O2 H- u  }, U
    *@dev确保msg.sender是tokenId的持有人
7 m' H! R# e" o5 {+ W% G" c- D: W$ b4 y* v( g2 ~7 f
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
  ^( m  e4 s' }" P$ ?/ P; W/ ~% r
1 R4 U* B2 L  s$ d7 k: ~* b    */
8 v6 w" U* d. C3 r) Z- M5 ?+ Y7 L( \
$ T) d( {- T+ C8 J: \    modifieronlyOwnerOf(uint256_tokenId){
, h5 h; C" [6 ~7 m2 \7 p
# p2 u" y* r) s    require(ownerOf(_tokenId)==msg.sender);
# D0 e# ^6 q- ~5 s( Q# H1 y7 H9 y6 }6 m8 L( f' E
    _;
( _: R/ k, u7 C2 W( R4 L8 N* j3 d( ^+ p: H4 m1 F
    }5 R& m& Y9 {- `: d

. u6 e* z; R( f  A" N  @: J+ O: D, s    /**
2 m8 H2 A( u# A) Y0 x
) f% ?1 m' B# s( Z3 \1 U8 w    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token, s6 W7 [* g3 T6 e- ?
3 n1 ~1 m/ C. N# t) i
    *@param_tokenIduint256IDofthetokentovalidate5 A  a3 r% a/ I7 w" U

9 x. v2 K* Q' [    */
0 V. U! N/ T" x, q. K) C' C2 Q- O, e: W2 a
    modifiercanTransfer(uint256_tokenId){! f5 p& ?# J4 j% }9 ~
" U. e& I3 \% U) u
    require(isApprovedOrOwner(msg.sender,_tokenId));
3 m( p& ?7 t6 A' `8 k1 m# l  j. T! i
    _;) b5 l2 ?# q) `% m7 P3 ^; `8 K

0 h: K% _, @4 q+ f% Y6 T    }
. t) ?% {$ `0 U. `, A, X  }/ d
$ S9 p) I) `0 Z& n2 [0 ?- b1 D    /**
3 g7 [5 Z: Y& L3 m
: Y6 t4 m/ |" p, [4 {' j! ]8 I    *@dev获取持有者的代币总数& {$ D% N2 d- D& c) I+ R. [
- P+ r$ d/ V4 U; u+ S
    *@param_owneraddresstoquerythebalanceof
. J/ ?: k7 F( k$ M  I" i  O
# s6 ]+ p. x1 }0 [/ a    *@returnuint256representingtheamountownedbythepassedaddress. }5 X& [8 G. ?1 p* m

1 B  r4 }% F! ?! C# b  L; S5 K    */5 v9 o6 g0 A" ~' O8 g  ^, s& ?; @
5 {: T# _+ P- v3 P( [
    functionbalanceOf(address_owner)publicviewreturns(uint256){
# V1 K- a8 m) X( a4 t$ W
& Y( i  y# q! v/ {" M- ~' d7 p7 o    require(_owner!=address(0));
; i: j  Y6 Q# ~0 ~% c- i% U
# \, h- C% _3 P$ |+ B4 S6 \7 G    returnownedTokensCount[_owner];
: u% S/ [+ [! f1 q( g( P
4 \8 @. S3 N5 }4 S    }& R0 S4 {/ l+ D8 h
0 `! r9 H9 }0 V- p" T
    /**7 e* `' z; A6 [
" @1 @8 V1 e2 t+ l5 Z" k( \+ j
    *@dev根据tokenID获取持有者) }8 v7 f" a' T# {' O3 ]
) F4 }3 b" s  Y- j- ]5 T
    *@param_tokenIduint256IDofthetokentoquerytheownerof3 L3 }# g% g! h- A6 f2 O
- V( |- A' H, @9 n& Z7 u' m
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID' {4 |3 X) d1 @: V0 I9 F! ?0 ^# {

1 M0 x; H* ?, O+ t# g( |    */
# d1 k& A0 Q+ y3 ^, b
: @  V/ ?% \( p: `- S1 I    functionownerOf(uint256_tokenId)publicviewreturns(address){
1 E! I: v* K& V5 x/ ^/ U9 R
- P  u3 I, ~3 s5 }4 v    addressowner=tokenOwner[_tokenId];
: g* t9 A) r+ U) r8 T/ Y% Z
  l4 y+ O+ \1 U. S    require(owner!=address(0));6 p% t* O: D9 H3 _- k. q! D

/ Q4 c* T; A4 e    returnowner;4 V" v( G. Z- F5 `4 g
; l/ ~, \" s. F0 C3 q4 d
    }7 d4 B- l+ {1 |2 x% r8 y
* h" n  b! o* D4 w
    /**- w3 t  g9 {3 g8 E

$ {2 P& V- S3 t+ z    *@dev指定的token是否存在
# t5 @# {+ P% o
; x+ V/ y3 F. a  Q  |    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
# U) g9 z! D) c# g( C. U  v, `9 b- b" f
    *@returnwhetherthetokenexists* T* Y, }8 K; E2 H/ H  M
" [! p0 M; D+ Z7 c8 u! |9 H' v
    */( _; G  L/ ]$ P) @: L) J3 j0 \

; z/ u+ A* p! @7 D. z' t& y8 I    functionexists(uint256_tokenId)publicviewreturns(bool){
6 R7 m* K" a) h7 C3 Y6 D* l: ?1 z
/ }! p+ r7 q8 ~    addressowner=tokenOwner[_tokenId];
9 {( v; c- T, [) k* r) |/ a- d- v# I+ m+ d( A
    returnowner!=address(0);7 W& D/ V* e  n! x) N( l
" c' p  q% a& G8 l% D* m- _& z4 d
    }
# m6 L; ?* ]( f+ d& D; O5 p" N7 J' ~) C
4 C* B1 c3 \  C) K8 l* Z    /**
/ ~: i7 J8 d- k- C3 @$ |3 l
! O/ U: |1 y4 ?    *@dev批准另一个人address来交易指定的代币
( [1 z$ B3 W% G; s+ t. h# q  E: _' \& D5 Y4 _% Q
    *@dev0address表示没有授权的地址
! h5 ^1 q( J( a
/ a- q9 T' s. d* n    *@dev给定的时间内,一个token只能有一个批准的地址% d9 `; t' m; [
/ f1 B* P4 {' B- V  z- m$ z
    *@dev只有token的持有者或者授权的操作人才可以调用
0 f3 k1 X) i3 F/ s/ u8 Y, u! A% m
  E1 P2 R0 l1 Q' L3 Q4 c    *@param_toaddresstobeapprovedforthegiventokenID
0 `2 v3 N# h$ O- f- ?' H5 @  T6 ]1 |8 G3 O
    *@param_tokenIduint256IDofthetokentobeapproved6 o& v$ \6 e0 c2 g+ q) Y
% z6 c  b  `  o" @& p' C$ Z9 R
    */( Q8 ]' t9 o( w# y

0 Y- P% o4 ?* o( N    functionapprove(address_to,uint256_tokenId)public{
1 |- ~  d* V4 x( ~3 G* @- O. A! P
/ i1 q% h- s4 c  M    addressowner=ownerOf(_tokenId);
  G7 Z* T$ O/ D, k5 _) ^$ }2 H3 j( @# @8 D' g) Q
    require(_to!=owner);0 e9 [% D7 e8 y: U$ v5 E

" V5 o- B6 o- y! u    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
, J( a& @+ O7 F6 S( J$ m! w
" Q1 m6 X0 e: B    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){% p3 P( y+ L; Y9 R1 V
( s5 y3 U! P0 q
    tokenApprovals[_tokenId]=_to;; B) q; p- r. f9 m8 I, v& B4 s0 V
4 x: ]) k: f; T2 m, S, W
    emitApproval(owner,_to,_tokenId);
2 d  i& l( F1 N, A# a, h! v3 L8 w4 [# O7 j
    }5 T4 d) O" }2 r/ v8 @

1 r& O( b. z& P; ?    }, Y2 f3 ^" Z* o- g! ]6 G

' C$ t) `: A" r' I! ~1 }    /**
) R3 ~' y2 L; ^( K2 ]$ }  H! }6 s' u( \4 Z; [0 U
    *@dev获取token被授权的地址,如果没有设置地址则为06 f; `* r2 K$ x; r% i, Q0 M5 p1 S, y

/ ]" u2 o2 `, B8 ~    *@param_tokenIduint256IDofthetokentoquerytheapprovalof& z3 [+ G' F) ?5 C$ t9 i
% o9 n+ \4 @7 ^5 n) r
    *@returnaddresscurrentlyapprovedforthegiventokenID
! Z8 c* z" Z" n) j# P/ \1 X4 p* X- j: M& ~+ I* d* v2 k
    */8 \; W4 J, ]7 S

" q5 \" E! \% s. @  p6 ~! ]    functiongetApproved(uint256_tokenId)publicviewreturns(address){$ H) h3 F+ v! P. P! W

. p$ i% V* a) }8 j* _7 G    returntokenApprovals[_tokenId];! ^( @. n4 V9 R+ j
2 n6 y  n# h. x% Q3 R
    }
: ~6 r( ~* E7 [0 V. N' Y3 l8 L
! F6 E; z3 x  Q    /**+ g9 K5 ?2 c6 p
0 h- h) N% f( w, T8 q7 x5 z
    *@dev设置或者取消对操作人的授权
/ I9 d+ J5 Z6 |5 i# N& h# i7 \0 s4 [: E7 K3 ?1 m0 B& b
    *@dev一个操作人可以代表他们转让发送者的所有token
  p& M' f% H$ f# t# L" z9 b( W& [2 H+ m/ L4 A0 q- A
    *@param_tooperatoraddresstosettheapproval
0 w) O1 c$ V5 d9 |' c6 M0 R( H% @: _
    *@param_approvedrepresentingthestatusoftheapprovaltobeset0 Y; s( Q4 g. H
" [' W+ T( X+ D, @2 y2 N
    */. C! y. `" m$ l. N

" O0 v+ \/ F- L4 ^& N    functionsetApprovalForAll(address_to,bool_approved)public{- _2 ]! S  d& V# ^) Q9 X6 i

$ `) G2 m0 \# r& A* u) V    require(_to!=msg.sender);2 F& k; L' @8 D/ l* _5 U" |/ j! c

8 t" r/ H7 z2 m$ t, F* Z    operatorApprovals[msg.sender][_to]=_approved;7 Q# Q4 ]0 S" T7 Y

: h# `$ o3 t' `& B    emitApprovalForAll(msg.sender,_to,_approved);/ c" [8 U& C' \+ @, g

) Y; d# Q+ [% x8 K6 x4 t& S    }
3 Q! f4 F  q/ ?7 J& _
# X9 d) l  c. q  N    /**
% ^* @* M. F) J: G4 J
5 ]7 I( _% r6 j& W6 D3 n0 D    *@dev查询是否操作人被指定的持有者授权1 T) Z9 e8 h% j, m' E

' K2 k$ T) ~% y, Z; X    *@param_owner要查询的授权人地址9 j  X, T& w# m4 f) n

' _/ ]# e- S, ~4 r% d    *@param_operator要查询的授权操作人地址
9 |. h( h8 j! j0 Z9 n& J
! t2 o+ r! X! A' u- w: b, |    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
. f- N9 Z$ ^# ]7 L8 Q& K% y8 o$ g( F3 L8 w. j! F
    */
) M5 p# F5 `& q
9 l1 G. D3 K0 `$ f/ ~    functionisApprovedForAll(
( P- E4 `& h) }- s# e0 G! N" R7 B/ k' k: T. }
    address_owner,$ ~9 @8 S4 `, s6 r
! Q6 `9 X# a! e" @" l% e% t
    address_operator* c/ I6 e& n% s6 e# V! x

: c1 ~6 Y( E$ U& ]& G4 Z2 E    )
; T" _; U/ I/ i9 R5 u( D& M8 Z& I. v0 Y3 q
    public
' X2 K! H% d7 c; V- M% g) k% `! Z) f: `7 h8 e
    view
2 M9 y! b$ W4 |! B; u0 d8 e8 c4 O9 Q
    returns(bool)
3 d* ?4 F" t+ m' h9 m+ n, u4 ^. r% [# T- t/ t* ^4 d5 l8 G
    {; v, V3 n. \! x0 |2 r! [

- \& e* t. C- L$ L8 j$ g5 k( L; W    returnoperatorApprovals[_owner][_operator];
2 t4 [6 Q( F; _* N. L1 ^$ e6 b. O  z! u' b- }1 M" Y" P! E
    }% H% S! P; _( m8 j

3 {" k$ `/ i; b3 `3 _  V    /**
' Y, O( z5 \! S8 g8 S* e0 n( v4 H7 Z1 v, _4 K  d" l/ W  U
    *@dev将指定的token所有权转移给另外一个地址
/ G4 V3 y2 t" @9 h$ ^" W1 i5 s
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`" h8 B1 {4 {+ U+ _! M0 C
) Y  N# p4 {4 z5 ?. M
    *@dev要求msg.sender必须为所有者,已授权或者操作人
5 Z* {2 y/ J: b' }. u2 T$ L! g- |: Y$ ^& l+ [7 c/ N
    *@param_fromcurrentownerofthetoken
4 U: u3 ?2 g; H: u- @9 ~
- w$ E( G5 {  a" j    *@param_toaddresstoreceivetheownershipofthegiventokenID
" _; U) W' M4 h" _& x% t3 V2 H6 a3 n. k9 l( W) p$ }4 s
    *@param_tokenIduint256IDofthetokentobetransferred* F# |5 Y& F- ?

1 `- ]; A$ ^+ P# h$ A4 L1 D4 k# l+ k    */
; Y2 k3 D4 {9 x2 e3 k4 c
  o( ^9 B( n+ X) z    functiontransferFrom(
6 l' v* F* n* |" f3 z* l
2 n& c* p1 A, C: U& i  _5 ~+ O    address_from,
, t, \" q. Z6 e/ z( b' Y& S# M  f  a9 V. [  G: X; q. r1 A
    address_to,: j* I; ~$ x! z/ E' {4 C9 v
. z, P0 o# V3 |* z$ \0 @# q3 g1 R4 Q
    uint256_tokenId
% q5 q2 B$ M& _/ u, u# W" V% e+ V% f) O# I1 W, H7 {! O* z- Z% `; M$ M
    )
1 W" O6 D" E, g: ^/ h+ Z- p6 u8 P
+ k2 g+ H) I9 \  p9 a* d    public
0 C3 q: U2 N" U1 ~$ r! e, d9 a) T
    canTransfer(_tokenId)
" \/ e4 I% I! g; C  I
$ B% x- w& {9 C6 L- v    {
) h2 a7 b$ n. A# `
7 J. e& h; i- G4 y    require(_from!=address(0));
1 C$ d* }/ r( |( n7 x8 ~* |6 ?" \# s+ i+ d: o7 h& O, }3 n% @
    require(_to!=address(0));8 U. S# U9 f) a% W4 m/ W+ l
1 O. v1 v) V: g8 W& _
    clearApproval(_from,_tokenId);
! p5 n2 O: V( n+ ]2 \8 A
) d$ H6 n$ A, {    removeTokenFrom(_from,_tokenId);0 }9 w% S: ^( f3 G" a

% r4 \! e  ]$ `# }- X    addTokenTo(_to,_tokenId);
# G: M; S4 `+ _3 G9 z  u% P$ H4 }# G& f4 B5 K4 M9 H3 A
    emitTransfer(_from,_to,_tokenId);0 s" s( V: b7 [, Z2 H2 z
. p  \7 K  X% @: d
    }
, t$ }; o% K+ m9 u! U+ K
! F6 i! o/ X5 ~7 @    /**
0 ]% I7 y+ H6 W4 C( [! i+ g
7 G+ g5 \: _3 T    *@dev更安全的方法,将指定的token所有权转移给另外一个地址4 o! G  [3 K1 O( c
/ s( |) o( I1 A( a2 B1 O! d
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
. f+ w3 t" V- X9 j' e0 n" t8 Y9 `9 @9 U4 `& K7 d8 i: B% _- P% Y
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
3 Q) v+ H; ^* g/ z0 N. o2 a& w# `, B$ i
    *@dev要求msg.sender必须为所有者,已授权或者操作人4 J# x5 R9 ?4 ]

2 K$ I4 m& e' l; E! a- ?$ u; ?    *@param_fromcurrentownerofthetoken3 Q7 G+ y1 I+ ~4 I$ |  y- }- L4 ]
0 p* Q# b5 A; _: w$ q, r3 m
    *@param_toaddresstoreceivetheownershipofthegiventokenID# s! L2 ~* q/ A" r* h* J3 |: P
( J) q# Y+ M/ v7 G* [
    *@param_tokenIduint256IDofthetokentobetransferred
, n, L- G  B* q- B' R! t
& b/ ^' Y3 \3 ]0 v$ g4 M    */. G: l  M7 S( m' ~2 T
) K  E- `, Q5 z/ n( w+ W% A* I
    functionsafeTransferFrom(
# S9 w6 u5 Q# a
* D( O5 r2 D. g- Z, ?2 x/ ^    address_from,
- `4 c2 @3 ?, f
: c1 O6 x0 V' m% F8 n    address_to,4 _/ a: T& A2 ^% S
' r) O  \( u) ^! \1 Y, i5 x) Q
    uint256_tokenId0 d" h6 f" \; l# @3 j

, Q/ k' f( i0 V- j! a    )# G* [) S1 G  k  Z* w# S% h+ A) @

6 H9 l. Z; T( d7 X& c    public3 C1 x: n% Z3 N+ z7 H
! j4 |2 C) J7 c& q. D
    canTransfer(_tokenId)
% j2 |9 V( k, R1 b5 Y% _9 S8 G2 y% k; P! ?
    {
, a/ C4 d# T* A( p4 G' d; _" ?" p2 a: Z8 Q
    safeTransferFrom(_from,_to,_tokenId,"");; y: p0 g% ?- G9 `% L" l

! h; B4 J9 V& Z+ v% D( a* t4 P    }
' C4 [" B! F% h% A& f( {+ ]* Y/ |, L! L# Q4 o
    /**7 F% u  S! x2 a1 K9 \$ [
" y* j- g3 z! `* K" b. X3 w
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
# w4 c3 z; \0 v9 H) T4 i% s
0 y; ?+ I; H% {9 n    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值5 O4 _2 O2 P& U( i: j4 @  c6 {
2 g$ i' g1 V9 V; W& |# p
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
4 u9 h7 c* b7 Y& f( |( t8 i; }; f
    *@dev要求msg.sender必须为所有者,已授权或者操作人9 N. ^, n, _, ]. R, J; {0 ]; Y
0 k/ I/ T" R* o+ g8 W: r; F
    *@param_fromcurrentownerofthetoken
4 J5 S9 E% ]: p% _' A* ~& V1 |" L7 z6 I4 S2 [
    *@param_toaddresstoreceivetheownershipofthegiventokenID- z) f+ ^8 V7 D% Y+ v# g& ]* f
' o6 J6 ?0 J! @7 f. Q  F: H! s
    *@param_tokenIduint256IDofthetokentobetransferred
9 m8 `( j5 p+ O8 u$ k. _
" z! z9 j. u3 S; U# h    *@param_databytesdatatosendalongwithasafetransfercheck5 f/ l$ f0 @- h8 H0 l) ]+ ^

; x4 S! P5 M5 ?    */
' Q" \& c8 p* E, k- o8 A& D- U6 D4 Y  m9 r9 N: t/ [
    functionsafeTransferFrom(1 V) ]# ^2 \2 J2 `( b  C* y  O
0 |: u" `- N2 Y2 i  U  }* E
    address_from,( R0 g; O( V1 L' B
, }& b5 f" v, T
    address_to,5 F! a% l5 J. U- l
# [( K# R5 D3 b" Y- M2 {; D  z* w
    uint256_tokenId," W. l, M5 E& f9 X& {0 Y
4 z% ~- ^8 v1 y9 ?
    bytes_data
3 b" W( b9 Y( o4 D! m& D9 U
, i) ~. s2 A5 A    )% ]. v- {# E0 F- C

9 @, ?  B4 S: c* W( d0 |( E; w% `    public
; x7 w5 ~$ D1 s# Q/ ]% S# X
5 t/ K" t2 W* E5 S    canTransfer(_tokenId)
1 Y4 E5 j; T5 g, }4 z. b2 F
$ S5 `) T; ^! a+ @% ^$ \1 ]; b, f3 ]    {: c4 O: U- H' m: ?+ L6 J

/ b( B  b: l4 V    transferFrom(_from,_to,_tokenId);3 ]3 c1 A( d0 U2 H- G

8 p( E% S9 x6 B1 t6 r% K. |+ Q- |    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));6 D  M& p2 @7 R6 Q+ d* Z, d
) c0 v3 v; {# F- m
    }8 [) I! {; x) k+ s
: [& S. c  I, n' Y
    /**4 S" _3 c8 N( U3 W) E  M

( h# d9 z4 T. }3 I    *@dev返回给定的spender是否可以交易一个给定的token; A& L& g) _, I  [
0 u+ \# J, \* M4 P1 {
    *@param_spenderaddressofthespendertoquery1 a: t( o+ t" D% R
7 @+ m! d+ ]+ q6 n& k& ^9 g
    *@param_tokenIduint256IDofthetokentobetransferred" \! W6 h$ t( ~) o6 x0 C8 I% A' i

- ~  \- T' W( t, s3 o9 U    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,- D8 W! c9 t+ d. T1 H" J. {
! v3 X7 n0 C! F' t" o
    *isanoperatoroftheowner,oristheownerofthetoken4 B0 u( B6 {6 @- ~- |" E6 K" |" `: L
; q% E2 Z- Y, |' f* n' `
    */
" x& R+ \% g) X1 \, D/ y3 T! v2 W3 c* I7 J$ e5 y- W! y8 j/ d
    functionisApprovedOrOwner(4 g  t2 e2 M! ^6 s: R( g
) u$ Q& K# q* N7 ~5 d4 J
    address_spender,
% M" d  R: c4 a1 l! c5 S0 a9 C) }3 E+ S  o2 J
    uint256_tokenId
6 v/ m7 r1 f# `4 _( N  B, k" M+ y6 R5 h' Z8 K# i* a
    )
+ d0 l5 ^& k7 m" q9 h* q, ~( o/ c. X/ H7 z; D# h- U
    internal
: y9 @% ?2 T* b
  z# i! x& M$ W3 m( P" O    view* B5 a! b/ E& O' M( S

8 h% |4 l% A1 b+ f* Q8 C0 `    returns(bool)
$ A9 }' ?8 w2 I9 u
8 z" h2 Y# B, c  e- o/ G% F* ?    {
. c' V. y0 S6 l. u; e( f) C9 C- ~* k
    addressowner=ownerOf(_tokenId);' a9 |. Q- x7 W2 N- E: k: w

* Q) \; I( P) c3 k) `    return(3 Z" K  p& B  W* M9 w( C
, Q9 g% [  Q. s( h* N7 y1 f
    _spender==owner||: v, Y. g  U$ ?1 O! W
0 ]" c# D' n6 V  F
    getApproved(_tokenId)==_spender||: k: J! k0 H, d, P5 h
  p- I5 v) f0 e! [
    isApprovedForAll(owner,_spender)
- j) ~3 R" N* w9 i
& |& Y4 Q, }- I9 x, }; d1 z0 D    );
( M( u& D* z4 t5 M; Z, q. _, J
1 m4 e$ U, p8 C6 T$ H) b    }- L) L  M+ o$ ~6 f$ S' q1 H

- \( ?6 h) z: ~6 `- E; r" G    /**# A( u- X/ M# A0 G  G7 t7 n; l& X

/ E: }1 P5 v6 S! v    *@dev增发一个新token的内部方法
( l$ N+ g# P& B% I/ ~! n; R% L; V+ _/ M+ M2 w
    *@dev如果增发的token已经存在则撤销4 {: q: @* O4 v7 x0 N8 n  g6 n

" B+ ^  h" ]5 A) [2 q    *@param_toTheaddressthatwillownthemintedtoken0 p+ ?9 c2 D4 k/ N1 p

+ M. l) R! [1 J, i0 n! s' k& U8 x    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender
2 M/ F" ^9 u, T3 m! ~6 a2 I6 K7 h7 y5 a* ^& X3 d8 v
    */
+ Y4 D  G; I- V. r" I- b6 g
6 |( s" \5 H4 Q2 W9 G- p# P    function_mint(address_to,uint256_tokenId)internal{" W5 o( Q! \/ J% ]4 f8 u- N

  S, L7 P5 U# @3 D! Q    require(_to!=address(0));3 \) S8 k8 C% L* ~  N
7 w" f9 f4 U3 s0 S/ e
    addTokenTo(_to,_tokenId);4 W- \( B2 f) L1 l8 S8 n, Q

% X0 L# S# I2 r5 S5 \! o* S    emitTransfer(address(0),_to,_tokenId);. b$ T/ b* v5 Q+ M( `( P7 z

; J' D2 n9 G0 E1 @    }
& O; |& ^6 k; O6 K
! Z6 Y+ E6 {) J3 V1 L8 H    /**
; v0 u! s0 {( M/ q! M* ^
# f* u) q3 U) A+ r( X: u! z    *@dev销毁一个token的内部方法% K, N+ G1 x1 M1 i: K( G# t* I

7 M! W6 l, I1 k$ |% y7 p    *@dev如果token不存在则撤销3 A. {$ t! ^% ^" w- z( m8 E
( D) T$ }, X& D( w) O
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
& M7 l6 r5 S8 b( g0 y4 `! ?; }- u( M: B2 M0 [: K
    */1 c5 L4 A- r, I* B1 f; ]) ~
. P, S+ ^  }! k. K1 J
    function_burn(address_owner,uint256_tokenId)internal{
) ^, i* f8 |9 q+ x  q- m' e) Y0 }7 n0 k
    clearApproval(_owner,_tokenId);( U8 ?6 l9 T. l. \

1 Y  a$ z+ G& s; @2 n7 \    removeTokenFrom(_owner,_tokenId);
% o  X6 U7 ~6 b0 z- Q, p# q! j6 P# _
    emitTransfer(_owner,address(0),_tokenId);
- O! `$ `1 _: {* p( z, p2 y( f$ g5 V7 u. g* P9 G
    }
; T9 d  B3 g; w+ @, x4 C
, J% K! T+ |# T/ K" i! X    /**
/ u- `4 H* r' M, E- J3 M
' s9 ?0 G$ E* F    *@dev清除当前的给定token的授权,内部方法3 D6 n5 N8 N7 M1 \* A
1 H1 d0 Z) x/ [
    *@dev如果给定地址不是token的持有者则撤销
  i3 g- D! f  s  C6 h* }
& `2 q  f( h/ {% F8 p    *@param_ownerownerofthetoken, C/ W  |  V$ u% \% _* t) P
* T, h6 w6 `0 g) \2 q
    *@param_tokenIduint256IDofthetokentobetransferred2 ^% H$ F8 {) x* Y- q! R7 f

# B+ B% ]. H2 j$ b& I- Q9 `    */
; D" s$ ^( \  z3 m
0 \( B. \+ R7 k& g) U! N    functionclearApproval(address_owner,uint256_tokenId)internal{4 E2 {# t% ]9 o# U. U

! u. N* G5 b  Z+ X1 R! Y    require(ownerOf(_tokenId)==_owner);$ z" B2 W7 ?% y4 w
8 t) C) _1 D; R/ w& R2 D1 J
    if(tokenApprovals[_tokenId]!=address(0)){9 I& B' Z) S1 u& X: G- l
0 }0 R; v5 Z) V8 }7 G
    tokenApprovals[_tokenId]=address(0);
9 k7 G, q1 r+ ^8 t: a5 B9 S% l  a% J! }3 g( c* P
    emitApproval(_owner,address(0),_tokenId);# F4 S2 V" A/ ^( J
6 d  i5 H4 N! [  P! k6 j
    }
* v$ j( {3 `( D) d" I) w' [$ r4 Y: |8 j0 S/ V: c
    }5 i6 ~8 z. @1 w# [" }: z
8 N: M1 S$ [4 x0 x( t
    /**
2 d# [6 u8 g+ Z7 y/ n7 f* J9 k' g+ f: b2 L/ r$ A6 u# `
    *@dev内部方法,将给定的token添加到给定地址列表中0 G6 I1 x5 g: f5 H) B

' f: B4 @' Q" v    *@param_toaddress指定token的新所有者6 O; l9 f8 G8 m9 @* n  G

' |) P/ k1 H2 L  N$ Z; r% U9 e    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress3 N$ @8 z4 o: D" S% c
* ^! ~/ v/ v6 Q7 \
    */& b* O8 @, ]+ E1 S! j) }3 H

9 a' ]2 o! S% @8 h. n' W    functionaddTokenTo(address_to,uint256_tokenId)internal{' N8 H) q' `% ~3 z$ v% ~

% u; y+ w( G" O- }% T! f    require(tokenOwner[_tokenId]==address(0));+ a4 D$ Z  z( e6 R; [

% O" ]! q# ?% `% p  f    tokenOwner[_tokenId]=_to;" m  P% b  `) j/ X6 k% b# u" I* X

0 P5 S6 o& h& s# K5 T    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);- I/ k$ E+ O& e" e0 A8 ^

3 c2 V5 t  Y! L* R* ?2 H  |0 g    }
2 p* j5 D# C) h
+ Y) F2 y) u- |    /**
3 V/ e0 c' Z& Y2 n2 ?2 E  h0 i% f; P% L/ Y9 P/ M1 B5 R
    *@dev内部方法,将给定的token从地址列表中移除1 w" ~) `- K! V) o
$ X7 V+ `. i; s. |6 ?! Z, F
    *@param_fromaddress给定token的之前持有中地址
# W7 t8 m/ l0 \  `1 ~0 I2 c' G' A3 A* s' T! q/ X* j4 P5 q% @
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
* K. T4 d- \( Z* g9 T
7 Q7 Y" ^+ m) [+ J    */
. r5 w5 J$ x) c; i' n; ]5 r- F8 n6 I$ b4 f& \$ i1 f
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{: v: `% i, H) H. K- Z

7 Y6 T0 J' s6 B; `. e    require(ownerOf(_tokenId)==_from);, i! V7 e  V1 i5 S: q3 v
9 I3 _+ K7 B; }% ~/ p2 _. p9 u
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
0 _5 A4 A; @' p+ n( u
5 P8 Y+ ]! M! A( ?0 y/ e; X# v8 ]* `    tokenOwner[_tokenId]=address(0);
- p% r3 T: E0 _+ \6 S
+ |  Z; u; R! s7 F    }
6 w2 l1 N$ U& s& H5 s4 a- U! X, P: a* a: e
    /**- C5 V5 F% m0 d4 E8 u; @
, l. h0 V8 w, e# F" u
    *@dev内部函数,调用目标地址上的`onERC721Received`# k( |: k  m2 |% F

) L, O, o9 F. p* H- C    *@dev如果目标地址不是合同则不执行调用9 {/ S! d7 r& N' ?; t& w% q

! J/ y* P. ]- m9 ~* ~& J    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
* ]3 E9 H* y+ h1 m3 _
* Z1 }& ^, n1 x) d% Y, Y    *@param_totargetaddressthatwillreceivethetokens) Y6 b6 q. n. }. b; M- U7 r

+ z* E3 P4 z4 m0 R    *@param_tokenIduint256IDofthetokentobetransferred
# {8 j7 K4 i9 L$ h  h  M! |) i3 S$ S& w/ j$ f
    *@param_databytesoptionaldatatosendalongwiththecall
6 D4 `0 b$ t9 G
# M3 H! r2 h- F6 X! b8 [    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue+ x: Y, U& {4 w% F( S3 q; ?
5 ?- t3 {. }' C! r3 L
    */7 y9 {% M3 ]9 s# x

  v& z# u0 }: {/ L$ }- ~) I8 P    functioncheckAndCallSafeTransfer(
9 T# Y8 y9 B6 b" [/ Y
+ @& C4 k; G2 I7 p+ Z: k    address_from,
) Y  C4 x& t. s1 L
% J0 }5 {" Q3 N4 W6 h' D$ b    address_to,/ J  r$ n2 m  v) J

2 d  K) j4 n: x5 f& @2 n9 n3 h    uint256_tokenId,
3 Y7 i! O! [; I# u4 z. [6 U. I2 J4 `& X  b9 }! E
    bytes_data
. x/ Q3 z- _$ a5 ^. G: J9 _9 D0 v( a# Q9 _+ Y+ h
    )
( A. [. K/ b/ Q  h
3 x4 ?+ N% S0 k# _+ n- P9 p    internal  d+ B& F+ b. P6 ]8 ^6 U1 O5 @% v5 x
/ E3 ?" w2 v# E/ V
    returns(bool): ^$ h9 _0 L5 s- U  V9 i

1 f$ b; R# P* J    {% ?: O. S, T% V' Z

+ P- ~/ U8 a& ]% I+ ~3 R    if(!_to.isContract()){; ^6 ]' P4 ~% ^5 P2 C
' {* i) f* i; g$ r- t8 x3 t" b  P
    returntrue;3 \8 r, M: k# P, b; U4 f5 _/ h, j

* n, z' Z+ d4 ^9 n8 i1 i    }
% W% {0 b5 L  B& \8 K4 b4 O& x: D2 d, \* Q
    bytes4retval=ERC721Receiver(_to).onERC721Received(
2 i  @  z% W4 [; R, ~6 T! g5 i4 X. c4 ]% X/ q& c1 A/ U# j
    _from,_tokenId,_data);
1 @( H6 T/ h' I6 V/ U3 m2 f' D, Q' K! w" U$ p8 |
    return(retval==ERC721_RECEIVED);
5 b  s$ u9 y3 q0 L* W( o3 V4 e8 y
% U, R' Q3 P- ^4 r% h  @& t    }
% x# h' Y8 ?! t. G: I) b5 T' f) U1 A5 c" p! v. k/ B
    }
; S# y: I/ c- G: _7 K- c! M  y; l: E0 l9 y0 u( t6 m" t8 f
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。, A2 H2 V+ h) _: P- B) ]( l

: ^1 o& ?. z! }+ E* c' x$ }7 p    ERC721Token.sol5 s6 A- J" L9 P$ Q6 J* V+ u
6 }4 m4 g% {$ ^+ s$ r6 M
    pragmasolidity^0.4.23;# `7 `3 h9 ?/ J1 r2 l/ ?
% a0 y2 v4 p. q4 N7 p8 ]  }
    import"./ERC721.sol";) ?3 [- A4 n) y7 F2 O3 h

5 R& W* t& h3 t! M, Z    import"./ERC721BasicToken.sol";  `- @% V" }1 F8 P7 P: i5 Q1 w7 r

. L& C# \1 `2 k    /**# l# W! X8 L4 M6 r# H4 s
" l( X9 l% X5 B/ q# J* n) c& K
    *@title完整ERC721Token/ p5 G# x5 p& L5 g
: }% ^/ @' q2 D. F* D" u
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能  J3 q% d( @. l" f4 P4 {
0 W0 W# q) a3 f$ @0 g
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md" {; _( v8 d; q7 J) }0 [1 ?
8 U. S% @( g( B  I; p+ w
    */0 l) \% N6 p' I4 j- x7 B4 L& ?* B+ J
/ |- m8 L: K) H/ I( c
    contractERC721TokenisERC721,ERC721BasicToken{
# {) _4 k. D8 U* {/ k6 j( q* j* Z6 N3 w5 b( ^6 T1 q
    //代币名称- W- |, r& l# \6 D% g4 |
2 c1 C1 y$ w- C- @  E0 g) Q
    stringinternalname_;
" v( V! J8 I- s" n, U6 f
- x$ n7 T6 Q3 u/ @; d    //代币符号+ R$ l0 T! N+ C: x3 H
% F' R4 c, k* ~6 O& ?, X
    stringinternalsymbol_;
9 v% f/ V! Q6 W7 l+ c, v3 u0 T. Y9 F7 E2 r  @/ _! G
    //所有者到所有者拥有的代币列表的映射3 P: v) R) F& T1 H* S

2 ^5 \2 |9 W  A5 ]    mapping(address=>uint256[])internalownedTokens;- v, T+ }1 A( E

( }3 |# w- g  m: Z. e    //所有者代币列表中代币ID到索引的映射$ m% g: K/ c  t8 t8 R
8 P& ?! I7 o7 T& u' Z; h
    mapping(uint256=>uint256)internalownedTokensIndex;
0 [$ A& p8 z) [% i+ P: I- V+ w$ l& q* @) X0 q
    //保存所有代币ID的数组,用于枚举
' A# |$ z7 _1 @! F" _! }1 F9 {3 {# \* N
    uint256[]internalallTokens;
% }  L% n- F+ W' k6 M; x; m0 p
! o2 P5 O6 a8 Y3 ]0 k    //allTokens数组中代币ID到索引的映射
3 g" t: A5 {% T6 Y* W( n' E
/ @! {, O, D/ a; m* O$ x, I* T    mapping(uint256=>uint256)internalallTokensIndex;, ~3 o9 U, Q* w! x9 T0 k# O

, f9 Q3 a. o; U9 ^& h9 I' I    //可选的代币资源URIs映射
  U: o$ V4 n4 t; E+ B  Q- j9 O! A( _. u8 J* e6 K8 f
    mapping(uint256=>string)internaltokenURIs;
4 ^: J& N2 E" |. R
8 j7 F! [% h4 o+ Y    /**' G$ F4 W% h$ o+ ?- t! A/ k

' u6 G$ S5 `1 ^2 x+ F; ~8 @& b" `& n    *@devConstructorfunction
" f5 A/ I) H: \- P% `- h8 m3 Z, \% \6 ~
    */
2 P' s; P4 ^, Z5 V$ j: x; d- f) x6 W- K% P5 b& G; {
    constructor(string_name,string_symbol)public{- u( M4 X. v! ]( f, r
3 z  f  ~2 z- N' W; ?$ o
    name_=_name;
2 I- M3 N9 x$ ^$ g# \# z: h1 M4 R! G& P- i
    symbol_=_symbol;
2 F, _* a6 h7 ~- o  E6 }4 f5 `$ ~0 s# O! Q; o3 S' [$ U2 z9 v
    }
& U9 l2 S1 X& O8 Q- M3 [  H
) X- K1 H6 h# ?2 b, p: W3 p. S! N    /**
; Z0 ?% {1 w) e. |; T+ Z6 w0 g' t* ]+ S, F) R3 S, Z% u
    *@dev获取代币名称
% s, E5 Q3 W" T7 f8 H4 V3 i1 J
: m) `) g; C6 D6 F, Y3 b    *@returnstringrepresentingthetokenname2 _5 r/ S4 m. L; n
" ~' c2 p) S4 A/ E$ I
    */6 q, O* m- \& S3 M8 B; P1 @
( p5 \4 w( [" L" `6 H: j! ]: `' h" s
    functionname()publicviewreturns(string){9 z: t5 z, b2 c: T+ r8 p* a  S

/ q5 W" E) b7 o    returnname_;7 Z0 L8 Y: @/ a" b& S- T, Z9 a

5 ]+ e- @2 c5 _+ K2 D8 Y    }
+ m; Y/ h/ o1 y7 l5 y1 r! o9 T9 E, {, s( T" a0 l2 O0 u+ y
    /**/ S% z6 T% N' @1 h" _- M
4 o# ]* K# L5 F+ R2 p+ j* u
    *@dev获取代币符号6 s( V" M; X( j: Y3 P% ?4 m
4 ]# s5 i/ @$ o& P) F% |* J
    *@returnstringrepresentingthetokensymbol
2 g0 U2 C9 N1 p6 X2 _; q" h! T
    */
# l( D5 X, T" c  ]6 f* X2 f. o
$ r8 S2 o3 a6 G2 e, d1 X6 G, a8 ]' Z    functionsymbol()publicviewreturns(string){
6 }7 H% W! L% T1 A
8 ?/ v8 A9 c0 D* D/ n2 v- z    returnsymbol_;
3 p% A! Y' K* K0 u7 A8 H  h9 w( u9 F' t) `! `) v( p
    }
% O; g1 p/ t/ a$ H0 l/ b9 @" Y! [7 m9 a9 F# P6 D
    /**
, F. z$ S, a; j; d9 y
$ f% }% c: n! Y3 q1 {" E    *@dev根据_tokenId返回对应的资源URI
  w- A2 f. o, K# M
$ }; i  d% H, j$ C/ I% m9 c/ ?; a; `    *@dev如果token不存在异常返回空字符串
- C) U: R8 c$ N. x0 f: w4 s0 L! r5 @9 |
    *@param_tokenIduint256IDofthetokentoquery
( S/ p6 `. n# d, {* I2 P8 I, @  s' q3 v+ t& b. K3 L; l
    */
, G4 e# k4 _$ u4 j" C
$ V# R8 V2 n1 j: v    functiontokenURI(uint256_tokenId)publicviewreturns(string){
; }1 ]) D9 m' m1 T% q" k, t3 F$ j* s: a3 w: \: E( h
    require(exists(_tokenId));
; }) C, G* {' ]  r0 \8 f) V5 i( l1 r+ U  F! X5 ^, q+ x
    returntokenURIs[_tokenId];
$ g3 B2 {4 E# i) b: h
+ ]1 k1 J; h, V1 l. x; H$ @: h/ G    }6 L+ s0 H# m' w7 J
: v1 G6 `4 g+ D" Z& u
    /**/ W! d# O" G( v7 A$ v, n2 X$ I
) q+ S% [1 l& @1 V) R( X) U
    *@dev获取tokenid通过给定的token列表中的索引% ], q4 s/ h# H3 u. Z
" }, @! ~8 ^2 N5 \* C+ t
    *@param_owneraddressowningthetokenslisttobeaccessed- Q& m8 [3 m7 D! ?1 p3 d

; X& D: a5 M0 N  x% t! L( d+ o    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
. W+ [" ]% b0 m% j, Q1 E- P
  Q% h- [6 O0 X/ x- S* K    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
0 Y% F  o/ u/ ?' E
, \: _  f$ N7 E2 r7 M/ C+ o    *// x2 Y; r' u) R! |6 {* ~
2 Z) o) R: g# ?5 g8 L0 G
    functiontokenOfOwnerByIndex(0 g6 B; c9 p3 J8 U5 n( c

3 U. m* \( o5 G6 j& {    address_owner,
6 n6 t5 ~4 F) U1 m8 W- Y% }4 _0 H, T5 t9 c6 {9 A7 e, y8 P7 Y6 O
    uint256_index
% S) c* S) p- V; z& l- k2 H$ [$ P8 X
" T  a3 Z5 W8 d- l* _    )
' D, \& `2 {0 i. l& Q1 t/ u# q: }/ K! p( l3 H2 _% O& h- E
    public
/ y# I* }, Y" U0 j; y+ n8 M7 d3 X% q/ N2 W9 b
    view  ?9 T" n3 M# G: H
$ j$ ^; e- y) U: a
    returns(uint256), |! v% |( g. K. U7 X2 M* s$ a; y
0 \& L3 e0 n! J& \% k# o. B
    {
- b" D% I* n; C7 |2 A) d% l" h% Q2 g: q6 s1 N9 X1 ~# I7 H' \1 U5 r2 E
    require(_index) w" `+ K, Z4 j

6 p- y; r, }& ~, {    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
. J: r8 i% M3 S* y; J( j3 v- F  J3 W
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2