Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2403 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。  D9 r; z+ K" Q! V' }6 A
; ^- w7 B' O4 s3 D$ Z
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。& q- ^) H$ o1 q# C' a0 L

8 r9 E" |5 q+ S    ERC721Basic.sol, a& |( Z3 L3 G1 {
7 E- k; k8 ?, \4 O% |  G+ V  }1 p# d7 p# `
    pragmasolidity^0.4.23;# @$ `, m; C8 o" H
6 [5 B2 _# b, _7 ]6 t' |; @
    /**$ G  l) }4 I+ {

8 O0 m  {! ?$ ?# X    *@titleERC721标准的基本接口- I  e  S2 A, i. ~: q! n
8 L! v8 [# t3 m0 v% C
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md  Z8 D# w) X+ d" I

. s* F- v4 |" x+ j* C6 C. m0 X    */
# H% e7 B1 t  i1 ?4 B, Z" T, t
  L2 d: S5 S8 I! M; U    contractERC721Basic{7 R" |0 u# Q7 d
7 d1 l/ m  P* v  g" `5 i6 I
    eventTransfer(
& s* D1 e/ V* o" x4 m& g5 E. j) e, |7 z
    addressindexed_from,
. j9 _7 A( X2 B( V; M3 ?8 p3 x7 I& l0 c4 w' \
    addressindexed_to,
+ Q. f1 v( N1 W* h+ q2 G* n2 P' z+ T% a9 B5 L" l6 Z- O0 i
    uint256_tokenId
: W% b7 E/ ^9 |% A6 o; a. x2 D0 [5 p! Y% \& H
    );2 Z, c* n: Z; X* p
2 H+ _) T6 b9 p. d. l
    eventApproval(' M- `/ M3 b) z1 \5 S. F

: d8 `% y, Z, O1 {    addressindexed_owner,/ z. ^7 X5 n! d" Q, h7 T' n

' U- }! q% Q1 q/ q2 t- ]" c7 g    addressindexed_approved,: ~9 Y. K3 d* M

0 X& Q3 J  r9 J. ^5 Z    uint256_tokenId; h( D: G/ D* U: V, c6 D5 _) s
* ~% ^+ o8 n5 s
    );3 m% M& `7 h% U2 R8 b
% q$ s3 j' q/ ^, p% n8 T
    eventApprovalForAll(
2 _& |7 S% J; M
& M, L. c4 @% {8 P: b    addressindexed_owner,
" u$ I& T: L7 c( ~2 Z: X, b
$ F4 `" ^/ S5 r% |4 J    addressindexed_operator,
; V& a! Q$ M, J2 [5 g& }1 S+ b' ~
  H" [7 J5 u" G; [    bool_approved
' x, N" D3 a$ o/ K& ~: |7 w
! {5 c! D0 ^4 f$ D; I    );4 F$ _$ u6 p, G7 ^( b' f+ B) g

% t3 n7 c0 ~' ~7 {    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);/ h/ Z, I4 Q- P' {; }

0 l4 d/ F( j5 ?6 @; {! W    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);9 {, H) d, b! g) D# u! X5 ^4 S
( X! q( @1 O# V5 z
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);+ B( m/ P$ }2 \: Q# v
1 g8 O+ F4 ]. S9 T. g
    functionapprove(address_to,uint256_tokenId)public;
# T3 I5 j8 u1 r8 c3 U/ z( X3 q
2 h, D& Z0 e( G1 ?' e8 f$ I3 X2 u    functiongetApproved(uint256_tokenId)
$ i* a/ l! i& ^+ }6 _
# }9 T! L$ k- E9 ]' _3 W    publicviewreturns(address_operator);
  v' R/ t; r& y- o5 D
  y. q& g" S2 `* L- |2 z    functionsetApprovalForAll(address_operator,bool_approved)public;
/ C) H! r+ @) f- W5 e7 E$ |0 r0 z/ D5 F8 D4 ^# f  o$ t7 O
    functionisApprovedForAll(address_owner,address_operator)* q7 y9 @9 |7 R, @! W9 n4 F2 {
- Y0 W  u( I" Y: r% J
    publicviewreturns(bool);
, _" L5 ]. e- p) ^% ^- s. o% m) w0 c$ E" P- V8 u9 X
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
4 v' L8 K+ N( P* U
4 k( l" x! Q% x4 i& [    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
( ?, p& x4 S! A6 ?; W) t6 j% R0 Z! E9 ?1 i# x* q
    public;
1 X( a& b5 F. Q
7 g  x7 b) S. I    functionsafeTransferFrom(7 U0 L! j* l: k! @# j8 f
& s2 T( ~3 Z7 F2 V  E1 R& n5 u
    address_from,3 Z' M1 S$ M/ f! N* i: j6 I

, N$ g+ [; `# T' t    address_to,
% @6 N2 _$ E# x+ n0 R
' m4 J5 e) u2 X; G9 n    uint256_tokenId,
1 M- j1 I5 T7 w' Q! i4 p: S
$ ~" ^2 J, T+ Z7 a; V# q    bytes_data9 v& M4 z+ D* Q  S, x2 _* z0 O

( t; [5 o  S4 n  z+ p; m2 O    )
( }1 d) o" R' b& g
' ?$ j6 G% Y; E6 v8 d4 B    public;+ _, a$ u3 |) D  @/ e& n7 n

" B& p! V$ y9 ~* i' n8 X, y    }$ u; g+ @, g, B8 C7 A2 M
1 ^; L5 v1 {- S3 L# }
    ERC721Basic合约定义了基本的接口方法:/ g, }8 T# X5 M& V, Q

2 l% q- P8 z' r( `5 S4 S2 J; v    balanceOf返回_owner的代币数量* u+ Z  R. ]/ d! |, e; }

. m5 T' {& e7 Z0 g/ L& \    ownerOf根据_tokenId返回代币持有者address
* ]( r& a. x- Z. ^5 ~
) E" d- e% w1 L6 O$ U& H5 D' G8 h    exists_tokenId是否存在. r+ P4 a) ]& G* s) B

" d/ R& u; {9 g! u( E7 O. M    approve授权_tokenId给地址to6 x. h( _7 A" d2 @, [

0 {5 L9 A3 J( @5 w% P1 I- p    getApproved查询_tokenId的授权人_operatoraddress
8 }& [& q( ~) r5 }0 d- p6 y! a/ g8 v8 y
    setApprovalForAll授权_operator具有所有代币的控制权
  u1 Q2 `* ]# ], n
, {: T5 O" X1 D0 ]4 N* |/ ^    isApprovedForAll3 d$ X) G3 N- S, [: Y4 a" C

: d) r. v- l- v4 e7 m3 X    transferFrom转移代币所有权
1 b( Z% b$ f' P* f9 H/ ~+ t
5 D- C: b5 Z- V7 c    safeTransferFrom转移代币所有权
9 C6 g! |/ K9 T2 h, T
$ R; m% i3 a# v# ~! {5 m    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
- M9 y- E2 Y( l  o2 P* r
" L9 Y: s' X8 j& P. A" M    ERC721.sol) {* S5 s" X: x$ d5 [& }5 ~* C

' E4 u0 |6 H0 j! p7 l    pragmasolidity^0.4.23;
. C/ ?; l' k8 E* p( T" P* r$ B2 L
    import"./ERC721Basic.sol";
$ m# ]; [/ m: b; |% X: s
* t- Y( \) z, u$ n3 V, K% C    /**
3 w' A- ?4 a. O- q6 a$ p: Q0 U, F$ ^, @  ]3 T8 w2 k; t9 R& _
    *@titleERC-721标准的基本接口,可选的枚举扩展
) O/ O5 B! A- c% i; W, o  ?4 `9 \: k$ @0 R( P7 T
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
- s5 F) \0 ]! C' R: q+ _) e# ~
7 U- k3 F3 G" j# l$ X0 G: f    */- C& W- @1 V# N0 D  u2 I( a8 l
5 K. V# `* `4 i1 Y4 ^  m
    contractERC721EnumerableisERC721Basic{2 F) n5 ^. D5 c0 \3 e9 j
7 F7 q) B3 ?( N, }2 k9 F
    functiontotalSupply()publicviewreturns(uint256);
# o+ c' W3 h4 ?) j/ M$ y; d. F6 I+ B7 a/ I! Y
    functiontokenOfOwnerByIndex(
; o/ u* h! R1 ?! P, n5 `: v, [: k  J" }  ?# ?1 I3 h4 x2 K
    address_owner,
! t* d  S: l! D) ^, d" q( J6 G) [- t, E! H  n' Q! D* `) B( }# N
    uint256_index* W- _" M; j' W4 m

7 j# |3 p* ^4 y    )
0 {) ?3 O; t- D" N5 I" u  Y
. ~4 Z7 R8 \* ]9 l    public. {) L9 V* ]3 H" Q2 ^  Q
# l) y# Q; g7 c4 `& ]- h
    view8 [. F; p" o% R, ]1 G1 u! }+ z
$ p7 ~. t6 H, d* H
    returns(uint256_tokenId);
$ y  x5 N$ f7 n% y, H7 R5 t
% [: u7 T* p9 c1 J  @    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
+ x8 s/ L% u# n
! @7 c5 N* l) s/ L    }+ ^9 {$ X4 j- [, a9 [/ A2 h
. ^6 ]5 Y+ z3 a9 _, L' b
    /**: \3 H/ @( W' @, h! U! z1 r; K/ r

! ?% r1 K6 m$ V, ~2 V4 m    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展: s4 V" |, i5 s3 {8 ]4 c5 t
, C9 O0 y) `  ~8 ^
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md* g' W% c# D5 h6 P, S) }" o  m
! o: Z0 ]# I; d- U, f- ]% V
    */" J1 |1 Z1 T! r$ d+ o/ d9 ?

7 e( V4 G9 l- B0 A    contractERC721MetadataisERC721Basic{4 O$ x$ h# f* B" H

" x1 ?8 H* E" e7 |4 O8 E    functionname()publicviewreturns(string_name);/ e6 o* c2 w5 v: V& H$ Y( b
8 T6 C& o% o6 |; z- y
    functionsymbol()publicviewreturns(string_symbol);
. r0 Y; H$ `0 i. A; d2 T! u* f0 [( G( w2 e
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
) I% ^1 M" w: R; u$ V; }/ p+ V' n8 I- m* c* k2 g+ D4 q
    }# M8 X8 n( f) y: T+ u6 {$ p
" e% ?  s4 h7 D* W
    /**% X2 g' b7 y& l, a8 c
5 p: ]* O& }  S' K: G
    *@titleERC-721标准的基本接口,完整实现接口
3 A. ~% }. u' n8 L+ b! m/ D
' T; s2 Q! d6 {( b    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
8 g) s2 M: S2 H, K* B2 D' |" N  F/ \7 S5 p9 E7 M$ }! ^
    */
$ n! L) D; c" r9 s+ X& _+ ]( ^! t  I' j! b' C# ~; H
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
4 g0 j% ?) _# o9 U* H) x4 V! u( n1 ?+ f1 ?1 I( B2 F
    }% u1 }! j* S4 y7 P" k
* @: Q0 r0 u. e! A) Y" a2 ?. [4 A
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
% x! j& A" {. j, L- ?9 w& K
0 A: `) z1 R( w8 T! Z( n: o! o    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
: ^! g* |: f! d( N* H" y
& q8 s; K$ J: _& x& }    totalSupply返回代币总量
1 k$ U) ?  K' K9 I
4 m8 J8 H! \( E# p; {. E    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
2 ^7 j$ J7 ~7 ^; T' `. k' J" M
! j3 z, ]# Z1 a. D    tokenByIndex通过索引值返回tokenId3 i; {. @& W2 e$ H/ {1 h7 b6 U2 r6 A

2 V0 }, l0 d& b0 M    ERC721Metadata元数据扩展哦用来描述合约元信息
/ N8 y; j8 f$ h: W$ }2 p5 m, c, `7 [1 v( a" Q4 G$ _7 T
    name返回合约名字
; e! k1 r% {! \  A: @7 u+ {0 [/ z+ d% Y
    symbol返回代币符号
; I* _  T1 x8 d  \) h% q7 ^8 V$ [! N
' I3 S2 Z" C, w' u" k7 Z    tokenURI返回_tokenId对应的资源URI
6 i) k5 A, @" c6 O* v4 h( B8 \! J8 m" o0 n. f9 @7 k! q8 S. P
    ERC721BasicToken
2 |0 h- _9 l0 ^7 q* i+ c! q7 O1 E9 L. u
    ERC721BasicToken
& Y/ ]5 ?- o2 T6 m
* E% |2 K2 Z+ H8 }. b* H' k    pragmasolidity^0.4.23;
) D" ~; |- C) i3 ~3 M4 s5 i7 g) v: p2 e+ v" G9 B0 y
    import"./ERC721Basic.sol";5 \/ F3 }5 H/ u
& G0 V; T8 }5 l5 Y* F( Q2 s& Q! h
    import"./ERC721Receiver.sol";2 x' ^, |; Q( m6 p) |

$ A6 \; ]( H  x" S' J8 m/ C- E( w    import"../../math/SafeMath.sol";. ~2 R7 v/ [' S& Y( r# D

* P; N3 X9 `  n    import"../../AddressUtils.sol";
+ I3 p$ H' A' T( H9 ~* B4 D; H3 w: ?
    /**
* S5 m8 |. v9 y: @/ ~/ E$ q
1 e2 P, H$ h+ W9 h2 u    *@titleERC721标准基本实现: [& o/ d+ `1 V- {& `$ v6 b

  R, L2 p9 e+ O' ?& [4 Y    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md0 U* _0 x+ I! u3 m/ G9 R

' w4 B! Z7 Y0 ^4 ?' M    */! x% f4 T0 F: {& A5 h/ o7 o* U
3 r1 s' s! [. w. i! A+ n
    contractERC721BasicTokenisERC721Basic{7 s7 D2 J% f. J5 i4 Y
/ i9 e$ W1 w2 B3 P; g1 \. Q: U, ^( ?
    usingSafeMathforuint256;
% s0 R0 l0 Z  u' A6 M/ F, R5 c# z1 T4 e
    usingAddressUtilsforaddress;
3 t# o9 S9 E: H2 A" X/ \
3 K$ Z7 B' x7 Y' k" ^    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`) h# w/ z- G( e4 q( q' _2 l
4 k/ ~; @, q; j2 V
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`0 `* C# n' U! w) G6 ^7 D
5 M4 w" X1 w3 V2 r; n
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;
! N' _+ ~% j. T- w; t
5 u: C3 E7 ^6 V& M$ J% t    //tokenID到持有人owner的映射
. I3 `! f2 I# H" a1 e  W6 c; J( M
5 w! L9 Z# _4 S# e  Y8 B3 k7 a    mapping(uint256=>address)internaltokenOwner;' o3 g" v9 W( P# l$ x; j! L

& S; _- Y  U0 ^0 h: W9 o    //tokenID到授权地址address的映射4 Y# q$ r0 x& G

* a) U9 S4 t4 {( _    mapping(uint256=>address)internaltokenApprovals;
# m, R. T: C& @) g1 n% Z; x) L9 j5 k7 ~. d8 R
    //持有人到持有的token数量的映射
4 C: P+ J* \5 I' ?1 x
) m: M! B; ?9 r6 W! v* x5 P( \# F    mapping(address=>uint256)internalownedTokensCount;
5 T9 `3 ^6 z; _! o/ `
2 b: e% }8 v  z' a( M, W& C$ I    //持有人到操作人授权的映射
" c5 s) w) `/ m( l% U( E% d: ?
, Q9 m6 |( c# R+ z2 ^6 g+ w    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
8 X" x! D9 \5 n2 L% p/ {2 D* c+ t0 G
0 G) u5 b( j0 P    /**( G3 D7 m" j! B, v! J" N8 Z

$ q6 `/ a1 _8 P9 m; |5 i    *@dev确保msg.sender是tokenId的持有人
' Q* A* S$ F6 b/ C' i" x% W$ i6 c! p5 j2 j
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
  N8 }6 W4 v- N$ C& y* X! s) u8 z
, P+ x% q3 R; \5 @$ l    */
& G9 A8 N$ s& @% P) X
2 G  i- E* f  w5 F4 B    modifieronlyOwnerOf(uint256_tokenId){5 R7 {, P7 J+ P) Z, u! |; ~7 I
; q7 g0 c- t4 N2 \4 ^
    require(ownerOf(_tokenId)==msg.sender);
. k: `( z- A: }1 ?: e* \4 P
- [5 g* a$ C9 }' F& c! Y6 T# b    _;
/ `$ V8 h; W; A) B$ ?0 W; D& f3 c4 l8 u* [$ f$ o6 S9 N  c
    }$ x" @) W5 F8 I$ D. s9 h
* B9 G9 }+ g* }
    /**/ F9 s: W, q, y1 z1 Q0 ?* h
7 h2 h* `+ M8 j. F0 }* H" M4 V
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
; Z2 A( ^. T2 V- u' a5 S3 \5 J2 j) j9 v3 i: J  O
    *@param_tokenIduint256IDofthetokentovalidate
6 S9 B7 x9 B1 X; u( V# `; s' b7 @! ?! v' [7 W% K# W' g+ i
    */
7 Q: V9 A& z+ i8 P6 o; |& R
% F4 [+ l5 }, Z, L( Q) v    modifiercanTransfer(uint256_tokenId){$ e* z+ o: s: }& Z: ^/ z- m0 j

3 W/ m" {$ l4 C" r9 W    require(isApprovedOrOwner(msg.sender,_tokenId));
0 O* O1 b4 N# U& b$ Q
' k8 u" f# \! L& M    _;, r2 l% u) V# v# W
  U( [6 G0 Z1 y4 s5 r
    }
0 I+ S. E0 d2 M4 i
8 @  \. M! C4 l+ Z" A6 N    /**
/ e$ b; o& @4 I" ]. u, t7 S& k% U6 G1 H  O% B
    *@dev获取持有者的代币总数
3 S8 z+ ]" P. ?5 v6 `0 P) G3 g0 B# s2 U/ h
    *@param_owneraddresstoquerythebalanceof
" T$ Q1 t& e% B2 S5 d# d. _! G6 w; D) C7 B
    *@returnuint256representingtheamountownedbythepassedaddress! R& n7 Y& i- ]+ W' F+ L+ D
3 u* p+ U0 m3 c$ U: [
    */% a9 m9 L* I* J% s

1 S7 L% ]4 g- H$ ?    functionbalanceOf(address_owner)publicviewreturns(uint256){
. r% B/ t/ z; }# A# h' L
1 j5 p* ]8 ]; m! O    require(_owner!=address(0));
: l1 a+ P( m7 T; A, r0 F# p' o  [0 J4 E' U" p
    returnownedTokensCount[_owner];
) [) Y3 ~+ b& u$ F: c  w
1 W5 h1 F# I% V; z: F+ |3 t    }
# {) U5 Z" K' P2 t, w' u) u
! U) ]. V# _; e' P8 x    /**6 A  a( D& j/ V8 \

# B% d8 c+ f5 @. c% C/ M. ?    *@dev根据tokenID获取持有者$ E. M( v7 }! w( q$ z; V

) Q9 |  F  ?* M  e; I    *@param_tokenIduint256IDofthetokentoquerytheownerof
, h2 L- W2 j5 a& s$ I3 ?, O4 B* _% y) _7 x& I, e  x. S) d
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
6 r; H! W' O1 C
: s' t+ v# \3 \* d/ h) o- l    */- h  H5 D* ]  _. m) R8 a

6 d* S) `7 b. g    functionownerOf(uint256_tokenId)publicviewreturns(address){0 g: T3 E4 D" q* O* r
2 U! r& J  I( N2 G2 `
    addressowner=tokenOwner[_tokenId];
$ I! r# X6 I: |
" w) F( R) r) ]4 f1 i( m# U& @    require(owner!=address(0));
$ k7 t, Q6 w9 b) P# M2 l  w% M) A4 x5 S. Z" a) _0 V# A- h
    returnowner;/ O8 _0 |$ _+ i  N

3 z/ o" v  E7 t+ p5 f8 F/ S; H    }- C3 B) N2 x& d+ Q. ~' H0 `

* D- t) |5 M! v0 Y6 B0 e7 c    /**
4 \9 Z3 L% c# H* G/ B
+ h. M; z7 w# |1 P3 F$ W: m    *@dev指定的token是否存在, v+ z& c& {6 o, }) N* H% K

" W( {. R+ h0 R2 q! Q9 S2 O    *@param_tokenIduint256IDofthetokentoquerytheexistenceof7 O* g" v! h& v- e4 {3 B* C
, H* \2 v! l' K
    *@returnwhetherthetokenexists( j& g; }$ K( U# a
* ^& \$ R1 r. Q: G; a8 _
    */% p! Q1 ^) a) o
0 {4 B4 T! W0 I, L/ I
    functionexists(uint256_tokenId)publicviewreturns(bool){
0 U8 l& V/ b7 ^+ U0 ]  s/ Q* `+ h4 b+ ^6 y, Y
    addressowner=tokenOwner[_tokenId];
6 J# G) B& Q; \
- r! h7 r* N5 b3 C2 Y0 J& d/ q    returnowner!=address(0);
: S" F7 i7 T4 o" R# D' F$ G
0 u/ ]% I6 H4 K4 y4 Z1 A- J    }
1 B( S* t5 y' g0 M' O; X  n: P6 e/ S' B  v) s3 H
    /**
( Y! J! @  }. }. v# c, y+ k0 [) W4 O: A6 d2 S
    *@dev批准另一个人address来交易指定的代币( i, p$ C" t; k3 `: P

3 ]. o1 [7 G. O" b( Y6 ]    *@dev0address表示没有授权的地址, [: W9 F- P' i; l

9 w6 [& c" v% L( s  N8 t    *@dev给定的时间内,一个token只能有一个批准的地址" M1 a: }! k/ {  T
# r; G+ K" w. ~+ T
    *@dev只有token的持有者或者授权的操作人才可以调用6 u. \, G* ]- m6 [; p0 j# I

, \. u" h3 b2 I7 e$ @    *@param_toaddresstobeapprovedforthegiventokenID
) ]1 g" N, |% ]7 q/ W3 x# m: x& E$ H
    *@param_tokenIduint256IDofthetokentobeapproved: A- R# d/ E# _1 l9 Q

, c% Y- y8 Z, I: c. T' o    */
1 D( J( O3 c4 r3 r* E' y: O# a1 K" G' k& G. N
    functionapprove(address_to,uint256_tokenId)public{7 w6 F7 n& t6 i4 e- F* w1 a' k
+ B. e. Y& k4 Q& r* ?1 F6 {
    addressowner=ownerOf(_tokenId);
. r: o3 s  B; Z+ j1 b" N6 K4 j1 T7 M; e! A
    require(_to!=owner);$ d; w7 q: f# r& {9 d) m- R
5 Y# J0 |$ q+ d8 V& V. c: G
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));: b! B. B/ N- p' |9 r* ?6 X$ M& I/ ?

" Z/ [( i! |  M; A& T* [9 Y/ h    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){- @* k& J5 k- S& \3 ]

- C8 Y" v& Z' n; S3 X* o' y    tokenApprovals[_tokenId]=_to;  V' i5 j$ ^+ G" G. G# o8 i

6 w) k( W. S1 b0 D' C    emitApproval(owner,_to,_tokenId);
# O$ _+ S/ f/ \+ M) O0 P. n& K* z( P4 v
    }
/ a8 L7 W+ K% b% i7 _  V5 g* d2 _" D
    }) i. P6 g% I! b8 q3 D
2 X7 p) ?/ v. }! c6 g5 ^$ J+ P
    /**
+ C2 |, _1 O5 k
! h" V( \* i) J, Y    *@dev获取token被授权的地址,如果没有设置地址则为0; D- T: n4 s& {0 f7 M: i& t

  ^( C  i6 @" g- I$ X6 h    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
4 t* u' p# V7 L/ V0 w' c) k
9 J5 Z* `5 T( K: q& S    *@returnaddresscurrentlyapprovedforthegiventokenID& L8 ?7 ^: D& U' g: ^& E
8 k& d/ Q8 `7 Y+ ?& O( E; l, \
    */
