Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2396 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
. ~4 p' ?7 A3 r% W
$ R/ q! _3 N; y: E0 C' k0 d6 a5 l    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
7 n& s9 N" e9 `7 G" F  ~
. z- ~- A+ ]3 I1 G, E    ERC721Basic.sol
% s5 T% ]  V' u5 A4 ?0 \
: d' \& W* ^. B, ]+ O    pragmasolidity^0.4.23;$ U1 u0 N, \; l2 L' w
' ?. i' V  u4 Z6 p; h' ^  D
    /**6 L! K$ u3 F3 c$ F8 b

5 J6 N# M9 q# K2 ]0 l  ~    *@titleERC721标准的基本接口# O& z/ }9 a8 W0 \) q# s

+ }6 |2 I' F0 _0 g$ B, H( v    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md* d" _: F/ @9 v/ U
. Z( Z+ U8 i1 g  L4 i! d. X
    */
3 l7 }" J4 [7 c3 |
* F3 J4 J1 u% P) K# p2 V$ s    contractERC721Basic{
. c+ }- M+ @$ b: P1 b# O8 |( B: f2 p- K  y/ h1 f- F3 F
    eventTransfer(0 j  R% Y$ ~6 z- I* c6 a

! Q5 q6 g' ?4 L    addressindexed_from,( `! U/ U0 R0 G9 ~1 z* w- _2 `4 x5 j8 C

# a7 g7 J) s1 y1 X1 J% H    addressindexed_to,
% q2 H4 ^  P% P$ S- E
9 ^2 i0 m9 _- J$ g    uint256_tokenId
5 l" o* v" G4 F  W" M7 M$ q( H7 \" |; C0 ?& X3 Z
    );
5 a% B3 y/ u9 p& D+ U) @! }! D$ g# x
    eventApproval(
$ O! _6 }* P. E) ?$ G
% Z( c# e7 {1 K. M; v1 M    addressindexed_owner,/ m2 m6 s2 f3 w3 @9 ?9 U; [

! Q/ k7 \2 Q8 R& U    addressindexed_approved,1 ^0 C0 _; u0 v+ \' ?3 F
3 v& `6 Y2 p0 ^. _
    uint256_tokenId' o5 ^9 f# i. Y/ `6 \
; [$ g) K" F- j' A# ]8 o% I# j. O
    );
# k9 o  A: j5 y  l* h% |8 u! C! v3 g$ ^
    eventApprovalForAll(. G# [) X! \; H/ J" h' I0 k
) D5 @4 V5 l1 C; f! |: o
    addressindexed_owner,
% E$ i# V; q3 \+ B) h3 z- v
2 A, G* e" [% i* U/ f    addressindexed_operator,
0 A3 j8 N2 ?( ]/ B$ F' C; |0 ^1 }5 f" c" G
    bool_approved- e8 Q9 J- d/ @5 U- h9 ]: k
0 _/ _  q7 ^% }" F( @% J& Z1 H
    );' Y5 C& O* Y  R* ~: q! z
$ I) `" e! J; S# H& [" E
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);, c* i9 M. I$ n5 j+ o; I0 U" @

8 o# j6 [4 }! e2 K3 e. S$ S; Y' O    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);4 \) _4 o* b$ a" m4 L- {+ |+ _# k5 L1 _

6 {) U8 G5 H$ V$ U" N+ I, F    functionexists(uint256_tokenId)publicviewreturns(bool_exists);
2 z8 b3 u; ~) |$ M, U% |9 J' f( ]* y6 x( X: _1 j
    functionapprove(address_to,uint256_tokenId)public;
4 {1 a) [3 x$ y8 B6 J/ H& b+ }+ t" l* x: M1 U
    functiongetApproved(uint256_tokenId)
0 u) h9 a5 G8 ^  q; ^* {2 V. ~0 {9 B
    publicviewreturns(address_operator);
- e. B' t8 w' z7 X3 R
$ H: w1 _( f1 w5 L$ Y9 \5 S    functionsetApprovalForAll(address_operator,bool_approved)public;! M" g- f; x" @/ i# O$ E

2 o( X* l  R9 Z! R% B2 s& d( q    functionisApprovedForAll(address_owner,address_operator): e. G2 `6 w; ]7 s% x

" X% b' k* p1 Q; \+ @7 w6 D6 k    publicviewreturns(bool);
- g! w+ O$ ~( g, N4 |2 ~8 n0 Q! l8 l. i0 z4 K$ G
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;1 U+ g, B" e4 r, ]5 {) M/ w

' B! e8 V1 y: b; I, X% i6 E    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
& Y8 \4 X: A' a
" ^% s7 B3 S9 E) f2 q: ?    public;2 ^) x6 x0 |$ k/ L+ |

' l4 ^( z' Z3 A    functionsafeTransferFrom(
) @/ a! R" N/ |% i# u( S. r( T5 m6 M4 e& e0 @# P7 v' O
    address_from,4 l+ x: \/ u, F) R" A

) i( m5 S! C- N( @6 i    address_to,$ [6 l4 u  p) A) }3 }

