Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2399 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
, i, A8 Z3 Z, X2 N0 x$ U
2 W+ s& t  c, b! K: ~    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
0 |6 G- J$ o+ o' l7 \; o/ H! `' s& ~/ Z) E  S$ G5 ~
    ERC721Basic.sol
# @+ D+ o* c7 l
' U% N8 ^9 _8 ^: {: w, e9 j    pragmasolidity^0.4.23;
# @, p4 j. y/ q/ d, T  ?  c  @" M( r! T; `
    /**
; m0 m  b2 X+ I: m2 z+ z+ V1 u  c; [$ J+ [5 M/ X2 E
    *@titleERC721标准的基本接口( M, x' c' O2 ~! p) V
" d: u! e) O1 o0 N
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md6 [/ V/ G3 |; Y2 Z8 j
6 ~) ?. P0 y0 G- y$ K
    */' x+ k* S6 z1 z
7 M. U9 n, N( `/ N$ L
    contractERC721Basic{
4 s) @4 P8 L4 I4 u
: I6 q/ `1 @3 y( ^    eventTransfer(
. A+ N( D/ q0 Y1 P% a! c1 f8 S2 j* y5 q" g4 r' d. x$ h, `
    addressindexed_from,5 X) V5 R- u/ p9 k7 j& g5 S
# ?3 [/ h8 q0 |: h, h3 q+ i" s
    addressindexed_to,- M3 m9 q- u! c

: k$ A$ z, a1 [- j7 q% [    uint256_tokenId% R: S- [7 M& p
0 O4 }! r+ o6 G7 X9 A$ O
    );
$ D$ j( C* U3 O3 F" F0 @
4 D  S8 ~3 c7 Z7 H$ \    eventApproval(: @8 H* d% m# r0 g# ]* Q
2 u- w$ B2 v0 B; G8 w) c# d0 L
    addressindexed_owner,' p2 D9 d- d3 B' R+ M$ ?
) l2 \) t9 e; ?" A& ^
    addressindexed_approved,
8 O3 }( j: u, @% d5 h; A. W! O" P  o) J% k4 o' S
    uint256_tokenId
7 |! f& M8 m7 F1 B5 h0 y1 I6 ?! f8 U/ B) U
    );( r2 u" n1 T" Y7 G7 M3 y" @
5 n# W0 c  o- A- Q9 n# a
    eventApprovalForAll(  q9 ~7 u+ j+ t4 _7 U' H8 i  r

+ D. M3 M* p  G    addressindexed_owner,2 N: f2 J4 r8 F7 `4 b
) S3 h: x$ j9 B, z- D' C
    addressindexed_operator,5 s8 u) b0 r9 }
3 s6 _, F4 S% F! d: D4 E7 b
    bool_approved
% X  r0 k- ~2 Y1 e3 Q% G
9 L6 H& E9 U! `+ ~2 b9 b    );! W$ E# G. l7 I

( Q* T9 G+ b2 D    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
7 M3 U3 s! T5 d5 E4 b9 L
5 e, f" ^6 [: |    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);# ~% ~. ]; f' {

# u) z. }  n: Y, j    functionexists(uint256_tokenId)publicviewreturns(bool_exists);, f% [. E" ?% n( r0 K
  J7 w, g4 @$ `$ p
    functionapprove(address_to,uint256_tokenId)public;
& `8 w: y! {, }$ z; P/ ~7 n( U4 S
# M1 l0 P; f* B4 u8 l6 L    functiongetApproved(uint256_tokenId)
' x3 t) _% y8 Q( e: o8 p7 Q4 w! p2 w3 C% N( \
    publicviewreturns(address_operator);9 p$ T! j- x- l' [7 i/ C

1 x6 `& C- O: y    functionsetApprovalForAll(address_operator,bool_approved)public;+ F$ q  ]% A% H* E9 g
4 p- o, j3 b; S
    functionisApprovedForAll(address_owner,address_operator). F" b0 ]2 l% x* K& S* T* a) n; y

1 |$ n2 @, b% u$ A+ a/ E, t    publicviewreturns(bool);
. Y$ F1 L" j$ H1 T: h% e' J
( c2 z8 F* e, l% J% l. R* K/ x    functiontransferFrom(address_from,address_to,uint256_tokenId)public;4 Z$ D6 f/ X: A& @
5 Q( A* R  `0 H) ]: e5 ]
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId): Y" b6 m# J& y9 c' R

/ k5 p. \5 F. W6 @    public;5 _! L1 F+ C% s0 v- C" L/ L3 V

- |. G  r6 Z: b3 o# l. h/ M! P! F    functionsafeTransferFrom(
$ s. k4 V0 y4 w) v
0 f8 p1 F( i5 ?; k    address_from,! Q; r& `+ P0 X  V# C+ J

; y, _+ N5 Z8 H  ^; |2 Z" f! [* c    address_to,5 F) w8 u% ~3 T
& k. A& F; }+ h, x
    uint256_tokenId,% b! F2 P0 u( \# X$ l" q
, r& o0 x. m$ s; |4 ^0 {2 d, Q) h
    bytes_data! `" m. N! ~# v# |9 i
4 C! k9 a$ `9 `
    )
' E9 ?7 P, E( }$ ]' o- ?; V2 C, B, B; h7 L; r* y" F5 R  `8 V
    public;5 U) _9 E0 i% f0 F* k
, }. t8 m/ g2 B  w; h- `) t" L6 j
    }
# Q1 X9 H/ C: B+ ?; ^; N
) y- }9 O) ^; ^/ m( }4 M8 n/ k    ERC721Basic合约定义了基本的接口方法:1 l5 A- d0 F$ m; o

2 a8 o# g( I+ c$ D! s+ e    balanceOf返回_owner的代币数量
" t5 Q- [8 O0 ?5 D5 ?! {; G
; C' I5 X9 Q) a7 E# }; J; ]    ownerOf根据_tokenId返回代币持有者address7 j6 c0 p  m: J4 o' U) b+ W

! f1 b, j& @- B, W2 z6 ]# H    exists_tokenId是否存在
: t3 g9 Q  F1 |; y% R/ [0 U4 L8 ~8 @2 S$ X$ k
    approve授权_tokenId给地址to
4 y1 k( {- P" J4 ~7 ^" [' P* q( {: E) \1 m5 s
    getApproved查询_tokenId的授权人_operatoraddress
( a; d( Y0 O$ T  }* Q% y+ C- u5 ^. b$ u
    setApprovalForAll授权_operator具有所有代币的控制权9 C- f3 T, }7 C2 c9 R

8 z) v- L; U$ W/ I: v. ]    isApprovedForAll
( M) o4 F2 |( X* `' j* z8 L9 N3 X3 f$ M1 g  \$ L
    transferFrom转移代币所有权