, `+ T# H; Q1 E- T* K2 Q
, E2 Y" t4 ]: \& U& H- x: Y    functiongetApproved(uint256_tokenId)publicviewreturns(address){
5 \* a7 ~+ {& ?4 h; I4 q5 _: n" j/ N7 a: o- A- ?. t
    returntokenApprovals[_tokenId];
# h0 |+ _5 I7 C6 L
2 j, i. b' d3 |    }. @7 N. Q/ g& U$ |6 O5 L: I/ B

  A( a* G; z% {! C    /**
# ?: n6 m. Y$ N, U; \
; o& @& O; [2 k    *@dev设置或者取消对操作人的授权6 b' J/ c9 t4 j8 I2 ?' }

# \1 g8 d9 U' Y) A0 c" q    *@dev一个操作人可以代表他们转让发送者的所有token4 r3 z0 N7 q; _5 h
: I0 \8 M6 Z0 e$ d1 F- B" ]- _
    *@param_tooperatoraddresstosettheapproval
8 K9 a( V8 e" m( i; X
' P2 D* l- n- V8 q- q* G    *@param_approvedrepresentingthestatusoftheapprovaltobeset- Y2 R8 [/ \1 ~4 l8 U( t
2 S" [% N6 s) ~% [7 `# Q& [
    */2 {; I, y/ p8 p$ V& E0 o
& I: o1 a1 i; P$ O) z) {. d
    functionsetApprovalForAll(address_to,bool_approved)public{
8 Z+ ?1 q. k: P  g# ?' z. ~
1 M0 r& Y+ F( l% u1 G( W    require(_to!=msg.sender);
+ F, O6 j8 S9 h8 o7 ^9 w1 N. v5 L2 V. I8 A2 r) ^( c' j2 R, O6 R+ ]* ^
    operatorApprovals[msg.sender][_to]=_approved;2 x( l+ ?0 E7 \7 K3 C

# l3 k  ]$ j8 N2 g0 d3 f3 `& t2 [    emitApprovalForAll(msg.sender,_to,_approved);, c, _! Y; P' G8 r

+ E* p1 Q1 Y# c$ G' r/ X    }
9 k2 f" d* C. Q0 h" }& O/ R( M2 U4 O: i% O# x: C- K. [
    /**
# F5 U, [6 E: k1 B' I( U
! s, E0 i0 F" Q( t: _* V/ w    *@dev查询是否操作人被指定的持有者授权) f. ~7 b0 B' [' ?. X# b
7 W: ]3 H8 ~7 T/ E2 p1 M" ^! y
    *@param_owner要查询的授权人地址9 o  A# D& @/ Q- b

4 l: O  N: C. \' k' r: v8 t# A    *@param_operator要查询的授权操作人地址
! Q9 g) B% q& b' R" f: A
6 f# G+ j! M# O: t/ [- y, X    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
* G9 k1 O( K8 H2 ^6 H# V
* A1 [  X9 M! k! A! w# G    */
" z9 c& q- ?. Q% W0 @5 t9 @, r5 Y3 K. L) L* w9 A7 g$ {
    functionisApprovedForAll(5 Z3 _& B" o" ~7 e) l* J! i9 c# e0 g

2 m5 X% h* m0 l+ F6 q; |    address_owner,$ S2 |) P0 B/ y$ L1 o
8 ^2 |; S) N2 W1 ~: Q6 _# d- I
    address_operator
1 u8 _1 H% p; Z6 ]3 B% S8 u2 w# P7 P6 l& D8 }
    )" W% D6 ?0 h5 @5 a& k7 v

$ D9 i. e' t/ H* U- k    public. a  n* s/ g6 k# L7 Q

0 }6 t) n1 s1 i( O, P% B    view
/ @1 Y7 c; I5 f5 ~
* n0 Y( v. Z" K  q- o, d! L% m    returns(bool)
4 ~0 O/ P8 P. `) I% U
+ m9 B, V* \5 Y$ {    {
  E$ x6 z; W5 S% f9 M4 c/ R
) Q- [+ a& u: G    returnoperatorApprovals[_owner][_operator];1 _9 m8 G2 J; \; P8 _% S

! O: O5 C0 J- e1 P) J    }
$ x2 Q5 Z- \# F* p7 I/ c  c2 F& \2 X
    /**5 W8 ^, W  W2 c, k
. P* r: o4 S* b$ ^1 W
    *@dev将指定的token所有权转移给另外一个地址2 I: x! q0 c5 P# _+ `8 ~7 F
9 P( O1 R  n4 s  C/ a$ w- m1 C
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`! n+ e7 {4 E6 P

+ x7 D  \; A: u) L, t* ^6 c3 x    *@dev要求msg.sender必须为所有者,已授权或者操作人) h3 F8 S/ v" S) {7 y% V
' J! g" [- z9 p" s  i) R/ O
    *@param_fromcurrentownerofthetoken
# p7 k& i. L; W$ ]3 G9 Z& c+ N! Q, N' w: a
    *@param_toaddresstoreceivetheownershipofthegiventokenID
/ `) ]3 d. E) @, t- t+ J. ^9 g2 o8 S7 h
    *@param_tokenIduint256IDofthetokentobetransferred7 e/ y& S( F  i  b: w+ _1 A" o

/ c8 p0 E" m. I! e7 t& s7 x8 m    */
& J5 h# Y: |1 M4 S8 Q2 L+ U9 a( e' M; E+ a* m
    functiontransferFrom(
4 E5 y5 ?: h7 j& }$ W% Y
  r& Z0 W1 Y) _: C4 |    address_from,