$ N! N1 T9 k' s) U: E: T2 g    uint256_tokenId,
6 x% O  [% |2 k: o: v# \
* K: X- [* M9 p* {2 K6 M5 M# \0 r    bytes_data7 y8 C) @1 Z. W# C/ `8 q
$ J. m5 K/ s+ V8 G8 q5 _$ F
    )
" E4 n1 ?( @9 y) c8 G+ }! Z' i1 f& w' B! C$ ]- k6 r* k6 n1 ]( q
    public;! [& B2 I: N6 B

! x: b  S( r: N& y" G$ }% o    }+ k9 ]) o# s* D" J) @
/ K. E$ ^+ a5 z4 W
    ERC721Basic合约定义了基本的接口方法:% B# F. p! g, Q8 o  Y
5 Q2 y" a- D+ F$ D, q
    balanceOf返回_owner的代币数量% t  Y4 d( [, W  N
; u2 `" ]3 m: y" `
    ownerOf根据_tokenId返回代币持有者address! F- b/ p1 i* K. b5 F0 h/ Q
: j  w. r9 @+ H7 ]5 Y( V; T+ u
    exists_tokenId是否存在& A7 Z' j9 g$ D! J/ M

, E8 i: A# t6 D8 p) F$ j    approve授权_tokenId给地址to' x" e9 U  }$ N: S2 b$ }
: ?9 P# k" q: p
    getApproved查询_tokenId的授权人_operatoraddress
! r) {: a8 A6 D& M3 C5 T  g; f; l5 I0 K& f; G6 K, Z- p* D
    setApprovalForAll授权_operator具有所有代币的控制权
' |' o5 X6 m  b5 x/ O, N% N3 t1 n! a: G
    isApprovedForAll# [3 F9 S1 A& }* c/ {
- t5 M% r; J  r: t& x
    transferFrom转移代币所有权
' L( s" B! [1 R; S# _( i
! ?1 f6 T! r3 k1 E! g; x    safeTransferFrom转移代币所有权
7 i: ?/ \+ j1 {& d
/ c9 G) G4 e: g' S+ H1 X) y# n+ d' w; Q( }    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
& v9 Y* U1 A0 ]7 Q+ N6 L9 n2 ~0 G  e/ d- ~! [
    ERC721.sol
, N9 A' H* |9 R; W: P3 X4 A& b; P. q# X
    pragmasolidity^0.4.23;! X: Q$ }2 G) Q" t# K
) `7 @4 b+ ]' `6 T, r
    import"./ERC721Basic.sol";
1 c8 _$ {% ]* B5 J* ^+ m2 `0 }% s/ G8 |& x# }
    /**  u: F3 z/ ?: x4 A  D3 g3 V
- f8 L4 |% T. ]# N+ l3 h5 K
    *@titleERC-721标准的基本接口,可选的枚举扩展
& M% K% A0 d) y$ Z
0 t0 ?( f& l( u9 E% P    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
! u& @9 _+ Y) K( M5 Z
  {$ R( \* I; J+ ~    */
  t8 p# n8 \; P& y9 L$ `7 \
  P/ Y3 C, M; ^5 f- u    contractERC721EnumerableisERC721Basic{' a. K$ b1 z/ `% m( n  F8 r
8 Z9 j: O3 I: k3 U1 p  w
    functiontotalSupply()publicviewreturns(uint256);( ?9 z9 G7 d5 {+ S
6 b3 j! t/ @" L  T
    functiontokenOfOwnerByIndex(
! D9 c+ G: p& [4 d0 C4 d% ^3 O& x' ~+ n0 j. k% K7 R+ x
    address_owner,
2 G0 W: n5 \* B# U; B  t  n- _& Q
, a  e! [0 G3 w& G% @, l% ?7 C    uint256_index
) M; v0 a* z3 ~8 F8 {" j0 H6 d7 T9 H
' r  n8 W8 f8 Q* N, O* M( Z    )% C( t- M( S7 W- {" @4 s2 s

6 ?3 m4 A3 |* z( L. G3 Z    public
! X6 t8 Z6 r. t% D5 X: x
0 t! Q: P: U  ~# T    view
. C* t. [# A; |0 |& n1 u6 h0 M" b: s3 K! [- S
    returns(uint256_tokenId);  z& c0 Q0 h. X1 z

9 [" v5 F* B1 C    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
2 T, c- j6 C3 D7 ]4 h
6 J* q% Y6 |! G, O% [% L: j    }
# ?' X3 l8 c. h7 V' T) `9 Y1 v6 A' m9 `7 r5 `- K1 f% T0 f
    /**. b$ N4 U( B$ \5 s* j' F, j

, c( j! `" C6 r! Z& k    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展; Q$ x) W* J, ^9 ]7 G7 h' z3 Q

5 S9 K& ~& n4 s' M6 Y    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
5 f  P; n0 U, y! o+ Z) e& t( r9 T; N8 @3 V  F5 v, [$ t( s  i
    */9 @: k! [- R0 K( i% g/ R2 N  ]
& ~% p$ P9 P6 T) E
    contractERC721MetadataisERC721Basic{
. `! N5 o( c- z1 t& X( N7 V
! l, w# n7 Y& q3 Z; d    functionname()publicviewreturns(string_name);
1 u. l2 t& y1 p8 x2 R
+ D7 J! c' a0 F6 ~# X    functionsymbol()publicviewreturns(string_symbol);6 P/ g) o, i; Q5 H
) w; J& |, S, I# q% X* D% I+ L, _
    functiontokenURI(uint256_tokenId)publicviewreturns(string);, h5 P3 ^1 e, H( t2 E# ~+ N  v5 X4 W$ t

5 i! J; g4 ?3 b2 i    }
1 O* O0 J+ z, \  a0 B- N  g& k' F
0 c( g. E1 m" ?& n3 o; t! Z    /**
/ ^& m* l! t8 c4 f9 V" e# i5 J7 Q, ~- M* m8 n$ ?
    *@titleERC-721标准的基本接口,完整实现接口2 Y! w& Z0 Z- E2 f! J: i! {7 U% {

6 m. o! i1 _3 G. `    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md* r. k' G3 v1 j, z! b
6 e6 q3 X! _  s3 o" P6 W' o
    */
. J2 b, W" N# r" o- u2 y9 k! B) _, q, i
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{, a# K$ I* T" D; v0 W7 h

/ p* F1 B' L, z; Q$ t) c2 I: l8 X    }2 C! k! W* y5 w

+ J5 e1 F- k3 B( O3 b. C5 }- R$ Y    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。+ u, L- W2 ?8 t3 x

8 F( H3 h( t. ?7 e/ b" r; Z    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
8 N! x$ N* y" Q& m5 u5 y3 q7 p3 ^0 m6 r9 s" h
    totalSupply返回代币总量
, h) \% q0 g8 M& o6 h! {; _. X" T5 ^  `% U: ?6 k( j& v4 `' m: ]
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId: Z" B& \1 ~6 ~& k' h% M

+ c$ L! Q& K. x9 u) n, C    tokenByIndex通过索引值返回tokenId% w3 }' A9 t, Y& `+ U/ ]  X( S% V

. d, j+ `0 J* D, B& K8 f& C    ERC721Metadata元数据扩展哦用来描述合约元信息
' u/ n# G# L/ n: n! b7 l
* G3 G  C/ B6 B    name返回合约名字
( a' Y4 e/ e4 l* k
& {: M* f5 O- W6 q9 ^% ^    symbol返回代币符号
  }% y0 x0 q& b7 i; J# v
2 N3 e( k) I3 t# s8 F5 j9 v  w5 G    tokenURI返回_tokenId对应的资源URI
1 U! Q+ z' i) w& J; j2 a, u. U2 f2 a2 p9 h2 M# f1 z' K2 m1 b
    ERC721BasicToken5 n. D6 p7 p* ^

& k) j$ L2 u* F    ERC721BasicToken
8 z- v: p1 d/ L, d% m
* u# L: S' f6 Z5 F4 x0 K- u    pragmasolidity^0.4.23;' g- \$ A5 I+ O1 q) n

, @0 n$ K( Q, r. y& `# C    import"./ERC721Basic.sol";& W6 x2 H' l! L5 D9 t0 X, U. ]

" l1 s  ~! p4 e. Y+ H, i  i$ p    import"./ERC721Receiver.sol";* y9 [# s) H3 A0 j

. q9 U8 i( x8 x4 K, k8 N8 C    import"../../math/SafeMath.sol";
5 U8 \/ A6 P) Q) n% b7 w2 h! t; o
1 @: b6 x' M7 b# m    import"../../AddressUtils.sol";
$ @  G' b( b+ C6 B. k% C
* M# ?0 h+ l4 B: O6 y  f2 _# N    /**
4 n* Q5 f* Q4 M; G: ?* i6 {
& }0 @0 F8 |4 ~  n    *@titleERC721标准基本实现
( y& L, u; M0 m: a; U) M4 S$ h7 I' m" d7 E( N( {: Z# D1 A
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md( Q& a, L  y" i
. V2 F5 {6 ]6 S3 H/ n/ f
    */, \3 @% t  t) G
( F+ Y8 p0 r. l2 E
    contractERC721BasicTokenisERC721Basic{
1 d" L* j  N- U" V" O: `) ^) h$ R0 D6 Y. R
    usingSafeMathforuint256;7 U  t/ }8 N. r: f; U; f$ z% ^% Q  J
6 F$ R0 {/ n3 a; L
    usingAddressUtilsforaddress;
: s1 x% t# N& p  E5 Y
/ s% R" f) }- y- ?7 h    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
0 x; [+ g* X# t( S
! @" D6 l- b1 |    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`9 b2 z4 l+ T/ M" O% h  S

9 A5 |# f- w* O6 P    bytes4constantERC721_RECEIVED=0xf0b9e5ba;+ Y: R/ c9 \& Y% I1 o( p
" ~" d+ }* K$ f+ G- w# c, c
    //tokenID到持有人owner的映射
& k' O1 y, O, @1 Z; q5 `; m* ~3 H! v' V# r( h" @2 X
    mapping(uint256=>address)internaltokenOwner;
7 |3 \; b, ]$ X# Q" p+ b6 P2 }9 m9 E! a, A7 v
    //tokenID到授权地址address的映射
1 x; Q3 w' J4 I( K: k7 D
& N. l: P; _  @# C' x0 m6 J  M    mapping(uint256=>address)internaltokenApprovals;
+ f8 [# C6 p# _( W
6 u6 ?4 G5 n8 T7 y/ V+ \, ]    //持有人到持有的token数量的映射
1 t: J- P% W/ Z2 s& l
3 I/ h3 s$ j1 ?5 I4 c  |8 f    mapping(address=>uint256)internalownedTokensCount;4 m! X, N5 l5 D
, \) N; k4 a4 s
    //持有人到操作人授权的映射' L; O" U9 H6 l9 ?4 K) B: S* ]" a

" i& K& w3 e7 D6 ]" s# I' M4 Z    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
6 r( s8 u& r$ U# H% T# v" E+ t3 i/ Z& G4 U
    /**
- p* b) P1 ]; N# N* U9 z0 I; ]6 \/ c
2 A! D( p3 O/ k' i8 v# Y: ]1 _    *@dev确保msg.sender是tokenId的持有人$ y. }* R* n9 _5 Z8 i" B' Q8 M! U

. R7 e& g9 u9 M- z# \/ p    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender* p- v+ P4 d: P

' |3 O: m8 P) J+ X  M) t    */
4 h; M( v1 V  Q2 Q; P2 d$ H9 o8 a
    modifieronlyOwnerOf(uint256_tokenId){
" ^' c* W& k( A# R: C  E. E
- A# b& F  x' x/ W" ~: h+ o    require(ownerOf(_tokenId)==msg.sender);3 E* M5 g9 k# b- @
2 W% B& P, y/ ]% i: m% N: e7 q, s
    _;* b4 X* {- Q6 }, I1 P9 G

0 L3 B3 W" I, \& b; A+ |4 U    }
3 }$ i, N! j+ G  ?% o% \$ p: c. u5 B* y# {9 {2 F- u$ w/ |/ ]8 X
    /**
; [; F$ q" j" R7 D4 `: j
0 B2 V- r9 ]8 ]. X1 c  {( W/ _5 Q  X    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token4 M; u0 {0 X+ y' Z

! r/ q" G/ n8 p9 I) k0 w- V& K& A    *@param_tokenIduint256IDofthetokentovalidate& K: u* j9 p+ s! ~3 U5 u: ]
* q. u( M; U$ b# @+ Y8 H# F
    */
+ o1 t5 q) W0 k/ ^, c3 B8 y, x
( R. N7 r2 s( Q3 L# J$ N* B    modifiercanTransfer(uint256_tokenId){
' _! ]2 x7 t# p9 C, q  |
% z$ R4 c/ R+ l3 @    require(isApprovedOrOwner(msg.sender,_tokenId));: u$ o- Y9 ~" t/ b! X
  t* s( I% ^7 e$ ~7 h4 E: {
    _;
/ ?, U8 ~" n# e4 l* Y: i$ @+ q# }, g
    }* T8 V8 M  l: _% T' r

% c- K, f: @3 {6 I    /**
2 Q1 B9 J  ^5 j
7 i; G$ c; k8 X( V. u2 p    *@dev获取持有者的代币总数
- r  J2 ^- T" I  ?
! d0 X8 n9 a* x. r! G6 Q    *@param_owneraddresstoquerythebalanceof: K2 n5 e/ W: V: @

+ y- `; l! M8 g+ z+ J" N    *@returnuint256representingtheamountownedbythepassedaddress
2 }* Y5 T$ t+ f& L! r' N  I
3 G! }, R7 }5 g- u, Q    */* J1 \: b  j8 J" G4 K
2 P: ~+ a: u5 J4 u. J3 N2 O2 [
    functionbalanceOf(address_owner)publicviewreturns(uint256){
/ b) F: b- F5 `# E0 A
; u/ ^4 l% H" k; e/ t    require(_owner!=address(0));+ Z. p9 [2 N6 }- w# g* f8 Z
3 W1 W$ g, |3 N6 t4 X0 i
    returnownedTokensCount[_owner];
5 j$ L5 q( L7 A% C  k
/ U- H  r, [/ ~$ ~6 D) g" ]    }
$ s7 }" k9 Q' c* j! S: m
! l1 v% A- w; f8 j( e    /**: P- g8 H% @3 i2 v2 X  k& U
1 D4 g" A9 @# P& v
    *@dev根据tokenID获取持有者
+ m: `, n$ p5 V
7 {5 Z" y" {6 w    *@param_tokenIduint256IDofthetokentoquerytheownerof; X, O) {' y1 W/ w0 j

5 T1 ?' Z! ^0 I, I2 L4 l    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
: D0 L: F" ]6 N7 Q1 z' ~* m" u4 B* ]/ \* n! M8 L/ g7 N
    */
+ J9 ~3 L* }" A* j+ u8 g% w+ H9 G$ O% @9 Y
    functionownerOf(uint256_tokenId)publicviewreturns(address){
% M" K+ r6 ]. h! U" B  U8 w! l4 B$ S( L: I
    addressowner=tokenOwner[_tokenId];
( H7 ^- T" t# k$ Y& P  w1 [# s$ x5 n* g* n! f, e) _! O
    require(owner!=address(0));
: o7 A( W5 O. ?2 u! c. ~; p  e
# Z7 s1 ?: i3 L5 y4 B0 a' B    returnowner;7 V& b" w* S0 t- I9 `. y

& e: d& A) e+ N' m. G/ a    }
  V7 z) S4 s9 N: d" A. `4 s! Y0 p8 W; l5 V& J
    /**
7 X  g- G2 x) @3 y
$ A/ W! f1 \) e    *@dev指定的token是否存在
: s- S& Q3 a/ b/ a6 Y) N1 y  C% {' Y8 T% j+ Y. l
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
" K' Y9 }; r( P# z; s7 k, U
" f8 Q  ?% K. U    *@returnwhetherthetokenexists
- ~/ `9 u; L, P/ H2 ^0 C/ C. J5 `5 n# f4 {" X9 U  S. ?2 p# Y
    */, A9 ~* n1 L% v! @2 u; e5 e

  U, i2 @( L* Q) I    functionexists(uint256_tokenId)publicviewreturns(bool){
& T& ]* B" L# _+ Z' C, Q# p
3 _4 ?& Q7 J5 |    addressowner=tokenOwner[_tokenId];
4 W; B  {8 c' A4 f' g. z
: B" O& Q( M# v) x6 s6 _    returnowner!=address(0);
5 q7 Q, D1 \9 G. Y" C" B0 s- x1 }' c; J5 g
    }
0 Q, m" d, M  P+ ^5 y6 A% J5 s" {% _* w& Y: M
    /**1 V2 c* j) S# ]) ?

6 s' G( c' B9 R1 L4 d1 i4 J9 S" b    *@dev批准另一个人address来交易指定的代币
% ]! n' |0 _; D, g( u, p# D" Q5 r% ~$ r2 ]6 w" l
    *@dev0address表示没有授权的地址
& J$ h+ ^' {, U# R1 s$ q: d. t% Z0 _1 s: P2 A  `6 h% v
    *@dev给定的时间内,一个token只能有一个批准的地址
$ L' u6 q$ L0 z, k' ]7 b
4 }* l( C, s( L, b" p    *@dev只有token的持有者或者授权的操作人才可以调用  H% i' I& f- T
: G4 W; I8 w9 f9 f, L, X" ~) U0 d
    *@param_toaddresstobeapprovedforthegiventokenID
: O0 w& Q) x2 n! J
& m0 Z+ y+ C( ]- d3 ~# K5 [3 `, J9 q    *@param_tokenIduint256IDofthetokentobeapproved0 o+ q+ M4 o8 m0 Y5 W6 y2 c

* d- K* N5 V0 N& V& Q0 m    */$ X: ?; _( y0 C" A$ G  c7 W% }; H

1 `1 k" C- X  X) \" C+ t0 ]    functionapprove(address_to,uint256_tokenId)public{
- z! O5 f4 i1 F7 {! x- q$ A1 [1 y$ B* y4 Q
    addressowner=ownerOf(_tokenId);
# A7 C: z; `- ^
: Y& P+ A% L7 g2 Q8 U' u7 O6 j' ]: q, R    require(_to!=owner);
. R" a7 g! f( [6 v2 ?7 i; p9 O+ Y7 f) Y3 q- A. _
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));" [& r% W4 V: X

& q6 I5 M  ^4 g* j2 E; v0 G    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
, t6 o0 n/ L3 M$ S, P
7 j  C  P1 {& |  X9 ^5 q    tokenApprovals[_tokenId]=_to;- F/ i( R+ Y! L( ^
- X5 n- G; ^! \1 }
    emitApproval(owner,_to,_tokenId);
; W' T% [# [7 ?6 y' ]* z6 s' U3 |
7 k3 V% ^3 s' {5 P  U+ o    }
; R) F" _1 Q. t5 i. ?; E5 I% q4 r1 M! j. a
    }
/ d( J! p$ H$ X1 J4 A1 ]& y
& n4 f' U8 T5 ]$ Y) l2 i7 \    /**
( T0 \3 F  S. ]" ]8 M' M4 j2 L7 L& W  t
    *@dev获取token被授权的地址,如果没有设置地址则为0
4 z1 H1 S% B# k* s) V' o2 C) q0 z/ b  x5 J3 O1 ]7 S# e" Y/ ^
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof1 g' r& R" ]- `

4 G* h8 ~5 y+ _3 g    *@returnaddresscurrentlyapprovedforthegiventokenID
' J, x) S/ U& [: ~" z5 g7 W
1 _* G# f% Y  }8 {3 P5 T$ I# E8 |' E    */
9 a8 S. _& o4 L. o
+ J9 c' h+ n& T2 R6 X9 A: q3 D    functiongetApproved(uint256_tokenId)publicviewreturns(address){
- Z3 G  J5 f7 _% E; W  X4 O# v/ a" x! c5 {+ [; G
    returntokenApprovals[_tokenId];* c0 P; C7 `, P& B1 \& C* k* k
" l6 `) U) b9 Y: u( N. ^( k
    }, v8 ~1 u( J- w! w4 o

$ Z4 |9 c6 x* r4 u6 `. ]1 f    /**
9 ]1 F" G8 V& I2 T) |8 [
7 _! q% Z- V! D! \' e. G- c    *@dev设置或者取消对操作人的授权
) v8 O! y8 d5 z) f" S( Z0 Y, O/ s! |- Q  A' {
    *@dev一个操作人可以代表他们转让发送者的所有token( q& t+ V2 c, A' T; ^. q  I- \

9 t* j; i% Y" x- `4 s    *@param_tooperatoraddresstosettheapproval
* t* _* M$ h+ B/ @. G0 g6 o2 K4 F  c2 t
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
% T2 V( `, O8 H
9 Z& {5 T* D' F5 z    */
/ s0 }; C! O8 {+ b, x% b( N2 x' D! c/ f5 d2 Q2 i
    functionsetApprovalForAll(address_to,bool_approved)public{
7 Z: Z# E! {1 H6 s) F. Y: m- K7 R5 s8 |" v
    require(_to!=msg.sender);( G% r. \% d  h" T8 ?8 B
# l% `$ C) q/ u" y) S
    operatorApprovals[msg.sender][_to]=_approved;
4 D9 y) `, `' G! o  P: [5 i$ |( m# H- u2 a" |8 J
    emitApprovalForAll(msg.sender,_to,_approved);( s9 M+ S+ Z8 ~2 \* [" E( [; c, D
) {6 f% M1 w4 M( F) T9 h. ^7 O1 \
    }+ z& M  q4 V4 x* M2 `* V% A
& k* w& @& e& r" y  o
    /**
6 ~: w, E1 I5 r) }0 U
/ O6 N: J( t6 |! C- m  x9 y& i    *@dev查询是否操作人被指定的持有者授权+ t8 N6 \! I3 _- j2 J
0 Z) [. g3 N  D' A4 Z" U: e  u/ j
    *@param_owner要查询的授权人地址
, f7 j+ v) u. U1 L
1 @$ Z$ g; n) M% s, ?% N    *@param_operator要查询的授权操作人地址
9 {, }3 A0 x. V6 ?. u# r4 B# c0 t6 Z# W9 B* Q. H7 k; t9 r  X. J% A" k
    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner/ x3 q4 p$ h; y+ K6 j$ H2 a
7 }2 i1 A9 N3 n) O- a
    */
. Y5 ~+ ^# N- t# ~; G7 o6 Y* Z0 e/ H5 G
7 N1 m+ L5 A7 D& ^' F2 a* ?/ d6 Z5 \    functionisApprovedForAll($ G, Y/ l1 z  g' {4 ~
& X, M! ~. Z6 D  f% k
    address_owner,% E; [7 e) }5 B1 Z4 a" {
3 f6 t; b1 X' a) U8 `
    address_operator9 f3 u8 S7 J( y5 r9 w
0 w2 l3 i7 E& {, }+ ^% ?
    )
% F7 `9 |2 w# C
& Q% e% X9 v/ L/ G, |4 T    public
. `( X1 L( Q1 H) b" v& b. ]5 t7 t7 |) J2 `1 \: E. ]3 g
    view
& i# \0 ^4 z% S9 P& h' R. l8 s! ]8 ~7 \
    returns(bool)/ B4 r$ \! \/ b, {

2 M, q9 u2 c% I" p1 [    {
5 v9 Y  `6 x) N# P9 X$ _, i+ Q9 X3 l- \% s" {4 C  m9 i
    returnoperatorApprovals[_owner][_operator];* a2 P, r9 J) f9 c$ C$ g: O
  F4 G" k* k' q) T+ w
    }  C( J: e/ j% F* G( E

9 q( F  K6 ]( Q    /**" ~" Z+ U) j( `; H/ m+ E) d/ d
4 y; |0 T* R/ j0 O
    *@dev将指定的token所有权转移给另外一个地址. o4 D: x& Q+ D/ T
7 {% ?! A7 U/ ~) K
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`: s+ G8 N+ o9 u% F2 r/ q

! M+ d" I. r/ j6 Q1 ]    *@dev要求msg.sender必须为所有者,已授权或者操作人
5 O( s) j% e; }" X9 T2 i' U. C( j# J/ Z; f3 K
    *@param_fromcurrentownerofthetoken
' R: J$ [8 a0 ~6 F  x7 D9 n1 z; U0 ?1 r3 A. v: R6 |
    *@param_toaddresstoreceivetheownershipofthegiventokenID
5 p, w  Q/ l! a$ @, y* ]
. ?0 ^1 ?5 n. E5 `9 [; x' E    *@param_tokenIduint256IDofthetokentobetransferred1 l0 v2 ]3 i* z7 d: B
. Y; C# j$ P3 O# v8 }! P) v9 q
    */
& ^2 s' \0 i+ h  K' Y) `  J0 k7 G2 Y
    functiontransferFrom(# R. `& I6 [7 k5 p

  ~) r2 Y9 Z$ ?6 `# k6 @3 b2 s    address_from,1 z1 \; ]9 g6 ?' F2 X7 ~
# J% J% G9 j/ T" f* H
    address_to,
2 f+ |' h" B! s# Y6 j
5 p1 m8 f- u3 D) ?  [. X4 Q    uint256_tokenId& K8 M5 l2 q7 y" B

* Z$ a# ~" S! q+ E5 N  T0 Y: D    )* ]+ v8 M+ ]9 }( |  T
% F3 ?  r* z2 _3 W1 f  S
    public
9 B) T' P0 e7 O- Z0 z4 W4 w
* n8 x+ I7 t* S" U  F5 |3 ?    canTransfer(_tokenId)
3 q& ]/ T& e+ u% P! ]
/ w& t9 r, O: W5 ]6 J3 N& w! z    {- {9 m7 s7 f- B

+ Z! Q8 b+ ^9 o, K' g( d    require(_from!=address(0));
. S) [) I+ L+ k4 F# J
4 N9 R3 F* t% \/ B    require(_to!=address(0));% t9 V# L6 S8 _# b# ?
8 i# P4 r& a# t2 A. Q; A, s/ }6 Q0 S4 f
    clearApproval(_from,_tokenId);! T8 u, u( x$ r

2 ?" i; {1 k2 X/ K. m5 @    removeTokenFrom(_from,_tokenId);
, u( }- l. k/ Z, a9 }( z4 X' E7 \
    addTokenTo(_to,_tokenId);1 F# v3 K, r; W3 I2 }( [& `

& i4 q; A8 c8 Q6 A    emitTransfer(_from,_to,_tokenId);
, [3 u  D( j$ {" I" U
( `* O7 C9 d' u; Q6 `7 p  V& }    }
; y6 K& H, b* G3 C2 x% v: e! _1 R* w
    /**
% V9 S/ {5 x: {; u. z# K/ k+ a# a) ^# G% _0 K6 e2 d
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
: T  S' Z1 ]# m; |6 f5 i* }
( j: c7 [& l+ }8 B    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值. T; D2 p' ?+ s( _" t7 y: O

  J/ u: O9 C8 E; a- G8 G) ^    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
$ P1 s/ [6 K' B) d. L) N3 X/ v( I
' [/ o" W5 ]4 `% F" o0 N' s, K    *@dev要求msg.sender必须为所有者,已授权或者操作人
, A0 G& ?  g; B  ^2 l6 f- O) Z# ]8 w" D$ c
    *@param_fromcurrentownerofthetoken
# x0 v7 U8 \* g* `+ y
0 j$ U2 ^$ U* ^: R8 M5 K$ [    *@param_toaddresstoreceivetheownershipofthegiventokenID
2 Z% k9 m$ i% v5 q- P4 {) z- q- p" l
5 y4 e2 N1 r( Z. c8 r! o) c    *@param_tokenIduint256IDofthetokentobetransferred
2 z( `) [6 [% Y+ d! P1 H) G
; \) m+ r0 `/ [( Y' Y8 i6 R    */
) G% m" e9 N9 i$ H- c/ z
9 c% v8 T" F- `# u    functionsafeTransferFrom(7 f3 O& J, |* j7 n2 Z: @/ v6 A! d+ Z

: U3 B: \$ l( G; y    address_from,
1 m$ ^- ^3 z! h! W# w
! B$ y# C9 x# n0 p6 O    address_to,9 E3 r; m9 [' @- e  l

: g6 r; v& g! e& X! Z1 o! W1 \; A    uint256_tokenId, m) n7 Q& ]5 n; X' `# T% n+ \

* m; }6 D! w' U; I6 E# I1 F    )
: m# A# e5 e$ Q( @0 c4 b" J7 y* u  W  @7 H* |5 t
    public
7 V2 `( H7 ?+ m3 H
& ~0 u' v8 F, g% C: P5 p    canTransfer(_tokenId)
0 [) a+ ^2 t0 z  ]! e) Q
% H9 e5 q0 S; w    {! J) ^2 w) g, m/ P' l

0 d7 Z1 Q8 Z/ V1 \/ Z    safeTransferFrom(_from,_to,_tokenId,"");) O7 x) ^, f0 V: G9 j  B7 x0 J$ c

( o6 i7 H$ v5 `9 i    }& D& p" X# O; \- |: o8 f
+ u/ E" V" z' A+ V) E7 G) b4 Q
    /**! Z9 d/ i* j6 B3 U" o

5 _( ]4 G9 v; d' [, h7 T. i    *@dev更安全的方法,将指定的token所有权转移给另外一个地址" o/ k1 U4 d9 G; a  }, Q! I- W
8 P9 ?( C5 S4 v6 e
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值+ P. z! n( ^* x) ^; \

4 V) P' U6 }( p2 g* l    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原( |2 }. r( b5 I/ u8 B

) B" M# R- T5 o8 f: ^    *@dev要求msg.sender必须为所有者,已授权或者操作人
0 \2 K& y" P! d0 F9 B6 B
* Q% ?( C/ f1 |5 [2 P    *@param_fromcurrentownerofthetoken
2 H0 \0 B2 N6 O4 G4 n$ r# B' p0 O3 g5 o, }0 d/ _
    *@param_toaddresstoreceivetheownershipofthegiventokenID+ o+ {, d$ d5 |# L
" K  Y- Y; a/ g; o
    *@param_tokenIduint256IDofthetokentobetransferred4 K# G$ P1 a# r) L. U7 J8 p
. v8 ~. z% M" w& Y% r$ j
    *@param_databytesdatatosendalongwithasafetransfercheck
$ }7 c+ U" K9 W. _- u& N6 {( }' g7 ~
' d0 K8 i' p5 B+ C% V3 H& g    */
7 t) {' B7 V8 ~  v2 R/ M
: ^  @( l. `# ~& y9 I    functionsafeTransferFrom(8 L8 J* q2 Z6 d/ r1 t/ I; n
/ @4 b' n" u: t  V
    address_from,
( g: C4 C* U! Q8 o
4 y1 V) Y& C/ H* }    address_to,
7 v7 p8 _3 K( ?
$ n9 D; t5 V  V/ ~4 {    uint256_tokenId,7 c1 ]5 L1 q& ?' v; }; E; @

% W$ U$ s3 _( h& Y    bytes_data, T# T1 I) t, j6 `7 C6 o, Z9 g+ L
$ k) y; U8 D9 K4 \- X9 O
    )
; d5 t. o. K+ s* }
' `# l/ x. x! n  |" Q: V$ Y    public9 l- q& K4 G2 D5 R

4 {2 q2 B" [- z9 \! D" a* {8 o" ~    canTransfer(_tokenId)8 X2 [1 T( q( s. u; c
" w. x$ l1 `- V/ _3 T
    {
$ n5 @. q$ @; b$ H! V1 r7 X; s4 f% ^* J
    transferFrom(_from,_to,_tokenId);
8 s( @# M3 j* I( U* [/ @( D# F$ s3 _& b
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
# T5 g# j0 |" n' [: n
' l! F- t* V' [    }/ O8 k2 i* J! \8 d2 ]

! m3 k0 ~2 h  D9 X) W/ F3 B) w    /**
6 T: e+ y: e: E1 v* Y+ c) S5 Q. A/ v3 U6 r
    *@dev返回给定的spender是否可以交易一个给定的token
, M' S1 O* r. O! C  h
. ^: X7 P: r+ N    *@param_spenderaddressofthespendertoquery$ J; y, W* A! Z3 _0 S
4 C1 D( z, {6 M- s* p" |
    *@param_tokenIduint256IDofthetokentobetransferred
5 K' T) m4 ~% N3 h  [* G: e
  u* ?( y& }$ @7 j, j, f; x# Q    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,* H$ H6 I# Z  Y  z8 Z6 F" |

+ j( b! D2 Z" T& V    *isanoperatoroftheowner,oristheownerofthetoken
3 h) P& b7 c- H- b. g3 i6 t$ @7 g& ^7 h0 g
    */4 x' N9 a) X  h+ o7 L, S9 O3 d

' e- ]- h4 L  p! `, p1 x    functionisApprovedOrOwner(
; `& @4 q: H4 v) s, L1 X1 S" `! s
8 e; V4 w: Y3 F1 n1 _    address_spender,
- a7 g9 f9 ]2 P3 b0 y/ y" s: Y9 r
+ m3 y) D, w% O5 r) T; Y% S    uint256_tokenId5 a, K; W! P, O: X

# h5 j, {# r2 \, F4 K" t, ?1 I    )' d$ _, T8 m  B/ B: `& Y

4 M+ U. Q9 T% `) r. T5 }    internal; Y" [" a+ S6 I' R: u

- F0 N0 p- q) _* m4 _9 z% D    view
4 k/ ~5 M1 S& `1 d; {8 a1 q7 U0 }% U6 i2 ?# I
    returns(bool)
3 p# a' H) g* ~' Q' A* g' T
& Z* y0 u; q+ m# P    {9 {6 i- T& `, u1 O
& ~2 o1 b2 S% b; G
    addressowner=ownerOf(_tokenId);
; ?* _2 I: E- T
) f) u' O! H* E3 E& F5 m( p    return(! Y/ ~( k6 S' C/ S( ?- {3 _
. W3 t6 h/ N6 T" n
    _spender==owner||: n9 p# D# b2 p, |! y9 o+ u
; c! ^$ ?$ }2 f. I
    getApproved(_tokenId)==_spender||
) w: E5 o4 ~' Q8 J3 _1 T3 j2 k3 V
" _0 b/ ?4 Y5 E' z" d& L    isApprovedForAll(owner,_spender). _% g+ m+ }$ o* N# L
: J5 R0 l6 v4 I3 m5 ?5 y
    );
+ ]' G/ s, F( P+ K+ y5 ~
; N& ]& C7 V: g) ^" c  l  W    }8 Z+ }& [7 L, g1 E( r3 U
% r. N  O5 `# p
    /**, Y8 [+ m! ^* Y
5 Y1 w9 w* X$ O: C8 x4 F+ X
    *@dev增发一个新token的内部方法
3 U  z8 A! F7 E& }2 c
0 C- ~# J) R! B2 ^    *@dev如果增发的token已经存在则撤销! a' f: C) x0 F, T: H3 K* E

4 f0 `) P. h, G, r  |( K3 `    *@param_toTheaddressthatwillownthemintedtoken
( S) v- E9 E% \; \4 I
, i  K/ K5 I/ F5 t5 i* ^" c    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender
+ [0 X1 G: {' W% E% Z) [4 _9 @3 w, O6 d  C- s4 z( }  j" @9 X
    *// [4 Y% `1 O5 [* P& G; @; b5 h
; g. A: Z  X$ C" R$ Z
    function_mint(address_to,uint256_tokenId)internal{- Y9 x( i  D2 w- J& c" i% y
, A! Z3 o$ m3 W7 g' Q6 \- v. C
    require(_to!=address(0));
% [7 y4 o& V3 K$ h9 G. w( M/ f  v, ]
    addTokenTo(_to,_tokenId);! H3 L; Y' L, t0 n5 K2 o
% p; e" f0 q7 P2 V! w4 p/ T: E, S+ S
    emitTransfer(address(0),_to,_tokenId);5 Y. M6 z+ b1 r% J# D/ V8 n
" m5 }7 S: P7 ~  t0 ]  _" C) g
    }
, d6 a  h7 r: x9 B9 i& v$ [" O: Y, k; S9 D
1 z% m  n* p% y7 J- Z( {    /*** |2 O+ X; c& k  g+ g# g1 R3 i; Y# a

# @' u/ \+ d! q4 s* _* m    *@dev销毁一个token的内部方法
% d. t' Z. N$ f8 Y! g
' ]0 m+ _$ P4 s    *@dev如果token不存在则撤销
5 \2 P7 d0 ^* a: j6 x6 j; o# o9 q+ T* J$ S
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
- r) q/ W# L6 p
% L, N, B$ L5 D. k6 j2 ~$ r, r3 u" i    */' D- C1 M9 ?+ \( R! q
! g3 @2 o5 `1 _
    function_burn(address_owner,uint256_tokenId)internal{7 R, ~: X- w. M0 \% \1 u' i0 {/ V
9 x0 T/ E# [; c+ X* ~7 y# A
    clearApproval(_owner,_tokenId);$ V+ m0 X. L$ f

. ~9 O2 h$ e& W4 X. o    removeTokenFrom(_owner,_tokenId);1 G# ^! Q/ w* n3 _8 @# k

! Q- S3 A' P, Z3 ~$ h    emitTransfer(_owner,address(0),_tokenId);
* ]7 t/ u( e% N' M5 ^/ P; s% N5 H+ c; \7 l
    }
$ ]& X. @" q2 S6 y6 e( i! Q6 k+ |
    /**3 }, s! ^9 z6 V5 G4 e6 e$ T

# c* u( {" i9 c# w7 i' m    *@dev清除当前的给定token的授权,内部方法3 N% R( x( n$ ^; F
! N. u3 c& ]) R* J) g6 F
    *@dev如果给定地址不是token的持有者则撤销1 p0 n8 j. o- q, }
- i6 b/ y6 B4 p/ U
    *@param_ownerownerofthetoken
- s8 r5 R0 Y- i7 u2 k2 q+ C8 T. _$ L  O# Z2 e  P& @# t% r" P
    *@param_tokenIduint256IDofthetokentobetransferred
8 S! L, W9 O: T; U. F
2 m( U+ n% S7 u/ ~  T  V    */2 S' V9 u0 d" {- L% e1 D

; F4 ]9 ^+ s- Q6 g0 g. b( S, B; v" p    functionclearApproval(address_owner,uint256_tokenId)internal{, `1 Z8 S! M0 F; I
3 h+ A  ?0 t( X/ j5 y# c
    require(ownerOf(_tokenId)==_owner);
2 Y: [5 Y- f$ a  W, d
2 C8 D: t# |* H  b- Q( c. y. q2 q$ e7 g    if(tokenApprovals[_tokenId]!=address(0)){
( f! E2 Y) q) H. ^  G  Q1 a3 c! b# z1 s5 N0 G5 K, E0 M5 R2 {
    tokenApprovals[_tokenId]=address(0);2 {* ?+ }# B$ ^6 X* J( |
; ?  T, [, W7 o# N* O' F2 k
    emitApproval(_owner,address(0),_tokenId);
# M5 J4 y+ B6 a. v: q2 k& P, [  t; ~; l7 o5 j! B" S
    }% ?3 t2 G; ?; q) \: b. G$ ^/ Q

) Q( D% T& v6 u1 z    }+ o7 P) z5 j$ J% u; ^- @. Q

. Z6 p) b, N$ n5 e. N0 _( R, @9 E    /**
( W2 o: I& S- t) K7 w
/ t2 p0 A6 U0 q; {( ]; q! v    *@dev内部方法,将给定的token添加到给定地址列表中
* p( _1 S0 `- q0 {0 d6 {' p4 B9 _
    *@param_toaddress指定token的新所有者
' \% r$ X  [8 s) r9 ^) k  D4 q: J0 Q7 z4 x) `- ?4 f2 `& D( r  B& ]
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress
, g6 q4 _  M# ?5 x4 W# L
- A) Q" }9 L  H! T1 I: d( \& J    */2 `! f8 j6 a& U9 d2 z! D! g- |$ j

# R' v+ b4 Q/ _$ ^    functionaddTokenTo(address_to,uint256_tokenId)internal{. |& v9 a8 C7 B" s! A0 P
: H. m9 w1 O6 G, O- z! N
    require(tokenOwner[_tokenId]==address(0));
, ?. f3 H/ Q/ i! W6 }# J
, v- l( S5 y. d( |4 [    tokenOwner[_tokenId]=_to;2 i! w7 Q& e( \8 k4 T. O: y8 _0 @. p
5 P) L* S! V, J$ U! a. y
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
3 @# Q9 a7 S8 W, M( u8 M: C. E1 n& l
5 @; j) r$ c2 T    }
- [! Z. O# z2 Q/ @$ W' J8 \# G
& k8 l3 b2 d- _/ s: W, t, U3 O    /**
, F2 `8 t9 j* J5 M) K
0 U1 O2 ~2 f5 k    *@dev内部方法,将给定的token从地址列表中移除
2 L  |- ~% y4 q1 O3 A% u; j+ d3 {. Q2 e1 R6 H
    *@param_fromaddress给定token的之前持有中地址
) p! Q( J) t1 \
$ X! _7 z. u9 g0 y2 A$ A    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress9 q  ?3 O! m  _7 h0 c% c% `

% W3 d! G) L2 ]; Z5 P( Z$ |$ y    */
# L4 \  D2 F. u, d" W: v% M* }6 D0 W0 M) \5 A
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{& [8 k# n9 @0 |) ]! M8 ^) e
" s, Y; G) B9 O! q/ ?
    require(ownerOf(_tokenId)==_from);& J2 b/ G; Y8 e4 e% D
% B, F. l0 K+ [. ~% @+ V; I' e
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);7 X) I9 o4 p% y" r" r) f7 X0 p8 [+ S

& j% E7 m1 t- l    tokenOwner[_tokenId]=address(0);
6 i! @7 N/ |8 U2 C
5 Y3 q4 z( q; e/ C  N# X    }
1 o- C1 I) v. b3 Q% w
! m. y2 V3 Y+ Y' o3 i5 W  E' O    /**$ b& _: E- v7 r) H

/ Y1 U( Q2 t/ O7 U2 U; H    *@dev内部函数,调用目标地址上的`onERC721Received`( d+ o* }1 ]" F) [! y; f

& R& |* U' ?2 _8 v$ l1 {. x# Y    *@dev如果目标地址不是合同则不执行调用
4 G: M. M6 ]- i. [* C
& X/ W. O* s1 Q- U2 K7 Y1 D2 r) D6 F% c    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID% U9 \1 s! x0 L: t

8 F0 Y/ T; @4 B% [4 r3 \7 z    *@param_totargetaddressthatwillreceivethetokens
. @$ l/ A2 t! Z* b) b+ ?/ p* m
5 B  V' a4 J9 T    *@param_tokenIduint256IDofthetokentobetransferred
5 c) ?6 G. I( O. `/ s% ], V( v6 M8 A5 l, ^. b% v3 M
    *@param_databytesoptionaldatatosendalongwiththecall! h! k+ c( P2 m7 ~0 I

' e5 D6 G" V+ s+ j/ N  J" N% V    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
6 g/ k, {. f" d7 B" d+ Q  Y& ~. G: V, `7 m
    */  |7 n# l' e; i/ G: ^" t

3 ~+ i4 e" y( ?    functioncheckAndCallSafeTransfer(5 h- n1 r9 P3 r& p3 ?1 X
' V4 Y$ F  Y$ K) p, `6 S0 n3 L
    address_from,* {- r4 D" P  L+ E: q

2 `3 M* z3 `- z! p5 `/ B0 ]    address_to,
& [. W2 Q9 J4 Q2 R( f7 R7 Y$ R5 S
0 ?7 E/ O7 V% S' B" E' ?    uint256_tokenId,
/ }" C# [6 h6 ~; c6 e( i" Y* T
2 E; U! [' ~; U, B. \9 Q    bytes_data
4 B5 F- P0 B0 }5 r1 s5 f4 D0 o& x  p: u/ K3 V, N
    )8 u. @9 Z4 F  E% ~$ v
' x8 c7 U8 Q0 f6 f$ Q6 `
    internal
6 d' f& _" Q3 j* S8 H6 d* h+ q. d0 p! N& G4 h  t* t- l) l6 _! i% o7 l: A
    returns(bool)4 v; y* H3 X0 g% y" v

( `, B0 H/ a- ^  y  Q8 T    {
8 B( U$ f1 t( }( Y6 d3 ^) W& m
: u) \) u( I! w    if(!_to.isContract()){, b4 L' W' a) w5 _: K# X7 E8 J

  d" |' t* ]% L5 c. H    returntrue;) o( R; p% Y4 `. z' D0 x" Z+ |

9 P) T8 h: _0 |9 r  ]% d    }
' E" `: a# U% @: E2 r# e6 ^# }$ A; u2 [  e: B* V, T
    bytes4retval=ERC721Receiver(_to).onERC721Received(( u) u& l: [" q) U' h( _
/ G. ]4 y% e- t$ K& S  T- L7 e
    _from,_tokenId,_data);
5 ^+ Q4 u# E7 ]/ |/ S4 ]4 ~: V& N! L
    return(retval==ERC721_RECEIVED);- @* K5 `# ?* E  a

3 u7 X/ O6 P9 S0 t+ X    }  Y; n% z% ^/ C7 P

+ F+ H0 \7 y& N    }, N4 Q4 S4 y& @1 q

2 t1 U7 J& ^( j7 j' T- v4 i    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
$ y$ ]. O% p8 D7 t4 b) e
' ?- g/ {4 N, `% T8 ?7 E0 q' q    ERC721Token.sol
4 M2 [9 n& c) v5 a1 K3 k
& R$ U. U0 L# ]- {) u    pragmasolidity^0.4.23;
9 h" ?1 W$ d9 n! M" [- F( W) a% U; x2 u$ r7 k
    import"./ERC721.sol";. l% z5 Y' R2 a) b4 [
3 `7 J3 j9 R9 R" ?7 K# @
    import"./ERC721BasicToken.sol";; {$ s; z$ f+ [* o% d
* r8 U8 [, b( G% y) T- k
    /**
  J- F/ @' L4 g0 O% q! Y5 i' n( Z+ \5 l# F& M2 M
    *@title完整ERC721Token5 X. e3 A) n% z4 _* n8 w$ S

0 E! Z8 \/ S6 E* f. F    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
0 d! I' _( M6 S0 \7 `9 @" E4 _
+ k7 G9 R  K1 |' E( @8 A    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
5 F4 K) W- g- V% e6 N# b5 k" b; W3 p+ E
    */
3 D; j, B" y, [
7 Q( E4 R/ |9 m& t' E5 V( k    contractERC721TokenisERC721,ERC721BasicToken{4 J: I! t' v* B7 x$ {
& P" q/ f; a& t, r3 Q" I/ T, k: \
    //代币名称
7 x, v; S. j7 B, q$ s2 _! B3 Z/ S! [4 I8 a3 ]& `* U: J3 f
    stringinternalname_;6 B+ A" B7 N* r; V

% v% W  }" D9 ~% H! b    //代币符号
9 V' y. h  Q. Z7 A1 g/ b# R6 S9 @$ z2 K  {; b: q# T! `
    stringinternalsymbol_;
: ?6 O$ l( b' `4 c5 W. a( i5 p$ t6 p( A! Q+ _4 e9 J
    //所有者到所有者拥有的代币列表的映射
. P# ]: n" T& ~2 N- S# w
0 ~' Z6 t. d2 l4 a, L& b( `( c    mapping(address=>uint256[])internalownedTokens;9 b5 o1 d/ w" ], o, d0 @
( D+ _" Y8 z4 Q  x+ l
    //所有者代币列表中代币ID到索引的映射8 i& X6 [. L6 ?* \2 g. T
! U0 E/ H! c, v9 ~+ V
    mapping(uint256=>uint256)internalownedTokensIndex;( a" c$ ^' v1 M4 B
; Z2 a8 ?" d, ]) S% v0 ~
    //保存所有代币ID的数组,用于枚举) l8 r2 S6 A& i* P: y
5 P4 x- C/ Y; m$ k$ p( ?6 w
    uint256[]internalallTokens;1 U3 L' B& T4 _/ s; y2 X- @

9 W" V8 Y6 a- ?    //allTokens数组中代币ID到索引的映射
3 f" k2 k# b2 x* y5 M6 `- X, w# f
    mapping(uint256=>uint256)internalallTokensIndex;- b+ V1 P/ _& [+ K
7 t; }6 E$ |4 R: P0 w
    //可选的代币资源URIs映射
1 B( p' W" t5 c3 f4 ~+ f
9 n+ h* R2 b/ c! I2 E    mapping(uint256=>string)internaltokenURIs;* p2 L8 |5 s" Y: S) n
" Q1 t/ w, ^: F
    /**4 C8 L& u( \/ S+ s$ q0 _8 z- M

6 }; d+ n6 y/ D$ k) n    *@devConstructorfunction
* e0 ]: X  T5 m1 T0 u* M. v5 }: S! J
    */3 r9 A2 T( T# g% l; J, Z! W

9 x; [: e( ]! p! h    constructor(string_name,string_symbol)public{
, Z  z! o9 |9 j+ p% W5 l% z  c, D; |9 `* A
    name_=_name;2 ^: p% e* y  \* Z( O
. K, U+ ~" Q- O2 _1 w- S5 J6 a8 I
    symbol_=_symbol;. \0 h: ^8 l8 C* ]( X

' B% n* c$ L3 c2 K    }; R6 O& J+ a. P. H" m: F0 R& h
# e& r4 }8 s/ k  Q' @
    /**- S6 q; E9 w6 l" Z* }3 a
" T% G- T0 z1 w* {: R
    *@dev获取代币名称
: s' ~6 [& x4 @5 c, b
7 b' t/ t7 W% e    *@returnstringrepresentingthetokenname  w2 v3 o' ~; J6 m: H; m) z

9 o3 K* q  ]! Q- }    */
- G9 Q; E! U* ~, a& M4 F$ F; z
3 i9 U- A! ?7 k$ K+ _$ Q) T. u; @3 e    functionname()publicviewreturns(string){
6 b0 S1 E. i1 W' Q7 Y: @9 O6 w
$ T0 ]; Q3 ]3 W( j7 W$ c    returnname_;
) _3 l7 r; p& r7 B; V0 `5 p4 w5 c3 T" K
    }5 k3 v- u# _$ n( q2 C) }/ W. P- C
0 X% k8 T% }) f  C. J% ]6 r
    /**
2 Z& y4 t: ]; H5 H% i' ~  Q2 W  Y  J% s$ w  k
    *@dev获取代币符号; A5 ]9 l6 w8 i3 ]) T1 E' W

1 m( c- U1 u2 C    *@returnstringrepresentingthetokensymbol+ p% K0 j% E) G

$ t( ~8 J7 q. \1 p  L* `    */+ [0 l: j4 L% }; j) q
  Q! w, Y9 }6 l/ B" v
    functionsymbol()publicviewreturns(string){3 \7 l7 M$ N& ^- a& F' [7 ^$ G

+ o8 w+ t% ~- G1 W& h6 u    returnsymbol_;- l% R" c# v; A" v8 R/ j; c6 [& k

# C8 n( n# X6 i) H( l- h1 r    }
1 }2 H- P( |4 f3 W# y& ?0 e) A/ @* {+ `; C! d4 A) L  g3 v
    /**
$ u1 U; v9 x9 O6 J' m7 N
" Z* u- D) d; k$ W. k    *@dev根据_tokenId返回对应的资源URI: T9 U" m1 ^. S6 g! R# R
0 V" j9 |5 v) b5 F4 p# }( O% e& T
    *@dev如果token不存在异常返回空字符串
7 V2 M3 a# r0 v" Z$ ?& y) u7 j! ]/ k" n" Q6 v) i9 W) B
    *@param_tokenIduint256IDofthetokentoquery
5 A8 n- V# a  N& ~3 ~9 A) {" A4 J* N& T) j3 ?. n
    */
2 C3 S' N& o: }9 \6 J. S$ E" L# c( Q$ [5 g; _6 K1 h
    functiontokenURI(uint256_tokenId)publicviewreturns(string){- _: w/ q0 ]. y' q0 o+ d/ @; ]
2 {' M& A4 p3 X$ _$ b2 M! b- V
    require(exists(_tokenId));" k& R3 C$ o1 d3 u% i* R; i! \9 x/ ~
- }# X; X8 b3 T/ k
    returntokenURIs[_tokenId];
# y$ T) q0 ?, l- A
# O4 L+ H- k- h4 P    }
0 ]3 k0 F& [; v+ l3 G* P$ H% C! ~! a2 s$ s: j5 j
    /**) C9 A# I7 r& M3 S, x
. P; V; j, E% D" ~& ]
    *@dev获取tokenid通过给定的token列表中的索引
5 f- l& C, {/ D* a+ Q, u# s$ Z( e9 X) V0 K8 V7 \+ q5 s. S
    *@param_owneraddressowningthetokenslisttobeaccessed
. p9 ]- S: Q0 l  v  |) m
" K! r) [4 d9 h0 {0 o    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist% f6 D6 B; Q# L

1 g4 W1 b/ d2 @/ U4 t! Y& r    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress& h- V, d4 }$ g9 l5 N& d6 [/ h

) a; C1 b6 m  c    */
; Y  w, P8 @7 i3 T( [; ^# e) O3 c1 S" j. Z5 R8 O8 O! V
    functiontokenOfOwnerByIndex(
: F' ?# `& w, U3 ]6 C
0 c8 D6 L8 Q# L3 |5 P; ~    address_owner,
3 `( c# Z8 ?6 F% m( n. X1 B0 A9 s# i" N7 Q
    uint256_index$ l, e' z6 u8 D2 m7 D* [) P: K
8 B6 O8 e& \  e9 h' c: G
    )
. c2 T' w, x. w
; M7 w. A: r( g$ Q# {! g' k. ?- ]& K    public& M( ~2 u0 H* D
" A5 s4 v. `( N/ K) k+ H
    view- `: O! c( h  c2 F' q/ T$ S$ Y

' P3 X2 ~8 {1 C2 i4 l) i    returns(uint256)8 \7 j% }: W4 _

5 f$ \  t# |, q5 o  h# Z3 b    {7 M1 \3 C$ j0 i" ^. q( G
0 P" a8 |+ i+ R# n' I4 ^3 V: R% t, i
    require(_index3 l+ B7 o/ g( t& g. ~& v/ S
2 j. \2 v, j7 {- N! c: M# B: h
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
, K) s# r  n( W, o) X
8 \1 J4 n+ `% \    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2