6 I& e1 R1 j! p( l" L8 H$ u) r+ ]* o" T( ], X. a3 f
    safeTransferFrom转移代币所有权
8 s8 {0 |; {1 z% Y
4 g% k0 [2 U/ V0 j5 q9 ~8 Q    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
1 _3 h, l3 |5 j% V# a+ A1 d; F% W
: W9 t/ I6 c" b1 C  k    ERC721.sol: r- N& }5 E, [& R
- ~" O) A& p2 p$ E" V& K
    pragmasolidity^0.4.23;
6 E3 ~  ?  K; Q/ r- h- K4 G7 P" G
    import"./ERC721Basic.sol";) C+ _4 h' a$ T- b
! w/ W3 k- a/ e6 s! A
    /**
/ ^6 M# _9 S1 o/ Y% z) ?5 A! \+ d  v) d* F0 C3 g7 G/ J) ^- t% n+ H
    *@titleERC-721标准的基本接口,可选的枚举扩展
6 D& m; L- Q& k! f: ~
* Y( A7 e  l/ z* ?; |6 A' d; J    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md: N6 d0 D2 P4 I0 M  @- Y

/ W( L' A# m$ Z6 x7 m    */
6 \* W2 m2 L. L0 O+ B  A" r5 m( L4 D" V  Z6 g/ I, s3 T# r
    contractERC721EnumerableisERC721Basic{
& D# d; ]( \9 M% w9 j* p; l* Z- u# Z6 T# l, N& [$ q
    functiontotalSupply()publicviewreturns(uint256);
& O: W9 R0 t' _; s+ d8 B
/ Q" c5 y+ e, ?, W. z3 j# y    functiontokenOfOwnerByIndex(1 U4 |1 {/ i6 ~
/ u8 p$ I9 n/ ~" m: T: C6 P
    address_owner,
0 F! T" @5 Q; _
0 A2 M6 l7 A8 k* ]6 S. W    uint256_index( E. E- E! P' M7 ?: z1 b+ w$ F

* `1 ]1 Y: N% V) b    )9 N4 e; e  ], G" K1 r# X3 W2 S
2 R0 X5 v) m# R
    public
- K- ~1 v+ ?2 i: f2 l
: |+ H6 ?7 V! ]% |2 p    view
9 m& k9 f! A/ X/ g. k- z; N) l; ]: x3 c& O; E/ y. E/ ~
    returns(uint256_tokenId);" `/ w: z! P$ D% L1 `
: D8 b/ }5 M, J3 {) J
    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
1 A+ h; G* o6 j0 `% E: I  J7 p8 {& U: @0 o
    }
' l; V  z" q5 o$ |, J: ^+ p4 k$ a# Q) I8 c6 Y7 _3 f1 ?1 }
    /*** ^! G% b2 Z- S. D! o

* ]* _; p% [! f, h2 ]* G( b/ @    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展
, r' m8 K4 U1 Q  l- f+ e8 D% \' U4 W
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
: }' K% ]: l: K3 ?7 T# b7 h4 I0 C& G2 H% T$ ~# \5 A
    */
3 L1 A2 N2 n8 U. T( ^6 [1 W& P6 K. ^* c" ~  j* \$ [
    contractERC721MetadataisERC721Basic{: A' `/ m' M: t6 o1 ^8 Z

/ H+ G; u( ~$ n    functionname()publicviewreturns(string_name);
6 y" F+ r* K% a+ V8 k. @& I+ M2 H
; p+ |0 ^6 z" C( X1 I, }    functionsymbol()publicviewreturns(string_symbol);( P9 M  F2 w0 d, {! o7 {! P
* i& D. }  r2 n, s- j
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
0 Z, b  ~. @$ J. A3 Y' o- z) _, y
! N) j! K; J( b/ P# V' b* Q    }: ~% M6 W  k2 H0 g. h) L; C) K+ {

: G0 j& _% C3 w% h    /**9 t7 T" S3 E- b+ ^4 s

, a& }8 ]1 S3 R    *@titleERC-721标准的基本接口,完整实现接口3 |& ]# i7 N7 h2 K( F5 D6 x# @

  V, E  A5 ?. s& h  {' E    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md" J( z6 k, S0 q6 D
4 e9 [! B; G8 _, C1 d9 Z9 e
    */
2 F+ g- U* t) d( N) A3 `
# I. m3 r# T* ]( }1 U& `7 D    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
0 R5 o+ h5 z- e' E1 {: O( J% J0 A+ S( e( b
    }2 D9 @# f  L9 }; H: }4 c( ]
- o2 A1 Y, L1 H+ Q' P" y7 h
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。5 ~! t. {# X1 F% d7 ~( B
1 o, z6 t0 W  ~. b
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:/ \2 O: G1 o. w% G8 r
9 Y/ g; A$ Q& _9 k8 z
    totalSupply返回代币总量
1 z, n8 A0 T) b; \- O9 Y- H0 }: V: J( I1 m) |
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId9 G/ s  Y: t* f8 r/ y

# k. Q7 V9 X3 H+ A    tokenByIndex通过索引值返回tokenId6 i' l0 z5 ~6 R! E. u& @

: W: Z7 R; j1 m/ e1 K+ N" j; n+ B    ERC721Metadata元数据扩展哦用来描述合约元信息
6 z" r" U3 y1 O5 P  l+ |3 D( F( y
    name返回合约名字1 _7 o3 K0 m- _3 R9 T1 I6 [

1 {4 I# x* x: u6 L- I2 a    symbol返回代币符号$ b3 n! [* O% H" `7 X8 j

7 _. o% v& Y# U$ M1 i* R    tokenURI返回_tokenId对应的资源URI$ |5 E% M5 Y) N: @4 k/ c' a1 L
& C: t" R7 m. i; x) ^0 z
    ERC721BasicToken5 W. V* b( c) N9 |* S+ O
6 X6 D3 l% B7 t( N) e6 j" {
    ERC721BasicToken
: p, ^. Q0 h$ P9 R2 a3 i0 b! M. P2 k& K  y  E% K8 u; K
    pragmasolidity^0.4.23;4 A! v1 K) T) N1 o# \5 E
. ^4 Q) ^, e: d4 n% F) ]( o$ ^
    import"./ERC721Basic.sol";0 N( F# E$ Z/ p/ J- G" r0 H

6 ~5 @, p4 r# \) h$ g% q    import"./ERC721Receiver.sol";% `% P& g7 ]2 I3 q* Y8 \# t

  v: A5 o2 s( ]9 d    import"../../math/SafeMath.sol";
: I( ]: S4 ?% n( E# v
5 l* `% `$ V2 o; E0 j9 `" f    import"../../AddressUtils.sol";" K% W* E* D4 x, s# V; a

% o: y# |; d; I8 s6 D5 {# d    /**( ~3 L: T% J2 ?3 e* e* W
. B4 W  K# b& T
    *@titleERC721标准基本实现
) ~2 a3 P4 [0 ?+ B% ?* o6 n+ H- x
+ u5 J- N( e3 p6 H4 S7 l) F8 U    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
$ O" a1 |" z/ h5 j3 s* X4 y& g
7 C) n5 i' O! D; p: o$ W( E; H    */' F4 m8 x# E' f
: a9 z( x9 Z# C3 S+ k
    contractERC721BasicTokenisERC721Basic{
. y1 E* e9 R: D5 X8 v
# Q4 B& u0 J3 V" a    usingSafeMathforuint256;% a6 Y0 a5 [. Y: `5 W$ W4 K/ @: k& Z
+ x5 a9 U8 m% v( u5 e$ g5 E
    usingAddressUtilsforaddress;
9 z1 C5 C  [: d
* D) O, Y+ J8 l0 z* O4 \    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
2 `5 ^& \7 N: h
0 P1 L2 p2 t8 g    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
0 h: b! y+ o( a5 k. P; h$ a% Z+ W3 c- l  X
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;7 D; b9 i- a* u+ q- e& Y

- l7 [2 j9 Y- b$ N2 d2 a    //tokenID到持有人owner的映射( v' s/ f3 F1 ~3 N
' l- K, P8 ^4 e, G/ j0 j0 l
    mapping(uint256=>address)internaltokenOwner;
. k% b& s" v. D+ z7 ~+ x$ d" S  W
) F8 i% L* ?# `+ z2 j( D  Q    //tokenID到授权地址address的映射
) D3 ?& `3 o2 e* ]" R" B' ]5 g* d4 {+ G9 E3 f/ R# z. }4 G( B
    mapping(uint256=>address)internaltokenApprovals;
3 R% _  T& s+ [: J& |2 y  K' N6 @; N6 v9 @; b
    //持有人到持有的token数量的映射
2 G" Y+ C4 r' w  Y1 c( S. }) N) u0 R
4 a- v5 B, Z2 L# ]    mapping(address=>uint256)internalownedTokensCount;. r/ {7 _- A2 Q7 q+ g1 u

( k9 m, B  t$ U2 z8 t    //持有人到操作人授权的映射6 d7 J& L( l" U6 O$ r/ k1 ?

( N) O- o; P4 b    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
+ u. ]* s6 V4 |/ Y+ Y% V* d7 r% t) n$ c
    /**
* W7 m! J: Z( J8 U! v$ D- b
  Z9 N) X) }, a: g% G# H: F6 w, y    *@dev确保msg.sender是tokenId的持有人5 y+ c( B! F) z7 u8 @
; j! @0 u. N& u8 w& Y
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
+ J1 U5 U% g+ i% B% ]" @& o' c) K& t+ w
    */
2 O1 Z4 o: G2 F) Z$ b" o" F
$ i  _+ H* t' @/ N7 S: v# H# {0 v( W    modifieronlyOwnerOf(uint256_tokenId){3 d4 Q' A* X' ~' K& |% ~8 q+ Z6 Y/ j" h
) v' L9 O9 O1 q5 \& U: v5 n9 {  u
    require(ownerOf(_tokenId)==msg.sender);
: E% V; a& ^* }  Y3 q! S: L
" e. h* B: {% e& J! a5 ]* N    _;% }" J) N' s  t3 W$ a* h$ H

9 L  f6 z' S! B0 l! [8 S; q! B$ ^/ E1 @3 k    }0 a# e5 j5 t7 F( I. r8 T( [6 F& j
0 S6 q  N" l- K
    /**# s1 B& i+ c5 T
, e' x6 y$ i3 |- t/ |
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
4 A2 y" u) C9 ^; O0 p, [0 K$ V2 s! W" F$ w9 r6 ^% q
    *@param_tokenIduint256IDofthetokentovalidate3 b# I" E4 T. i3 P: p+ ?

; ^, z# c& |/ L( w: Y( t2 K    */  G* u- b* z' u+ F( Y

1 Y8 b7 W/ {0 X$ a" M3 }3 q: S    modifiercanTransfer(uint256_tokenId){
3 q, f- j* {2 m- L  y6 i' k# C$ D. x. ]( o
    require(isApprovedOrOwner(msg.sender,_tokenId));
, Y) R, l6 a! G4 m1 f# _8 m
0 {( r: s* n9 q' q2 H5 C9 P( A    _;$ P& G" ~& l# \; @# Y; R
: x5 c0 X2 e! }3 M$ V
    }
' a$ h' H/ S6 s! S
/ ~* A1 d, \7 I  w& T    /**
  Y6 `& Y, ~4 R- N! q6 B3 v: t. K: |
1 }4 s8 W2 _, a0 G+ p% W    *@dev获取持有者的代币总数
0 g+ d8 {5 ^# i# D
7 _+ ~& F" t5 |    *@param_owneraddresstoquerythebalanceof
& d; L, g$ E1 r- j
* ~6 o6 M6 V1 l    *@returnuint256representingtheamountownedbythepassedaddress$ s7 F0 K8 U# i! p
. ~- `( A1 r5 d% S  j' L# l
    */' ?1 p! J& K; `% D1 q# E
8 V) I0 U$ r: }3 \5 W
    functionbalanceOf(address_owner)publicviewreturns(uint256){+ I  I% q1 o8 M  e& k+ E

% q* k. F& D( {' |% s3 j) t7 c  z    require(_owner!=address(0));
' }5 z6 P3 \' [+ z3 K! Y7 m5 i4 D. b" }/ S0 h
    returnownedTokensCount[_owner];0 H! }2 @3 |5 d5 J

) p4 ^7 s! L7 r' w    }/ K* O$ H! _: b
( f8 ^6 p2 t, w+ a1 {
    /*** M1 J3 ^$ K+ H/ q0 g2 i

7 D8 C: Q, t! }, C/ s    *@dev根据tokenID获取持有者
5 X- A1 [* S/ ]! S- ^
; A+ k+ A$ a  Q" ~    *@param_tokenIduint256IDofthetokentoquerytheownerof( j* k! G4 x5 N7 ]4 H
4 d8 v# {9 _$ C) Z3 }
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID4 O. ~, j3 E+ \4 y$ L0 }3 \5 J0 i% ]
$ K4 a2 G. d+ h& Q9 w
    */# W* k6 [5 C, z6 V, W  \* ]: u

- I  f; |/ @  z/ Z0 ]    functionownerOf(uint256_tokenId)publicviewreturns(address){; \* h- n+ l7 c7 d4 }1 n
5 K: w; k* m! C8 l3 c6 B8 ~
    addressowner=tokenOwner[_tokenId];( k: c) [6 a6 ^0 r/ V% @
, [" ?% v5 a# `& [
    require(owner!=address(0));
1 |- n' ~: I# Y7 N* Q
9 R( o' a% c, u    returnowner;& i1 Y) q5 f9 I$ G' C( e2 k
$ Y1 V. I- t" z, @" c
    }7 S& A' h- B/ f5 e

; I$ w  v  y6 B. D    /**
& c& S9 y" w5 s" s1 z; o% h2 Y) o, A# G4 ]3 D* y
    *@dev指定的token是否存在+ |) }! D: w% h, _

: B* A% f7 g0 _    *@param_tokenIduint256IDofthetokentoquerytheexistenceof% l+ L  l* k5 B" f* a) Y' ^
5 R( U7 s$ \3 p5 ?4 N
    *@returnwhetherthetokenexists
9 g4 J( j  q  l1 X
8 P- {. k4 b5 s2 z    */, o  q5 i3 p% ^  z. C
* V( v# D5 T3 V" a8 U9 W
    functionexists(uint256_tokenId)publicviewreturns(bool){# N# E+ j# T0 q# k

1 h) Q" Y: Y$ u    addressowner=tokenOwner[_tokenId];0 }9 A7 `* q7 R, t
" h7 t+ @6 d3 X' b4 ^
    returnowner!=address(0);. A9 x4 _' P) _0 v
! V% `" V6 ?& Z9 u& [, J5 M0 D
    }
% k& p  I. {2 A3 V5 v- H
: ~' B- ^% D( s! l+ K& @    /**! [" G7 c6 d- L2 \$ {* s' q8 g# K

$ V9 W: \  w0 T9 m4 d$ G. ^' [    *@dev批准另一个人address来交易指定的代币$ J: h  I' C$ O+ ?  w* t' R' O

; p: w0 R/ ?6 x( F1 X& o4 r9 J    *@dev0address表示没有授权的地址5 ?$ j- }+ w. F5 ?5 Z0 V

/ f) I, K- b8 p& [    *@dev给定的时间内,一个token只能有一个批准的地址) D' T" q7 y( D3 f! m2 Z7 L* }2 C

; U: s! M* a) a- m2 t  P8 @7 y# C/ @    *@dev只有token的持有者或者授权的操作人才可以调用
! A- g4 ^9 y8 f( t4 m) {6 F5 z6 u' g  Q
    *@param_toaddresstobeapprovedforthegiventokenID
6 f2 v6 t$ i0 m- O* J5 d7 c  R
/ `6 y, e1 U+ L    *@param_tokenIduint256IDofthetokentobeapproved
5 r; Z2 K/ N# ^- Z% r( q4 M: J, G6 S* J; Z0 @
    */
/ D# i3 l7 L& L6 y7 }7 y) T
! Z" q: s+ ^; w    functionapprove(address_to,uint256_tokenId)public{3 o  x/ r% y, H
8 g. p5 p# q, L* r- L6 Y- o
    addressowner=ownerOf(_tokenId);
6 J( W7 t4 O8 s" M1 x8 r1 c7 R9 q# ^
    require(_to!=owner);: m0 I2 o( y, d
- a9 H. T1 z" U. m
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
! t! p) c) g, f6 D# t4 T1 Q
# w9 g9 U, K$ _$ G& w+ q% G* g- h    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
( x- W$ @. v5 f
( q3 I# G4 p- @" W/ k3 v3 M    tokenApprovals[_tokenId]=_to;
2 B- g6 |7 ]/ n( b1 o; H# z2 Q6 R! _! ]7 |' _
    emitApproval(owner,_to,_tokenId);
7 N& y* l0 t! @' M) g9 T0 ^( I, B
% i9 `& U1 U/ h' U( X    }+ ~5 x; ~! j5 X9 b% h- u2 Z
3 H+ L# M0 h! {# X& N2 O+ k
    }
2 X9 O. F) D0 o; |; }5 E, K* K5 N. F
    /**
0 V" ?* j' b$ I; l" ^8 _) u$ |( r; `6 G' ]/ r, n- L/ e; p
    *@dev获取token被授权的地址,如果没有设置地址则为0" g" D( l- O! d; X: z; w4 {1 l$ _! X
$ U; F- {  ~# b& O0 B7 e% P/ [
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
7 c' b; M0 M+ u' X/ D7 a
9 a6 _& D# }* ~' ~* r    *@returnaddresscurrentlyapprovedforthegiventokenID; ]4 J5 |" D9 E( x

( L5 E7 F9 G. P4 {& I    */* |) s' G" y$ h  x9 B: [
: b1 ~: d: N: s4 J( V+ Q
    functiongetApproved(uint256_tokenId)publicviewreturns(address){
8 u  e1 Q, D2 C. {+ W% ^+ M2 X, ~6 g" @( `" I
    returntokenApprovals[_tokenId];
+ t/ X( V0 D2 @: J+ ?
% T* h2 O+ _. c1 Q2 V6 h9 s  Y7 f    }# M& ]" z$ T; Z# M- p. }! e

) B6 b8 B6 E% ^$ P/ k" O. e    /**
0 |2 w( o, p5 n! D' s* _  C% `. [' d7 F! b
    *@dev设置或者取消对操作人的授权
5 T& S, f% S9 ^: C. a% |5 \& x6 o, P5 Y) ^* C
    *@dev一个操作人可以代表他们转让发送者的所有token
% ]  i( P1 ~  O: p& K
  l( U: p& H9 b: p3 O) g) F# k    *@param_tooperatoraddresstosettheapproval
7 r" y  G5 W* v9 j  ?$ B2 z7 I- T  g# C; }( n- s
    *@param_approvedrepresentingthestatusoftheapprovaltobeset9 T- z5 @0 V: G# V* f
) P  t  L) J5 a" n5 T6 v1 }4 }
    */
! _& O8 w3 N* d# D% W  I
/ }, x3 e6 `! |: Q4 h    functionsetApprovalForAll(address_to,bool_approved)public{
7 K4 B7 \/ o' u/ Z  H, z. C7 w& E% {0 d+ |: A$ U" c6 Y4 c
    require(_to!=msg.sender);1 ?7 N: U/ z$ K. N; ?0 q" n! _9 u

0 m+ x! r- o, t) R% r    operatorApprovals[msg.sender][_to]=_approved;; q+ d, Q# M& G: [, g. l: x

, Q; F& b4 S, L$ J) D    emitApprovalForAll(msg.sender,_to,_approved);+ O" g; B) _$ G+ f7 [

: }$ X" l7 ?2 X( [7 P    }
# ?) j' k- O  G* |& b; e5 j' c5 D' s) D  r' Z7 V
    /**
5 @0 d5 A- q+ {8 G# g+ [/ c2 g, J  m% ]/ B) h# @) G1 e
    *@dev查询是否操作人被指定的持有者授权7 A1 t- B) Z; X0 W0 _; y- f( z/ n" O2 [
# L. f- z6 b7 Y: o: e
    *@param_owner要查询的授权人地址
  e( P" }0 f% U- x% n
1 @+ Z  \) U8 P( R/ r( r    *@param_operator要查询的授权操作人地址
' N! U  O/ h7 J
6 x3 k4 `2 U3 h4 B9 Y    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
2 g" ]4 Y+ U7 y: f( H
+ H! U6 Z+ |' z* }3 P    */
& g9 n+ }; g" X; \7 o. I# @5 z7 n6 ]3 W* `& T6 [
    functionisApprovedForAll(7 x+ ]& l! H9 k" u* Z
" k" F0 N# g* u3 z& q3 h
    address_owner,
. u, v) J/ e3 e6 N# o
+ |# C9 f7 R) k5 |, ~    address_operator
5 D+ ^9 ^4 W/ ^$ T9 [( D2 h3 j' p/ R: ~2 o
    )% J# n# ?/ {- K$ u2 W. K

( j$ f! I6 g& s; d5 _$ R- J% E+ @8 w    public; ]7 \/ M9 R; p5 ?

% A) t/ C! c* v    view
$ {! _* i9 T9 j# Q' N1 t$ U1 e0 R- r; |2 q9 P* E; K9 U
    returns(bool)
3 ?2 ~- v" q: q1 L/ G+ i# c' l2 d* f" p  \  e- e
    {9 E. b* J; J5 V& p; e  T) D1 w
: A& A' U% [  H6 E: Y2 V
    returnoperatorApprovals[_owner][_operator];8 @/ G" z. A/ O' _' b5 I

( s4 O3 G$ ?/ A9 B    }
6 a7 ?$ V8 o1 l9 J6 i$ e0 K, U* E  y) v9 B2 o# ?$ F
    /**" @4 K2 E" b( Y
& P3 ^8 D$ l# \  C/ y/ O
    *@dev将指定的token所有权转移给另外一个地址
! I8 a$ c" B0 O5 Y- h& \/ S
) @: Q: b8 w6 B# `    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
5 K$ w; ^% P+ Z' p5 P
; v0 i+ |. {; R    *@dev要求msg.sender必须为所有者,已授权或者操作人
, |, N4 d& }5 S1 O% I) J
) A% c( T& D. S& N9 _6 ?    *@param_fromcurrentownerofthetoken5 w3 U7 C7 u1 n; |

: w$ W& k, X) z1 P# D) q/ V4 J1 C    *@param_toaddresstoreceivetheownershipofthegiventokenID
. _2 b2 h8 n# n8 F/ l
3 T& a4 \& x) \) O) v+ l( z    *@param_tokenIduint256IDofthetokentobetransferred
% y5 P) b4 J* `, a/ l# h& H
) U- s9 q. \8 X' a# o, ~+ a% e    */) H, v: A# F, d" |; W+ b
. H& O8 p+ i0 K
    functiontransferFrom(
, O/ q: p+ r' `- i* }) I- W( e; U
2 _# W0 M8 O4 P$ q    address_from,
% H. j  ^5 K; S' y# f: O* p5 ]4 f: @
    address_to,
; f  S% Q0 d( W% g- a* @8 @- A  f% j% p2 t' H
    uint256_tokenId
, R& j; M. N/ F, A; U: O6 Q/ m
$ ^1 i% Z6 T- U$ I5 D# B! y# r    )& L7 s9 G7 J* r# u
$ k/ p- }3 _) A
    public% l6 ]0 |; A: M8 x% ^# a) L/ k
  P: ?# c1 q* x+ y7 ?6 k
    canTransfer(_tokenId)2 w. a% L% r/ K5 ]! |/ Z! o# E5 a
7 C& p3 \: L& _: u0 }* Z7 ?* X* \
    {
# [- x/ `8 W/ S% }3 r" j' ]3 v' f' _
    require(_from!=address(0));# p- i9 G- i, e: ]; s

; d- W4 }, f" y1 b: n    require(_to!=address(0));( S$ c! m. g+ G5 Q

. ~3 J/ q& [2 W! Q. a, m. P, X    clearApproval(_from,_tokenId);3 P: J8 v7 N# @2 g3 G

6 F& B9 y* C; r    removeTokenFrom(_from,_tokenId);* D( b  C4 X7 _  U% ], g0 w. B7 A
- m' r* ]# U0 r/ W9 \4 @& k
    addTokenTo(_to,_tokenId);/ M0 i  }1 @3 d
2 V5 @- d0 J2 d( m$ u5 j
    emitTransfer(_from,_to,_tokenId);
, M6 l  Q' H, m4 n4 ^3 l
$ p1 M# O" x  U: b2 J1 G, i% r    }) T5 [) @- N( |  u2 ?/ B

8 ~6 b: n  L" I  Y1 h9 j6 P. `    /**. e) K, H# h) x" D9 X# M2 ?' q
& a( I- o7 C# s# O( I; l
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
0 g: u3 z' X2 r$ W, V/ h1 l* E% G! F: r. K# J9 {
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
& ~% u" F$ y* n$ n/ F6 Z
) Q$ E+ X/ |. V( x1 P. A    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
: [- _; [0 h6 U: ?0 b! ?) j
1 s5 Q" F; e! h7 R9 m    *@dev要求msg.sender必须为所有者,已授权或者操作人) ^$ Z* m. H+ P
- k: k2 l" z& M: N' ^
    *@param_fromcurrentownerofthetoken
8 ?% D  b3 w9 U+ T' ~3 C+ ^+ l- S5 z; q
2 ~. u1 K! {2 t3 k- n    *@param_toaddresstoreceivetheownershipofthegiventokenID
0 b! G5 O/ d6 t
5 n4 F# {# O( h# u, Y" D    *@param_tokenIduint256IDofthetokentobetransferred4 S3 y1 T" j/ F& O$ J8 A) Z- U

5 n* X: @3 r/ ^6 A7 h2 c    */
, `+ I8 D3 L6 _* m  ^
: b% _. E, S& l. U6 {    functionsafeTransferFrom(
/ \! T# k4 L# u' }, w
* o, W$ L) F' t" j! |( N4 `    address_from,5 j& ^( L0 H7 A# \
. n: T  C% Q, u) b. l5 h0 Y& y. ]7 z
    address_to,. ~' M4 i+ h: p5 }
3 y0 T; K* Q9 J6 r) s' _9 X
    uint256_tokenId
# V7 ?2 h: Q& W; J1 [* b3 y8 u4 I: H1 K: K# q# p  @
    )
# b' ~4 H: L8 P$ o4 V' E- Y' ]& L5 j$ d1 n. g
    public$ D! m$ I9 P9 y
6 u0 C; @& v; F
    canTransfer(_tokenId)
/ H: W, x6 G+ ~3 ~. f) X
$ l  _4 \$ U8 u& [" B6 `    {
) E! A$ @6 @9 f+ Q( n5 g* A0 g
; d& c+ c6 l, P4 G1 [9 V; N6 z    safeTransferFrom(_from,_to,_tokenId,"");
+ ?; _+ J6 z5 D" C# {3 Z! A4 e" M
5 Y( b/ j' b) W; Z- w    }" e/ Q5 Y$ ?3 m$ B& H/ N" f+ o* C+ V

4 N0 ]# F$ [6 r2 _4 U0 K& _& K    /**- C/ r7 A, b  o: t% P) }

0 P  C) O' G  Z. f; E! R    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
3 W: s/ _  G( U  L  w4 k
% G, m1 g, }- i    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值1 k  m1 {4 f! r$ U
+ l' _' a( ^0 I' H
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原4 G4 ]6 b9 o# O! j4 p
" U$ V6 O4 k- K
    *@dev要求msg.sender必须为所有者,已授权或者操作人
6 {1 o* @: B. g) J
2 T! y9 S: h2 v( M3 h% i    *@param_fromcurrentownerofthetoken6 y: B8 Z5 E! U1 I( H5 X$ Z1 I
6 z& _0 G* I" ?
    *@param_toaddresstoreceivetheownershipofthegiventokenID/ y; i$ o$ y) ^% p6 Q

3 a2 p, ?* E, ?! @    *@param_tokenIduint256IDofthetokentobetransferred6 o! v( C: t$ `7 R+ J2 E! u2 R
# a% I6 i# j& W2 G# @
    *@param_databytesdatatosendalongwithasafetransfercheck
2 }/ x' B, ^* W3 V8 X1 ]: O! D, n$ Q* n) f$ `* p# F
    */! F/ f$ k; `; C/ K1 H7 q
) K4 ^: Y) t1 f. G
    functionsafeTransferFrom(( C. w; J: o9 w( w& A
( P$ s0 ?4 g  n% Q8 Y; `: b
    address_from,1 D" m+ Z5 K2 y1 Q5 u

4 z* [8 |4 I* t: Z6 E; k* N9 g9 G+ G    address_to,# Z4 ?! `, s! O  T& P
7 s: A, |% N) D: c
    uint256_tokenId,& W% Z8 p# f" E
: b& \( v7 _6 \$ B1 X
    bytes_data
( N& N: i2 h, O1 T6 G$ e& C. K2 A+ D* Q0 x# y
    )
+ R2 j" N+ g7 m6 j% g+ v
- {* t3 C1 P; D* j- S5 A: B9 v    public! _0 @, C% |8 ^, M* B  A
, E7 T4 r$ l3 a  L- n$ ^
    canTransfer(_tokenId); W" H! K( a7 t( w
9 J; q, r3 E/ m9 \) Q! ?
    {4 s' V- B+ [* W7 n

$ t) G8 A2 f" a( H9 `9 Q    transferFrom(_from,_to,_tokenId);
( u9 `3 l& ~) S9 X* [' A7 }' ]( a% a) F- x  l
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
+ f% A8 }9 v: ]4 H* \/ O6 r3 U9 \6 y/ e( i" W* k
    }/ }+ b$ x; i- n* ^5 H

: S  L3 p( v% n6 a% \    /**
  h8 T& W- H2 A. i) ~6 L" u# S# h1 }$ Y8 n/ r* O; v5 N9 D
    *@dev返回给定的spender是否可以交易一个给定的token
- M0 G4 r8 p8 B1 j3 a7 Z( G7 g, I; J& a! O6 e' h* r' u
    *@param_spenderaddressofthespendertoquery$ Q$ @8 O- ~0 h/ Y
# r1 Z5 [) K* _. l
    *@param_tokenIduint256IDofthetokentobetransferred8 G3 H9 _! L2 U; D7 e% m/ l
& @" L7 j' h' I; @. |
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID," }, [9 }8 x" c
9 [. b- k4 A6 t1 K. w6 L
    *isanoperatoroftheowner,oristheownerofthetoken
4 |( Y6 }- K; Q9 z) p  u
. l% r; b/ ~% Y( G. j- \/ I    */
$ A! X4 d! f  |4 s& U7 m4 V1 r
/ b7 d( E: r# y6 C( a- J4 R    functionisApprovedOrOwner(
, G3 E# |  R! I
4 P' x7 @6 V+ F8 V  e, ~9 w* y    address_spender,' E8 J% S5 i; l9 E+ z2 l! j4 k) G+ N

$ J. Y: g( t3 s0 v- g' F: m+ I: z    uint256_tokenId
/ i( _9 M9 K6 S4 A7 g& R% d# O' T/ c4 b5 f; w- r  W
    )% T" A; f: x7 Q

, k# `8 s/ h% g7 c    internal8 C, Q! z/ [# Y: M
# w+ T, ^+ Z  j& X0 @8 |
    view# o: p2 r/ J9 d, C
1 ^" ~9 Z0 }( Q3 }5 `- T
    returns(bool)# s5 r6 v3 y$ f
8 ^3 L3 e, o, f- ^
    {
6 \5 P4 _( K+ [6 q3 e1 j; G! X8 ^: ~* \! D3 o) E1 ?
    addressowner=ownerOf(_tokenId);
5 a8 |; L! I" l0 T2 z6 ~
7 |1 H2 ?6 T) N* F  h- ?; |# o    return(
! C$ V/ o  w. C
+ `$ k1 |: ?0 T    _spender==owner||$ L5 m# z  V6 e. t0 k. Z5 q# E

) |- i+ b" L6 ]! |& U6 w# R    getApproved(_tokenId)==_spender||( v5 F- Z2 M# S5 A: p

+ h+ c" u( b/ D0 R; c. O+ Z' P7 s    isApprovedForAll(owner,_spender)5 ~: i8 z1 b9 ~& R: H

+ R0 O1 V3 e: h% ^    );' [! m3 S- n7 z2 Y3 }

2 `" N8 |8 `% ?, y& e    }) k* K; c. l  H9 S9 ^
( ^% V9 v) l6 r0 G2 v
    /**
: `8 I0 y  d; `* a& J7 v# K# i2 D% y* N# N' y* d- Q2 E% g' D
    *@dev增发一个新token的内部方法
2 h4 b4 ^' V+ ~3 {
9 t. F3 {! M7 w5 }) g3 T7 x: r    *@dev如果增发的token已经存在则撤销
6 j4 q, x$ n  o* m6 K( d- Y% K! o$ }; ~" G( u) P# H
    *@param_toTheaddressthatwillownthemintedtoken
$ Z5 _. S; f3 ^  M; H1 F$ C/ P
. u1 _0 L/ J4 u' E) z    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender  Y/ ^0 V* }; s6 I9 H
- z+ M! ~& n8 w1 u* l9 m
    */; _/ a8 g5 h$ a2 ]7 c! H
/ Z6 {, y( b4 b/ `( w8 c
    function_mint(address_to,uint256_tokenId)internal{% j& J- K8 b2 ~; n" b
% x" ?2 [# K) {  C. J  U
    require(_to!=address(0));$ A, O# B) c9 p" ^/ G* H+ ]: S) b

: L; @' c  N* L! t( [- c    addTokenTo(_to,_tokenId);7 x/ E, N$ R- S2 K- F6 D
, s7 B8 l; \  C* H" \
    emitTransfer(address(0),_to,_tokenId);
! m3 @  l) [0 d6 \$ Q, \
* [1 G- J/ G. n( t& o    }
: S9 G9 R/ _/ Q+ X/ X* h$ z" P/ i: O* K; _9 |% U+ }
    /**
8 P, F$ g4 \, \# z0 X0 J9 p2 v* C1 g% t( }: _8 c3 l$ N
    *@dev销毁一个token的内部方法' m- s8 f' [; a

- `: m- |8 F. b# v; J$ Z9 O" O    *@dev如果token不存在则撤销. U0 g) [! g, \  ~2 P

$ ^/ P) c2 D. c5 J$ _    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
' ~5 @' a- U( w
( @! f5 @) l7 ^; H% O( R    */3 A4 f/ n6 E* @4 a; v: _
" Z  k/ f  ]6 X7 ]
    function_burn(address_owner,uint256_tokenId)internal{# {! g5 Y6 i9 R3 w8 P. D2 @! R
2 O0 l5 ]* q7 F! Z. \( H
    clearApproval(_owner,_tokenId);4 r) K: ^6 S2 j5 ~2 t6 v" m0 A& O
+ I" q  r8 s* s, ?
    removeTokenFrom(_owner,_tokenId);9 w4 v* ^" I9 a5 h+ q+ D

  u& e& u$ P0 H5 ?! u$ u# |    emitTransfer(_owner,address(0),_tokenId);
4 T* K# Z+ a4 ~& j
8 r' ~8 e  M2 @3 K; c5 p8 d. x    }
% W  c  i2 @$ A/ ~6 M1 e8 M/ J
0 E* Y! f' N' @1 G& q: Z    /**. O1 c$ R4 p8 h0 C6 j( Y% b% T

+ v! ], z& [" q4 V; n2 f7 H: s- M    *@dev清除当前的给定token的授权,内部方法+ A( ~" T% e& W$ c; l1 ?

1 @3 I4 |# r9 W8 O    *@dev如果给定地址不是token的持有者则撤销
, s; ^# @& y2 t- O
' M- f2 T2 G$ _9 T) M% t+ j! t    *@param_ownerownerofthetoken3 I. T5 P3 @2 [& s6 o4 B
# B" X: J# i+ S$ N, @$ j3 I* }
    *@param_tokenIduint256IDofthetokentobetransferred
% ], c* ?+ v9 G+ G. f& T) r
4 u% q/ A. m& _    */
1 B8 K: Q/ l. Z+ H: R/ u- j* }% m1 a  R2 q- U* \' U$ s
    functionclearApproval(address_owner,uint256_tokenId)internal{
4 R- `4 z+ R; m; q# i$ Z7 N  T5 E6 U" @4 {
    require(ownerOf(_tokenId)==_owner);- ?5 g( b8 b+ F

4 m4 i4 ~; d5 b1 p# q7 f    if(tokenApprovals[_tokenId]!=address(0)){  k3 A6 {0 F4 ], N% K8 Q

& _" E1 G4 E6 r' T; X    tokenApprovals[_tokenId]=address(0);3 k2 W+ z" |9 n' m

1 z% A* M- x0 ^9 s) {    emitApproval(_owner,address(0),_tokenId);( c" l& w: X. Z, P$ U
+ J2 G' U! F6 i+ p6 |! O
    }
2 @. X* Y' {  {  e* R9 @7 d; E
: u" F1 t1 B" W    }
2 I% d3 t- W) t% x  h6 a9 x2 n
# D! o. y8 c3 |4 [    /**
; Q; H. E! D- K7 r& G/ }/ s! p: B
9 \! \* Z5 K3 @1 i    *@dev内部方法,将给定的token添加到给定地址列表中
$ Q3 v" ]7 G9 H7 U% L* E4 u# D2 @; u. |8 n$ K- J+ g
    *@param_toaddress指定token的新所有者- v* S& U, T, W3 i& g" u" M

, I4 |! T- P+ ]4 {4 N; T    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress, ^) y8 i, y# T# H! `# j! F3 A
' T% ?  P8 _) b7 ~
    */9 h1 V, s/ c4 T, ?" K: e& G

* w! Y( D$ Z. L( w) ?, D" Q  X    functionaddTokenTo(address_to,uint256_tokenId)internal{  T$ q. _, O- w' [
9 T( Q3 N& M( }
    require(tokenOwner[_tokenId]==address(0));
- B0 a" }) {- @* h  \0 T2 w5 t4 U# H; }1 w% b
    tokenOwner[_tokenId]=_to;* A7 K5 ~- T# P; ]4 n# }
, x2 J+ B/ S8 y5 X- H
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
! g. c8 b( C5 h" r  R! k+ X/ Z# x. X5 b) z2 m
    }6 _3 m8 g3 w$ X
' d. L4 A( x$ g  h8 z
    /**
2 l" @& T4 F% y7 A0 A& E
( r+ ^* K, K9 @: m  X    *@dev内部方法,将给定的token从地址列表中移除
( G) K7 Z# n9 W* t% Y9 T; Q8 j5 u! a
    *@param_fromaddress给定token的之前持有中地址! r2 A. ?2 _; \+ [) O& N

# W9 ^7 H' N4 o! A- `2 H5 i    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
+ ^, o( Y+ }+ ~' w$ \" K9 y
2 a- l9 w: n. j7 [    */
4 j, y7 p+ P6 b$ R8 t' @8 C( _) ?! V: h
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{
. e% R2 G2 O- x. ?6 ?1 k
" ], c4 e& p6 ]# `# z    require(ownerOf(_tokenId)==_from);
* M* K& p9 P. j5 D! ]: ^4 |
  q! J4 ?0 r1 t    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
7 W, D  L) @# z" h6 [' i2 u/ _& m1 S
    tokenOwner[_tokenId]=address(0);4 s. j" j0 l/ s6 g. G
; Z5 y6 {3 m7 F- E6 y- f
    }
( P, F0 _0 \$ d% H
( b/ u- O  s/ x4 ?& x9 K# S5 l% T    /**
7 @7 Z5 G) c& P$ O, ^- f5 `
" V: |/ l" I$ r9 S7 W0 q    *@dev内部函数,调用目标地址上的`onERC721Received`( r6 D$ E1 q  G7 [  ?, }, H5 F6 m
; |: r7 s( z3 b3 K; i4 L
    *@dev如果目标地址不是合同则不执行调用1 [* C( Z0 a* ]5 N1 K" ~

6 j+ ]$ ~6 U+ d    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
; N7 D: v0 V" Y$ V  X  i4 _% w! F% T+ V  y* z6 f. @
    *@param_totargetaddressthatwillreceivethetokens
+ D3 G/ L$ o3 \5 w8 f. j, x3 i0 k0 ?6 f8 u
    *@param_tokenIduint256IDofthetokentobetransferred
4 m2 L5 W# K" ]& L
2 i6 |# v( e% i$ I  z5 @, {    *@param_databytesoptionaldatatosendalongwiththecall
) E6 _* o+ G4 g  t5 y$ Q3 ~8 ]& M9 o' P3 c, h
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
9 X( N. V2 u% Y7 X4 x( |
, {( e2 b% {& O, e    */
  J) {* e& \5 U! z* k: r" L+ `# i2 v1 n! E" W
    functioncheckAndCallSafeTransfer(
2 ^9 `! m% ^# G1 C) [& J
" N9 Z6 d3 G! ^* ]7 ~    address_from,; R* y# i# O, K# `5 d; h
9 v5 D, s* _& d# C3 x; M* J
    address_to," H  N% I5 a. w) Y
4 Y. u$ p/ I4 m; F% j
    uint256_tokenId," P/ `3 U1 R  Q7 K) G* @% P0 e+ n
, y* `5 t' a: S( w; }( L2 x* a
    bytes_data, g2 N8 n( V. R# r. w2 n

, d: s: G* V# n4 w7 G8 a3 l    )
! ~2 Z: S" N. O6 i- H- T- F  S+ k. N6 X
    internal
( d* t; j2 U; f! h8 h9 S  G
; r5 v" n/ \8 v3 {" K$ k# I4 a    returns(bool)2 r! l" ]2 R% g+ M. _% u7 h6 Z
- P9 F0 ?0 h) Z7 o( f
    {7 `3 V; n3 Q  g5 u. `
: L+ ?* Y# a- i2 r( z- r, Q
    if(!_to.isContract()){
% J2 {5 E- G3 `: P/ @# h- P" {& ~) Y: P2 O
    returntrue;' W8 U1 Z; ]5 o  F* r, c
; I/ x4 K3 P- S/ h
    }
, Q8 }. |) T5 g7 p- D( B- E
" {. c" i6 @  d; d$ ~# P* R4 ~    bytes4retval=ERC721Receiver(_to).onERC721Received(& {& Z/ J& d% J- l. L

! y: X" x5 ], |" \9 ^    _from,_tokenId,_data);
/ v3 j9 r7 j7 d( E9 q# n6 O: r- t  j/ d
    return(retval==ERC721_RECEIVED);1 e8 x' ^* k0 T/ q
) S; @: g$ g( h. O% S+ o7 N; j
    }
, D1 P+ E3 @0 _& G9 c+ U1 i' w4 x/ ]
+ W3 {; W& O: s0 t6 F: y    }
8 B- {7 K; b* R8 M) I+ V0 X. G! T& k3 C3 {/ w4 d6 k+ e
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。  [! }  s0 S7 p1 `: m

+ A( T6 ?- G# H4 y- j8 U# `! h    ERC721Token.sol
0 f* J! r  b! f- A/ D( Q* B0 c( t9 D% |" N
    pragmasolidity^0.4.23;
. Q8 J* N0 E$ {9 y! i
/ u* o2 ?2 W% r1 _    import"./ERC721.sol";
5 Y' L+ r6 E- V5 T2 o! [7 s
- r) v. s5 C% Z" n6 L) ~. h    import"./ERC721BasicToken.sol";: q. Y; L( X( B4 R' t0 ]! A, v
+ A9 u  F8 c% n7 i" ~% ?, f
    /**% U5 N+ A( F! h. `& ^8 x, ~

+ I9 a0 l4 e; b6 k/ z1 H7 d    *@title完整ERC721Token5 z/ \1 U! P% \
0 o  k7 B0 v* M# Y: m
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
# y) Z  w" R5 i) H3 Z, @2 C: q7 K7 }$ \
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
2 c% {1 a7 K# n6 e0 H! ^. a7 W) e5 l9 @2 M8 l8 G
    */# Z" u& v; p* _8 f+ E" C
" v( h; J/ m$ A. [6 S* y' F
    contractERC721TokenisERC721,ERC721BasicToken{
" \% h- j- d% R$ U& q6 w! c- W( m1 B, u, u
    //代币名称
8 U1 C8 b0 ]  M1 B5 L9 q" V2 K$ {/ _8 e, z( g
    stringinternalname_;
% ~6 s# }0 o6 O/ L( D" l: k! a7 {, \- R( ?: u
    //代币符号% C4 x. F9 o4 z) k

8 M1 N: r% n  E    stringinternalsymbol_;
! v- o& l/ y6 m) A" Y. a3 S
) x: b  _1 U) s5 D7 v# s6 h    //所有者到所有者拥有的代币列表的映射0 w/ |5 G' x' ^6 T' p% |6 G
2 Z2 ^; {0 U/ ^4 M% S; U
    mapping(address=>uint256[])internalownedTokens;! Z* @; g/ \8 E" @

* A) E$ `, t; Q6 A9 y" [1 C* I    //所有者代币列表中代币ID到索引的映射. i' j6 Z% b2 A8 a) M- D

/ r: g9 N0 A5 ^4 B' k0 M    mapping(uint256=>uint256)internalownedTokensIndex;" Z$ r. `3 j/ d+ t  H% e% v9 u

! ]: c& J% ^6 k: S" Y4 G% P    //保存所有代币ID的数组,用于枚举
) K! \; H1 `) i4 Y
) i/ n1 u9 r# U    uint256[]internalallTokens;3 p7 \& @% D: ?
0 |2 ?; u# d! H) N8 K  k6 v8 \/ L2 m' ~3 _
    //allTokens数组中代币ID到索引的映射
2 v6 r/ I2 j. T) l& j# n: E% e8 Y2 r0 f8 V7 ]- {& ?0 {0 ]# u% ^( `
    mapping(uint256=>uint256)internalallTokensIndex;" i! X' P: {: h( N9 T( i

$ O2 o$ m8 @  B! @& w5 M    //可选的代币资源URIs映射3 N: |8 ?/ t+ R- \# L* Z9 {2 F

, C6 w5 U- e; k$ p; Y    mapping(uint256=>string)internaltokenURIs;6 U! T: c' X( z, p* m
6 M3 K! g8 I1 K+ x+ o) z
    /**
# {9 l% H' L. P. J) G0 l9 D! D  X5 P' j% e5 A+ L: r
    *@devConstructorfunction+ P8 p* o' m% t1 @$ m0 x

: \7 V, a$ n9 l    */
3 b; `5 M& g2 A. s9 c( R, S! Q* A  b7 W- ^$ q2 y6 S- M3 c, V
    constructor(string_name,string_symbol)public{. [* D3 p7 m+ C0 v' V0 t4 q4 u
2 b2 s5 q; ]; `& K5 p/ q& |
    name_=_name;+ Z5 H( a; _0 F' i
* H2 h7 `" e' H- c3 P! q; p
    symbol_=_symbol;( t; ?' A+ `( j- u1 P! q
. ~+ p6 c7 @; @$ q1 C' K1 ?4 _
    }
3 W5 h: R9 C2 d% N* x/ N! h+ r5 d
- t4 \7 e  X, M! w$ W    /**
2 ~, p6 y1 i% H( {2 ?! F6 y* L& P
6 m, w; ^7 g: j( N6 c1 e5 b& `    *@dev获取代币名称* B  p! T6 H$ j* {3 f
$ K( q8 o* C9 h: S8 _6 N  A
    *@returnstringrepresentingthetokenname. q# r% H' S: f, n  b! ^0 D; b

8 M( A8 x" _/ U- Q# O. h    */+ Y6 X- f6 p# s8 A$ h. C6 F- Z

* D6 I8 h! V0 X" V/ l    functionname()publicviewreturns(string){% M! {4 R8 S( [$ k( p. D
& u. W, R- f- V- ]# t" P7 u
    returnname_;
' R6 Y/ |# g$ H7 n
4 ?' B! V+ `+ R7 }/ l    }( E! i# ~; B/ P7 I

9 V  h/ T1 O* J& G9 r& D' e    /**6 t8 q9 o; I; u; f! I
# y; w" W2 r& S
    *@dev获取代币符号
6 N: h' m6 y0 Y1 ?: Q1 E& }6 @# X( ?
    *@returnstringrepresentingthetokensymbol
: G  x1 P" A: E4 K0 G6 V" m. X5 a4 V  T
    */
+ b6 `* L! V1 M2 v7 M2 }+ p+ @3 p" A' D1 @* w
    functionsymbol()publicviewreturns(string){
6 y( N- P. ?( Q4 K5 e9 o$ u5 h/ r/ v' g. Q7 n; b0 t7 _1 s3 Y
    returnsymbol_;# J  @$ z$ N+ B* N  U

" h! H$ f* J, }4 j" E    }0 v+ ~( I7 j8 u# c: r+ x! E; a0 B

' c! }1 J$ j+ S4 z    /**
. t8 O) c  v3 Q' \: g) I$ i) i; x8 j. y. I7 }' h' s8 p
    *@dev根据_tokenId返回对应的资源URI& m& m. {/ z/ s" y0 Q
. H! @6 E1 g8 d  u* V# o
    *@dev如果token不存在异常返回空字符串5 _& O# D1 {, ^4 O
3 g  V8 e% E- l; y/ q5 E
    *@param_tokenIduint256IDofthetokentoquery$ u& v: u* o% T0 w9 r* R

3 o/ ~! a  J* X/ d& K/ W    */  b- Z8 c" H" `9 O( {
% g! _5 z4 b  y, r
    functiontokenURI(uint256_tokenId)publicviewreturns(string){
5 |. G( ?' z& k: L' g% [$ v! ^" d5 M4 O! I4 J, P
    require(exists(_tokenId));; K$ h2 S: \& y* L" N1 [

8 b! Z) v9 {( ~, _/ @' M" g    returntokenURIs[_tokenId];
% }2 j6 V1 ~6 s  ]6 y7 L3 t! i% e, x1 d: o6 N
    }
9 N9 A% A" i" Q. @$ L- T
( ?; ?/ g8 X/ h7 ^# V    /**. [' Z$ C- O$ Q, e9 q
( Z7 B; `" o7 m, d# g
    *@dev获取tokenid通过给定的token列表中的索引0 T& m- ~9 m4 q" [# v

3 s8 P- [2 f7 O  Z5 m/ O    *@param_owneraddressowningthetokenslisttobeaccessed, K& X3 }4 v9 N

1 u  {- K1 i& Y% ?  i& [( C    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist9 I+ h$ S  E7 i
/ {! l# Q* Y# e. v! c3 Z+ o
    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
2 Z/ R8 }6 \5 `' E5 z  {, w% l" A: U& a- k. E  }5 z, K3 D
    */
" x& x0 e* N4 Q8 X7 b$ ?$ Q
0 z6 z4 N+ O3 E* ?    functiontokenOfOwnerByIndex(, y# B& K7 f. _2 E4 y

# e3 C4 T/ f5 B* C" i& c- Y    address_owner,/ ^0 w- m0 M" C0 X! J; k
, h' z+ `: y6 T/ t& A% B" t
    uint256_index
0 g, V' Y8 T+ a- e* ]# i3 z, t8 ~( R4 f6 K, |
    )
- Q: _' Z: \) H( e4 W$ [2 q% A) ]* c; y9 O% Y+ K6 F) O3 ^1 H2 G# d5 l
    public% o8 \7 c. m2 i+ y* W: |
: T; p; L3 b) o
    view$ H  f: ~0 p2 y  a4 ]8 O3 \
. g# H2 I' M) N+ u2 x& s( P
    returns(uint256)
9 _3 |+ B* E: G5 b8 X
6 J% i$ c7 J1 v% p8 Z, n$ T- m    {
3 h) f3 D" g& y( o
, g% g2 S& y3 m8 ]    require(_index+ W6 p/ c/ `5 ]# k
! U* m: i8 _# N+ {
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。- A6 d/ Z1 z. h. z3 K1 A
( e  r7 d& I5 c
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2