Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2466 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
- i" g' A8 v) X  i2 U9 ]+ c
( s4 ?1 L  N: t+ a    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
( Q! `8 A& |  `! g; o. ?
/ @7 v, R3 C1 i/ w5 {, y    ERC721Basic.sol% d3 x4 f3 f4 W  X8 \
5 N8 i9 a/ |6 v; m- z
    pragmasolidity^0.4.23;8 s6 v* Y# R+ {
* c, M9 p& N8 C
    /**
* a: c  t! C0 B& j9 r# {9 ~0 W% t7 E& v# ^8 {/ j
    *@titleERC721标准的基本接口
! F* C2 }1 |$ x/ E& p0 F' o* h5 K0 |
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
7 K' J' z9 a0 I- M! E% T3 N5 D! Z5 }5 w- l& t" `
    */; P0 }; x. f2 M

3 F2 b, B& |* y    contractERC721Basic{
7 E, V4 M2 g/ o& s# w# g- D% c: p# r, F/ S5 \8 V" U/ ~0 @
    eventTransfer(
5 h8 j- k5 k# G2 U  Q) |. D* m2 K8 d. x% Y7 |) n3 J
    addressindexed_from,6 M+ q. E0 B! W& D) B: t- [8 F4 o

% W" }  y, A- d8 v* R5 _3 `    addressindexed_to,& ]$ M# ]2 O8 y. O
' r, E4 f- T5 g+ J' R. h8 m/ p3 n
    uint256_tokenId
/ U' J3 }0 H! I0 N3 g. J% O9 r3 P
    );$ C7 I" ^' t0 L% b& P5 g
+ }4 L% Q4 u3 H: K3 E3 D
    eventApproval(
' u$ u! }0 A2 X/ M0 a8 q4 U6 b: ]) d/ I
    addressindexed_owner,9 a! n, U: E( a, G
( ]! Q" Z5 {" K/ j. O
    addressindexed_approved,
6 X3 ]( V, h+ b
4 Z/ U; c# A. F( S; w    uint256_tokenId/ m  Z1 Y% _) }9 s

) L% q; G- h# {* m& D    );4 ~/ q6 D& O; O3 K

, k; ~% }& \+ Q$ d! y0 a    eventApprovalForAll(9 z% h  K  v9 I: e& L
1 C5 {8 j- g* s) F8 ?: e1 M, `/ \
    addressindexed_owner,
4 o6 N6 L. C7 _- t
2 h$ K7 c9 f& G4 ^9 \  V9 Q    addressindexed_operator,( N0 N  [1 I5 s! N- J) C' Y& n

! I* @4 S, F% y0 h0 x0 O* f    bool_approved
& w) W  S7 X) {, x3 j$ p* {3 W1 b+ q1 N$ s
    );
! @# M1 s: Q* U) c6 C& F" m
) v, w/ }5 \6 t! p    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
3 Y  U  V6 `- D2 W- O) E9 P. }2 g' D0 _
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
4 d& L# x% B! y/ ~* o' t9 F7 e. p! E0 R9 [- o1 L
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);
% v( ]. \; K: C) Z9 f! G! Z" }1 L) G( H6 [3 u$ i/ O* h% L6 [
    functionapprove(address_to,uint256_tokenId)public;  b: Y& E. ]( w: r

8 o* r# ]3 J* C3 z6 ~    functiongetApproved(uint256_tokenId)  l4 \) I- m0 ?1 r4 ~/ A& X: r9 ?

' S+ z( G* o! m# W0 W9 ^    publicviewreturns(address_operator);
) G! E- c( v' J( x- d9 D* a, e: s5 G" E# \! x1 r
    functionsetApprovalForAll(address_operator,bool_approved)public;
0 m2 h% P! h; Q) u; V( j: g: f- }* E3 e/ j$ h0 l; C, G
    functionisApprovedForAll(address_owner,address_operator)
& Y9 v0 L% o' m" \9 ]8 @% e) d5 a* K. E! n4 |* @' A- A+ f& ^
    publicviewreturns(bool);
& X5 s0 X! ?$ Q- U: {, M% V& r1 K& K/ V+ N/ w4 _0 {$ Z
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
9 b' t7 k$ R1 K  m, a- B
) n0 [3 y' |' g2 |6 X6 m) r1 R    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)4 @6 i$ u0 ]- ?# j- x" |

$ y% c, n0 l( C- g" C) F    public;& X: q" t: |2 P) l
7 z9 g( H# V4 P/ h: ~
    functionsafeTransferFrom() ?0 [# R* |) t7 M. b

; @: k6 J- V& ^6 }    address_from,
$ O7 j2 M) [, \: e, c% g' w6 t2 O+ M. ]/ M- O- I
    address_to,$ ?  l3 i+ T& [" E3 d
3 r1 Y" h7 Z/ S& U1 {5 ]
    uint256_tokenId,
4 o9 L6 J) n/ ]% I2 B. Q  }, l! u+ j* z# W- I0 z- G+ g( b
    bytes_data$ h1 U: m6 ?/ S) O* u
) _% j# v' B- R3 V% F9 R7 P1 L6 N( G; p
    )7 [0 |7 K, E1 v: i. X
8 h+ m" a9 Z# W% Z/ ]; i) }& d
    public;
1 {; k9 W) ?% L8 d2 |" @, i5 W! W/ b* s' P% m
    }, @: J6 b3 }# c" f& a& A5 e
  U1 ~- j% Y- I" `1 h/ [6 C- N
    ERC721Basic合约定义了基本的接口方法:
3 t) r+ G' x0 O
/ H4 {( G& D' a) A. U- @    balanceOf返回_owner的代币数量( y, ]1 Y' @% i) q0 O
- u& |/ f/ B! U$ R0 v/ a! m: m3 a
    ownerOf根据_tokenId返回代币持有者address
: L7 B) S  ]) Y! \7 T+ g4 P" ]/ F$ Q! ?3 h
    exists_tokenId是否存在7 h2 u! `" `) f# W. R# W
# E1 |0 M  l. E; X8 j$ r0 {
    approve授权_tokenId给地址to
