Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2498 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
/ p: k5 [$ t, f. s& n. E) |2 w) `7 ^6 ?' A! ?1 R8 q3 [! S/ g
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
2 E6 b. c7 S% N3 X6 D  U
0 C! J6 C: r# p9 A3 p2 O6 `! S( J    ERC721Basic.sol5 W, I0 `8 Q! E# v( j. j

5 b8 Q2 R: O$ ?: j3 v    pragmasolidity^0.4.23;
2 k6 \/ j$ H! s- ~
+ j8 |6 @$ K9 N. C    /**
7 X$ P" i* _' F1 b
4 v3 B) t' C1 w& r( u    *@titleERC721标准的基本接口
+ D0 t9 t! I/ `2 x& C0 h7 o1 ^8 j/ n8 {- I! s! g* b
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
4 [# \% D+ A& ^
! Q( ^  @0 _8 I; [; e* i    */
: \9 K) ~% r% |( s4 P  t1 K( c
, ?# p' W* L5 I7 j    contractERC721Basic{& U" [+ f3 X- _+ G3 K
4 t1 f! F" N& E! p3 N0 y7 e) E3 C+ l
    eventTransfer(  L, t* h- O0 e8 B, ]+ T1 M

6 ~; ]$ y6 ?4 g' H  U4 U    addressindexed_from,' ^1 L6 s5 h& ~* n( v
/ }' q. \9 L% L4 v% h3 k
    addressindexed_to,
$ f! Z( G( r5 @! R! x
" y6 W7 V. u/ n" @% S0 O% c- g; r    uint256_tokenId
, z% v+ \  F1 [$ ~4 t2 ?% _, o: u) g$ F! s
    );( T0 X7 t# B, J; W# Y5 i
$ ]9 D: \3 t4 Q1 P
    eventApproval(# X* ?0 A, x: t% O0 d: U  h
5 n- C* l/ E% D0 c) l
    addressindexed_owner,; q" K/ C* M( q- |: h

! D$ p7 W5 v5 ~9 u- G4 J+ F' ?/ a    addressindexed_approved,
+ D0 T2 O; s4 B! v) }
9 H9 ]  \4 v* t" I" g3 B; r: f    uint256_tokenId
9 Y/ p/ [* v* t8 w! h+ O
6 F9 D8 d0 T- a1 {    );1 P* d9 v1 p" @: Y+ w& L

5 Q' [2 z, R+ h% _7 y$ G- K. T    eventApprovalForAll(3 E$ h# e, t+ D% d. g$ C. L

& H* a, U- i& u. `    addressindexed_owner,+ f: l, S: q+ w7 l! Z+ r4 C4 C

5 u# J0 p! C2 p: ^* M/ G    addressindexed_operator,
( q' h. C( I3 ^7 Y: c' K
+ f5 J5 F- l: w- H! Y, k    bool_approved: e6 Z( M& z9 E# J
+ L; V) X" ~8 c, u) \8 K' t
    );1 d  A2 }( c- {* O  M
# F0 c) c/ d" }9 S$ G& Q" ^& Z
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
. {: ?6 H) C( N+ J4 |% R3 W, K, ^& B1 V" j& k$ x, }
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
' o) `% z& Y3 f$ h( L/ i
& v3 u& s1 p; G, t1 P! h+ k; v    functionexists(uint256_tokenId)publicviewreturns(bool_exists);) I5 Z3 m8 E$ G5 I5 J1 V/ G

2 S( U' r0 w% n    functionapprove(address_to,uint256_tokenId)public;6 M+ ]  |) i+ s6 d

% P4 {" H" f2 p+ }8 u3 N    functiongetApproved(uint256_tokenId), S/ \" F, D" R, h  \! d

. ?) o; f) K  ~6 c! X$ q  _5 `* X    publicviewreturns(address_operator);
! n2 s4 K  `8 T' B6 c: ~( l
& x8 y  R% N/ K% M    functionsetApprovalForAll(address_operator,bool_approved)public;+ ^7 j% M+ |9 a% V4 v

9 g- T* j: F; k    functionisApprovedForAll(address_owner,address_operator)
# h- I' Q+ J9 x* t
9 {% e; [+ k# M7 S0 \" R    publicviewreturns(bool);& B7 }7 R; m( ?  p; R

  d1 A+ j( l" u6 k    functiontransferFrom(address_from,address_to,uint256_tokenId)public;, C  H. a9 c9 @1 l' E& O
0 Y% i) \3 G4 t
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)0 ?# F/ e' M/ D' }7 _9 H3 U

5 p, v7 a, e9 f& c0 i9 m6 x) s    public;" `+ J/ l  m* L0 H! @4 l

: z/ j2 D9 x* G' f3 k    functionsafeTransferFrom(' V; C: i$ p; r" \( O% L. W
% p" G0 s. q5 E3 ?: D: {  H
    address_from,  H2 c1 B2 Q9 j/ Y. i

; J  t7 m) z8 z- g  a    address_to,
. {/ C3 x( B& g- t3 R0 Y, O7 D: H
    uint256_tokenId,
* R) l2 b0 l* n6 x
& H2 a$ ^0 T" ^4 X2 y- F" w    bytes_data9 n; ^+ K" n; n/ {# h/ C& {
# z8 i7 Q- \! D) z
    ): a6 Z1 |/ r0 q* Q3 N; J
( T/ z* W3 r! H( v3 }  p' O( |
    public;
2 \1 ?3 A7 k# N( }6 N1 g8 e
! a' c: A5 l& K    }
$ f4 w) j9 g) ^4 X$ [$ i9 R, I# D# e- D# f6 a! J( M
    ERC721Basic合约定义了基本的接口方法:8 P9 [/ D% Z/ n* i7 t/ b& ]! V  `% b* c

9 _- N4 g" K& A$ U/ r0 Q8 _    balanceOf返回_owner的代币数量3 m9 u. f9 i3 U2 f- H
: i( ~1 \: x0 K% f
    ownerOf根据_tokenId返回代币持有者address9 Y8 D. k0 r! n; Z
$ V* k3 f: l* D
    exists_tokenId是否存在( T+ D% `- G5 u3 j
) C( u+ u2 |2 b. v7 `
    approve授权_tokenId给地址to
- C  u3 n' l$ H6 p* `% {9 v: ^( N* R, m0 l6 a
    getApproved查询_tokenId的授权人_operatoraddress
2 W( w! y$ y  k1 z' X# w) M6 ^1 i/ {. S9 A
    setApprovalForAll授权_operator具有所有代币的控制权- F& G; y0 c- x: |, O
, S' J5 F: `8 o: C! A
    isApprovedForAll
% Z0 w  T" o% u# H0 G) I
. N0 c9 c+ o8 m5 W3 E$ Q8 |    transferFrom转移代币所有权
7 B* o, E$ f8 y1 C) `+ q: W# U
# C% N2 e: I* o4 \4 ?# J    safeTransferFrom转移代币所有权8 L% _5 L" R5 P' ^4 v# N
  {5 y0 |1 u, \4 e7 b5 y. ~
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。7 {* b4 c7 b; }. p1 A" d* t% p

& \- X# V4 K# ^& e    ERC721.sol
0 o1 Y$ O' Q( ~3 q& ^1 ^) e  e- _7 W% ~: P" t
    pragmasolidity^0.4.23;
) V) z& {+ E# Q. {% G  r
  m5 S; n- n5 [& H4 S    import"./ERC721Basic.sol";' c, |# @5 r% b1 p4 f3 N% s
. ?5 c5 k% p. J4 m* W1 e- g8 T" }
    /**; e5 y1 L/ f. a; B& {

8 ~5 ]: Z7 L, b' `7 B    *@titleERC-721标准的基本接口,可选的枚举扩展
5 [( s6 b4 M0 }4 X6 V* `" O( [' V1 D% G' |
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md% Y) [, q( N/ s

7 F% p* U; e" B) e2 l) ]0 ^    */* N2 e" a2 G' R2 k$ O2 A6 d

% Q0 k$ u8 H5 U% j! Z    contractERC721EnumerableisERC721Basic{$ B. D6 o+ p+ L- j0 \
$ \1 J, ~2 N% V- Q' T3 Z
    functiontotalSupply()publicviewreturns(uint256);7 i( ?1 X9 N5 x5 \# Y
' u& k0 p* @$ ^- h
    functiontokenOfOwnerByIndex(' _. s( n/ I: s$ j2 X

# K: N& t5 z7 [( q0 I    address_owner,
. c8 t7 e6 O" b9 i5 v4 t' o8 k
1 S* W+ ?7 q7 d* L2 x+ [    uint256_index5 @% j! w0 W7 ?/ ^8 H3 A* X3 J3 H

0 U3 \" h9 Y5 D6 L    ); O. M! f3 M) G' {0 n

$ ?$ u; r" L3 q! x* Z2 n) Z    public
; L! a" f" N( O3 n
  M- ^; @! E& k9 G    view
+ d0 F% y! a. H
/ o" I! U9 j) P6 ]7 v    returns(uint256_tokenId);9 E* b1 i# o' ~  X) C
) ?" k( h2 [$ T1 s: [
    functiontokenByIndex(uint256_index)publicviewreturns(uint256);+ x- w: n+ U. L+ k8 L; ?' y8 B

3 q) L; C2 O9 A    }
! S$ h; O0 F9 L' I
4 m3 `9 w* I) N2 b+ @& I6 E    /**+ {2 Q0 j& W+ M% W- F9 C0 p+ C8 W
9 k/ d6 h% ?4 d4 W9 i( l
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展
7 m/ _6 @$ k( ^2 H  ?% l! V/ a
/ j6 X$ j! q3 D  P% N9 h" O    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md  w$ R! _8 y( u+ K+ n$ q2 d
" H- |3 k- N# V
    */2 [4 y6 O4 }/ ^: v: p" K
6 |! U* U' G; c* l9 [  `& M1 f! t
    contractERC721MetadataisERC721Basic{! T) g) }4 |- L2 a& L, S( b

1 P# o, C, a+ y- f9 u9 e3 n    functionname()publicviewreturns(string_name);  M$ g1 x. a. U5 R

( S8 _% }# W+ I5 c! O% m  t3 \    functionsymbol()publicviewreturns(string_symbol);
* [) [: z! [0 I& {/ s( ~2 J+ u0 _4 B: W6 S+ Q* R% p/ J5 ?: z
    functiontokenURI(uint256_tokenId)publicviewreturns(string);! \& O7 T. g9 C" O

9 G9 A# k" N3 s) N" |    }& n" r' Y% q  _0 @
5 s" n( q. W! X. k' M
    /**  {8 v6 y" I/ A3 V" |5 ?

( k) ]" b) _8 A; y" f- M    *@titleERC-721标准的基本接口,完整实现接口
- [1 k0 d# {8 ?% S% A* E& \8 f& v* X4 h
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* s% b9 e' U" [, c
1 |' D- ~. u0 v$ t% i    */
5 ?2 m- T8 o# n! x/ D( Y$ v% p
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
; h6 j: W/ W9 A2 L# t4 P  p1 z( m
    }
6 d1 e, Z( Q& H7 e& U: w8 h
8 F+ I- H5 s4 H) n9 x    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。% s' P, g( \/ h& A, Q$ @6 J* i
0 ?+ r. f3 I* |, Z+ i
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:1 {4 a  o7 M6 c8 n2 a9 ^
* c5 M8 B' W% D/ w
    totalSupply返回代币总量/ N' ?! ?+ G6 ^  G

0 h% a- J6 [$ y  U0 q' u6 @    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId+ }9 ]/ f- Q1 U7 u* I
" g5 \5 {" x% J
    tokenByIndex通过索引值返回tokenId
0 b: L0 N$ [( h' ]1 t# J3 \0 {* H9 v& n5 ^
    ERC721Metadata元数据扩展哦用来描述合约元信息' I& p0 m  v$ S$ b5 z! r% B
  ~& K' K, s! c1 k. D0 D' t
    name返回合约名字7 I' Y# I1 t. U
* x) C: `" ?* e6 n
    symbol返回代币符号) A7 a! r* a6 l# e; u$ v

$ f; R+ J* O& Z1 B7 s) T    tokenURI返回_tokenId对应的资源URI
1 w* ?7 V: \' l, D6 G8 c# C+ d
# b/ ?4 _) [& M- k    ERC721BasicToken) J% j, L9 V9 S/ G
& y& l# e8 r0 K- K: @6 s: L
    ERC721BasicToken
% D, m% U/ s0 \& C8 f+ C, H$ @- @
    pragmasolidity^0.4.23;* V2 F+ _9 |/ T3 I! E/ @+ h& J2 _5 m
4 e: m. S% X" C' X# ]+ @' q, N% H
    import"./ERC721Basic.sol";' k8 D, P1 T- n) U7 w
+ o& |. H3 w3 t: W6 _. |: Y. R
    import"./ERC721Receiver.sol";
1 o% O; k6 `) @4 e( F8 d
% b- _8 s6 G. s, ?5 A8 c& ~% \    import"../../math/SafeMath.sol";" l& V4 u3 \$ _8 H# D* |& e
, ~1 U8 Y8 I# o
    import"../../AddressUtils.sol";3 s6 e! T% ^6 h0 _
% `+ Q1 e' R6 E. g- `
    /**0 A$ A* i8 F( q4 T  v0 ^

/ n+ ?8 t" e% z/ p5 R" T    *@titleERC721标准基本实现
& x: L; D# l5 A! _& n. K( K. P3 ~" i* u+ d
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md# X; R/ P% l! {7 ~1 a' ?1 j6 Q
# B) i. f9 g( X; _. i  a- H
    */: X' z4 |4 ^+ X3 x# w0 |
. K0 A9 D; P9 O" O, y, M
    contractERC721BasicTokenisERC721Basic{
4 f; X6 R4 U4 u' `7 _) h
  ^6 P7 b, @+ d0 O6 |    usingSafeMathforuint256;) i8 u% _0 I4 B% ], Y; M, l1 n6 ^
9 ^! H) p  P7 Q" {: j# g  ?& Z  T
    usingAddressUtilsforaddress;
7 D! Y1 z8 w# _. H+ p) a8 e' J& t& Q& M
    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`: N' F& A3 _5 C+ B0 N! p" |
$ R2 B; r% |" j' h
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`% z. x# F) B6 e' ^: P8 O6 M9 Z  n

4 V7 S) k8 o# X3 A    bytes4constantERC721_RECEIVED=0xf0b9e5ba;/ k$ R! [% d2 r

8 z1 v% r( `4 c# {4 h1 O! |    //tokenID到持有人owner的映射
8 |+ w$ _' E/ ~+ U' _4 ]# j$ T( d8 \
    mapping(uint256=>address)internaltokenOwner;
, Z7 Q# M5 s4 k% i. O. n* x
* Y+ c/ n0 g7 S; h8 L    //tokenID到授权地址address的映射# S, f8 T7 m8 c5 d% M. a9 z+ D

  Z4 x7 W% x5 ~. V) F( @: n* E    mapping(uint256=>address)internaltokenApprovals;
! D2 k) S8 S- N8 W
; A( N& M- K- {  c# O  ?6 W    //持有人到持有的token数量的映射
- T( }9 b1 v" T2 [6 v* o. i: Q9 Y3 o( M3 l. n; k
    mapping(address=>uint256)internalownedTokensCount;
. O7 ?; L6 s" p6 m2 V
( h! ^+ u/ q# \9 @    //持有人到操作人授权的映射
# a& q1 b9 x0 `( f; C" ?9 C% a( w, M9 z" A! s2 O! O; n
    mapping(address=>mapping(address=>bool))internaloperatorApprovals;6 q( d, N* L1 I  L
, ~, v2 C. Q, s4 J: z# r
    /**
$ x6 l" @8 z3 R$ x
/ f/ a' P% Y: g; C* e. [    *@dev确保msg.sender是tokenId的持有人( F. R- n. k2 ?
0 }$ @. K+ E2 e, J" q
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender5 D9 L  b% A1 ?8 E* {! R0 @  G, {+ Z

" i/ r9 y" s) u. Z! I    */3 a5 r! L1 ^/ Q9 d

) Y# M5 h: b; m! q6 e$ G: a3 d& v    modifieronlyOwnerOf(uint256_tokenId){& T* d1 v# d7 w* A* y

* ?$ D: c7 G9 ^  V, m& A' {0 C    require(ownerOf(_tokenId)==msg.sender);6 ^5 |$ _) Z5 Y
* x+ n' {3 E0 H. u
    _;* d3 ]  g+ F/ C- u/ i
5 F& z3 r0 f7 {2 ]( w: s
    }/ I! H8 ]. @+ ~6 r9 ]$ t8 o0 C. J" V
: ^9 ?5 {5 i8 F) w9 i
    /**
# y4 N$ f5 F* I/ u+ a% Z4 i2 A3 n2 v9 Z1 T
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
; y9 C, A  S" ^4 p. x) G, G% C" T' D6 \# ~( z# p
    *@param_tokenIduint256IDofthetokentovalidate  @* u5 q; b" ]
0 x. ^: q$ g* Y* x. S& ~
    */
  I) O1 N$ m/ ?! |, H9 p$ j: a; E' `! ^
    modifiercanTransfer(uint256_tokenId){# c6 @# B* J: ]) j
  A* m8 r1 B2 |. O( @8 m7 K6 U& W0 J
    require(isApprovedOrOwner(msg.sender,_tokenId));
9 \, ~$ z* p  h  ?2 W
- v6 r: @" C, k1 R) G' v    _;
, d) e( n5 Z" c
) U2 I+ \0 `+ g  A. H    }
1 I" P1 |6 A& o/ J
& W+ ?: c3 b/ w9 v  F    /**
& R# E$ A. o- ]( b% S4 Y! j
  Z  \- _+ b: j# q9 c9 @' l) E) _2 d5 Z    *@dev获取持有者的代币总数
* R: `0 ?$ ~6 v( n6 F$ U/ z. ~- X- }, Y5 t2 ^
    *@param_owneraddresstoquerythebalanceof. {% ^4 P- D( L1 _

( q0 o1 {9 m$ {( V; v  }" m    *@returnuint256representingtheamountownedbythepassedaddress( F. j( f) d* k) T8 V

  E6 t0 X6 J: x    */6 L2 ~8 D0 }6 n1 y8 n
3 F( [/ B) K6 ~. d: Y8 @. g# ^; P3 _
    functionbalanceOf(address_owner)publicviewreturns(uint256){0 d$ s: q( W( B3 K. P. E
* m7 a. p! g- i  b( G# V
    require(_owner!=address(0));
- q4 M) J& A1 l, c. Z; k& n+ b! u3 Q- G" y( k3 h; p) s4 z
    returnownedTokensCount[_owner];) r$ K4 Q" Z) h9 L# X+ X2 u; C
+ Y% W8 P5 u/ H: V6 q1 s9 z8 W
    }
6 {$ G, }7 ]1 C9 w* V9 h0 ]4 E
; P& _) k) H6 \$ g3 A( m- Q    /**
# p2 r1 h; J. p  z9 m
, T" D! I! w7 K+ G( `/ u+ i    *@dev根据tokenID获取持有者1 K5 Y8 {" S% \9 Q% M8 R+ \

6 Q6 C, d6 k+ F    *@param_tokenIduint256IDofthetokentoquerytheownerof
2 W1 Z2 v- c5 Y: P2 q6 B: O8 J7 O1 `
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID+ Y5 V2 t* H1 \: P7 ^; p4 \2 A
9 U6 R4 v7 K9 }$ z: z* D
    */
9 K/ I- n/ p# c( k+ G( O+ Q- _* L# g! {( D) i! g& I2 Q. m% _1 @( q
    functionownerOf(uint256_tokenId)publicviewreturns(address){* n! l  }+ K: c

8 P6 P$ B8 J9 Y# n2 B) u3 O    addressowner=tokenOwner[_tokenId];
  B: J, s% L, n, p6 r0 ^5 u" ^' p+ j0 f( ?# `( s4 k1 v
    require(owner!=address(0));/ V- B! x7 _7 V: y" I

  X8 y( k3 ?( @; ?4 ~! o    returnowner;& q1 {* c8 V" X8 _0 {

% A% i- k' F* {- H    }& b# a$ i; K* y- ]

; o+ H! a3 @5 v8 u; k1 B9 S    /**
+ R0 T% R. A% _6 E8 g- A1 j/ P- A
    *@dev指定的token是否存在
) B7 u: J# m& f' U7 u( b' v% c/ @$ e+ F( j- j. `
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
+ p6 e; U' i- ?1 _2 ]+ V2 O! }$ x4 f* I8 b$ @' {% f) v+ T
    *@returnwhetherthetokenexists4 Y/ Q; n- w5 A+ }

5 M* C  C- c8 @- i% a    */
+ f6 A+ P1 J* I% |+ p  t3 [* K# T( M2 C6 H& Y' U; l
    functionexists(uint256_tokenId)publicviewreturns(bool){9 V' h% k5 ^$ b1 ]  }

4 D' e% U$ G2 Z; w- a    addressowner=tokenOwner[_tokenId];
+ a" S" }. Q: ^9 k8 b$ L# {0 o; `! g0 Q" X! L
    returnowner!=address(0);7 G$ g; `1 L! X1 H/ \
/ x0 k8 M. B/ K" w; ^7 R
    }
2 V  y  h$ J, m1 @: h; @( ]7 K. B8 M5 u3 L2 k& Q+ }- Z5 n
    /**
1 |$ C# \  G8 R( g0 e" r/ i! E# M7 W9 d
    *@dev批准另一个人address来交易指定的代币
! b! `: Z" b! `
3 e5 a5 q+ G  T    *@dev0address表示没有授权的地址' z$ v2 Z0 @1 D7 ~) h
5 g5 x" F5 d3 S( h( _( P5 }0 A
    *@dev给定的时间内,一个token只能有一个批准的地址7 o; k) c9 D! K) `$ e

/ P, L$ L2 |0 i5 [& \    *@dev只有token的持有者或者授权的操作人才可以调用
! E) {* z0 h+ s7 T! g* K/ y* p2 K9 Y
    *@param_toaddresstobeapprovedforthegiventokenID
* u( L+ L) n: \% x2 Q
- ~4 n6 H& }; f/ w, k8 M9 @    *@param_tokenIduint256IDofthetokentobeapproved6 c( e. k7 B+ D2 S, |2 X, o5 @

$ _& T$ n1 y# \  ?' {+ o1 t; ~    */
' a8 \5 h5 P% G' W
9 q# h' `/ A9 B2 L3 J8 b    functionapprove(address_to,uint256_tokenId)public{
. `# v4 x0 l2 S+ f7 \7 w9 a0 f9 m' O" C" C
    addressowner=ownerOf(_tokenId);
% d2 x( S4 `4 I6 a5 k% s% ?9 U/ O
7 f: e" d$ K$ R) q  e) I& s    require(_to!=owner);
3 `9 d* A+ E( L. W
0 [& h; {( r9 ~! R: p- R) X    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));4 a  P4 H. Q% j
9 P- G, h1 i& \4 R4 q, \9 A- u
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
- [& l9 F. G( D) T2 K3 K* t
6 e4 W, g5 }7 e# P" ?" S    tokenApprovals[_tokenId]=_to;6 b9 O' Q6 i0 V; ?0 W- j

: Y3 p0 B/ s& G; @( y: R$ ]; J0 c" O    emitApproval(owner,_to,_tokenId);' C, B9 V  P  F9 f0 a( z4 w
$ M' h2 Q3 }7 }4 [$ r6 ]
    }
( z. H1 a; z+ \% M
. H5 e! _' r2 U    }
' B% s* G" d7 u: J2 ?. _3 _3 L
/ q' h) F" V' i+ R. }7 f1 O4 q    /**
! x7 i0 e- s0 y: [( k9 Y4 m& N) S' |; t
    *@dev获取token被授权的地址,如果没有设置地址则为08 d2 S2 d+ G) ~* g) {2 q

* l4 y2 ?8 }* ]- U2 o* c    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
4 O; z+ b" c& Y: ^, @+ U/ N
) A# S2 ?; |$ V! P' Q; i( u    *@returnaddresscurrentlyapprovedforthegiventokenID# E; ~1 H( X" n) P

6 g) K' u6 y0 T$ G0 P    */
* y8 o$ d! O4 n- r# [$ d% n4 P6 k( L! O4 g/ f! i* G
    functiongetApproved(uint256_tokenId)publicviewreturns(address){2 |) R3 V, o5 a5 B" `
( w  y" I4 x+ d% b! d6 L+ s
    returntokenApprovals[_tokenId];
3 m1 r  j  W1 y9 B5 B" |3 ^% u0 N
! S+ o% K  ?# d) l2 M" G    }% {$ Z2 a8 N4 i3 p

  |4 f9 I7 B# K( q- U    /**
- k% B+ a- q: p) |  K/ k3 M8 B. U/ a: e! q8 B7 v
    *@dev设置或者取消对操作人的授权% y- _+ b8 v6 f! l

3 \! A8 X* [5 P( `7 B) n& F: [    *@dev一个操作人可以代表他们转让发送者的所有token( I+ z8 h1 v; o4 I

- h1 ]8 ?- r1 X4 x) _    *@param_tooperatoraddresstosettheapproval/ p( k1 @' O" k9 J

2 G3 a0 z0 a# P    *@param_approvedrepresentingthestatusoftheapprovaltobeset, k) T' s; Q6 r# g$ x6 R

3 U1 S+ Y* S) d' D1 ]# d    */1 |  `& |5 a1 r9 F% f# C

9 [6 I8 Z: S& ^6 E+ O    functionsetApprovalForAll(address_to,bool_approved)public{- m% O8 U6 R* c) a2 ]' U
* J+ |6 s: a  z; d, B0 W) W5 A1 k8 b
    require(_to!=msg.sender);" r- {$ l! S& u: N( O
4 Y, ]' U% J( W2 K
    operatorApprovals[msg.sender][_to]=_approved;
) ]3 X4 K6 B% {- k" ^& ~) Z0 ?' a  p! B* C
    emitApprovalForAll(msg.sender,_to,_approved);
& o! q, x, l$ R0 j/ Z. c# S+ A1 K) U8 K: R. O) n
    }
. f. e$ h  U7 e; P+ |
$ M9 R* {, F9 J5 S0 L: y3 U    /**8 s2 ^2 _  C7 Y. o' f% ~! \6 [

: C* D+ W6 t$ R( c8 T    *@dev查询是否操作人被指定的持有者授权
2 \% z9 E% J& ?1 C3 X
$ a* C! }- `6 W2 `. g7 \    *@param_owner要查询的授权人地址
6 d! y7 b$ l. ~* c$ K' f
: [2 m1 ^0 ?' n: {& X/ c) I    *@param_operator要查询的授权操作人地址
' J% r3 ?' |0 G3 x/ H
) H4 {5 B; O: X% }- v# r    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
2 s' c' G4 D  I* w+ [, a
" B. l' l, V& x- O) e    */
' B2 t. T4 _" k' i; r/ ~! m/ Q$ t' M
    functionisApprovedForAll(9 i/ u8 M5 Y+ K* r" h
0 w( F+ j: Z1 P; V- t# a
    address_owner,
& C. |! @, r: d: P& e
( Y* c! b( [! a    address_operator8 ^1 J8 N4 l- a% E3 M0 U0 I
2 h( i/ ?' M) \
    )5 o$ t, E  {' r4 j; T
- J( s& v$ M7 U0 e  F
    public
7 a* d3 d, e; o/ }$ c
; V7 K$ |% i2 g* v    view- Q2 |! I7 m$ h" @3 Q/ h, r1 ^

6 ?0 T7 C6 i3 _  E% u    returns(bool)
2 C( K6 r* q% {, l) ]0 I3 ?, Z( U9 F7 `* k! L. H( A% S
    {# N8 K6 k' q" b* F% R+ R

8 f' }& [4 S$ }; H" S* T/ R& v    returnoperatorApprovals[_owner][_operator];( G& X) P: H$ ]. T' u9 _  `
' f  _/ V! F7 E4 |$ b4 J: W0 m
    }
3 X$ l  p8 H+ o* n) }1 y9 H  y' R. O/ V1 N; R/ X
    /**+ @4 Q' \# x3 ]
) b$ S1 H* J$ p. [, y
    *@dev将指定的token所有权转移给另外一个地址
8 h4 O, Y2 }3 \, z5 l* \& e, s! Y% |3 z9 d0 J
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
% i3 \% T  a- I/ i
, \& m2 t( H, m9 ~    *@dev要求msg.sender必须为所有者,已授权或者操作人0 Z+ r6 M' X  c+ i8 j+ u$ i6 A

3 r! o( g5 X3 a( ^& p    *@param_fromcurrentownerofthetoken8 d$ `8 Q4 }% y

6 q, ~9 C+ i0 k/ s    *@param_toaddresstoreceivetheownershipofthegiventokenID4 g* j! f( B: c: P" @

" F3 s; q+ h# _    *@param_tokenIduint256IDofthetokentobetransferred6 O/ X) \7 X4 M. T; ]" n

$ \( t$ l0 D1 b4 e    */
9 Y& V8 I6 z% G- Z, t% V* `8 C/ y) D
    functiontransferFrom(
. X* x# q! q; t" K
% S$ i* T0 s' V2 |1 }  a    address_from,
& h$ [( ~1 N% }
* k. U- Q# E7 d* K2 [    address_to,' J2 L: s( ^" J/ [, I( H/ D% w

& l3 F  X* u$ R! E/ v- e    uint256_tokenId
" d  l9 v& m& F% T+ M% i8 ^8 ?/ d( V& g- Q* `5 Q
    )" d/ a7 M* w* q/ l3 j' ^+ U
; k- k3 y- `* F5 Y
    public
/ r- u$ v* [5 A. V: {/ n- F. ?) \; i* `
    canTransfer(_tokenId)- H$ b0 r# A! q
1 R% @' f! u/ [
    {* \1 q# \7 _) w% v
; E. C0 j) X! E9 o
    require(_from!=address(0));
# Z" V) C5 ]9 ]" G( y' K) O7 z+ h- M
    require(_to!=address(0));
" A6 J' m# ]& ?$ g/ `
' w6 X2 z2 i* G0 ]1 R: f    clearApproval(_from,_tokenId);
$ N2 U; T, a0 ?+ x6 c" R7 Q" L; E" x' ?. H% O% z; [. [2 G
    removeTokenFrom(_from,_tokenId);
! ?! P0 o3 u3 ?9 u
3 h  ~7 ~5 Y6 Y3 o    addTokenTo(_to,_tokenId);; i: x6 V7 n7 d1 R+ m
* t1 k' N( h/ c, v4 r
    emitTransfer(_from,_to,_tokenId);
0 C9 p* O8 ^& z+ |" U
% A- b# G6 f& p& ~2 `) j" B) l    }( G1 ]/ s$ p( X8 u3 W
7 c+ B- W8 l4 y* ?" i
    /*** Y* E: n& r& ?' n
4 o- H+ u$ Q0 T  L( G+ ~2 b
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址# M. q+ |# C8 b- g5 z* L5 P
- v  H& c" p1 O
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
' K5 w6 m0 t2 d' ?4 I* x
9 a4 S8 u$ X8 K) x4 K    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原0 ~1 j. C  S5 |  D  ?& C) `
5 X9 D0 l  X& _" F- Z, G
    *@dev要求msg.sender必须为所有者,已授权或者操作人
5 v5 H( c$ M) T. ^- Z% k- w3 x3 }0 c9 {1 e/ ?. ^1 M- z
    *@param_fromcurrentownerofthetoken1 T& ^" Y# N. w& o4 h

- }# y! d% N, R! A4 |* |2 _$ `% b    *@param_toaddresstoreceivetheownershipofthegiventokenID
5 ^' M1 G% d8 x; k  q9 v) C+ j1 i8 v2 |( Q9 U5 `* _  k
    *@param_tokenIduint256IDofthetokentobetransferred$ Y6 d) Y% ^: D1 W' ~( i+ r# H1 x

; W9 A5 K; m% u& ]7 Y    */
6 f$ `" x3 l, @; c: ?+ X! @; _  o  I% t) h9 f' e* W
    functionsafeTransferFrom(
- B; G0 O* {, Y8 O/ c+ G9 Z
5 n: ^4 |( c! J- T; m& @" b    address_from,$ v  {! z' G+ {. j. {/ D3 F
8 g* e% K$ m/ F: ~
    address_to,- F, z% |3 E7 ^& W4 C1 z

& k2 q" }* L3 n: N; O    uint256_tokenId! F1 M, T' G/ O! \# h

$ D% Z5 S. B# r: Q    )) S  i5 ]& ?) o$ h- _' R  F

2 Y& E! ], g6 P7 A: k2 ?    public
  A0 C. `( D3 K  j5 u* I
: t" \2 o2 x2 V0 i    canTransfer(_tokenId)8 Y  d. @9 H8 q9 `2 D+ V  i/ U6 I

9 Z: Q) B2 _& l- q; @' t7 T/ h2 |6 ~$ u    {
. A8 a2 C  G1 P. x- Y0 _( J$ ]7 R  Q# |- J
    safeTransferFrom(_from,_to,_tokenId,"");' E& ~( R# u* V
# H7 x* Q+ N2 O, A' T0 J6 O! w
    }
+ X9 ~3 Z1 Y/ ~. j1 _5 z3 b3 m4 g% c8 i/ q, B! n* o
    /**5 x% O0 \6 _2 p0 F# a, G/ W
+ x2 B# J1 j/ j3 N: L
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址+ e& a$ J* ]& V" H4 a. Q1 I; h
; V% Q6 {+ E! A5 J
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值9 q. \) Z* ], E) [

, g! }- S5 z7 B- ~+ j/ t; X    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
- r( h" h  V" V  y
! Y' E1 P" H; v" ^- |- i2 N    *@dev要求msg.sender必须为所有者,已授权或者操作人5 C& B, S6 {1 G
% X8 O. o# I( g) I3 y
    *@param_fromcurrentownerofthetoken7 E5 m6 ?. k, b# Y/ x- [
1 ~; e  _1 Z, q& f) r
    *@param_toaddresstoreceivetheownershipofthegiventokenID4 R1 s1 M3 Y$ z; C; _) z+ K3 z
/ S* M9 R6 G: F1 H5 z4 ]
    *@param_tokenIduint256IDofthetokentobetransferred
4 P6 ~+ u: z9 Q5 w$ M, w* G) Q2 O" b0 b; Y- U
    *@param_databytesdatatosendalongwithasafetransfercheck6 q9 X1 e9 w( x( c8 D8 a5 f  P/ _

* x- o8 {* U* \    */( W+ w5 Z- Z) R6 l
& n' ]4 Y+ ~1 f3 ~9 J
    functionsafeTransferFrom(
5 i( A: D$ S2 L7 T# s6 J
# l' d2 I0 O+ O( h5 q    address_from,
! @$ v2 B5 ?& B. q
) P' E$ W* l) `4 S1 H& m$ O3 r    address_to,
0 y# W" O3 P/ w$ z/ p$ w$ L4 r) U* Z* t, E" |6 m% R( X
    uint256_tokenId,- a+ B7 w' }) \

, \5 V7 a& `9 Y3 ^- `+ g    bytes_data7 ^7 ]( n% b0 I) b9 T. l% W1 f$ j

4 d1 ~: H  B% T8 C- H- V4 o    ). }2 l/ D+ M) |% R

% u0 j& |# ?+ U$ _/ v1 V1 v    public0 \7 S# C% A% C0 k: I1 k7 m
/ M  ^  ~  `4 m: J6 J. p3 N
    canTransfer(_tokenId)- l5 Q8 N! y' m* F

8 [) x- E1 A# j, I    {
- u" V- q+ h3 X2 J! ~0 {
0 z0 \6 K8 F8 l' Q+ @. G+ N    transferFrom(_from,_to,_tokenId);, M' m" u6 G: U8 B1 u$ ]( I0 {
( c( |* O8 U4 |& i# J' v' F
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
/ Q' _, j, J- h" Z
/ p5 k; L* q6 K8 ]4 S% V& E8 D3 V4 J    }( x+ o) O, v$ V( d# g6 w

2 n2 R% @9 W; a, r& N- J- f* h    /**) [6 j* A5 h- Q

: J5 N& j4 U7 u* h    *@dev返回给定的spender是否可以交易一个给定的token
$ `' X" y% b( R! B6 O8 U1 R3 B
$ X+ t( ?) Q" |' C8 Z! a    *@param_spenderaddressofthespendertoquery  T0 c7 v: L9 Y8 a& [0 Y( x
1 X* c3 j4 h* @* @( M4 T" _
    *@param_tokenIduint256IDofthetokentobetransferred
  M, X$ U. r# A+ x, x+ v" @4 `" R# K: P& e9 T" X
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,$ Y5 p6 V" l7 ?8 m
5 r, s- L: x( F2 [& ?/ t
    *isanoperatoroftheowner,oristheownerofthetoken
1 C  g7 C6 f  H/ U0 C3 q. v8 n( {- w5 M+ ^
    */6 W3 e5 C/ l' R# c! R; z5 S
  L: g. k$ Z/ A% S2 J- Y0 i
    functionisApprovedOrOwner(5 J. u9 m' v4 L
+ S# B) [. E, N  K7 T
    address_spender,* U8 ?# N3 l" H: l

) g% U5 W3 u; e1 p2 P/ t: D2 E    uint256_tokenId
9 C  X. ]- E/ ~, N
/ d+ }7 ]1 x) P, H    )% }6 C2 I$ O" ^" P$ S% J

1 Z/ z  p: A( W2 x    internal
$ c, d) E4 J6 E; O2 U* C7 M0 B
6 x: d6 t4 T  m    view0 @! t. o& I! V3 [3 L

9 ?8 v& n- A$ b+ B    returns(bool)
: ?) o% h5 H- \$ w- v3 z' p* t9 O
# n& w# R# P8 k% ~- ?    {
& L6 t$ Y. x7 J/ A
; A+ g: N$ r: @3 ~0 n" B; U- a5 G    addressowner=ownerOf(_tokenId);' s# D0 c, g  {! f

; q6 G9 Y7 L$ Y2 U% Z" ?    return(. s' a: a. ^. L9 y- S

5 v+ l. [. S3 @% n3 [6 V    _spender==owner||: ?, c/ x- u9 F0 ]; F1 T

" G; ~4 x) B9 v    getApproved(_tokenId)==_spender||
2 M! v& j& S3 p1 n
" O- v. I5 A  g    isApprovedForAll(owner,_spender)
) l9 _& i5 R( v( \
, a8 T2 |% r: n) ~4 f3 i1 |2 W5 ^    );
. V, u( a; H7 b) z& V5 r
% Q: V" F. q4 c3 }    }6 }: g8 S, Z6 ^) X$ D
$ `) m- `! y5 n$ \3 C3 K
    /**2 U$ n( [! s  d- N5 _- _" A# P% j

3 j/ ^2 e* z" W7 y: y; @    *@dev增发一个新token的内部方法
/ V& U! }- u) _1 e/ l4 u
9 E# H' V+ q* I8 ~7 M    *@dev如果增发的token已经存在则撤销
  Q: ~7 r6 E- H1 w/ Y( M  u
& R$ U* @2 a6 U1 I$ k- H/ J; O- _  A    *@param_toTheaddressthatwillownthemintedtoken# _, G, Q& _, B/ ^) _- J
' [" I: h: Z, O5 c7 q" T
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender  I: E( K' H& A' a) T

! H$ h7 L8 k/ b9 s. Y( {    */1 |4 b& K$ R) v" I* x9 j
% X+ o  e# t7 B0 ~* t
    function_mint(address_to,uint256_tokenId)internal{1 S, B  W# i: K+ j' s

% k1 O& p3 S6 V; G0 G    require(_to!=address(0));8 {, @6 A! b0 c6 ~$ l4 K( z
/ P: e! |# s4 e7 {8 z+ @+ w% K5 b: F3 C
    addTokenTo(_to,_tokenId);, {9 B. N2 m0 ?+ V7 s2 c5 G! k

! O  [7 w0 D6 p' U    emitTransfer(address(0),_to,_tokenId);  J* ?, `+ L  J, K% B( J

( T. h/ w  t: ?/ b    }5 G+ u" n  k  O) z, ]/ b9 I
% d. [4 a" z9 d4 D
    /**2 {% k& f  {0 H6 ^% D

  s0 W% H' F5 U- m8 C    *@dev销毁一个token的内部方法/ W3 O: D, V* [! f- S2 _

! Z" c; j2 [  v    *@dev如果token不存在则撤销
9 W) k/ N8 I! a" ]' Q4 c# _0 [( S2 t6 m" P6 t, @
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender* i5 Z& t3 k- |- o
& B  {& |; {0 e+ Y; c
    *// A, ^. D; H7 X( T% s+ l* u
) S! J$ d: A1 Z, q# {
    function_burn(address_owner,uint256_tokenId)internal{
- q* v* z5 g' }9 R! [3 X" ~% y8 q+ u
    clearApproval(_owner,_tokenId);& l1 t, A; @. g, R4 J# B

; [+ J- z' o+ K1 J- g3 k) G    removeTokenFrom(_owner,_tokenId);& J- _) g% t3 f
+ I4 Z' X+ j3 {+ I
    emitTransfer(_owner,address(0),_tokenId);
! d; Z  h1 }+ O2 m2 s& u7 W# h. ]
- G* s; u' R% o& y% b. f    }
; G& z5 E- K# g' A2 B2 _% t  s5 _  S$ F! y
    /**
$ u! a: T: {2 A
! Z5 l+ S4 U; h2 X3 D9 o9 ?    *@dev清除当前的给定token的授权,内部方法
2 l& P3 A% O* P/ `' e4 N% m, E9 z9 c% _1 q* k
    *@dev如果给定地址不是token的持有者则撤销8 }5 S4 a. Z1 {% i# o

6 R# {! L- J* x& y    *@param_ownerownerofthetoken* u9 h5 ^7 c/ \
5 u5 A% x6 N) X' f  h
    *@param_tokenIduint256IDofthetokentobetransferred; n4 V/ |) Q) @* n+ ]- U
- B" x0 R7 `. x7 ?; j+ [7 G- L
    */9 [3 G+ ~* ~2 f* ]# m

# q. m! [- m& g. i0 y4 e    functionclearApproval(address_owner,uint256_tokenId)internal{
( \3 e: F, [  [; c2 n7 ~
* k" C+ p6 r1 c9 w7 b3 z, A    require(ownerOf(_tokenId)==_owner);2 N/ i: b* o" u% N$ F1 t
5 a8 ~" G, w2 I; p
    if(tokenApprovals[_tokenId]!=address(0)){
' y4 T( i: [9 m; j9 u! F9 C1 @* O( c9 {
    tokenApprovals[_tokenId]=address(0);
4 [$ ?" t) P/ E$ ~/ L! k
  U! a& k8 v# {, m5 |# l    emitApproval(_owner,address(0),_tokenId);! j8 H, S: [* q5 w5 k

# I; s7 X3 h# d2 |    }8 ?4 k) D* J0 i0 K

- D8 p$ ^/ L0 j+ W& {& y    }5 {8 |; f: R* c& |6 y

( H6 d$ |" W5 q, q- g: W! j    /**
9 V1 H" p5 `9 g& ?: \! B! ~0 H% Y
    *@dev内部方法,将给定的token添加到给定地址列表中& ^" ^0 k. l; w( P
% N9 F+ T* t$ m5 N* k- [
    *@param_toaddress指定token的新所有者
+ m2 B$ C* ~0 c, N* I: I) K3 O* s1 Q$ C: J* M
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress! {: d$ b, |% B8 b0 V

9 y" V/ c( Q+ n1 F" T    */
, w' \+ b+ j% {% D$ q
. l5 v0 M  W9 K# e5 R% A    functionaddTokenTo(address_to,uint256_tokenId)internal{
4 [1 y. A; `# w! w& W8 C& \/ a1 I. U& P' w8 T. w4 A
    require(tokenOwner[_tokenId]==address(0));- Y9 B) E: }. P

9 W& d) F3 F: Z5 @3 u    tokenOwner[_tokenId]=_to;
( E$ @8 |6 g' F7 p1 U* N8 h+ ~7 b! C  x
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
9 o5 ^- W5 s0 j3 V. R; D
7 ]" A1 o; p, m9 i2 `5 u0 i    }
3 }7 e8 r5 {- }$ h
/ l/ j  X% P8 a. V    /**
: }5 T! t$ G# A4 K3 |* ^* U# N8 o" ~6 Z" E: s) D+ n9 [4 s
    *@dev内部方法,将给定的token从地址列表中移除# Q& e, |2 A* |7 {% J
5 {. |, e& W9 ^6 y* E4 k
    *@param_fromaddress给定token的之前持有中地址2 ?5 N! ^: Y! s/ {' |

9 \' D# F! j+ B* C& a) x0 i& w    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress, E- A- E# _- m5 X2 {+ `, Q, o
& t! w$ G3 @  X! _- R
    */
! ]5 k. n2 [( r; g- C9 C4 s4 d4 f8 y% f  J7 m7 Q! H
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{  j5 J$ t+ s5 ]' ^4 g, c$ L

% v2 R8 r5 e: q$ M/ W    require(ownerOf(_tokenId)==_from);
  e9 B# F8 E1 o7 N+ l( \2 F- ?0 h5 U" H, E2 Q! j
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);2 p; H2 [6 x. |! k

" @& V7 c+ f3 Y8 k/ ^5 M    tokenOwner[_tokenId]=address(0);9 p( S4 t4 N3 h* J0 K% m

9 ^& Z! {5 L+ J4 d    }; M6 ?' f% Z+ a
0 [2 K/ ^% B* e5 @  [# I
    /**& c' c: T6 A9 B3 y6 z- j5 G

7 q; x% s. N4 n% @$ C  a; y  x    *@dev内部函数,调用目标地址上的`onERC721Received`3 |0 G% f5 E& z; l' [
7 F+ K! ^+ i* y$ x
    *@dev如果目标地址不是合同则不执行调用
+ R: S2 H' h5 |! x% Y2 [3 k; Q, O/ @# |. Y
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID3 ^' P1 B$ O; u  ]  t

3 G- F, H4 p8 K0 {; \    *@param_totargetaddressthatwillreceivethetokens: m+ L- a' M( d; V& q
6 P) M& L  r* C! y: A8 F& s4 \
    *@param_tokenIduint256IDofthetokentobetransferred
0 Q- [5 t% {! g) E- _. a. Q
! X' R: @" p& x, ?- x0 X    *@param_databytesoptionaldatatosendalongwiththecall
2 b1 ?2 X9 B- R9 z: P* w
4 w- ~6 i5 R. y5 {9 x: C0 [    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue5 M! h+ K; f8 S+ x
% s# o3 s. h+ j9 J1 \# w
    */
+ _+ w; R1 y) X8 r
0 b+ C! Z( i  a- Z    functioncheckAndCallSafeTransfer(' l% N( r7 Z1 f# r! C

$ K5 h7 p4 r0 m. Y7 j) c0 ]    address_from,4 c4 U* E( a2 R7 ?

. R; b& C( t* D: M    address_to,
5 U& F! y* C7 F6 z
' C9 o% u4 G; r' z" ]* G5 X9 x" Z    uint256_tokenId," X& H5 n2 r) \$ d: t9 f+ \) p

+ K& J8 R2 d8 O$ P+ s( d' P9 J    bytes_data) f/ b5 f* A) |
( d' `1 _$ E3 K
    )
. Y# Z- W- T" Q+ v) m
( X6 O3 X& q( V$ G: _    internal
7 [6 T. O4 N3 S1 m- E( j) c  H
& Z0 Y) U: h  f  n" S    returns(bool)' V/ Q+ G% M: f& M# [9 r

+ t, z1 k5 ~  E% K7 a; ?  D    {) R& l/ E5 a# G5 D

! z2 j; E8 S- l$ D2 @    if(!_to.isContract()){
: h# k1 Q7 X0 X* B: ]) f; |$ B- `# |- f5 l$ n$ o0 Z
    returntrue;4 G, k: H0 Q& U
3 Y# L+ v( V9 T, a3 Q
    }
, P& r( k3 i/ z, X6 ^( x) r
' t% f& G: `; [: x2 S    bytes4retval=ERC721Receiver(_to).onERC721Received(( O, y0 @3 b$ I  [# @

3 R1 q& M! |5 F* {& s    _from,_tokenId,_data);
% |3 ^. k& O& v. N  n$ {3 R' Q( ~  O9 O4 Q* p$ g) Q3 V: T
    return(retval==ERC721_RECEIVED);; }# p: t4 _, ?- o6 `3 _( T

' a# z1 b* J" e    }
( Y: ]( b! B: _" \. T# W& Z' W5 M; F5 G. [1 U! ]  ~8 q
    }0 d5 p( `# W' z7 |5 T
* Z% w# D; f  z- ?
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
! }" x  ^# R1 t- Z" j
9 T+ ]  _# l# A6 _( v& s, {    ERC721Token.sol
0 s+ J. m1 p5 b% l# V, E2 i* i0 a1 l! Z, M( c4 O3 B0 z" m
    pragmasolidity^0.4.23;
% Z$ f+ G0 X4 Q8 F+ ]7 ?& p* G1 G( w9 j
    import"./ERC721.sol";
( }* o; `' \) D6 P8 Q7 J1 J1 G+ _( V
- f* f1 F. D. U# W) n! g% ?    import"./ERC721BasicToken.sol";
- y' L1 F0 L/ _/ D& r
9 D/ z! y0 r$ z    /**
2 `& C! H8 D3 V- \/ |" u# Z+ k" s0 g* H% {* z, s0 w% W
    *@title完整ERC721Token
5 \- o: d9 U% Y$ k+ B# v4 ^
' H  ^& [/ }- ^2 X9 H    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能! ~) g7 D2 y6 t4 @9 X, r& \

# D. ~1 q% f1 L3 i% p! N, R    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
0 p/ [- z) o: e1 `# g8 K, c" ^
; Q# R* ?' J, E% Q+ F9 [+ g1 J( {    */
: r2 @. G- Q  j4 Q' ?3 o+ ^, c2 ]
    contractERC721TokenisERC721,ERC721BasicToken{
. X! I! X. g' r# j" J
( A9 @/ ?2 r7 C$ i$ j    //代币名称, R& d* i3 {) g8 N) q3 p" p

$ ]7 h7 W2 H7 j% q; g    stringinternalname_;
. `& G) K+ s5 o# \& k5 z9 ]3 ?' k
, ?4 z; }# |5 j  \8 u7 p9 }# M9 R9 x    //代币符号
+ }) y1 m8 Z5 d2 _1 t
8 S, p% T7 Y  R( q6 r7 F1 ]& A    stringinternalsymbol_;" h6 I, B0 [# }; p" H: H
' R* u- ~. W- J- h0 o
    //所有者到所有者拥有的代币列表的映射
4 I* g0 N( u) B7 o4 o' s
1 q9 X$ h3 T6 x& z  m  ?3 D    mapping(address=>uint256[])internalownedTokens;
! ^/ n: m3 @9 G2 w/ D6 M' z' o, ?. D; I0 X# V
    //所有者代币列表中代币ID到索引的映射
5 S" p7 H% u+ L8 r) _6 F
# Y1 l0 }8 N, F2 m+ m+ q# t6 ]6 x    mapping(uint256=>uint256)internalownedTokensIndex;
. M) O# h* c. W& b3 H
; `$ y5 a# W% ~/ W0 y    //保存所有代币ID的数组,用于枚举' K% W, p- U2 u& G
% B& P8 a, M' ]8 K
    uint256[]internalallTokens;
  U, j+ D1 o' T+ u4 p; l- t) O* `( S) d! U$ k1 O
    //allTokens数组中代币ID到索引的映射4 f  I7 s" c. T" c! i
7 X/ {( W7 B& E
    mapping(uint256=>uint256)internalallTokensIndex;
. L$ P! i- V! m" L: Q5 G" d( x% ?" g+ k+ ^
    //可选的代币资源URIs映射
- u: P* _) g0 z! o% k
; Z$ Z. R0 Q1 q! ]6 \    mapping(uint256=>string)internaltokenURIs;
5 }4 D/ @9 m! k& P0 ~$ G/ y( n5 ?7 f. I, D. Y8 t  }( w0 n
    /**6 b5 Z+ ]# ~# _  o1 T

  F6 N0 I6 z" U8 T1 O    *@devConstructorfunction
$ v. g& x4 G3 p# @" k2 }0 i$ A8 [; O8 j8 ?9 U
    */0 g$ [, R9 b' H- q% o
. M  t4 w. k; J
    constructor(string_name,string_symbol)public{
; P4 s& D  m: a! O" f
$ X# z1 d2 c: H1 x6 }    name_=_name;
% C1 {' C' A" z. f
0 _6 G* P. k4 Q* ~" F" h7 L    symbol_=_symbol;' Q/ J/ H4 b* M. k0 b; l& }

0 a0 R' l; y" }( [* f; `" x    }
. L5 F8 I# G) e  G; Y4 r
3 Z& E1 @- \  L2 u5 o    /**
0 C- E# u7 s5 M; j% Q7 V) D2 z3 k! J2 D  o$ e
    *@dev获取代币名称: C- c, n8 Z& r, I* V, f

; U! M2 m7 g$ U6 L3 B; Q+ W! y1 D    *@returnstringrepresentingthetokenname2 ^- E! k& V& V5 |( }$ F9 f

9 F, |$ ^/ |; R+ x9 H# p9 Z/ d1 K    */" X* D1 Z& p' U0 M$ x/ o5 ?: s# }

7 y- {* }3 m' [7 V: A: Y    functionname()publicviewreturns(string){
  U9 m7 V5 w# l1 {; c9 v/ y  o5 J  z5 J* |9 c' ^! @( }
    returnname_;  u; C; k! s' f

. d4 B# G7 |/ P. j% G  c) L+ J    }' L4 m0 u4 o9 `8 \! n8 q6 s" a

6 u6 f6 J5 G3 w8 o3 g/ }- I1 B    /**
$ j/ p8 [; j: I" ]0 m" u$ B& k& n& b4 O/ Y, |4 Q9 A
    *@dev获取代币符号. |# `* ]$ X' q' Y; M7 D- D
  J4 n: m0 }* x8 l
    *@returnstringrepresentingthetokensymbol
. B" B9 r+ E; q7 W5 s5 F$ {, P
# K4 w5 U7 s8 A) A4 d8 w6 i    */2 T, w% I7 m8 {; n2 j  S  b# W
1 g7 C# q* p& H& T; J1 Q
    functionsymbol()publicviewreturns(string){' r8 U' K" M7 Y5 ^

5 S, b' [$ W7 {. h& K" Y0 y    returnsymbol_;! L- F  _6 ^7 E( h
7 w3 U* a9 s( S6 K7 u
    }
" s3 u9 _- |9 ^; d4 {0 b. n9 A5 B' n( b$ {9 {' B
    /**
3 L; E6 g% A3 B7 f  h+ q! }7 c  y+ q4 H
    *@dev根据_tokenId返回对应的资源URI
) k7 \3 O: b# t3 z
$ t* @  L# l0 E& I    *@dev如果token不存在异常返回空字符串. Q& d: C3 X+ z! }) T# J8 C

2 L$ k( f1 ~0 ~& U7 F1 p1 j! _2 X    *@param_tokenIduint256IDofthetokentoquery' y, k! @7 u3 X0 e
4 ]$ T6 E+ D% l( @% H# F
    */; I7 v/ X0 O% V

+ U$ F' |7 K" t    functiontokenURI(uint256_tokenId)publicviewreturns(string){+ W" D0 _  o" @
. X/ [7 c6 _- Z. A# l- ?) P
    require(exists(_tokenId));' u& F. ~- u* p( s2 Y" }, d" h" X

9 j/ `, [1 l+ k6 s    returntokenURIs[_tokenId];
, K; a4 I8 R* p* Y* E4 w2 S+ l
, n" J$ A8 Q, F1 z# ]' A    }
# G" L5 a  h3 e  ~2 @: J/ C( y  F& V! D
    /**
* j' k8 e0 q# K" ^( {! G
' P2 w' b" P/ \$ J) U    *@dev获取tokenid通过给定的token列表中的索引! I/ i5 p0 N3 ^5 {+ e4 Q; r6 ?

( a- p0 |& K# h2 b0 a" _    *@param_owneraddressowningthetokenslisttobeaccessed
8 X- g3 L) F# G5 K! x# P" U9 G. |+ V1 s, L" S$ Q
    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist9 o: x; Q4 M! j4 d

, Z0 _3 A+ _* K/ Z4 l8 Q0 F    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress% E& Y, e7 z; M; w

% Y# t% `( ?3 W/ H: C    */
) G, z, j+ f, f: V5 R9 ~
# B5 ^4 j6 c9 H) g1 L! |1 J' t    functiontokenOfOwnerByIndex(7 [2 P  W" a. C% Y

& B4 L% h  Y7 B% A    address_owner,
1 r1 `1 `- v' B! J, W# {
% k: s& R' r/ l5 r/ q3 t    uint256_index! d9 c2 U/ p: a, m7 F
% F1 K, ?4 U4 w8 b: I
    )$ q; {! O3 Z$ s1 d! P
( F0 a  v, X$ ~4 s$ ^9 Y: r
    public  B  E7 k1 Q# L
+ D, }+ m6 n" N/ m7 t" H
    view
8 n% i$ N( \; U- n" U6 J1 _8 g
    returns(uint256)
7 K. ^! q* [, M5 S+ t
8 S/ E4 C' I$ m1 a( D; T) x& _    {
% @; {* L0 r# s/ J# \! ]1 \5 R$ B# r" }8 r; k" @: Z
    require(_index
: C: X- S# {4 k# y9 u: f, b( q2 C- }" u& P9 `( N3 g
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。4 g7 `8 w9 G/ `! m
- K! \6 g; }1 p7 k) o/ t; ~
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2