7 e- ?+ B0 o. _0 B1 ?: p+ p8 ]& n- G4 B- D+ o
    address_to,# Y, }5 S5 q/ r* u

, y2 D2 B$ }+ s    uint256_tokenId
: O/ ~2 Q+ M( J! _! Y
- U; A1 K- q% t4 i4 B( \$ @    )
5 `6 b0 R( x& W  k" G
+ {; U' x5 k" d) U: ~0 o+ q    public0 p+ w3 G, V0 L% N, Y" F  ~4 |
/ a3 ~9 P8 @3 _4 G7 ]0 j0 A" h
    canTransfer(_tokenId)# r: a7 h2 p( N9 T: r

& G: r8 z" H8 I8 Q7 @    {
% t* d0 s! l! U1 V  L6 J( N( K6 T" I  M) Y0 s6 T' N
    require(_from!=address(0));- @/ X5 e2 R; q! d6 T& U

1 j. [5 V5 W3 ?+ h0 {/ V    require(_to!=address(0));# B0 ^1 V5 j1 J+ q7 ~' L5 n; Z( E
8 }4 @$ C" y  ~9 y& o
    clearApproval(_from,_tokenId);7 o* ~, K7 D& [  U% c

( Q! Y: b$ e6 X& P4 q1 q  W# x: i    removeTokenFrom(_from,_tokenId);* p  e8 O+ v8 Q$ \* Y
* W  R! a) b. o! Z( t  ~7 n
    addTokenTo(_to,_tokenId);# J( m1 I( n5 l# z; c( }  l
  z$ u7 K2 p) S( f$ ]# ]
    emitTransfer(_from,_to,_tokenId);
1 e/ v: Q" N5 Y! D3 u- M3 v% Z7 o2 w' L6 D& |9 X; [" \0 D
    }( b6 y" ?# E& P, w' `3 }8 ^

) G: B3 l3 r$ \! e% J    /**# _1 ~) ^" g2 H, C2 m% h" v

# x  y: \0 u2 m7 \    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
& B. k7 F6 K4 A; C* v
8 k5 v: C6 x3 T+ I, U* q; P    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值: m: w8 S* d9 ?. h9 }4 N

) u/ t8 n2 Y& |8 F    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原" x5 w4 n' A( l' R

/ G% j0 B- o! g; t1 d1 r6 b4 ?1 ~6 r    *@dev要求msg.sender必须为所有者,已授权或者操作人+ }8 x& w8 G5 ~/ q; i; V
1 B7 D1 i- l& u
    *@param_fromcurrentownerofthetoken
+ Y( L6 v; X: R( U
8 [" G7 e/ _; Y) G    *@param_toaddresstoreceivetheownershipofthegiventokenID! {  V7 x% q: n% R/ R5 [/ ?
4 c9 \. U' b) {# q) n) V; c: Q
    *@param_tokenIduint256IDofthetokentobetransferred% ~. V8 |! U/ L! X0 p8 G( g

" F- z7 Z/ c0 U# w/ A: d) n    */
; I5 W1 c; H/ p7 `4 [, V0 z8 ~
/ v- @7 b# J0 H( x    functionsafeTransferFrom(+ u& {/ a2 ?& z8 ~8 @) u* v

+ \# M3 I0 Z( g# x0 x1 {0 Q7 e    address_from,
( y" J/ Z" j$ w, J' I. B5 B
# ]. O0 q. o  ^5 o    address_to,
. K8 Y! a  Q* k# x, n
; \9 Q) p3 ~" U  G    uint256_tokenId
# u8 x+ {% K% J, B  T, g+ Z3 Q8 G* j' Y# ^
    )
# g9 Q3 V" E% p4 v. {' t; @, N) p) p8 W
    public
( u! a' S9 [; F# m; v0 t. T- ~! Y+ g  L
    canTransfer(_tokenId)
% }9 t' b$ U  T3 @) k5 ~( G5 T$ p" y* V! N7 o! H6 u% ~1 V$ t! {
    {! {3 v- r; F# D% m- I/ M0 w9 a

2 k, t% i, Y8 w5 H: K    safeTransferFrom(_from,_to,_tokenId,"");4 m) o  d) n6 S

) y- F. Y) Y  q! y    }
/ p0 }0 v- @5 ]8 u: ]6 k0 D9 v' o) S7 P8 W; Z
    /**
0 q$ q, N( r& _9 O/ A2 y) {$ Q" c8 K" L  P$ f
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址1 y; a6 ^3 c# s( R
" k- u: d, G$ V3 \4 [
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
; ^5 I8 n& v# s: ^& c" N: }, e2 b. d+ X% \+ L  _) W: e
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
) R8 q# y' F. U5 d' |+ ?2 g; O2 a  J
* K' _: ^9 x8 y' E/ B- U' g  d    *@dev要求msg.sender必须为所有者,已授权或者操作人
6 ~0 R/ {" D; ~5 C3 v8 f6 A
, I) V5 `7 O) I# G* w3 e! q    *@param_fromcurrentownerofthetoken
- a2 r+ m0 d, U& D1 r% [" ?- K$ E+ K- [1 w$ i# x
    *@param_toaddresstoreceivetheownershipofthegiventokenID
! `" r5 x/ h6 ^2 e/ P6 V7 e' T4 o( r% |+ N7 Y1 i
    *@param_tokenIduint256IDofthetokentobetransferred
, x* B# C( w! u$ p8 C
7 r0 q5 [5 |2 z/ I6 i' b    *@param_databytesdatatosendalongwithasafetransfercheck  a" _+ J$ s9 _- s! M

8 p6 b$ j0 L2 n: B# d9 V    */
! L& I  T& }. ~3 l; K
# ~/ e- ]$ w4 p0 x. b) k5 X    functionsafeTransferFrom(
; m8 e# \0 y4 ]  B* q
) P5 A1 ]! ~4 E" v6 W0 O6 Q    address_from,
2 m& X! ?6 r- s
. w6 `$ J, p4 {/ f8 T    address_to,
* R' H8 j3 f6 x! ^/ x- T6 N, H( h  ?  v* U  }4 ^* B
    uint256_tokenId,. c0 ^. X) P, _7 ~# \: c0 h
( K9 m3 x# @  E4 v
    bytes_data
; a. W( m8 Q. ^1 f$ P, O7 R
# G- Q% z- z% m    )1 C9 f7 h6 p2 M9 n4 J- i

2 b9 r; P3 g) O/ c1 m- z7 U    public
6 [# c7 x# s' j' N
1 J# L8 {+ d9 T, B/ `- w: j    canTransfer(_tokenId): d  X/ s( e) q1 u3 ~
, C4 k0 B! @6 q# a2 W% t
    {! h$ Y! f8 k+ a2 E3 d
& t" T7 a: c# L6 U9 [; g
    transferFrom(_from,_to,_tokenId);
! w; F3 P& ]4 ?( J  ?
* E- J0 l& s- q- Z; H6 Q    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
$ z/ s4 ~1 `$ H
& w2 j2 n, f$ m    }) D' M) C+ s3 z" g* f  E! o

9 e. W3 L  c+ f% o0 x    /**
3 l% }7 d; m8 I, l+ U5 @7 ~7 s3 m  P8 q6 [. \0 ?% [9 R* @! T6 \- d
    *@dev返回给定的spender是否可以交易一个给定的token: o+ @" p- c; e0 Z" b6 x7 ?3 o

6 F8 q, x# G% L  D, p7 j  g    *@param_spenderaddressofthespendertoquery
$ n% i3 b" T: k: g- B4 }( P. s- z+ t+ B) B* R
    *@param_tokenIduint256IDofthetokentobetransferred
3 Y2 V! d5 T% @0 W9 e
2 U* Z6 {0 G( [9 U    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,
+ p: u1 A; n! \0 q  b* f0 h7 N* j, p8 [6 m6 o/ {# [4 e
    *isanoperatoroftheowner,oristheownerofthetoken* k3 w. J$ e% x$ x, I9 c( c
' N8 t8 V- Z8 J! U8 F5 I' a
    */
/ J4 ^3 c! S  w( |& z# B+ t; n( l4 }% Q) j
    functionisApprovedOrOwner(
1 s4 M4 K& z( \
$ b4 ?1 }# i* L/ S$ y9 l/ T5 q3 p0 N    address_spender,
: D! T/ J2 \# N3 X, I  C7 O  }# D  Q7 F1 r
    uint256_tokenId* l4 E+ N3 n, v3 S

; f) X; P; z" O$ _7 s6 D/ F    )& t9 ]# n/ A! ]& H" I8 w  N

+ g" E* T) p! e& k  `( d( V    internal
7 `" I, e: A9 _& l8 Y4 G* q( u  p1 M2 G; [6 o9 N- E3 E8 x0 V/ n8 S
    view- E0 P4 k) l$ {1 r) H' ~4 B1 K
6 q0 M! }1 V' Y1 B# @* A
    returns(bool). b( U5 B- P2 L

# r! e8 t$ v  ], K5 r1 {    {
4 x) P4 q$ A7 f# y3 A: Z7 Y" B. b# \# C6 S# N& B0 i& y
    addressowner=ownerOf(_tokenId);- U, `8 t# ^9 q" u+ `
. q3 n1 T6 S! |' @0 M0 j
    return(
, E0 I; ~- O1 s; o+ G6 N5 D/ s* d' N% G3 B) g: H
    _spender==owner||: Z7 {9 P, ]8 t3 Z4 H

3 O% X9 C; ~# n    getApproved(_tokenId)==_spender||+ Q6 w: r* U4 W/ {. b

! V* H3 ?* M; b  }7 E/ ?    isApprovedForAll(owner,_spender)6 c8 B& z/ ?4 x

1 u2 p7 o4 V2 Q    );
4 {1 _1 F$ y8 U
3 E8 X% S% l& ?" r" o- i' W    }; J8 P8 j4 o8 q4 u( g

9 F$ V* e) X* g0 K    /**
- ?8 I' A" |% [! q
. T3 j% S! J% N/ O5 A    *@dev增发一个新token的内部方法
5 ]3 R5 r" Y5 R9 C& ^9 {/ \0 O2 N8 |* l
    *@dev如果增发的token已经存在则撤销# U9 g) u; ?. ~1 x7 ]5 \3 I

/ t7 l  M9 e; {4 t    *@param_toTheaddressthatwillownthemintedtoken7 i3 ~, w# j. c+ t( S

7 U, z2 W: l9 k' y    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender8 M3 D' }- L# G( b0 m" V# N, s5 |. ~
, n+ {9 X* }- q1 v1 L1 v* T, M
    */2 s& }, z4 \$ o

, Q# z5 y) m7 t3 r9 J    function_mint(address_to,uint256_tokenId)internal{! U. f5 y1 a, K' E& D2 p* O

0 v/ B9 f8 |/ ^    require(_to!=address(0));
" N( A$ B  P. @) Z# i
' S% _. S' ]% v* C    addTokenTo(_to,_tokenId);5 }7 B; ^. E( X( d
8 \7 r/ u2 _: ^2 r; p7 r9 n' M
    emitTransfer(address(0),_to,_tokenId);& h5 u" a1 W7 W4 H3 Y: ]' b" H

' H# e5 M; ?5 Z2 G- g    }2 W# n( N1 a/ E8 W0 t
: g& E+ ?1 L$ I5 |. e' z
    /**
! @4 b/ e/ H. d3 }* w1 T( Q) P) E
    *@dev销毁一个token的内部方法
2 {" B3 B% `) ^  y/ [" c4 M
6 u& U) _- r+ B- R7 o9 M8 O8 e    *@dev如果token不存在则撤销
# w" ~% ~) |2 |$ J4 ~: a4 x& `* ?9 C) d) v7 Q# [
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender5 E4 t9 C# Y! u  g4 O( Z: `

6 a- @" `( D3 \8 V2 R4 M6 b    */
' }# A+ }8 q0 m; B& p4 V' R6 t/ |3 D8 [1 o# i% g
    function_burn(address_owner,uint256_tokenId)internal{1 u5 |  D/ O- t) B# F  A1 x
& u0 C0 L+ v1 X3 m
    clearApproval(_owner,_tokenId);) l) b# e5 i! G4 Q: E4 X( _# v4 V
) B. N: p) Y8 ?& b; B+ D
    removeTokenFrom(_owner,_tokenId);
& ]5 D2 C2 _7 @8 o* ^9 U
0 ?2 x8 e5 x; g5 D) u    emitTransfer(_owner,address(0),_tokenId);
. b( P& b) n4 Q- A
# m( |% D% y! l" _    }
6 p+ e! t  ?, o, h0 A* p1 w# Z) P! s* _: K7 b0 Y. i; V- g
    /**
1 E- q- k2 c& o, t. _! z4 v
8 w, L' i' s( }, G! a% u/ j: t    *@dev清除当前的给定token的授权,内部方法& W1 T% `" d" j4 W
- e  T* e% G7 N$ f2 A. n' G
    *@dev如果给定地址不是token的持有者则撤销
" [. S% y) G! G9 A! H- i8 \
0 U5 I5 U2 f& H- f# U    *@param_ownerownerofthetoken
8 R2 c0 Y' d/ [, i) C' }. J* ?- a" p! N) A( K9 V; o& @+ f
    *@param_tokenIduint256IDofthetokentobetransferred: j% }: }1 E1 j" Q! b/ d( s
# |+ m- x  w7 }/ V& c2 v8 y* D
    */% }/ c/ z' i) K7 L, r