- N0 T  b( ?: E/ h" ]7 j: i0 \, k" v
    getApproved查询_tokenId的授权人_operatoraddress
, ?) _( V4 b' M  l
$ L' R7 `8 d! }, j$ x+ V    setApprovalForAll授权_operator具有所有代币的控制权0 a' L1 y5 g( H0 A2 F$ T

, c4 _' v; s+ t: H5 u6 ]    isApprovedForAll$ N) X7 ^6 g' G3 @- a& I/ p

9 ~' a# c9 o, D& P    transferFrom转移代币所有权
3 t" U) Q+ b6 o
$ C% x' ?8 ?5 r" |    safeTransferFrom转移代币所有权
9 o8 R/ T+ w2 T9 }. v( b$ p( u
  l. M$ i) L  b  p3 L( F/ n    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
. z5 t8 R+ x8 W8 y+ a- c: n& \$ p9 U" q0 R) q
    ERC721.sol/ z2 g# t  d& @8 s6 L$ s9 m/ S
: n8 b8 X) U; R5 H: X
    pragmasolidity^0.4.23;5 `% \6 T8 \2 {5 a5 B/ \
3 p# U6 u) O8 W5 {4 h
    import"./ERC721Basic.sol";
. @! @0 T& W/ i# ]
8 {. a, L; A% y; w    /**
* s4 t. }" A; W7 s
5 q; Y* v9 o& D3 b2 B( ^$ ^    *@titleERC-721标准的基本接口,可选的枚举扩展
% T9 \! W0 i0 B6 B  O7 X. G- [% `
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md+ n. H* c+ j% d1 O! ~

1 B: x# b0 d! C( F/ y; v" k9 e6 c" N    */
: r+ b1 o2 V# U5 f* o3 v) P6 r- P5 v  A. S( S9 s
    contractERC721EnumerableisERC721Basic{
5 a4 w' R8 n, L. y7 U$ S  b# ^+ E/ N! u) `
    functiontotalSupply()publicviewreturns(uint256);
& ]" T& V  R9 i& t1 M2 W1 V+ D9 Z/ J# ?, d
    functiontokenOfOwnerByIndex(& ~& [& e' X( {6 H+ a6 E

0 W8 }; d. a: J2 F* H: Z/ e1 g    address_owner,
$ M- t8 U1 v( p
; v9 {  O/ O, a2 v- q    uint256_index- X% K7 `5 R7 l3 f1 |! r5 O

! h+ Y( g8 Z( s    )0 ?. D. }) P' S1 K+ O2 m
9 b4 G# {! ^% [& O
    public# G6 V1 E, r# V6 X

3 `6 x3 D3 _3 L5 P+ D  }    view
; _) _! {$ j1 a1 k3 F- p$ d! e/ E' d! O( N+ G- u$ D( X
    returns(uint256_tokenId);
: V, f1 j0 W: q. E( W
1 [2 A' h0 ^! T8 j  o    functiontokenByIndex(uint256_index)publicviewreturns(uint256);0 @" j; ^* B' p* g5 h
4 a3 a# {+ Z' {
    }( W( m; @- T+ {/ L, a  ~8 n
6 q3 S, m. t* b. T5 g& K( T( R% i
    /**
" w& ]$ h) c/ s/ e: L$ Y# k6 ~, V- H9 L! U" ]7 `7 J
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展3 w; W  s) [2 [7 l' x5 u7 d$ G* |

% J8 D* i* |# J7 V: P    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md+ A  T* c7 j8 g' X8 c6 d# b
6 B: F4 q7 K. ^) d, Z) r% V3 h
    *// t  p& Y. I& Z. ]
% v8 X/ ^5 e5 J" |- G# C# V2 S
    contractERC721MetadataisERC721Basic{+ W5 h* [  c& L) P' q9 P; A
" C# H: J' E3 U
    functionname()publicviewreturns(string_name);, Y3 u+ P; i% q
5 n: q" e' }9 p" M8 |$ v) B) `
    functionsymbol()publicviewreturns(string_symbol);
6 D: [8 _* t& A/ `$ G$ ^; C* F& l% e; b, ^6 x" G" U2 @0 v
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
+ B* }7 [+ p/ Y' c6 y" `- }' O; b" B) a) k; I, Q' `
    }9 u- i* L, D- ]$ e
  w( H+ z" t4 Z$ {3 q
    /**
2 e5 e+ z+ A6 \( A+ K% q
; T% L' Y9 \5 |7 L    *@titleERC-721标准的基本接口,完整实现接口
0 m3 i* _" h$ H1 X( R2 a" p* H' w6 e6 |) {( G- c" B
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
! l+ x( B  x, G& Y+ c+ v' d
' M8 n' `0 f, I) g: m0 b    */
8 i0 ~; h& G5 N5 X" u
7 q- R; q" x0 Y8 w    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
8 F+ p  Y+ I6 ~$ u1 k$ B' U) P- L- j' p8 E
    }& z3 Z3 `1 y" g  ~) M

: F! @1 P+ p$ y1 J/ N+ d: y    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。4 V  s& ^6 Q. j6 M9 y) D
3 n5 \7 ^5 o4 |! y
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:. T% l) }& i$ f/ g

$ O7 W4 S7 g- _  j4 W2 ?- f    totalSupply返回代币总量
9 P/ Z( d8 e3 z4 O7 Q7 e0 X  j$ a. e, Z
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
. G3 ]% ~( e, @( q! K# S
' o) v. b' |* {2 b: I8 Y    tokenByIndex通过索引值返回tokenId
- f: R6 S/ u: U) w! _* b3 n1 S; i2 F8 L+ I. S& @, {
    ERC721Metadata元数据扩展哦用来描述合约元信息2 }2 S+ L- `% H7 \$ b. E

( c, {3 d) E' x7 B. |4 h1 }* V! n    name返回合约名字
3 r* t# E$ w0 h% T$ @) l9 X0 ?# }4 y. l5 J+ v
    symbol返回代币符号
) A. r; c8 U9 p' }1 Z
/ E- M5 H; j. \" w# N    tokenURI返回_tokenId对应的资源URI+ |" T) c2 r7 I# H" u' P
7 N' t7 J7 r9 P! m/ h1 k( N
    ERC721BasicToken5 l! N) {, Q& h5 ]; W

! g0 |' I4 c8 P; ?: w6 A    ERC721BasicToken
+ E: ?' c( S& }5 N. u# x
; Z6 ^1 t% F0 L: {. o" J    pragmasolidity^0.4.23;6 \; z# ]) Y6 r/ P0 \

. D8 P$ x& h' [7 R' W( V" n3 C% H    import"./ERC721Basic.sol";
. ~; @( T3 E% T5 f2 i2 D; [# ~6 F6 Y
. c: S4 B+ j2 P- p* Q* g    import"./ERC721Receiver.sol";
* N; R3 a5 T* ^3 _7 @$ |1 y6 R
; y+ e- s" m1 O* E2 A    import"../../math/SafeMath.sol";' K, Z3 h) E! c# d% W, d5 [
. P' C# Y& s; q; M+ h8 T. e
    import"../../AddressUtils.sol";
. s0 i0 j; I- K) Q. ~5 i8 `, |1 ~. o8 T& h+ V8 o6 f4 W7 Z
    /*** u* v* h8 R9 Y- K9 I. Z
# c& W0 c0 A) v5 [" x4 l$ p4 w' Z' f
    *@titleERC721标准基本实现0 M, v) J; D' b" E( m+ j* h

1 K" o- b/ W$ g+ S7 C! k    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
; v1 f* }. _7 ?, O3 I$ k, H) p! L% a6 }; A0 a4 u
    */
0 V8 ]* f" g* g3 R/ [) J4 f& u; Q. A! [3 a  {- N2 j& J
    contractERC721BasicTokenisERC721Basic{3 ]0 l4 c, R- p' J; V/ v5 q$ [; m; w
( @+ x* }3 z5 X. u
    usingSafeMathforuint256;
  A) L% T( D3 g; q' A
$ H/ K8 g# r/ V; A$ Z    usingAddressUtilsforaddress;
& [" }+ ?; t  @* V+ m0 m; s0 j1 G1 C
    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`2 n' X6 W3 k- v  k* _* M3 _

3 i+ v, g' `9 x* A. h' O    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`# w" X6 e: H' J1 u5 L1 l) n
2 {, R7 u, M' t% R2 c
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;" {% }2 H* ]4 y4 g' a

0 k7 h) b# K' C! G  I0 u, c    //tokenID到持有人owner的映射' a0 W2 U$ \' O0 q. F/ e9 Y$ L
1 z* J/ z- C- |" @
    mapping(uint256=>address)internaltokenOwner;5 r( k, X5 M3 `& t. r( f& D; y

( T) ]8 [9 |& t4 {    //tokenID到授权地址address的映射
7 m' h) n" v8 H) l0 N* x" F- C' a6 ]( D
    mapping(uint256=>address)internaltokenApprovals;1 R4 ?' A2 q# {" O7 f3 ^/ U
: D( {& Y/ H" Q- \1 N" T
    //持有人到持有的token数量的映射
  J( ]* k7 C* ^7 o9 S* ?6 Y- E8 T. ?9 p# k% }$ S
    mapping(address=>uint256)internalownedTokensCount;
6 V2 X0 H( j% R3 Z; g( \: y' b' a1 f; L2 X8 P
    //持有人到操作人授权的映射
$ v4 ^+ {4 t6 X  I8 Y
! o2 H6 }) a, o$ v9 W' M# o# r# {" m    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
! `: M1 D5 G  Q% p3 j5 `1 R1 d0 R0 @3 @3 I1 W, z
    /**$ x) g3 e/ e" u( r( g  t# D

& f! Z- }' I8 X/ ?# d    *@dev确保msg.sender是tokenId的持有人
: d6 p* R0 k5 {, Z4 p: C9 \4 O+ Q- f- j5 c
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
" L( g$ z* Y3 m
- P. ]8 j6 ^' @. E    */& }0 P' }" c6 E7 y1 C# X- m1 l
# F" R% u: X: R3 M
    modifieronlyOwnerOf(uint256_tokenId){; Z" C2 a+ |- Y
6 _3 p1 a3 i0 z$ `1 `
    require(ownerOf(_tokenId)==msg.sender);* q  b  _, q! `/ C5 d7 K
, r2 ~0 C; }, t! x. Q* a* }
    _;
5 U% C% G2 _& U( k
! I8 R! J* O" V    }- ?4 R: M8 t2 d0 g

" j% Z1 `9 d! F+ B% ^    /**
# P% w+ A, n: k$ E2 \
1 a4 a9 ?! }# R8 w" \5 D- d    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token6 O7 f' y5 |$ P' d0 r9 b

( I/ f7 v' x6 H0 t& f5 z& Z& s    *@param_tokenIduint256IDofthetokentovalidate: p8 P( b; W$ E" @( H1 Z& U

& i, J% L/ `" H8 D+ W+ T5 c* |    */
, a. v3 C) d% f6 V+ B* X9 w+ y: b6 S. O0 ?
    modifiercanTransfer(uint256_tokenId){
, Q1 \; F+ F7 O- N. ?. q
( b: j$ F, ?* `9 ?$ o* D+ c    require(isApprovedOrOwner(msg.sender,_tokenId));, r5 {* x# S: H2 Z  N
+ S6 R1 Z- R) w. i: Y
    _;% z; J% [0 v. U: @

) r+ f/ p! b+ L    }
1 f: E7 }6 G) u" \+ B
4 P8 x% E6 I/ r2 i' f/ I, R- I    /**
1 {: }7 [. o; t& f2 n% y# i- m3 c  o: F( h: ?+ X
    *@dev获取持有者的代币总数
6 f! [$ m: S3 e4 {, S& u: s
7 j% `$ g7 F+ M    *@param_owneraddresstoquerythebalanceof
- L9 i% |- l. L0 }& }# ]3 p
# _% r) |. R6 T* P( ?' n0 l    *@returnuint256representingtheamountownedbythepassedaddress
( S: ^9 p/ ~; L0 q0 z1 V
& K/ P. `& U* X. F6 I' ~' w* ]    */
. Y" B$ W( M7 |% @! ]7 _% i9 ]3 z1 s: O: q: `
    functionbalanceOf(address_owner)publicviewreturns(uint256){
9 d0 x7 _6 A# W9 U+ ~% S: j9 }: f$ M0 ~: D  A- }' O! ]
    require(_owner!=address(0));9 V, ?$ n& B/ i' M0 M9 T
# N: X* l1 E/ J& W( V4 p; g
    returnownedTokensCount[_owner];/ X8 O0 {: H, j) j

" I8 B7 r6 ]  S4 X    }7 g! g  k* S  M; Y
' [- p; }  U3 K% h8 H
    /**
# U  Y( v* B1 H- E" d. V3 W. ?2 C2 g% p0 p# O. _
    *@dev根据tokenID获取持有者. q2 u; P( X; D9 ^' z! O- i. W+ o% a+ F

$ ]9 U, z! t8 C$ x! D- @    *@param_tokenIduint256IDofthetokentoquerytheownerof
# P" q" {3 i: ?& y2 q5 w) Q. u* E4 m* p" F
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
( S- @6 R$ f  `7 k" {* U" v7 L6 I5 p& g. v& b1 u
    */
9 Y: v# q2 N6 s' u  G7 o1 Y% r( ]0 v
" p- J% F  J/ G# [7 N- K! Z    functionownerOf(uint256_tokenId)publicviewreturns(address){* B1 g/ A/ Q# {3 m3 @7 j4 t

" p, H) @- p3 S% \5 ?% F: U    addressowner=tokenOwner[_tokenId];) c& N* P# l: b. n$ w) h2 f

* z2 V4 o: @8 c7 l    require(owner!=address(0));
7 Z: h1 r6 m5 A
. [6 s. R+ B8 F* Z  D) A8 [    returnowner;
' D! q& Y# G8 Y1 L( f; t9 C) d% p7 y* h/ Q
    }6 x# F, o  S2 ]$ d  |0 W! {
+ I" O4 @$ Q. D1 n. R2 d' W
    /**
. g3 \4 @9 _' ]9 P4 P( j" m7 D+ ~5 c1 }$ e% n! R
    *@dev指定的token是否存在
$ {; W2 ~: S: {" _4 @) v: u' I: y) W5 P& g- O1 j2 N0 E
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
7 M8 D" f- ~* o0 a0 w% ?3 F: Z; M+ q; f, ~) q! L
    *@returnwhetherthetokenexists* I+ V4 l' @/ s, ^

* P: o! b- c" w" L    */3 @9 U) {' _. g' Z# A) Y5 d+ G
/ h1 X% m) G& h9 Y+ H/ B( A& A
    functionexists(uint256_tokenId)publicviewreturns(bool){+ [# z) _' H! w- w& Q: p  g8 Z

, x. z+ e% r( ~0 `: n3 o    addressowner=tokenOwner[_tokenId];
1 t# g4 q( g  F& F5 D7 _% `3 K* I  W7 r% I, E- o  x1 N( \
    returnowner!=address(0);1 j+ ?, G, I4 d0 ^; g4 x8 o/ n
/ l- h! m% ?1 S* y* ]& [
    }6 U+ ]% M3 U# @! i+ G+ |

0 S" P1 ?% o+ p% T    /**
5 D) c! A, e: t1 t' l+ O7 s/ Q
1 W0 B& t0 t+ |$ m1 i$ e4 O    *@dev批准另一个人address来交易指定的代币
" C" v" w9 m. c8 q- i  L; j9 C4 Q" `9 v- c/ i+ c4 B
    *@dev0address表示没有授权的地址. Z4 p0 M9 ^5 z+ T* l1 W0 _* K

8 ?4 C, h: l+ m0 l3 F1 {( F+ ?3 k    *@dev给定的时间内,一个token只能有一个批准的地址# T% `6 d" ~) c& o0 J0 m# ^
4 x, T; E$ c  {2 Y% o+ ^
    *@dev只有token的持有者或者授权的操作人才可以调用
+ K, ?) g6 F5 B! B9 v  ?3 l
2 P/ l  A& p2 R" J5 x    *@param_toaddresstobeapprovedforthegiventokenID% \4 W" }, y: _$ K4 k# N) H7 c4 ]

7 |3 f* b7 D6 |0 k6 Z& |5 |    *@param_tokenIduint256IDofthetokentobeapproved
$ E6 e" M& S2 K: |& F7 f% E( i1 a" o, E# B- M7 i  h/ [9 X
    */
1 S3 B4 s4 ^( P8 o1 v" _9 ]# p0 a' @9 @( s
    functionapprove(address_to,uint256_tokenId)public{+ o: A4 \5 x7 |' V) F

! F  Y/ q* t" i# ]    addressowner=ownerOf(_tokenId);
/ z9 f% R7 `& X5 y
4 d6 Q# E+ E3 |$ b5 Y% |3 e    require(_to!=owner);' y4 Y" R5 w" |) E% X8 Y! h3 x/ s

" {0 C6 K2 k, J; n# _/ Q    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
7 R" x  _/ D* \% Z  u: U9 O2 w! d. A+ F
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){% l7 D! D$ Q% S6 x

8 Z' {  S8 v$ Z7 w1 G& V! _    tokenApprovals[_tokenId]=_to;  ]! j9 n- S+ {6 s6 z: R
) k! H% y2 v9 [0 x
    emitApproval(owner,_to,_tokenId);
5 E6 B' s9 d" u5 S  L( Q5 h- ]
7 Z5 u) m" _3 E/ A2 C" a8 O2 S) r7 [    }$ V4 p; T, f, ?  n
: ^, C+ Q. y9 N  A6 V- v
    }' z2 g- T4 c7 ]3 M% W

% g( N; Q$ D4 L* \! @( ^% A    /**
+ y- \, {8 Q6 o1 ^9 [) c% Q: b- u1 t5 k/ J3 \
    *@dev获取token被授权的地址,如果没有设置地址则为0
6 p- D( j/ h/ V$ p; z5 o( ]! w" @# J* q" h( G7 V
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof0 y$ t3 M/ e# Q. a$ e- E# j- a

# O- y0 U( ?6 z  X/ V$ O" q    *@returnaddresscurrentlyapprovedforthegiventokenID
3 l6 j* o  a1 m1 P- L
4 q" ?1 O* v+ S) B    */" I, q$ q2 o0 X; m
  N- L) w# n6 p2 V
    functiongetApproved(uint256_tokenId)publicviewreturns(address){
) c/ w) q* q. V, i7 A1 b4 R2 G' t( `# {7 @) K! b
    returntokenApprovals[_tokenId];* }) @! F8 w* q2 X* n: n  D; ?9 F

7 k" \$ J7 p$ B3 l; C# L' j( m    }
9 q) _; H- I8 E5 c
8 y! f5 H% c9 U    /**( R" H  E7 J3 X' D
- i0 K' |3 c6 j* [4 k- f6 W1 q
    *@dev设置或者取消对操作人的授权3 g1 F) ?( B, ^; _) D

0 r* V6 V% ?3 K( C  ^    *@dev一个操作人可以代表他们转让发送者的所有token1 t5 ]  [4 \5 j6 W
$ s- C1 B8 l' p1 g' [! t( N
    *@param_tooperatoraddresstosettheapproval0 t4 W5 w' ]  u$ H& Y
7 p- ]/ [& W6 C
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
' K# b, r  H8 h- z1 t, Q
$ Z% F3 g2 S( h    *// d& I5 ?% T) x7 R: ?5 ~/ x4 {
$ l& V- ~4 F4 z8 j! s0 S4 V7 T) M
    functionsetApprovalForAll(address_to,bool_approved)public{3 S# k( e. s* m2 E: v

9 _! V% Q7 M* r4 `! P* c; w    require(_to!=msg.sender);0 @: F7 l/ K" \5 {' V

8 D' d6 i* J0 v* V. p! e    operatorApprovals[msg.sender][_to]=_approved;; K5 c) j2 o7 @! @$ i* w8 p$ \

5 V& C! _9 D% P4 O    emitApprovalForAll(msg.sender,_to,_approved);- P, n! S' J5 j

8 W! R1 y% H% E    }- T# e" v8 O% R( c* V) u1 O
3 o" ]8 e' |- m% U/ n
    /**
, _  a- F# S% s) H+ E7 c2 P$ u& Z, o' Y. V! u& D! m
    *@dev查询是否操作人被指定的持有者授权
. w* O7 W+ E1 k6 _7 d5 {/ r  p6 Y& w, N% I
    *@param_owner要查询的授权人地址4 i% D) M+ S$ h) ^
: c) @! G7 i- p7 ^( A/ P* S% x" |7 L
    *@param_operator要查询的授权操作人地址+ O5 a8 f) [' c: C! U" Y
, m4 g7 e7 q9 ^
    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner' y8 g: Z% \7 e$ f
) W+ c+ g% y8 F+ y% p% I
    */4 G" H# Z  ^. y3 U$ @

4 V* d6 P3 o; x) S: Y! E    functionisApprovedForAll(" d$ u# J4 y+ J

: Q6 n" l) d; N! |& S    address_owner,
2 Z% ^: V# e& a& ?! _! y+ w# Q8 ~8 w1 W, L7 D
    address_operator
0 P+ a, T1 I2 l; i7 y3 u+ w  {; [, e9 X  \
    )
, p1 I8 [8 m: B" ^- Y4 k6 K. [: l1 w2 \
    public
  I  o) P& k+ g  [  g- q6 c9 Y
: M5 s6 `9 t" g: H    view9 }% @% [, ^2 |
. ^9 H. t3 K. h' k
    returns(bool)& s+ [4 y1 `" v& D6 M& o

- R. c0 j% X/ ~" V: W    {/ O. Q* ?: [6 S( w
6 K  H! H4 C1 Z' \4 J: U9 t
    returnoperatorApprovals[_owner][_operator];, }7 _8 k: p9 I/ B: v7 x/ P

8 B- g" e: D, ?6 M    }
' D- ~+ c4 r) A
- l7 f+ k5 S( g7 Q& k* f+ r    /**. D, C' @. T* \; o" Z4 C

4 a1 ~, O2 W, U5 x7 B/ V5 L7 X    *@dev将指定的token所有权转移给另外一个地址
& n% Q, x. U! o& M
* l1 y# @9 I4 {# |3 d    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`" N1 H( j3 p$ _% d0 ]

1 q1 |- n9 a) K; S/ X5 H* k    *@dev要求msg.sender必须为所有者,已授权或者操作人
- c1 k! X! B# J0 ]# v  w$ o, z7 A+ p
    *@param_fromcurrentownerofthetoken# `  y6 n% J% {9 d- X0 d1 V

% K: H8 V. c7 f" @    *@param_toaddresstoreceivetheownershipofthegiventokenID
; g) K, b9 v) r( ?
$ x4 u% o! J, M" o# [    *@param_tokenIduint256IDofthetokentobetransferred
/ J/ T. Z+ U+ [0 m6 a
7 `" `6 \" K9 V- ~/ L    */
' w0 r& a( q3 |/ d
- f: r! Z7 q5 w3 A. V    functiontransferFrom(' I0 l+ n1 z; [5 p6 E* p1 Y  h

! x- s2 ^$ i; w! v* r    address_from,
4 n; k3 M0 P1 z( @# H; R5 _9 J. W" ^6 I5 {: e
    address_to,
5 i5 Q5 O6 l' h9 P+ j% }7 P2 E& @, f( D! F
    uint256_tokenId, ~# |3 u6 _1 O$ v* k
3 j- n& e7 b- `7 s& X# b$ v
    )) c8 m3 b0 O" y% y. o

  Y: M; H7 k" j" H1 H- c  J    public% a) t5 l* A  x7 \; X7 @) Q+ P2 |! B
, q* y. o; W1 G8 H6 a
    canTransfer(_tokenId)5 Q! Z8 {0 m" y: P0 s; q9 n
2 u, G. @& t$ a. b; E
    {
% |9 b7 k7 {& U4 i& F1 `( }9 w& S$ V$ ]( z& j
    require(_from!=address(0));" c  {) s1 d/ W+ B5 A4 r: p; w4 p

+ b+ U/ C( q/ s( w( _7 M+ c    require(_to!=address(0));+ }, v! k, b5 J3 H& `5 E( F( z

# x8 d: s& V& E  _    clearApproval(_from,_tokenId);/ [& f# \5 y( k, P0 e' z3 n. u! A
. n3 m; Z1 n# \, k+ P
    removeTokenFrom(_from,_tokenId);: l3 a0 K, {* @' r

; O0 h0 a2 ?+ k. @    addTokenTo(_to,_tokenId);
7 w, u1 n" b/ s3 y+ N7 z  Y# I
' h$ |$ U% t9 N6 ^% C    emitTransfer(_from,_to,_tokenId);
, Q. t: r( D% l- A2 z, l: u, P8 r/ ~
- k* y( b) G3 P% S% f    }
  `# e( m1 u3 x0 i% h+ z  X& ~: t# A3 N2 w; Z! Y7 R
    /**# q' v; a! w% e: K6 h: |/ G+ d
. o) A" v: d2 H) P; X! j% V* T! F! r
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
: ^4 s  h2 V6 Q' H& v5 W3 |& A
# W5 a& ^# b6 ^$ Q    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
! F$ _* D3 L& X7 {3 z) _+ B: f9 M
" t1 |9 x# k* i& ]9 u: Y    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
1 ~! O+ x( c6 L% r3 f$ W& J8 t8 ]" w6 R4 S' n0 F
    *@dev要求msg.sender必须为所有者,已授权或者操作人
% \  ]/ {  q8 _( A* L0 u$ E0 _5 f& E2 U. P, w+ A4 g0 Z
    *@param_fromcurrentownerofthetoken: _/ F& F1 J# b
1 Z* M# u6 Z- O7 ?3 N
    *@param_toaddresstoreceivetheownershipofthegiventokenID0 M2 ^9 \5 j6 f2 q7 Y
: K  b7 O% \, S1 k
    *@param_tokenIduint256IDofthetokentobetransferred
; Y( x; |- F+ M. `. X* j2 w; X- i3 d$ ]( \' j; \1 Q
    */
3 }' b8 d: C1 |  E' ]
8 o$ V8 ^( R7 \9 W/ V    functionsafeTransferFrom(, ^" r9 ?! n  u) U7 s
9 K4 y8 l# E+ h+ D& i9 I/ |
    address_from,4 b8 ^5 @7 b5 E4 c, M" P2 i9 l

4 @+ m( T" k: a( d8 a& l    address_to,
3 f8 u1 Z! u# _1 P; I. G- ~. ?4 s9 C. B
    uint256_tokenId# y$ P2 V* o. z. Q
5 N5 G! p, g) @0 f
    )
6 A+ k" @* C: H7 X
- k/ q# ]# Q7 W# M5 R    public5 m5 T5 C& t7 w7 V' w5 `% {( K3 n# P
5 m2 c# {- N! @' x
    canTransfer(_tokenId)
( M$ l9 y6 ?# a! X" q: x  p1 T! {" J$ f4 z
    {/ M; b4 n2 k8 D& Y% L  `4 H6 D
) z, ~+ _% U' R6 j3 _# q
    safeTransferFrom(_from,_to,_tokenId,"");' [0 N! ]; a2 _

- J* [" k2 X* L  B/ x$ w# l! K$ d    }
7 |- A! ?5 n4 r# n2 S7 O
: H/ z8 ^4 ~: K, Y, x( v9 A    /**
* j2 d' Z/ q/ J2 F5 s% Q7 L# Z6 E/ e* y8 s4 \9 a& n
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址# d! S  C0 @2 j. J( Z) s

" {# M* }1 R6 s    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值6 Z. e$ r- s" }  `7 z4 n3 x+ r0 y
, F, N$ E/ Z' O( \
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
" b- O, T0 I/ W* i( A
7 ^: q/ x- P& I% j6 L    *@dev要求msg.sender必须为所有者,已授权或者操作人  G3 U$ u$ k$ K) J2 j/ U& O$ o! q
2 ^! c! _4 P9 y) l- {7 f4 U
    *@param_fromcurrentownerofthetoken; s% p# f. C2 i
- v, D5 O* h: q2 q+ [7 G: i$ A
    *@param_toaddresstoreceivetheownershipofthegiventokenID, j. R; O9 A0 `) ?! s+ W3 p5 j/ B9 y

" R, ?4 Y6 b! h+ L1 z. A( z    *@param_tokenIduint256IDofthetokentobetransferred
& k+ R& @, V' x7 |- D8 y2 V  d  O# k. w# U$ h& F
    *@param_databytesdatatosendalongwithasafetransfercheck
$ k: i/ M/ t3 M8 D  [& Y% v. w& K' D
    */  Z- ]$ G) V- l, ?1 k6 H
6 c! Q2 I1 B; V3 d# [1 B
    functionsafeTransferFrom(1 i3 }- o9 M6 L6 D7 O2 m
0 K) \1 v" q: t9 |6 L. @; Y
    address_from,
% f8 k& w6 r8 W  T3 n" o. H3 q. f3 q3 f
    address_to,# n0 l! a- ^+ |2 Y4 k3 h
2 s5 S& @" }% X5 ~. H; f
    uint256_tokenId,3 b/ S2 Q# ^$ s# k! a
/ E. h: v5 V4 E$ a3 Y
    bytes_data
9 U* L" c* r% W
1 T7 \$ `0 H( D' w    )
0 k3 F; D3 J5 h! S  D2 T- b( m0 U  j4 r; Y0 d6 K! a, R2 J% y
    public
/ D* x, d& {1 `; n! `5 K5 u  {& t: D/ g7 ^" W' ^+ c" J% `# e/ x
    canTransfer(_tokenId)  v2 }% j, Q1 b  l0 J
+ V/ _3 @+ A' |) ~4 {+ [3 `; ?
    {1 q, k1 W+ G$ c; w7 g
! @# e4 g7 [/ x! `7 }1 U
    transferFrom(_from,_to,_tokenId);
+ M) C$ C8 X; m# D6 x+ |, Y' `! Z! Y: I9 ?4 X8 i! V9 A/ f
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));( }! F7 P5 `) d

# K, ~' P2 B+ |; I) L: {( V    }3 I! `3 J+ G3 ^/ _) ?: I% h5 q4 H
- o3 k9 ]' j' l9 ]- D* p* Z
    /**7 f0 b3 s+ h  S5 o4 H7 L) e- i* b

, H  Y3 l" e# O; a& S$ G    *@dev返回给定的spender是否可以交易一个给定的token
: o0 A% t2 S. C2 q2 H" T
5 w! o! Q: b1 m7 N/ z: `( l( _- @! ~    *@param_spenderaddressofthespendertoquery) D( @3 h' }2 J& `. j  x

: q' e, r- ^) ^# S3 F4 b    *@param_tokenIduint256IDofthetokentobetransferred
+ Z9 a& U/ J6 e$ w+ m5 [. B. o+ a4 X0 j1 w" r' F: `) V7 u
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,
( w; ~. ^, Q$ O( H7 `
6 u# f, t( o" w/ @) k* Q7 Y    *isanoperatoroftheowner,oristheownerofthetoken, q! X% `& u7 T1 J" j1 {3 x

. S1 [! D+ `# Z    */" K0 z$ S  M4 @/ B0 B9 T2 }

- P3 L' }/ ?6 J0 L    functionisApprovedOrOwner(% Z+ @8 Q! V0 Z  |8 J7 `

- L- z4 S- a0 {3 f1 f    address_spender,, G$ g9 C! l7 X1 K2 c$ z$ ?+ K
  f$ F# j  j! c; N2 i. Y4 b
    uint256_tokenId
9 ^) i5 V' x# P& o  E. A
. |. j( {, @; R$ a( s1 D# ?! w    )
, n- J7 ]1 d% t% o& d0 R
* [7 o7 h- z7 w& \% N: \    internal( L2 u% j& Q/ ?+ s

* j  @% [0 d' u* h# X    view1 J. i3 v% J; v  V! h' s8 n* Y/ B
7 o* P/ l0 \% s4 W
    returns(bool)
9 P. ]0 O0 k+ R% K" q+ ~1 E, |: k" F# l/ E% g8 x
    {
. e& b! u/ h. L) J4 @' g! l: K' G1 `; X; n+ g
    addressowner=ownerOf(_tokenId);9 n3 W! F. R7 c' U& Y' x  j

( d- ^. t+ K; d* s' F2 U5 z    return(* o3 U1 E% l3 C; F- M
: {1 f# N8 Y: y" W( F% e$ z! l
    _spender==owner||& V" t! e, t; a. V; `2 K5 I! A: w
' w# n6 C- B7 _; |+ U* |
    getApproved(_tokenId)==_spender||
! i% c" k, m& A0 r% d4 S: H5 f: m% L$ J- x4 A' r4 i+ b
    isApprovedForAll(owner,_spender)
! w! I& ~# u/ s3 G) x: U1 R3 ]
% t! M6 j1 H* k# x) |2 z. y    );1 U: h) W& L' f' U" c, E9 J/ \7 T* c

; t$ F) e* ^6 \% f* P# z4 ^    }! s) u3 y( L2 d% k

8 q0 H8 u  [) U& j3 A8 m2 |9 W    /**+ x% w  i1 J: f8 X) V! D
+ X1 K/ t0 o- K* w# E# {
    *@dev增发一个新token的内部方法
0 q; [/ C1 k$ m  x: i& ~7 S
3 z5 U$ W8 s- @) ^& T( p4 P    *@dev如果增发的token已经存在则撤销
- z' M: Z6 P& ~3 g& B, O5 S5 F4 _& g* T, ^
    *@param_toTheaddressthatwillownthemintedtoken5 {& ~0 q1 y5 x$ i6 p, [& ?3 o

( a6 \9 s( i- h! ?" ?    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender, w8 d( z: e8 O. k1 d" j3 C- M8 q3 \) \
7 V- G5 r; X4 ^9 G/ r
    */
  y& m% I3 q: q! }3 T  E# C! d- ~& s; j3 \1 G, }
    function_mint(address_to,uint256_tokenId)internal{
# b  a) i7 G  [7 [; R4 p* I6 r) e! |& k2 ?5 {
    require(_to!=address(0));% B2 x' p) H: q6 P8 O" U7 _
# O% k' ^# c: |+ Q( f; Y8 e
    addTokenTo(_to,_tokenId);/ b1 N" h' h  e8 E2 k+ z2 t5 X: z
+ o  I! T4 x. r" V  x+ O
    emitTransfer(address(0),_to,_tokenId);$ t! w: E* n: d, h( N- C
  {2 ~2 B# x: y. K; V
    }
4 `8 i: \: J% w( `8 u4 T& d) g* X9 m! [+ }1 ^4 X6 S) B/ H. q7 k
    /**
7 B( B( _" Y: q9 O5 Q% N2 u/ \6 h, |; k2 ]0 d2 H/ @* G
    *@dev销毁一个token的内部方法
' R& O2 d2 b0 e1 U. ~- I+ y2 p, H7 s+ c( J7 c
    *@dev如果token不存在则撤销
/ x/ p6 Y8 h: Q" H' B8 P: [- l, n. r( s3 g
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
0 {* e( ~3 W) S( Y! S  _1 _6 w' R/ L$ k- D: G+ G+ o
    */# i( g% V7 t  o

8 U) J# `: k& W9 ~* |, r5 e    function_burn(address_owner,uint256_tokenId)internal{  n2 l1 M) |4 ^9 E8 O; t2 _& j

/ N4 q- i5 @( {    clearApproval(_owner,_tokenId);
. h  ]7 @0 W% ~0 H4 R9 _% Z! b& Z; D/ N4 K, n1 M
    removeTokenFrom(_owner,_tokenId);
( d2 \/ w! a* k- }! b: P$ e  d! G. T7 v0 a, m1 ?. m! S* u
    emitTransfer(_owner,address(0),_tokenId);
- h9 t( A/ g# D8 K/ [  R
- o* @3 Q4 y1 @& w( Q+ J    }
* j" V- t+ c5 Q2 A4 M- i# P- S9 ?/ n! w! D0 }0 D9 k
    /**' [3 e3 F; j, v0 l* B) h- c

) }/ `: K, e  `5 l: }    *@dev清除当前的给定token的授权,内部方法0 g* n% k; J, [- U3 M# @6 V
* R' v. n4 P/ H5 m
    *@dev如果给定地址不是token的持有者则撤销
' l3 K" H0 K5 L3 d0 ^& X4 X% C( n. Y! J3 x; c
    *@param_ownerownerofthetoken
' C5 l$ q6 |; z) Z
( |5 N8 F1 `8 [: M" a" d& T; a    *@param_tokenIduint256IDofthetokentobetransferred
3 y/ ?1 |. Q3 u0 [0 B1 V
1 L8 g: i8 _$ N% @# v# Q    */
) i; ^- [: f; o
% A2 g' I5 J1 d* Q    functionclearApproval(address_owner,uint256_tokenId)internal{
) ~6 x7 b% P6 H* g, ]
8 q% O- n6 E/ k5 z, e: _    require(ownerOf(_tokenId)==_owner);
" e+ }: M/ Y3 ^* D$ S' Q$ ^" s& R2 T% B5 F. ~- b
    if(tokenApprovals[_tokenId]!=address(0)){' I- _& N1 c: \( k0 {! E. L) V# v
8 X8 {$ t6 i% E+ E4 |
    tokenApprovals[_tokenId]=address(0);
: J6 _+ i7 e1 Q0 @9 v' X" a- m, ^& N% Q  [' n
    emitApproval(_owner,address(0),_tokenId);
' F, B* d" C5 W3 n- i# A) J) R2 P# M4 R5 b6 b5 O2 A
    }
& u* t0 G8 G3 |5 T* p& ?
" D+ _# H3 w; g$ W    }
) r! z' h2 _1 F" _' |1 m9 l  s
7 v" Q# l6 M" K  `. }- e8 h6 \    /**
4 t9 L$ R7 b8 o, ~1 f# e0 u5 f( s$ |. E, P5 _$ D+ `
    *@dev内部方法,将给定的token添加到给定地址列表中
" S* u2 r: w2 X; h" }9 H$ N/ d9 ]7 I4 A* H9 }
    *@param_toaddress指定token的新所有者
2 `/ Y# g9 F1 y/ K1 m
! `& d7 @* y4 W" ?0 ~/ d3 q    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress. F8 B( J& u1 K. F& r
2 |9 y' l4 X. Z
    */" {' ]7 o6 ]4 d( d1 Z
# _6 t4 o( E1 Q' z9 f! L
    functionaddTokenTo(address_to,uint256_tokenId)internal{. Y" [9 ^$ V, N2 Y
7 }9 s' N5 J( \1 N7 Y& }' Y
    require(tokenOwner[_tokenId]==address(0));+ H0 f( a1 V+ B% I( O5 I$ b
0 V% n# N9 N) c
    tokenOwner[_tokenId]=_to;
& e7 ]- G  \. N7 v- K/ @) P( d5 `7 L8 N' N% v. A
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);+ m: D/ p/ o% f4 B1 T" D0 w
6 z: R& m9 h+ C" C, X3 H1 n
    }
$ _9 L: [% p. w
- M2 v! [* m. @8 b# `( d9 d0 i    /**( s6 N- K% X0 z
0 S3 i; v1 f8 K/ n3 ^
    *@dev内部方法,将给定的token从地址列表中移除' q6 Y3 r  R% d4 C3 m/ q* s

6 R. _; x1 N- u& p3 T    *@param_fromaddress给定token的之前持有中地址
! F. F2 E( A( b/ z; ~, w/ M& j+ w6 V) k
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress6 f  M2 C& H% t* ?; _( X0 C

. G1 _7 w. \  |  u4 P* B& d" L- t8 g    */
) ?! m- u! P4 e2 ?( `& a2 `+ s  C
) D; L( R$ B. o( w) e' b  }    functionremoveTokenFrom(address_from,uint256_tokenId)internal{
' q" u9 T0 |9 A5 m; ]' r# w5 b4 V/ _9 Z
    require(ownerOf(_tokenId)==_from);
' k! P5 i3 V% c6 H7 k' w
; {4 S5 H2 j+ w& w6 a7 ~! X# I! C    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
: N9 j+ `2 s& R0 Q, l
; X% v) P/ Z) l0 T: B7 m    tokenOwner[_tokenId]=address(0);1 d* }$ N, Z& U6 y

' Z( ?; x6 O: h; o! o    }
; T$ P' D( |% _, E1 p$ n7 Q
# ^/ _- z) J+ |+ U    /**
9 o. b0 d/ k# l: c* g
) i! G" R1 M1 b, U) Q9 R( v    *@dev内部函数,调用目标地址上的`onERC721Received`
# G" p, g; C0 a% ?; R! X) I9 c$ l4 u6 |/ P/ r, V6 p% X- c4 f1 |) b; V
    *@dev如果目标地址不是合同则不执行调用8 |: ?  R5 \  \0 u, A: M! s
1 E: \! @; [9 x: _/ C- W) k
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
; N5 Q. M  L, t- l9 p3 k5 J. `* E6 D* Y. C
    *@param_totargetaddressthatwillreceivethetokens
1 Y0 \: `7 e0 \( W3 c9 U
% q+ m9 U6 h! V7 G. M0 Y( w% g    *@param_tokenIduint256IDofthetokentobetransferred
" z8 `% I5 q$ Y- Z
: r0 `3 e! u$ H, F( I& l8 m    *@param_databytesoptionaldatatosendalongwiththecall
$ g9 J: L; m; c7 f( D1 A1 D' n6 w- s! M/ e0 o9 a, U
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue" y* y  q5 r. i. l3 [8 p

7 B( j$ z( {( m) |5 l* ~" c    */
7 l+ Y4 W7 n7 \' g( L: u5 i' ^& _- Q# {/ b& T$ h7 M; v& |$ K- O
    functioncheckAndCallSafeTransfer(- Z8 ?( P, n% I3 U

; b' |, w& R- u" c) Z8 w; v    address_from,
: q0 ~) @. J; N
5 L" s! O; ?$ Q( {$ C" ?# c    address_to,( ]4 b# H, j/ l- p

% @; N6 |* Y5 s% P0 m2 s, X! I    uint256_tokenId,
; _& e: V# J2 n& B( n
7 t5 @6 ?, R! @7 O  B7 g2 l. o) c    bytes_data
8 M8 [) f; ^  X+ N) ]/ i
  ]/ O" m3 x2 S$ c1 ]" f    )
4 n4 _4 `" A  x( J) A* @
7 J! D9 [2 y; Q    internal
$ u& L: D$ ?9 [/ L; h% `& y7 G7 w+ q" r; Y
    returns(bool), o- S) F4 r6 U* \0 F3 S
- {# S% x# e  N$ V" o" ]3 N
    {/ W5 c5 B% a5 B8 H0 R" W* Q1 K8 w

; y4 }/ R$ x7 b3 y& ~3 O    if(!_to.isContract()){8 M1 a1 Y) h( A2 y' t0 o
2 H  P& m' o+ h  Q
    returntrue;
; E( K2 y9 a# c% U! H1 a, Q$ @  _( t
    }) |1 r3 {+ B0 f" |% d
' d" e- P( u$ U1 x
    bytes4retval=ERC721Receiver(_to).onERC721Received(( A4 b1 m" a, v* H6 S

  u3 Q; e, q- g6 d+ I0 i    _from,_tokenId,_data);; W, s  z2 o3 P

6 k( H$ e3 P+ L0 M  F: w$ J0 r    return(retval==ERC721_RECEIVED);+ s. D, {7 y* g! m4 \9 \( y1 S4 J
# q. c, t" }8 |  T8 S
    }$ l- ]: \1 s6 {- J: s( G

- [9 k2 y- J; }  R" ]    }
& e8 Z5 n' D+ c- R& \# X  P  {7 m3 x
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。( o3 e: E: A  d- v  q
& P4 `, Z* ^, Q7 Y6 |
    ERC721Token.sol
1 X! X4 G2 m; X' n- h# u
. A2 i' [% R4 E; x    pragmasolidity^0.4.23;
8 t2 C* j8 R  L, ^$ g* f9 q
# n6 X1 c. J! Q. ]% {    import"./ERC721.sol";
- M! s+ D, ~2 `0 J9 e7 y5 [8 r$ k; m& }) w4 A3 ~( S
    import"./ERC721BasicToken.sol";* \( u8 X4 B. t9 w9 r
& a! F: q/ O" H" F- P
    /**# `. q& a3 ~) ~9 j4 Z3 u/ H% u

# t: |" r- M$ H# L7 L+ s: X    *@title完整ERC721Token% g4 y8 O  J& P$ _$ ]  s+ g2 w

9 s: B2 `5 ?8 \& P+ g& a5 n    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能7 E8 U# f  Z1 m

9 ?% i! C. W1 c2 {; f- n    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
2 d8 \. o9 s+ @! ~% [) u. `. Q3 m+ C7 R  G
    */* |+ [+ ^* R1 b6 h) J* M" d
+ V' ~: }4 U1 {" F+ w
    contractERC721TokenisERC721,ERC721BasicToken{
. F! o5 ?# s  f& G4 ]
. F8 G/ I' l: w8 |0 B- _! ]    //代币名称
  a) @, M# d3 X5 w2 g9 r3 L$ L+ u  B8 m1 F2 c
    stringinternalname_;% Y3 v3 L% c! u( e

3 E0 s5 @0 G% b2 u    //代币符号' [' n* h2 m6 b6 k8 M& t0 n
# w: o' D3 T  S$ E4 a2 f
    stringinternalsymbol_;6 i2 i* E1 B( |/ w/ A3 b

- U4 W1 q; C- P* m, |$ @    //所有者到所有者拥有的代币列表的映射! n  i, c7 Q6 Y1 Q! R* O

/ J" \& k  D' b% P( C; Q# q    mapping(address=>uint256[])internalownedTokens;$ Y, I3 C) g. L3 N
4 j& D4 e; r' o
    //所有者代币列表中代币ID到索引的映射$ |' W1 [6 h/ s

9 S+ _8 m2 X7 ]0 A8 N2 S    mapping(uint256=>uint256)internalownedTokensIndex;( ?) f4 F& B9 N4 O7 J9 f  x

7 _4 Q- x- ]# b& ~    //保存所有代币ID的数组,用于枚举: p+ g$ X4 t9 Q7 ], E% P/ ?4 q
2 b  Y) L2 B% o$ j1 ]! s
    uint256[]internalallTokens;
3 s  }7 t: ]: {, j/ F% Q! C3 `% v4 i9 k- `2 h6 h5 I9 H% q
    //allTokens数组中代币ID到索引的映射
( N# z! v' V/ |5 f: e: U  ~1 E6 D5 j
1 ]1 y+ A) U* }! j5 @    mapping(uint256=>uint256)internalallTokensIndex;) ~: c! @' p* W2 C
$ q4 ?+ m% H' S2 K$ C  a
    //可选的代币资源URIs映射
! g5 Z9 o5 n& t% W  D0 {1 w7 p
4 y: @9 ]2 L0 P8 M' o    mapping(uint256=>string)internaltokenURIs;! w6 {6 O: E/ q  d9 _: v

% i$ u. J" l$ T8 H8 r0 l# {- _    /**
# f/ Q' x" p/ Z( h
# K7 Z6 @. _) c- G+ u) S" }2 i    *@devConstructorfunction
6 C/ N6 k4 ^3 I( j/ b  A
2 p: f5 z& `, @! \, N    */4 L( F+ A9 i1 ^. ^8 p6 `
: h8 q7 g( t1 D) f) s
    constructor(string_name,string_symbol)public{
8 j+ k" r+ b. ?* G0 W4 b4 d. K& S6 i9 J1 T
    name_=_name;
8 z8 |' I9 m0 P# n: h- a# x3 c" i& `6 q
    symbol_=_symbol;
- c* K" ]4 U* c/ ^: I7 ]2 T! P3 C
    }
6 E  E* }& J+ p' [, ^4 p
$ b4 {5 a! L7 G% }/ f. }  e    /**" T" y7 v1 H7 Z, n  O0 @

& l2 p: d& R: F- y    *@dev获取代币名称
: E# J' p3 l9 b' d! z! w5 ?6 l1 W/ H+ B$ E
    *@returnstringrepresentingthetokenname
! l0 b9 @. i0 U7 ~/ E- j" Y- k( ?
$ F. n* h; V- S% l+ k    */. a6 v1 q  `2 V3 K
- l3 t, H% T4 D2 y% }
    functionname()publicviewreturns(string){% V0 G& s* L( O1 A1 O

; X# D9 J( q1 s    returnname_;
" Z8 K8 j' l# _$ I/ `3 t* f! J5 h; X. S" K% H3 E1 @
    }# H  D! ]7 p8 K+ ~4 B; q. P# f
/ H+ p1 D  c. S
    /**
  W; n/ H/ X" a# H9 \% o8 h# ~/ h7 J& S; N) x6 c  U- O4 h
    *@dev获取代币符号
! D& ?2 L, M, _7 s5 e1 t9 J& J  I. h! f& o6 M
    *@returnstringrepresentingthetokensymbol/ A; Y. y( C7 `

( _  R! J4 m: _    */
) o- M) y; [) G  O& `, Q: V" W" A* c) f2 u8 V# ?& J4 ^0 q
    functionsymbol()publicviewreturns(string){
% ^4 \' c, F6 _# i( m0 w0 b- Y7 l4 S. R5 X9 Q2 A
    returnsymbol_;( U0 J( j; }, C' L  W& j) I
. }- U5 a; v7 b# M! L" `
    }
! x$ a; [8 t4 S' ^& X
' G/ r$ f. a) @" ~; s# m0 W4 Z    /**
6 z. _/ \& E7 I( \7 j1 [; s
2 L5 l) ^, ]# Q: F! |0 W    *@dev根据_tokenId返回对应的资源URI
6 M' U3 `; m# |3 l0 M+ m; d  J2 D/ B/ ^: D
    *@dev如果token不存在异常返回空字符串' c2 Z8 z8 S1 t6 z0 h

& N" k0 E5 |7 U: H1 V- Z7 B% J0 B    *@param_tokenIduint256IDofthetokentoquery1 T1 Z: y  Z- w& \; C$ x

; q* t0 u0 k& ^' v8 M& u    */
9 ~! T- `8 z# e* N, g
% `3 e0 z% e1 A+ j7 Z    functiontokenURI(uint256_tokenId)publicviewreturns(string){
8 l3 v9 @7 x/ u3 i  \3 R  |8 ]* H+ t9 R' T& v5 {! L3 r/ U* f- D0 ^9 g
    require(exists(_tokenId));
  q) A4 L/ D, t8 M, `7 p
) f- G/ K/ I8 m6 o; ^: C6 b; D    returntokenURIs[_tokenId];' y; r  d" r/ A- h, v
9 H( e- e/ `7 _1 }2 a: A. E3 o
    }
  q( r  Z0 p% F, t+ N7 _/ D3 ]' P0 u) z  |$ Y
    /**
/ c: q) c8 f, l8 P* }* V- i# D0 C  p3 a/ |8 c7 n, s. M. |7 J- e
    *@dev获取tokenid通过给定的token列表中的索引& q' f& b& g3 R4 G; f1 |
. ^, \* i( L9 H$ x$ m, Q
    *@param_owneraddressowningthetokenslisttobeaccessed
( }$ `/ R# @; M: v$ _
( T/ ^% e* o& K    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist8 P& c( \9 k. f" h" c3 D! F

7 c; ^$ e" l' i) n# C    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress  n$ G% G/ a2 S% B

" {. S5 B! T! o6 E    */
1 H: v/ r+ f: X9 G' g- x6 K$ B. ?. q* Z: W' \
    functiontokenOfOwnerByIndex(
- t5 |8 w2 W( ]
; C: q5 R4 _: O" S9 p# Q7 R/ Y% Z+ d    address_owner,7 t1 A; _9 J9 v  m# R3 F9 o
* O! H6 H" F, U! W- W
    uint256_index/ `. b4 M' Z) k7 x) \! _

: v+ ]$ e5 v) [; F    )9 m+ ]; r5 T3 O! ~$ Y
5 t4 _) S8 L+ V) W3 @- v
    public* H/ M0 m+ g0 c

7 A2 q- A9 n0 r5 H( a    view7 t+ D% r  w. g9 U
9 z5 Z5 _% a8 ]$ ~3 o$ {
    returns(uint256)4 q; o4 P$ a! ?2 Q% M! n& \

6 Z& q! c: R2 K5 g  k/ L    {
( d- i  U, n$ G& w4 y4 s/ Q* |0 E
+ K) C9 }6 s- Z8 J    require(_index1 A* T4 S: |, ~9 z6 K& f3 Z, N

* A$ L* W" z& B/ ]8 @    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。* W" |) F! L$ s7 x; M: k. D

6 ?* \( v2 M4 D& \6 s    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2