8 m" W" ?) z/ F    functionclearApproval(address_owner,uint256_tokenId)internal{  U3 _3 w2 l) x: X* `: s

6 n* l0 @7 g, G/ k0 `1 [( S: a    require(ownerOf(_tokenId)==_owner);8 S" b6 J" C8 s2 c' ?4 v. y9 x$ c5 X
1 P& i* i1 I& Z, [
    if(tokenApprovals[_tokenId]!=address(0)){1 N# j* D8 y  v: B- X' n- p9 S

, N4 h) x+ y# {0 k' }( B, L    tokenApprovals[_tokenId]=address(0);
1 f% T& M& c+ G, i3 E% \8 \% s
% g% ]1 X/ s1 J  Q9 v    emitApproval(_owner,address(0),_tokenId);
# f# i6 _: u+ e8 c8 P" {' L1 O2 k5 q
    }9 L6 C) S- }0 a3 k7 O; g
4 ~  I4 z( L6 q) z% L" t2 u+ Y
    }. k! ^5 O2 H8 R8 l$ m. [

6 k" s6 y: b5 R" c! v- k    /**
0 x* H# T& M: v' }9 o  h" Z/ V# K7 ]0 x  @
    *@dev内部方法,将给定的token添加到给定地址列表中: P3 P/ l; p, J# {+ W9 l7 e
! X8 ^* C6 O: B/ @
    *@param_toaddress指定token的新所有者
  f3 ^. U2 x( J/ p2 P" e0 l4 ?
# y2 h5 B1 t: @5 k) M( H! y+ O    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress
8 d! K( U( a3 F7 T- M
0 F8 a7 |8 t7 w, N; J3 ^9 _/ h    */! p7 s0 X2 k/ o* J) q. {4 m
" L! t/ U& ?3 u9 g* c+ i
    functionaddTokenTo(address_to,uint256_tokenId)internal{1 G8 ?4 p' }+ h* t( v7 S# f: q

2 {3 D. T' T. q5 F/ K& o    require(tokenOwner[_tokenId]==address(0));% B2 a9 _) q& ?" H
8 y1 U& E, j6 o9 ^4 v
    tokenOwner[_tokenId]=_to;" h" B/ a: P' ?2 Z+ G& k5 J8 F4 R
6 w# _2 I2 {' v: Z. ?" W2 |
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
) v# a+ ]" r* q5 O# _7 ?( g* Q" y
' W/ ~' a* q, s' a# @8 S    }
7 C: D3 p+ }9 ^7 U0 k. n1 I$ g
* R$ {* a, Y" @" S" p3 z+ j7 C" C    /**. M: z. H; d4 E1 J: i
' f: R" D6 _" o0 ?' }
    *@dev内部方法,将给定的token从地址列表中移除  `6 x6 t  C1 X6 G" c- t4 `
1 l$ G4 E0 Y  W! K5 [4 A1 `8 _
    *@param_fromaddress给定token的之前持有中地址' Z/ \$ N) |3 Z) i
2 N# r% A% B0 y; Q, Y, m0 a
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
0 U: |0 |7 l  H  J/ F9 K8 y. J( t( u! C9 J
    */
' o( w" a* P2 T& a8 x. P) g- y2 y. P+ x
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{3 s  k3 o" [6 K( O1 j
" e' |, @5 z; `( m9 ?/ e7 f* o
    require(ownerOf(_tokenId)==_from);) m4 A! D3 i8 G5 r4 o, e
4 F  m+ f6 O# S& Z# f# j. S3 \
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);5 p$ j/ {+ k  r6 i# P; W9 ~
9 o" x) l# i* K" ~) j2 \4 q+ o
    tokenOwner[_tokenId]=address(0);( z# U7 ^: D9 V/ y" X8 I" W

! Q$ e' q! x3 e$ \( n8 n- P    }
; K' m. m; f* T. Z, _8 w1 A& F: [* A5 m: N
    /**; b. h. J! |1 B5 i9 Y8 T. v5 o! {

2 X; ]2 E! F1 \7 n    *@dev内部函数,调用目标地址上的`onERC721Received`
+ o) t1 `2 Y, ?# w
, |& s! {. L3 A! O) ?% h    *@dev如果目标地址不是合同则不执行调用7 v- A8 F/ ?& U( @8 r8 X
5 T+ t$ x* t& W, _8 P7 U2 J
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID* Z' ~6 c6 J/ b( O9 f

: q/ X, X( R7 `! S0 q    *@param_totargetaddressthatwillreceivethetokens
5 \' j0 t% O0 M) R3 J! u( j2 r* F0 {* t, y8 k) e
    *@param_tokenIduint256IDofthetokentobetransferred
) a8 X7 E  X. M* v; t& ?! _( m; J' v6 a1 y: W  Q2 o
    *@param_databytesoptionaldatatosendalongwiththecall$ B" e3 j3 T& }
3 x7 v; y6 b* D  n: U
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue7 O. @) q' [- n" C1 }( R6 Z+ c
9 @9 G) M; r" R1 e3 O! U
    */6 k6 I: |1 `" y
1 r( [- B3 U2 B) E* b
    functioncheckAndCallSafeTransfer(
/ o4 ]2 m8 h3 E  @3 o3 @9 o4 E) l7 I2 ^3 o" l) O
    address_from,! h- }( ?9 f/ q6 ^( A' m- O( ?
# J$ X$ c# _/ r$ m0 d8 j: u% o
    address_to,- O  _' V# q4 U8 R/ S4 e2 S6 }3 v

8 B0 H/ g2 O  I; m% j    uint256_tokenId,4 g$ C; f6 y6 s5 I2 V& Y
* }3 i2 h% @) j3 V8 o
    bytes_data/ t+ K9 Y7 e4 p6 N

& B; ~2 ?9 {4 Q3 Y: F    )9 C+ w( f1 g7 Q# l% @
5 {2 ^* c' O  c7 z) C+ s3 E
    internal/ g+ \  G7 Q2 g8 {$ n$ R3 v. @
* z' l8 s0 }8 F6 ~6 _
    returns(bool)
" ^$ X% {" A3 P& ?! F/ s. u" d/ G6 X8 _, U  c0 O+ U! z
    {
* k3 Q4 I0 k1 ]. b! o7 Z. Z6 k6 `5 p  U# F$ N. p, X
    if(!_to.isContract()){, ~! j% n/ W# [' G! U

3 o5 k- d- u. q( f( T    returntrue;$ d, T5 y8 h! u: o& n

% q4 `6 \- d. ]; [    }
. L! ?! [4 s/ P$ g2 X5 @
$ w6 P5 [$ \  |    bytes4retval=ERC721Receiver(_to).onERC721Received(& q9 g  S+ r% b* j* r5 }1 O! i

) S8 X- z- K$ n% ]. Q! a% N5 x    _from,_tokenId,_data);
$ H5 T% L* h. \  C/ U: h6 p! }$ B( B: q$ ]- o8 L6 C0 p* W
    return(retval==ERC721_RECEIVED);( f; M& C: H+ d) z: n
' q- Y1 H( s- T  c1 L" x
    }
5 d/ o; _0 K# q7 D* [! _. ?4 z) `% L7 Y* ?4 `
    }* L& p) c6 T' v9 }9 \$ r/ g  y& V
- I9 \- }3 ~0 f1 Z: Z) Y+ _; x4 Z
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
4 Y/ g8 m5 P/ w  ]  E" l8 c
* }* s' N( t, _! q, U    ERC721Token.sol
& w5 Y( R. @& E# R9 ?
* L7 I2 n/ }; S1 o/ [    pragmasolidity^0.4.23;
; j0 a& A* H. a0 L& R/ ]- L+ {/ R: r- m$ O
    import"./ERC721.sol";& m& y( I+ s. N- E+ Q7 n

1 I+ y8 Z6 ?/ N$ S    import"./ERC721BasicToken.sol";
$ O' ~% [, s/ q9 m* Z, c
; P: N; s, `2 B3 I4 k. O9 K    /**- w9 r5 e1 v/ I, r9 E' f" V

$ T. \$ `( i& T    *@title完整ERC721Token
, A; Z, g, Z4 _" F8 z8 v2 C$ k) \3 X2 A9 T  I& O+ J
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能1 O# K  S) Q9 |# Z: F+ I7 C# L" ?

. P" D6 h; A. C& I2 ^6 G    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* `8 b: e# V' |7 [( s9 z* q* ?& C0 c7 h! U" v8 |
    */6 O. f1 p! [0 ~( b8 y& |7 w* Z' J; _; y

7 P* o; Y9 N* ~/ y" N    contractERC721TokenisERC721,ERC721BasicToken{
5 f7 r' ]9 v. r3 [# ]/ M& C% b& E/ K* v, R* [9 n( O: ?; ?
    //代币名称- `* b& u" L5 [4 E
- v$ H2 }  E# g/ d% \) m4 h, Q/ `
    stringinternalname_;
- O0 ~: b; T3 }, `1 Q& \' ?& u5 x( d2 ~+ a
    //代币符号
4 H0 ~4 u% a) h3 z5 D  _
( n+ |7 l" u, C    stringinternalsymbol_;6 B& u& |& \' k0 q' f; ]

! Z$ t( I4 _  H4 m0 L+ y( G+ a    //所有者到所有者拥有的代币列表的映射
1 u2 s5 u8 K& G( i
4 A3 j( c7 ~% X0 M    mapping(address=>uint256[])internalownedTokens;
8 m' k5 h8 s, S' P5 n" s) M" x$ C' J9 o2 |' v* F
    //所有者代币列表中代币ID到索引的映射
; @/ n' Y2 ]# A8 R( M/ W- q8 y( [( ^5 ^) S
    mapping(uint256=>uint256)internalownedTokensIndex;
0 ]6 G- w9 W! C/ [6 `9 @3 D/ A
7 m  o8 o  L% L+ R1 q2 G    //保存所有代币ID的数组,用于枚举7 p- K2 t% D% X! u6 m4 H. N2 s7 ^
- h' E! d( E+ d% E* N$ I; E
    uint256[]internalallTokens;# f; h9 K) u0 K% w6 ]* W& J4 D9 W' J
. l! E+ p/ w) z+ f* v; F
    //allTokens数组中代币ID到索引的映射
) g1 b0 i' f& M8 a  h$ v2 F% a8 _1 v% |" l
    mapping(uint256=>uint256)internalallTokensIndex;
1 k" Y8 q# V% `6 Y5 q5 j8 J/ e' m, g, ?
    //可选的代币资源URIs映射0 n3 ?- R& u  h2 k: |( [! \

) g) v. w/ l# Z3 n: ]    mapping(uint256=>string)internaltokenURIs;
* s( [6 F$ b0 O/ i4 Q, i: a
  i+ d7 p3 O' u/ e    /**. ~  \* T  h: D/ ]. m7 t

1 X' {+ t& j* z! C    *@devConstructorfunction
# S5 T0 O$ s# ?! E) A6 h9 D5 ^- X- g) w7 h2 F
    */
) h" v1 x( T! P! O8 ]# c: R' K( z5 ?8 Y
    constructor(string_name,string_symbol)public{
1 _, v8 B: Q8 m" K& I
% |3 H# a( s* h1 e+ L) S* @! U    name_=_name;
( {) N8 h; m) }/ \8 \* Z
& y9 l/ t7 T) u. a7 I    symbol_=_symbol;
0 X  M- k( s. U
# H! `. W) x8 n( y1 E    }
. W' `; u4 c% Y9 i( I9 u. I! s7 N2 `: m: `) \
    /**! x2 a% R4 a1 p% g

. \2 f4 S* D* }, H3 [    *@dev获取代币名称" E: P( p8 f. l$ E

6 w$ S2 [( m3 @& f: o  i' ]% r. u    *@returnstringrepresentingthetokenname
; T) Q# G' H$ q& F5 i# D. z* a- j+ }+ D* a4 M# l( G, M
    */
+ e' U: w4 u1 H# Z, w7 \
' G% r! m- ]1 y2 L% ]% L    functionname()publicviewreturns(string){0 N3 }8 B$ B+ U* I

$ ]  A4 s" i0 m* f+ Z    returnname_;
# y* }8 d; g* y! G$ u* L
% {9 C, [) y! v5 g    }
- O+ a3 d' P: t- F: X9 r7 B/ X; f5 g1 t% ?: h
    /**
* v9 |2 Y: Q0 W! {  A- p7 L: R2 _# y2 x2 @
    *@dev获取代币符号, p# ]% X+ k2 C" r- L
6 C3 X) Y" T# U/ u
    *@returnstringrepresentingthetokensymbol
3 {+ H$ @3 }; h' g/ J1 o4 @/ J
, V9 x: Y3 y8 ^8 M    */5 J3 c1 I. b7 B
* {* B( g9 k& A5 V3 @7 {
    functionsymbol()publicviewreturns(string){+ g2 U  j9 I) S! X, s) Q9 D! u

' }  V: S; }8 B( A    returnsymbol_;" C+ O+ u$ M& U/ d  X

; x) Z  k- j6 o! I- D    }) _+ V8 e: M* H* [9 O" l+ t

1 Q2 k2 S3 l, k" L  z8 X  x    /**9 Q  b! ]" S1 c7 ]9 V' ^
+ B$ }  o& z0 }: d, a' M
    *@dev根据_tokenId返回对应的资源URI
$ e, P( T6 e/ ?" W( P
) P6 w- }" v4 s0 k; k! I: [& ^    *@dev如果token不存在异常返回空字符串
4 V* Q# @$ x5 Q$ v( I- `- ?, M" o
% n3 F! o7 z+ K8 q8 `) i    *@param_tokenIduint256IDofthetokentoquery
# ^% q! X+ ~+ V4 |% p% t
( t# t+ _- i& A2 m    */
$ X: m& [- Y- i3 v  e$ D6 A6 f3 E: ^8 s# ^$ v3 v7 [
    functiontokenURI(uint256_tokenId)publicviewreturns(string){
1 ]+ V3 o4 Z  y$ z2 Y/ h
' }4 X" j' R0 C( O4 g" q    require(exists(_tokenId));
1 r6 Y- [; u9 q1 q0 L
( s) a+ w0 |/ @5 x; v" P8 g    returntokenURIs[_tokenId];9 z3 w0 p4 {/ g6 k+ K( b* y  W

* _2 D3 W4 H1 p- H9 Q6 J/ A    }' k7 {) |& T: F% x& C, o/ a
* O( t# P/ e% W* E
    /**& O6 N& w( k& d2 }0 T) |/ m

4 [: r" L" X6 w" y& e    *@dev获取tokenid通过给定的token列表中的索引
: I5 X7 L% W+ v* |  W3 o- u' B5 M
    *@param_owneraddressowningthetokenslisttobeaccessed
. a4 I& w$ {/ t' n5 e
* P" V: [3 D" E  X- N9 b    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
6 O; w4 y. J  e& v, p3 R! K/ p! [& Y2 i* q$ p
    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress2 z/ R2 m& x; n! d6 H6 D/ [

4 d! \  K5 a0 q* c7 _* P    */
( \6 m: C, P) t5 J# ^1 N, s
& }# U* E4 }" b& B    functiontokenOfOwnerByIndex(8 G! Z( i. y9 M0 c( O, y7 {3 M
2 |. M% A- Y0 x! j0 z
    address_owner,
, j0 R( Y8 L3 ~/ i0 E6 c4 h0 n1 @$ e' B. R' e
    uint256_index
% y2 ~* w# \6 y- ~( r9 Z% [# T( X, _* @4 }# x# w
    )
$ n) C4 R3 t9 Q0 w% E1 }2 s
4 L! M: D, |0 J; C$ O- H! D    public
4 z  I8 {+ E2 ?2 v& }; j3 H7 G7 J& N" s- x$ F2 f
    view
1 w4 O0 u1 Q3 v3 Y: i$ m+ Y5 p/ n; k( c- T1 L- z8 S) i8 i8 d
    returns(uint256)( Q6 w& H, K7 }' D$ i
7 e! J% u' F3 B& Y) ]
    {! f; G- m7 A& \3 s9 b2 @
7 k( `+ Z8 p" A: ?+ [, J( o# ~
    require(_index
* h% Y8 S4 j+ P  }1 h
% H1 y7 S9 }* ~  w    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
: o; h# ?" @7 a8 t5 L% g$ }1 Z- a) h
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2