Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2480 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。% }3 Z3 i% }  P$ o# p

' ?+ |: G8 D, [' e1 ]5 ?2 Y    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
2 R& @* ?% I) ~1 ^" J1 c# P0 B
1 ~( E- S4 _; @0 t5 C# }6 ~" j8 F" X    ERC721Basic.sol
% u/ o: ]3 l' a# `- T! ?8 U; j( m9 r$ b& G* J$ N# v
    pragmasolidity^0.4.23;2 t( Y/ r7 O% U3 y' d% V5 }/ B
3 C+ c; m3 k5 v4 V; H0 h
    /**
4 }9 e5 M6 m- \( I: A
+ F* [/ m, j1 i9 f  W5 I# \    *@titleERC721标准的基本接口8 ?. s6 P9 p, B! ?' s! \% ]* D% t1 }

- C4 N$ J. U/ C0 O! }3 e2 X    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
8 K, D6 W4 W" k2 n) E, @  i; f2 A6 O* b
    */
7 G# H1 O5 L0 Y& X
5 t5 t4 h8 A  O4 e& C    contractERC721Basic{' z" H" G: Q7 b

7 Y7 l; {( o( t) k5 B6 H8 r' F    eventTransfer(
$ |0 K. g6 |$ ^* B$ d( o! V: r' C2 _3 ?+ }+ e
    addressindexed_from,
0 Q% M+ n8 ]) @  A* }) d- G- C: S: u7 K  Y
    addressindexed_to,
' m3 ?& l( e( J; A  [  Q* p
* |; |9 x, z' E, u/ Q$ ]    uint256_tokenId4 A* t9 y/ P8 ~4 {0 @1 M" `

, H5 A2 B! J, `3 V# t    );
. ^/ f9 n' f9 H; L
+ o  p. r7 l2 C( S4 L4 V" X    eventApproval(
+ F5 A0 k% \. G' w6 R: n: u$ N! W  m# L% ?8 l5 E9 x( \
    addressindexed_owner,6 D; ]4 T. ]$ m. f0 X
# n1 ?% I/ D# W. O
    addressindexed_approved,  Q& j/ ?' F9 S3 l3 W* ~
5 b7 {) T  b4 e0 d* i+ c6 r
    uint256_tokenId* t4 `2 x5 m0 K5 L) z# L/ f+ X5 N; M' c
" L: t# l* p% F3 s
    );
' D0 g, z) R2 d0 K3 Z
0 `  f# z' h: i6 t5 |    eventApprovalForAll(
2 W# V! ~2 H2 X3 W4 D; c
1 w: {! X, Y4 [1 n, t; ~# m% `" g    addressindexed_owner,0 g' v' ^5 Z( w/ `" j
$ A6 W+ r( z$ |4 @8 Z6 D- k" K# D
    addressindexed_operator,
; ?+ ^+ |6 B5 @- @+ H" Y8 l$ B
. z' D9 @2 N3 v3 b* I    bool_approved( F0 Y' a& {* r" g

3 }) W* E% o: [9 W    );
% E7 Z* i& J' |4 v9 w, F) W( _! w, D. J
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);: b5 |- z4 |* v: r) t- \( O* t

# e$ r) t1 U1 G    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
8 {6 A0 y0 p. ~8 s, p$ v; w
* n6 I. a7 X' P$ l: C7 ?# P, t; q    functionexists(uint256_tokenId)publicviewreturns(bool_exists);. {# R* e+ _- e2 S2 a0 I8 g6 y% [) F
: `3 h' u3 a9 c
    functionapprove(address_to,uint256_tokenId)public;
- d& I9 @& \8 p' V) O1 h( L  F4 V7 F& L4 U  H
    functiongetApproved(uint256_tokenId)
* u- M  Y0 S  P/ j$ |( ~% D% G4 W. P4 e, ^
    publicviewreturns(address_operator);
* @7 ]2 y; u3 c/ R% c( n! H/ F# m8 e* m
    functionsetApprovalForAll(address_operator,bool_approved)public;
. H9 U! I) D2 {* c( l8 u; ~8 Y! ^$ ?* B) f& z
    functionisApprovedForAll(address_owner,address_operator)9 H' D6 H- q$ f& Z
! V7 n+ ]9 g8 {$ f" z8 E: s2 O
    publicviewreturns(bool);
+ u/ A4 o7 J* @2 N. D, Z# b
0 S! F2 B% c5 S5 ]    functiontransferFrom(address_from,address_to,uint256_tokenId)public;- j) z! Q5 h0 ^# |4 @
) k0 [5 G6 r' ]) C% X
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
, t  g3 G; d4 N8 R* h3 R8 F/ L/ i7 r  h( i
    public;1 A9 }; }! z& A/ o1 w+ T4 C
  a: f8 F0 Q+ q* R% ~
    functionsafeTransferFrom(
! j5 B! q: l9 w" u7 ]" }, Y( G# F8 X
    address_from,6 b( Y6 [7 I: d6 J3 |9 q+ V

( l  l5 |8 D& f3 Z5 ~, c    address_to,; f' e& }# A0 V/ C4 A+ V: `

4 ^0 d# V' B% O! ^' s    uint256_tokenId,
$ X/ a+ D( r& T6 t7 N/ }" ^8 S' D
    bytes_data
, o9 @2 }2 t' m" x7 o" f% n
; v1 ~5 ^. h* x% p0 b    )" ?) D9 ]. |/ d/ H) i( B5 e

3 t. t2 a3 T! x8 X0 x3 q    public;& F% j% v4 v1 z* q- ~1 H/ i6 o6 W

  r7 \: m" r8 ~& ~5 T    }: B" }2 ]5 X" u% M% a
! `! L$ h  ~" L# {& v
    ERC721Basic合约定义了基本的接口方法:
: l; Y. }8 |# x( `# R6 q5 q' E" w' Q1 n% P
    balanceOf返回_owner的代币数量
8 k2 Y! R/ {! Y5 `2 D8 ~" a8 E* Y1 t" C; A
    ownerOf根据_tokenId返回代币持有者address
& c) e3 h+ s- ~
0 ^5 B0 x! P9 `0 ~- K9 F    exists_tokenId是否存在0 \8 v$ _) m5 e8 s5 P

! Q) G; {+ w  P( G3 T7 h    approve授权_tokenId给地址to$ r7 R$ k1 l2 a+ P# \6 w
: H# i) K" c. M$ u" |6 Z
    getApproved查询_tokenId的授权人_operatoraddress
: F. [8 d, Q: [7 F; f1 ], ^4 c
$ z# [6 `, b8 y/ |% ^' Z$ X; [; G1 e    setApprovalForAll授权_operator具有所有代币的控制权
8 n9 ]' B7 f3 S# T; n! _- O; E
# x' o: @* d7 b  n    isApprovedForAll  z  `# [; T& L% C  G
4 _) M0 ^- Y- o; |: l5 E: m& d
    transferFrom转移代币所有权$ g& w" U8 z2 P- V( j4 k0 `7 h

" H: U8 \1 m( q    safeTransferFrom转移代币所有权  e" s8 J4 K) T- |8 ]5 Q3 d. p
0 p0 s2 U$ Z( ^- k9 z; U! Y1 M/ J' [7 z
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
8 C4 s! w; Q! t9 f/ I. W6 h
7 c! W0 g$ H6 {& I    ERC721.sol% A1 d! W7 K$ c' W! L+ k3 H7 ~+ W6 t$ M

1 ?% t' p& l5 e0 N- S+ I3 K0 O- k    pragmasolidity^0.4.23;
! m" `3 ]( X$ |/ B7 j9 K! p5 K8 W# ^
6 g& e1 j" ?* r5 t4 Y( `    import"./ERC721Basic.sol";: C7 [# J  I. H# K

% {: b* [4 H0 \( ~# O    /**+ D& T8 ^% `$ |; b
: F0 G+ v6 e- Y: j' v
    *@titleERC-721标准的基本接口,可选的枚举扩展
3 p7 B& Y! r/ o9 N9 P2 H- l8 }8 }8 k" N6 B, v
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
" E+ f9 \' u! g1 X1 }8 L+ i
* U+ \3 M4 k/ ~0 @! H8 f    */" f* x6 I, g( j( o* I

$ E( B4 T- R" o4 v" G# ?2 C    contractERC721EnumerableisERC721Basic{8 M3 P( A6 u' M
/ w3 d( _/ P, c' g- U2 ?/ }
    functiontotalSupply()publicviewreturns(uint256);
; I# l: L. Q) ?: N  \6 G- W, `, A# d( W4 Q. D, ?" R1 z5 }+ o: j
    functiontokenOfOwnerByIndex(* _$ t3 e: e. g/ X2 b5 o

9 \" f) I+ ~6 P    address_owner,
: N% c+ K3 V! b, d7 o: C" F8 c% w  Y0 k' D" f, J7 Q
    uint256_index! R* \" f% Y5 t( D

$ h2 c6 T& \. m* y1 z1 Q    )
, \; h2 ?! E( T  j: m1 q2 e" ?4 d3 M6 j3 G' c  }
    public; J, r7 o! J$ p9 C. E# V  W) s, g
3 k1 K* f- R+ `1 }+ u
    view! M" Y$ z0 Q! p6 l/ {1 k- l: G$ Y

- @0 j. v5 z" e$ @8 r3 L    returns(uint256_tokenId);
$ v) e, y0 w3 s6 v2 e6 W+ V& n1 ?" c! }; w
    functiontokenByIndex(uint256_index)publicviewreturns(uint256);5 a7 C1 Y& T# y& }
# X; X4 h8 @' t2 ?8 a
    }" V6 J/ @- d/ X$ B- o7 G9 k
9 i$ O3 o% Z, Q8 _
    /**
8 v- D9 Q  F/ W1 i4 p0 r5 v. x) }5 R+ N" [1 [% f$ ]
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展8 D# j9 M- e1 Y, |7 [- S

7 U% @, D- m: C  I    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md2 K9 O$ H; Q- i1 w# Y) a! g

9 h$ U  f2 f' g    */) |; G* i9 {, a4 {
0 }. h0 x& j) O8 j" a0 l* ]
    contractERC721MetadataisERC721Basic{
  F. G, n: F' X  N4 @4 f" D4 _; h& d9 ]5 C) C% j
    functionname()publicviewreturns(string_name);: g" ?: J* t" v5 U

4 l- w& a3 l8 p$ \& F  P    functionsymbol()publicviewreturns(string_symbol);
' n/ s# z3 p4 {# A
2 f2 h# J+ E" }. z    functiontokenURI(uint256_tokenId)publicviewreturns(string);; s0 \* n2 }4 K) w. e

  x: Z) M8 d, f, n    }
1 J# f+ d+ V/ e3 F4 N' u8 X0 c, S( @& r' t. \* l4 u6 a$ g
    /**
6 v* P# ^& G8 e8 k  `( ^8 h  O, U- j. @
    *@titleERC-721标准的基本接口,完整实现接口
1 n+ d" Z1 H) u. S& _) h8 i. M& o. \5 H& ^
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md1 [! L0 U0 l. K. P
4 x( J% H7 I/ Q8 ]2 `9 I; L2 U7 G
    */6 ?9 v* P9 M( v  ]) _
! e; q# t' U. a5 G
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{2 Z) T0 x' R" {5 t& h

. j, C4 T0 g/ h( J    }
+ a+ S% R/ S* }$ _- l  J* g+ |  E9 V6 X! O2 C" w
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
/ C# n4 p& p" B& @( U: @* n2 K0 [
% n' f. [+ h1 R    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
2 j* @  L' O" L1 Q% H0 `& x5 _& W4 ?. }
    totalSupply返回代币总量6 p1 G4 F6 N; i8 T
+ O. R& ~( J; B2 }1 F6 w6 i
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
7 a2 W1 X6 G/ w1 N- N
5 ]+ h0 m; G% n( e( u    tokenByIndex通过索引值返回tokenId
2 q/ C, n4 o( B8 P/ W; Q8 |" I' R9 `2 U* i- g
    ERC721Metadata元数据扩展哦用来描述合约元信息
* h$ ~# B9 k, }$ {
2 U+ x5 H1 t4 p% t    name返回合约名字
$ Q: N9 U" y: N4 p5 [! o0 w/ I% X6 X- a* i
    symbol返回代币符号
0 u7 w: ?6 k+ W$ h) R# b0 Z! ^9 p0 b! y5 v# J
    tokenURI返回_tokenId对应的资源URI
  V$ k' A& Z( x$ X1 f4 ~/ M+ \. Z  t; O0 d; D# ]$ R' ?4 N
    ERC721BasicToken
' L7 H) X, C- @. \: @8 Y
: U1 k) y2 e% Q" k$ F" u8 E4 v    ERC721BasicToken4 W- f. H/ p9 a/ R; M$ \' h9 p8 T

6 q" F, B5 B, t' e" z$ f1 j( y' T    pragmasolidity^0.4.23;
( C- C' R3 y" N7 B8 @; `- {! s7 r* m/ v( ]6 S" a
    import"./ERC721Basic.sol";7 K2 A5 N/ O! _- z% _* _
5 o; j* d# r" L
    import"./ERC721Receiver.sol";6 i8 @8 x' _. o6 q7 n4 }1 Z

. }" n; I3 B4 r% L( s* T    import"../../math/SafeMath.sol";
* i9 d" Z  z9 _
8 Q: Z8 C) y% I! }1 s    import"../../AddressUtils.sol";
! A9 P. A3 e. Y+ L, F, g' z
" [0 \/ C; l' h. W9 i3 T: F$ l    /**
) E! r; x; b. L- n& Y  v5 s
7 A/ Z) v+ W2 |5 v; V    *@titleERC721标准基本实现) k% g- t3 w# k& W+ J
- K! D) m, N1 m) E2 G; {6 ~
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
( z+ k  N# V. v' `; }, R$ k3 i# B" }6 M+ v" x' l) e, O" C
    */6 C2 w3 Y% A/ J
; a7 @8 Y" z' s3 ^
    contractERC721BasicTokenisERC721Basic{1 V" X* j" i) v6 ]: p8 O! |$ ]

1 R4 N$ `/ k5 s( ~* ?( j, s    usingSafeMathforuint256;
8 e6 O5 R. _* j7 m
& ^, {* d: H" [7 r) d0 M    usingAddressUtilsforaddress;1 C- j2 u: R# }; T8 e$ Z4 p/ k

$ ~, C) x2 J6 e, F    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`2 [( O8 i9 J  ~& M* ^$ j+ F6 Q
. \( H" M( S+ {; }
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
4 m* Z3 S. u3 D# v' c
* E/ V" P$ {$ i3 O" Z    bytes4constantERC721_RECEIVED=0xf0b9e5ba;- q% ^6 S' u7 J$ O8 Z1 b
- p7 j0 G& a; f9 T9 T
    //tokenID到持有人owner的映射7 L; S' ^) X$ p* F& d

0 U; Y; K) I0 v( V4 u: J    mapping(uint256=>address)internaltokenOwner;
  B% r* i5 v7 Q! g3 ]! k" ~4 s
    //tokenID到授权地址address的映射3 k! G5 F* Y4 R8 H2 F# S$ U
! V( m0 ]. w9 ^+ S& \" \
    mapping(uint256=>address)internaltokenApprovals;
) @, [$ F. M' {( o, v+ F# G' D8 @/ a- v/ L) ^& t% r/ n) T
    //持有人到持有的token数量的映射
* }0 y- R. z' {# T. q" ^- L2 @# v9 ^% F! Z$ f( J  ^$ m
    mapping(address=>uint256)internalownedTokensCount;: ?( b1 [1 U/ V, B
* o8 s! @' m) N* @0 Z3 H
    //持有人到操作人授权的映射
; Y8 z- f# m- j3 @8 B! n; x! i6 Z  X* {2 ]" G- J. r+ [
    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
% }' p# M1 o! v* E/ K' Q
4 W* h6 V. b+ U$ Q, V* E) k2 f    /**
; L, Y3 G0 ?, b; a( D2 i8 C! ^( l% t0 a/ [  Q
    *@dev确保msg.sender是tokenId的持有人
" Y* C7 w7 d+ t5 y; T, L/ J9 ?% _9 D1 _8 }+ ~& C& E9 Q
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender$ e, I6 T9 m' s1 s: ^4 L( c
* ?$ K, A1 d/ l
    */" L3 p3 X7 G" F; X

: C$ ~. d/ y1 e    modifieronlyOwnerOf(uint256_tokenId){
+ k3 _( T! D7 M$ V" v3 m9 c3 G5 M* w" @
    require(ownerOf(_tokenId)==msg.sender);
, L6 D  q5 h7 e5 w$ i) [3 {3 y9 n" j$ w: q, R
    _;
! N$ v# a% P/ J7 m6 T% K" t8 B4 V' p% W1 r1 w3 W
    }$ T% o/ }/ r. U% V, i) Q8 F: o

% P9 T: b8 T# `, t. \  Q- v' K    /**6 g- i1 m7 d: C2 @+ x" d7 g
/ w- ~' A0 Q1 B( g) w9 e
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
1 Q5 {2 N+ a' V% J$ o) c
+ f3 L/ ^* j% p  R    *@param_tokenIduint256IDofthetokentovalidate
4 I1 D* `- u# [9 d2 A
8 `; L: y- a+ u# j( W6 @    */+ b" u1 k- s" n& G5 n3 {0 U
" H1 t4 t, z$ G+ p1 B0 M
    modifiercanTransfer(uint256_tokenId){
/ m: T3 J" k! m% Z. G5 d2 d" d9 m, I/ K/ m- n
    require(isApprovedOrOwner(msg.sender,_tokenId));
; C, t3 s' _# r) r+ F2 {* c1 y! e' k$ P6 P  d. T/ I
    _;  T: U. x7 w/ U- d, L4 j
9 e% L) [$ k. o! O! M
    }
& _( J  ^$ I1 M4 n( `9 U2 e* g
1 q6 Z* g7 o" }: H& W    /**
. B1 h9 s. a2 L5 k! E3 _3 O+ P. A* ^4 Z5 {; I( l9 x
    *@dev获取持有者的代币总数# J6 h! a" B# I: E  s
/ ?8 j$ B, E1 P" Y+ {3 J
    *@param_owneraddresstoquerythebalanceof0 ^8 H2 u4 m3 x

5 i0 e1 g" D# z* q( h* S# l" M8 K    *@returnuint256representingtheamountownedbythepassedaddress
' `5 Y) B* [# T1 W5 _8 K0 y, T
: f9 S$ K( `8 q+ I9 L    */
* D  A' w2 S# E4 A/ `, T: v! r3 E* _0 _# o; q6 m" s! m" x& I2 ^
    functionbalanceOf(address_owner)publicviewreturns(uint256){
# U: @$ L+ M- n1 [
2 y; C. j: K3 |& y/ ^    require(_owner!=address(0));+ R( `1 d# h  F, L
8 N1 g2 M: j& Q6 L
    returnownedTokensCount[_owner];
( t8 {$ D) Q9 _
- ?' `. u& m3 D    }
' e$ @6 u2 v& n. C) |
3 f( N. S% d( X0 X' o    /**
) J8 }! B. T# n: q/ Q( C: ^( N
, C- x! h1 l7 S% P' l: b' x/ q    *@dev根据tokenID获取持有者
8 {9 @* [( @8 g% K7 r0 n. A
3 O. a: F5 a$ S  @9 K) ~    *@param_tokenIduint256IDofthetokentoquerytheownerof$ q$ y% a/ ~  J6 [, b$ T

. @! p5 \. T) A+ R    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID$ @0 w9 R, I) P' V7 c+ t/ K. Q6 e
+ e# X, R7 @( X& T  N# L* [
    */
9 n3 n. L0 O; a% J- l% {
- V; D, G3 `& z# l6 L$ i6 C    functionownerOf(uint256_tokenId)publicviewreturns(address){
1 ^; W& Y0 z- L& n
0 ]6 ]' r0 P* D    addressowner=tokenOwner[_tokenId];
- Q' `5 `% ]& }, z+ f% a! u( m
% c! W$ g0 L7 f& t    require(owner!=address(0));4 p9 R- r& a9 P. N! @4 U8 T
) U- \) E/ O8 _9 T
    returnowner;8 \; D/ e8 P" ~4 W
) Q0 n# b+ H2 p6 u' w) \
    }
9 M# h2 `. [4 j8 b$ K2 _9 O1 m( f
. M3 R" |" [; v% [; p1 ]- X; A    /**
6 D! _, O; ~% @1 e
9 _6 j3 q8 N) Z1 N    *@dev指定的token是否存在
- ^2 B5 c# O# k$ P. X" }
/ M2 `0 y. c; S" x0 I    *@param_tokenIduint256IDofthetokentoquerytheexistenceof9 g1 q. b7 {4 g6 B4 V! ?; G3 W

/ |" Q5 Z# K- V! x    *@returnwhetherthetokenexists
0 M  W5 B5 q3 D( k2 ?
' l3 \2 \1 J; u/ ^0 H2 [/ L% ~    */
7 }3 {$ X3 f% D/ }# C  I& r( o# I9 Z* S- |% ~- Y
    functionexists(uint256_tokenId)publicviewreturns(bool){
# D( @3 k- n. N  g3 b0 Q' E" }+ ^) ~$ A6 {4 M; j
    addressowner=tokenOwner[_tokenId];
9 Z1 R* v1 i& T5 F8 g. z, j: w5 a7 R* ^& h
    returnowner!=address(0);8 }) y& I( u& S) H7 W# W  W
! B# Q: f9 j5 N3 e3 S5 j( H- D6 w0 F/ V
    }3 j7 h9 \: t$ a# j8 ?3 G

( _; t+ a9 a- a+ A+ |    /**: B" Y4 C0 y3 Q; M
3 y! t  D: g) v1 n
    *@dev批准另一个人address来交易指定的代币+ I4 H' e; L* K" b3 O! B

1 p/ ^; Y. k3 X! E0 t& p: q  @% q8 K    *@dev0address表示没有授权的地址
# f7 Y& @3 Q" N' e" L7 Z) ?4 ^# x1 e) _; f& k- F$ U
    *@dev给定的时间内,一个token只能有一个批准的地址) Y8 K6 _/ E( U

6 n, `/ x( x3 J6 a9 E( X5 \) ]    *@dev只有token的持有者或者授权的操作人才可以调用
4 I' @% M! n, [" s  J4 w; T, P+ t& V% K5 R8 |) t  R0 x
    *@param_toaddresstobeapprovedforthegiventokenID; F4 ?  l+ h) {( F- m5 _! L
0 \' v8 l3 [6 q! b
    *@param_tokenIduint256IDofthetokentobeapproved& I! B+ K) L+ D9 i; N' k6 Y' Q4 I3 {
! ^# J8 m/ r8 d- u; _8 d
    */
% b* {5 X6 W  z- }( }2 l2 b5 r5 w4 H' V( X' t$ b6 P/ T
    functionapprove(address_to,uint256_tokenId)public{
3 N% h& I3 O1 A+ q# D, |, l2 s" i$ B6 T6 s
    addressowner=ownerOf(_tokenId);
, v5 M9 R. V2 S' f% c
6 C7 n+ i% m- Z; ~    require(_to!=owner);+ n. M+ G  _" u9 f* |
; C) Q" n6 w- \) e
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
  C# c) ~2 X: X! R( d- t4 G; s7 P. b
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){: q: A7 d* I; S

: ^3 C1 K' Q( _! F7 P    tokenApprovals[_tokenId]=_to;; d/ y. p5 P" |# r1 y1 P- W

5 \/ {4 W  W8 [& ^7 {    emitApproval(owner,_to,_tokenId);
8 Z5 S6 e% i1 d' M4 ~- z! s  M3 h  ~. z2 f
    }
/ |2 q. D' o+ X2 q8 C/ r5 P) k
6 x" u1 f: R# U: s    }
( G7 S( O1 O* o: ^8 {+ E
& Z1 W5 W; K3 X    /**% Z) {, U* ]; Y, M( g

3 l/ W# F" `# I3 l! f    *@dev获取token被授权的地址,如果没有设置地址则为08 n& w, Q) }  \1 a

  {% `! H% d# W$ b6 c3 g" b0 p" q    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
; s3 Q4 P* n3 ?6 v% t) |
6 p2 Q# t6 g2 U0 e) a* R    *@returnaddresscurrentlyapprovedforthegiventokenID
7 V: K* j, O" ?' b
  T1 }) J( n4 C  l    */9 N* s( R6 ^: l2 C8 G/ b0 M( ^

1 Q0 W& w2 w1 {. ?* J2 z    functiongetApproved(uint256_tokenId)publicviewreturns(address){- ^6 T: n/ D1 X, R8 p
* o6 U8 c9 J0 o9 n
    returntokenApprovals[_tokenId];% h# O2 X- H! E" C

$ }. P* o+ L& w. X  ]4 `8 o2 W    }
' ?* V* B. t; M
! |) x7 i4 ~7 I7 V7 }" M, c    /**
: K* G* Q  X, E7 u' z; ]. M7 i) x, G# N3 X8 N# r  b2 D! H" T  U4 x
    *@dev设置或者取消对操作人的授权
: o/ U! M% v% \$ B/ n* V. n
3 r5 n3 U+ i% i4 n! @2 W4 x    *@dev一个操作人可以代表他们转让发送者的所有token5 A2 X$ a& U4 F5 d8 X6 V& u
- E- B( ^8 o3 `8 `& r- B, |1 P
    *@param_tooperatoraddresstosettheapproval
! ^7 L! H& m: f  e7 r5 c5 i* M0 O% e. c4 B+ t
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
, }4 z& D$ i3 X4 G
3 E. o$ H- K" A5 U* R- b    */& }0 N% o+ J: ^- y: p  i

6 W6 j! h) @" Z( }. i* n    functionsetApprovalForAll(address_to,bool_approved)public{
7 s! V7 y7 g& y$ G! m% O4 @8 e% Q8 u0 K
    require(_to!=msg.sender);- J9 E! U/ K$ K1 B

  G* `2 Z$ N4 Y$ R: P- c6 n! {    operatorApprovals[msg.sender][_to]=_approved;- P  F5 c# N. ?0 \) z' t3 d
3 ~6 C' F0 z5 ?3 |3 k2 k' g2 V8 _5 o
    emitApprovalForAll(msg.sender,_to,_approved);
+ ?8 ~7 F9 P8 ?& p& E
4 w: |% i" V4 U- v% d    }* h8 w& R! J& }+ j& @$ x# W4 E) O

6 _5 |- G( K( C, J, i) E' Y    /**
9 B3 h  {; j' y4 p9 |  E' {: I" F$ n
* X: u+ N4 a3 b0 N5 |. C    *@dev查询是否操作人被指定的持有者授权" T* M; D- w1 l$ r3 p# {8 k
6 T! M. ~3 I: M$ s* U1 `; _
    *@param_owner要查询的授权人地址/ P* @5 O* M6 V9 e

6 |. T6 f: g) U! j$ V    *@param_operator要查询的授权操作人地址
: ?+ H$ P1 Q( w7 Z6 V  S5 R4 x/ S2 q# B9 C, D' Z+ B' H
    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner5 h; q3 K& R' F' m0 C7 d
2 \0 G& j' k2 t; @, G$ W1 U. J
    */
* Y* ^" b. r3 c* o/ \* Q& m0 T) Y' S  J
    functionisApprovedForAll(
9 f0 [: x2 U; q/ a  O  k1 ]& B+ m& D* c5 X/ V7 o3 J/ ?
    address_owner,* ~  Z8 h2 R! |, \, ]: |' J) U
) {( l+ w& C0 b4 g8 ]
    address_operator* O7 A/ P( S9 L* Q) E9 B
& y6 G5 T8 M& \
    )
4 c3 M' t; c, y( g4 k9 e4 E5 i2 r  o, r$ j8 Q/ C- }7 ~: l
    public
  d0 L; B8 L( O9 H
5 T5 Z% @# H. }& v3 _7 x2 }    view5 q# v5 R8 C. u8 z

: K' G' Q6 W- S7 V( @" Q7 O; S/ t' }    returns(bool)
, G% b$ ?) F! q" F# u) s% v- q  q* G$ |4 I: a' w: G
    {
+ s/ U' `6 |' s9 @* F9 S8 C" H( Y
    returnoperatorApprovals[_owner][_operator];+ u" K! M% ]( K1 K) ~% A
) b- z& A& a5 t: ^4 T6 t: i
    }
! }  _4 G+ a. N' ^; \# ~1 ~8 f- N) B) i& i7 o/ t
    /**
) S0 b8 r! G9 R: C# E, N
) C, I" @2 Y* g9 t' b6 C5 p    *@dev将指定的token所有权转移给另外一个地址; G6 W3 C, ~  Q7 M8 J& a. D

, [& K/ V7 l+ y& q    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
) M6 B* k; Y6 c; c
" ]# C/ s! `/ c' c: z5 l- W" P4 |' W    *@dev要求msg.sender必须为所有者,已授权或者操作人
+ G; {6 x) u3 Z0 R0 A2 V9 E/ ~* n! Z6 k
    *@param_fromcurrentownerofthetoken/ }, h' p* `+ D( L0 e9 o% ]
" ~5 p1 `5 J) M: w* h
    *@param_toaddresstoreceivetheownershipofthegiventokenID
, v7 n2 ?1 [+ N0 y9 T6 u1 \1 }. Y- e% t
    *@param_tokenIduint256IDofthetokentobetransferred
) ]% G4 ]2 X+ b$ m0 R* D0 _9 o* W4 i
8 Z! n# r& D5 c7 D; y    */% Y6 ^- U8 }  Z3 u$ y9 Q: |
* g& w; I! T0 K2 p) S4 J+ |
    functiontransferFrom(
5 |* ^% f2 Q, E
3 N2 [, W+ T6 T. t- ^* _4 ]& e    address_from,
3 A7 {" K% X4 ]7 i. T# l; N: J2 ^1 z; k3 X, e* r
    address_to,
3 n2 |7 ~3 I5 m1 c. }
+ @% y, L, U) D% T' S1 ]    uint256_tokenId# T7 o- n: I& A% Z

/ i1 u) m1 W; q; S' a' _2 [+ c    )
5 Y+ j- R2 r$ ~2 S6 R  e# w
" F1 m8 V1 ?. |    public
/ V# M. _- U9 X. a  b3 J
3 K& q) C1 Q1 i    canTransfer(_tokenId)7 d0 L( Y" d* a# {8 k

7 u6 b- R) x: i# L    {; T9 k- x: d1 |4 `

! R9 s: B1 B0 s& N1 y    require(_from!=address(0));: h* ?" J, \+ }9 {4 J
9 [: X5 A9 i, p# V3 o6 F$ w
    require(_to!=address(0));
$ p+ [! G' G- D  d  r* T2 _, E0 ~) i- K3 f# T) e6 r
    clearApproval(_from,_tokenId);
; ~# i4 v( J( _% y: v# f4 o. x, E: }! m& [( L* b( s6 T* a( l
    removeTokenFrom(_from,_tokenId);" B: p" t. j- k. U
& N6 o$ H+ a/ s3 m4 V* H
    addTokenTo(_to,_tokenId);6 g2 m: d7 K& ^: h$ x" A
+ \( T5 E; g& C4 m+ j8 ?
    emitTransfer(_from,_to,_tokenId);
2 Z4 m; _* _3 W3 e/ d# c& [( c
. I. |5 f  W0 v2 O3 {% n    }
4 B- V5 ^. |8 Q( G$ X$ H7 t1 J4 l8 }. d3 }  Q
    /**
' T( F' o) |7 F
2 u/ a- y' X  J* b. U    *@dev更安全的方法,将指定的token所有权转移给另外一个地址; E9 ~/ ~$ O4 N/ E, N

% t* ^3 I% v/ Q4 v    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值1 Q* p: q1 a7 O' V  x3 o

$ i7 w5 k; }; x$ D0 ?    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
7 G! T' X+ N+ c" N! x+ |
# c1 q( i& f0 N! o. e. A0 ^" c    *@dev要求msg.sender必须为所有者,已授权或者操作人
2 ^' j$ Z) J) ~) @: h, F: I0 P# ^; U' p. e
    *@param_fromcurrentownerofthetoken
# q1 W2 X7 Y$ W* ?- q. v9 x
! g: F  [5 L  G$ c" w0 w9 Q    *@param_toaddresstoreceivetheownershipofthegiventokenID: S: c" h' }: g" S
. x2 c# @, T1 n  I7 O
    *@param_tokenIduint256IDofthetokentobetransferred
! `: ]* G4 d; i" @$ g6 K. d/ p( U" d2 E& I: U' {
    */
4 x7 N7 X9 F: I8 \7 K
6 W1 I& s4 L" G) Y! P3 r    functionsafeTransferFrom(
6 X! U/ O% \1 K; i6 e& M5 r* c( ?  R2 \+ r
    address_from,  ^7 f7 ~1 {. a9 f: E

8 [; @: ?* M0 b& `5 [5 N+ `    address_to,
6 r! L9 w' K# ]! `0 ^
8 V5 n- T7 C( E- \; c    uint256_tokenId
3 e: O2 ~; q8 M' Z, x. z7 d8 t: i3 [; |9 ^& J
    )" ?6 r9 b( s0 E8 j3 Y9 U9 J
$ X, ?) K7 T* y; ?& l0 H
    public
! m3 o$ E" q/ u/ ~1 _) I( @4 b* w
; S2 R$ v# x$ m    canTransfer(_tokenId)+ T. x) F8 h% `& D0 p& E# H; I

4 P, L7 P- A8 y, g9 K& }    {" R7 m" \* H) g: |; \% s

4 P, k" K  v5 \* b" U' M/ D    safeTransferFrom(_from,_to,_tokenId,"");
6 _4 b" q& a: k; e3 w1 F  p% [+ }& C( v4 R
    }
8 B7 ]3 f, h4 h4 s: h6 T2 q; J/ \; p/ ^7 G) x
    /**
# |/ Y: A5 S! h6 U4 i$ H. {) T3 k' P- I' M- U( f4 C9 b1 D6 e
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
7 j& u# L3 b# @" `5 \7 y6 r9 l! I! q6 f: C5 R1 r7 W8 @- U- L
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
- H) m+ L) y; Q" ~/ r2 g6 q6 n) S3 I
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
5 Y; ~7 B  T" _: L3 p" m
- c0 b2 ^7 c( N( X    *@dev要求msg.sender必须为所有者,已授权或者操作人
5 x# r5 N1 S6 s" B0 h
' ]- |+ P4 k( O7 l    *@param_fromcurrentownerofthetoken4 B. h8 s5 e3 a) F4 j: p

2 \* f. ~" Z+ A: o; H; ~6 o    *@param_toaddresstoreceivetheownershipofthegiventokenID
3 t, y) l0 S9 c" g2 P- ?) Z' V# H
    *@param_tokenIduint256IDofthetokentobetransferred1 r( M. T( H& q/ _$ @& ~

$ v* u# E+ h8 l& U8 X3 ?. }    *@param_databytesdatatosendalongwithasafetransfercheck( J$ T' i; l1 F/ C
: k1 f( i( K; p$ _( E8 R. s# ]# X
    *// T' y' Q( }) Y

3 r% t  E" G. R$ z$ H7 Z    functionsafeTransferFrom(5 L5 `4 t- ?' }" F+ ]
  u0 b9 Z* X8 R+ A
    address_from,
' S2 ?' c* H5 P* E; P, F4 m
# H9 v2 g) ?2 a1 r' n    address_to,
4 [$ w* s1 W. W/ |9 y8 |; w5 v5 R
/ ~3 N/ v* n' S8 H, z& a( b    uint256_tokenId,
8 K0 E" _+ A; m( I9 j; V( N" j# C. g. k/ F; ^, H7 p% \4 E# @9 m
    bytes_data+ h! M$ f$ z$ x) ?0 @# `
4 x+ X. _1 E' O- E1 H2 i
    )8 ]" y# E! L; E6 I; Y4 k- K2 @8 {
- Q" W% f! u" l
    public& r. j9 Z& Z; f* }- g8 H

. p# P- i# f1 O2 r    canTransfer(_tokenId)
6 C5 @$ r7 }; v1 i# g( x" H
% [: ]' P2 K0 |4 l+ j    {* @2 A7 J8 K' D) m5 K

9 _' V9 Z! [' z; W5 W4 r: V6 x# s    transferFrom(_from,_to,_tokenId);
3 L6 P0 G4 X: n9 I  Q
- |- r# |0 u7 ?9 M% A# y    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));9 \! a1 O  j6 R3 E% Q& G: h, s! p
/ e8 A3 t) J2 ]% K4 H# y0 `& v6 B4 e
    }
7 e8 B2 X; H! H
* ?+ F% `# B3 H! ^  h8 M    /**
# Z1 E1 T: B: R9 |+ h1 ^, t, k" t' A: Q. W- |
    *@dev返回给定的spender是否可以交易一个给定的token
) I5 z" t8 Y0 D5 y% U! X" v' Y8 K8 a- s* `+ N
    *@param_spenderaddressofthespendertoquery7 }% N2 x3 y) J! ?4 _& z

8 Y( y4 H% E2 V" t+ h, k* U    *@param_tokenIduint256IDofthetokentobetransferred7 h5 H1 U# `1 ?7 ]) V- R9 ?

' }) n+ Q" J+ \  F    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID," D+ c, @5 {0 g! h  X# _
/ K( X6 a. d9 \
    *isanoperatoroftheowner,oristheownerofthetoken
+ C, K- `3 {+ y1 F, v# G5 Q+ T7 A; }3 ~. R! W
    */
6 _% ]3 J) X- y& m" U7 ?, {) B' Z* i& }4 ^% E  M) P, x. h+ O
    functionisApprovedOrOwner(; \& `* f6 v7 `- n) t
2 Q9 Y: D* b9 r  g# }7 h2 [
    address_spender,
" A& o+ o2 x7 `, b( @+ j
$ m/ _/ @7 Y6 j/ p3 p, q- l    uint256_tokenId, z7 w- t9 E  l: n+ X- J8 R

% [2 w, k8 F; q$ }) ]8 o/ E    )- L, D, H; a; J4 u0 [9 T& Z

/ t3 q! [6 w8 I) I    internal
, _1 b' V7 ^+ u' t$ L5 I3 t* \5 E+ ~
    view/ q/ K. B1 a1 V, M3 h6 t. O4 @
0 ]4 n& X2 B* P2 B: s9 g
    returns(bool)5 Q' ?4 z, w: u

  I2 z1 m  f( p$ x: H    {
5 A: t3 d% W# y! |. Q7 Q0 ]; z& D  C5 {7 S& }
    addressowner=ownerOf(_tokenId);/ E3 W  o0 x9 S: u# p
' L) z: J; p) g
    return(8 M2 t4 G" R$ m, y( q# d
) H4 ~5 Z. V" l& h) k
    _spender==owner||0 j5 z# b( n! I5 O

; Z- o& R8 e4 k, Z8 T# B( g    getApproved(_tokenId)==_spender||& ]$ R' u+ m9 G, w# V! n

3 C/ q- n. o# i    isApprovedForAll(owner,_spender)2 h0 @+ Z1 D7 b6 q2 g

0 @( r( f+ V# j  r$ }    );
% H$ j. H7 x3 `0 a, u  D% _$ F* f" i  ?. w* l; O) L2 z4 `
    }
- j" _* Y9 K) X9 @! p0 k% u3 D+ \
$ W1 @$ u# T! r! B' a, K    /**: A1 a5 h+ s  ^/ g9 }' C
0 G' k! Z% q3 E. O* _
    *@dev增发一个新token的内部方法
* ^) I. ?) [2 k8 J7 R8 F
3 W9 I; _' G% a  V    *@dev如果增发的token已经存在则撤销
5 I8 U2 o. g& G1 L3 F( q: h
* p! b9 |+ X. s8 r6 V: x    *@param_toTheaddressthatwillownthemintedtoken/ \7 Y4 l, N! x$ V- Z; }4 I6 B

% V3 F% l: D& h! t9 v6 Y0 t; b& x    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender6 t* v5 {" a$ g  p: R, O' {, \6 ?
- d7 j9 q. s% g
    */
7 ~/ K- o6 [! @+ N4 D; p
' W: s' n0 T' d3 o  U    function_mint(address_to,uint256_tokenId)internal{
' _+ p# O6 m  G1 {
# l  z) u4 o* [8 l7 O* Y$ Q    require(_to!=address(0));8 A- b/ g# \$ N/ Y  {

  C/ L8 p' ~1 R$ @    addTokenTo(_to,_tokenId);
3 O+ E1 x4 g) ^" T( H! v
% F/ n. F3 {( }9 h    emitTransfer(address(0),_to,_tokenId);
/ k+ C# E+ X0 d$ ?! ^: B
9 N  z1 o2 j5 j1 S* l    }& H+ Y: {  H+ R- q

0 I! Z1 e4 N# z, t  i    /**
% @3 Z0 A$ }# y: a0 I& M
1 v$ P* ^! \4 d  h8 n7 h- p' y    *@dev销毁一个token的内部方法3 ?( l; \3 M; X8 n) D  q
% x% \9 N* _- X0 O3 |; {) [4 z) H9 T8 o6 @" Z
    *@dev如果token不存在则撤销
) ?" t  |+ \+ a0 q  M
" T* P7 s- N" C2 c    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
% ^3 d; u. }# [; U5 B# V
/ c. V+ T! n* M+ p( ]. w$ y    */6 h( n( I" a4 ^

9 f+ I4 I7 @0 T" Y% r7 N# X    function_burn(address_owner,uint256_tokenId)internal{
0 h# w5 z. [& ]" f) E) n9 k9 t" W  }: J0 @# P, Q* e
    clearApproval(_owner,_tokenId);
; W7 T: K' i5 I5 T0 V' G( z6 E9 i; l" B% F# g) E
    removeTokenFrom(_owner,_tokenId);
0 a% ?+ g" ?! f# w$ ?/ s+ j
: z2 L) u' ?" v5 q# g" j9 @$ N' Q    emitTransfer(_owner,address(0),_tokenId);, H" e; S! I' ^; R1 U7 w

5 Y( D* D3 e2 b& q" y    }
% X. B- z  G$ O' `; ~& w/ c
# @! r/ t. y9 p( d    /**$ i7 t0 ]/ V& \: `- B0 @

& z" x% a6 I6 j4 Y: a    *@dev清除当前的给定token的授权,内部方法% \4 C+ i! T2 D& _; ?  u1 l  z

8 W* `8 _" C* o- n5 E    *@dev如果给定地址不是token的持有者则撤销
8 v. P$ P* E! r$ \, C: s) ?
$ E8 i% P! S7 @6 U' m$ g" H4 b( o7 F    *@param_ownerownerofthetoken
3 P% i' Q: z" V! P' H* V7 I* E& h$ W$ r" x- o
    *@param_tokenIduint256IDofthetokentobetransferred
0 L- b. l% d" I! {8 g% j2 |8 p+ U7 J6 ]$ l- H
    */
& ?9 _5 |" O4 H$ P1 ?; L+ u  V7 q, C; Q4 l( a( L/ `% ]5 s7 I
    functionclearApproval(address_owner,uint256_tokenId)internal{( F2 H% N. U* h/ g7 O
4 K' U& s# ?4 i2 y" V& F
    require(ownerOf(_tokenId)==_owner);
9 l. I* E" _# `' d6 U7 @
; J5 O7 u3 z* f4 g    if(tokenApprovals[_tokenId]!=address(0)){
; `$ X1 ?" y: a
8 y, Z2 k: V; a    tokenApprovals[_tokenId]=address(0);
+ L# v( v8 C& Y3 n( ?# A' L5 D& d; {. D7 T! H8 S- e7 L
    emitApproval(_owner,address(0),_tokenId);1 R8 s/ R: o  _/ O* x
8 s1 I- c( ]) D$ P1 f- q" K+ Y/ q
    }
$ A. T5 Q$ Y" R  T, m+ t3 T( ]! T) v$ I+ Y2 I; c& \# W+ t: T- S
    }' @% [) q2 o2 D8 L; ]" v

7 n' |+ z. L3 j, t    /**. `% ]. O: R2 @: p
- R$ F8 ~; `  W7 V, _( J
    *@dev内部方法,将给定的token添加到给定地址列表中
) L+ I; z* W; ^* `3 @8 U8 {+ W- N# T  o0 h" @' `
    *@param_toaddress指定token的新所有者6 }7 Y# ?1 L1 I: O7 t8 X

1 ]" E! n1 A/ e) O; c    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress* |  O3 q# l! K$ `
! Q9 S) b9 P- l3 q5 I- ^- J) v
    */
* h7 f0 @* J# ]* ?  Y
' d. o1 k) h- W6 x( u    functionaddTokenTo(address_to,uint256_tokenId)internal{- g4 a! M# x. [5 t6 _
/ t. R( N+ \7 ?" q4 `) d" z
    require(tokenOwner[_tokenId]==address(0));
9 R$ i6 k5 R+ i6 g4 K) t2 p# N3 E8 x6 g' `8 a
    tokenOwner[_tokenId]=_to;% T9 k( N3 @2 G0 O% s% a

  b) \  u6 x1 ^) P, n* Z" U) v    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);" W/ |1 C/ I7 G% b; c- u  V

+ z3 \. Z1 R' l4 k: i) h& `( c, H& ]9 |    }& e1 P5 }8 k# s3 k  F4 {9 {2 @7 ?
! J) {$ I9 J5 _+ J& a
    /**3 a5 b9 t* z' I9 _6 O$ j; E" [

; R* Z3 a. b4 }" e    *@dev内部方法,将给定的token从地址列表中移除
  X& l8 H8 {$ a. u
- k" O' s( J, w% Q; [( @    *@param_fromaddress给定token的之前持有中地址) y. v6 t# p* g2 I- F+ b

4 }( T# z' A3 k4 X; Y( F    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
: t% p' K. R* P3 b
9 |7 t% \) [1 [; w    */
. j+ Y0 C% \4 u; V( S* Y
0 V5 Y4 @' f# A) j% i: T    functionremoveTokenFrom(address_from,uint256_tokenId)internal{" N% h9 g9 E) a( v8 @

$ A  k' m# G$ J: K* j1 p    require(ownerOf(_tokenId)==_from);) b& o* Y3 ?3 y

: G# ~% x! |& B" e    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
$ w- H: y- s6 O- B. W% r# T
  d& O7 h" {) t  G2 w0 c9 R% t    tokenOwner[_tokenId]=address(0);% p  W! x: {9 t% s7 v3 Z6 j

* T) d: E* a! z% I    }- \; I$ I7 X; [/ `5 r; Q* H  X" C

. W  O; z( [8 O% e8 T" \* k    /**. v0 E5 I) H" v# I' y; b1 I5 c
3 h- H* }4 ~7 m1 m) _* Y' Q
    *@dev内部函数,调用目标地址上的`onERC721Received`
6 s0 N$ P; S' |4 `, n2 Y6 M- k5 m$ V  {/ {- w
    *@dev如果目标地址不是合同则不执行调用
/ g- z1 l; m4 d1 a' u: y8 B- _
9 k5 I3 u! H8 V7 J7 `/ _* G    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
$ M/ Y) V2 H' p/ b! r8 m. D! K/ ?  M0 z% }) k3 J" o( |
    *@param_totargetaddressthatwillreceivethetokens
6 r; u1 ?% p9 @3 ?0 m
: Z* L& j5 g& Z" C0 p8 v$ P    *@param_tokenIduint256IDofthetokentobetransferred
+ c, H7 J5 p6 m' z+ m) A+ e; V3 R+ R% D$ c, m, ?
    *@param_databytesoptionaldatatosendalongwiththecall
: y  v' |* y0 x2 j3 B( s7 X; A9 c7 ^* `
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
/ j  [, ~% h1 ^4 ]: p5 ^$ f8 G9 y: f4 Y0 ~0 K5 r6 {
    */
' |$ v4 _* E$ v& f# u: J' c
6 H2 [0 b3 E2 u6 M; x9 A    functioncheckAndCallSafeTransfer(
4 T3 z0 _5 O/ J$ s( ?/ |# Z! y
/ ]  V+ ~7 {! x/ T6 }    address_from,
. G9 q; x' x9 w8 j1 q/ L( z* {& V1 X% T( Y% M& j6 I$ N5 B
    address_to,
3 b( c" ~& V! ~+ N# O4 B
) t( Y8 B$ |# \! R2 S' O- X    uint256_tokenId,9 F0 S6 y7 K2 E' a8 }! K

( ?$ q. O# y/ G    bytes_data
; v" w( g2 H: q# Q5 F+ M$ h) B/ @: m2 d4 x( J" E0 x
    )
* u+ J+ E# D( y% p2 v* p2 }! {# p! T5 P8 f
    internal
. R( G, _2 o" H3 V5 J  m; K: g
# H+ G& Z- q0 }" x4 `    returns(bool). @( _' I: ^- {2 ~# {6 k
- x, s' K9 {, g( b+ K
    {
8 C# U7 f. |. x% X
- s/ p  B* s2 U1 Q    if(!_to.isContract()){9 y0 u# v/ r+ z3 ~

- G% R+ k6 x6 f5 W- v% f* s% X    returntrue;
  c4 v6 `# @( R! [* e
: O6 K2 o0 v% `8 W    }7 O4 P$ v6 P% d: p  t& X5 j" e" P
/ W7 D, Q) D7 z6 x, ~
    bytes4retval=ERC721Receiver(_to).onERC721Received(
8 V( _0 k! R! K  c; P
0 R9 A# {" R5 F    _from,_tokenId,_data);
5 g6 G  |& S% u" S, _  f' Q+ j
3 @: I: B) g- }) N$ p- B    return(retval==ERC721_RECEIVED);
  q: e  \7 ?1 [/ A
+ _- ^' F, v0 C; v9 J    }
* o0 J7 P1 n5 F! U6 ?, O- ~6 |  F* h6 q0 E* {2 o/ w
    }, N& z( e9 _' {3 [

, v6 s/ |- Y9 ~4 Y; p! u2 i7 \    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。7 g% }$ Y/ X1 o4 J% o; O$ s2 s
0 B' E. Q5 ~$ ~6 T
    ERC721Token.sol8 d+ d6 Q) J3 s7 u6 n, C
  K3 I5 x' S6 ?% I
    pragmasolidity^0.4.23;  Q. o+ |& d! f6 v

9 U% ^* |; v) K7 I5 P' f    import"./ERC721.sol";
+ Y: i) c9 E5 d, [
; ~) ?# r. I4 t9 d% P5 y# q( |' y5 v9 @    import"./ERC721BasicToken.sol";: L1 j/ V4 ^  I/ I; a+ l

; k0 J4 y9 |& l) m1 \$ v$ }: F2 y    /**& }/ _2 ^3 w  {1 D: H3 C$ i3 [

$ G8 h; D# s9 Q9 J! s+ C  |+ k    *@title完整ERC721Token
! p. w, ^! z) X5 @9 s6 h2 j2 v# L6 X* g2 _$ P9 g
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
' ~# o& y$ Y6 `, B# d6 c( l- M; k" K
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md( [9 u' J, F5 f9 X6 a% s. t* N1 V

7 Q2 j' k/ Y! ^9 z1 a4 c    */
  [5 [/ d9 M4 v. Q
8 [" U* C) F- b# v1 _! z    contractERC721TokenisERC721,ERC721BasicToken{
+ N( u' k7 r# f; z8 @0 `4 V8 C: a7 f
    //代币名称* J8 \. h* Y& @- G- O2 r9 e5 ]* l

- J" S! U$ T9 W3 k) U* X3 u    stringinternalname_;
! T* N5 o! _8 u9 [! r2 B% n5 S8 v7 O% n/ {
    //代币符号( a3 J" W+ ~9 T& I* W
2 |1 w9 ~6 Q9 P' v3 z, v/ p
    stringinternalsymbol_;
4 {2 n  C+ Z0 \% ]& W! i$ r9 F
0 b/ m6 B" N/ G8 K2 k& V7 J    //所有者到所有者拥有的代币列表的映射
8 Q/ d* g7 ?: k+ M# P8 _# _+ c  p! u+ Q+ R2 @. l, e6 W/ h2 B" R2 l
    mapping(address=>uint256[])internalownedTokens;2 z  s  X8 s$ C0 E2 }- ^
6 v: D+ |! m& A) C% H
    //所有者代币列表中代币ID到索引的映射
2 ^6 W7 L! ^' j6 B5 y: T; C0 T& e1 t1 `; A0 m
    mapping(uint256=>uint256)internalownedTokensIndex;
& ?' w( `/ P/ P; J% J/ I  b" j( ?9 T, x7 `& M1 P3 y- \# N
    //保存所有代币ID的数组,用于枚举
! J- ?! F& V) ^$ w9 }  Q: V: f" |- t% ?- k
    uint256[]internalallTokens;
' Q% M( Y0 w: f$ @5 ~. J0 e% ^* P+ H. a
    //allTokens数组中代币ID到索引的映射
- s2 s' [4 n5 t, m, f
& N$ K* N& y' N: B    mapping(uint256=>uint256)internalallTokensIndex;6 Y$ H+ ^  a5 f9 f
9 d1 v5 v9 l7 O+ ^, R  k
    //可选的代币资源URIs映射
; p9 d, P! e$ G2 [" x9 V6 M; C! H  x* E
    mapping(uint256=>string)internaltokenURIs;
+ J# E* y* W# ^, m# }( K
: J/ J! r8 h+ q0 e" i+ w    /**) K6 \. c8 F$ }- a
* M) \/ ~' w; v
    *@devConstructorfunction
6 v# |- D6 y, W" {% k
; P, @8 V. z3 x: A( g0 H5 ]0 X    */
* X$ J+ ]! \; k1 l  c3 G: d$ i# ?- N& K, E" f8 k
    constructor(string_name,string_symbol)public{5 `6 L; U' X$ H  o4 Y# v. E

: K* z( H, }& @; g+ E# w7 E    name_=_name;3 T' I, u- N+ u: ~4 e5 W

& h& h0 U' q/ q  G; r6 i# X! S, d    symbol_=_symbol;7 Q2 o% k' B! \$ d; F

2 u* I5 e3 Z9 i0 k0 H    }2 D* Z, D5 j2 n2 T( ~8 p

1 Q, z, h8 W9 D& _3 R4 Z0 D6 B4 o    /**
+ |4 @* o+ E1 L+ d4 c
# g" {# P* _. p, X! y: m9 T; z    *@dev获取代币名称7 g  h+ {0 k! t- e8 x6 t4 z+ K

$ {, y# x( ?& b4 W    *@returnstringrepresentingthetokenname
6 }9 z. R, t  B2 x" r
9 ~' K8 w* [/ D& }8 |$ t" _    */
" e1 y1 T% o* V6 i8 ?5 n" i" k2 N$ W- a# M7 q. n2 H
    functionname()publicviewreturns(string){
7 @2 Z2 y" T9 `' v* E( K- A$ g; X6 v; e6 n* [
    returnname_;1 L( Y. Q' m4 k/ J

% B3 v5 L4 m' j8 f    }
, `2 ]9 T% {3 c( {
- N# l2 C9 V5 n( d5 u) Y    /**! T$ H. F  ~4 b5 ?4 _$ G
4 _5 N* q+ x  k
    *@dev获取代币符号
6 [+ }6 J4 y+ d1 t, Y* d# \0 s% j% Y4 |5 o
    *@returnstringrepresentingthetokensymbol+ K" U/ i; F0 K0 l
! s. x+ m% z) V. K2 j) k- @+ X
    */
2 O: D# T6 w) x& M8 |! v( ^- a4 P6 F+ i
    functionsymbol()publicviewreturns(string){
  ~2 o* f/ G6 C, }: e
' l- ^3 a& C6 ], s! _1 ?' N    returnsymbol_;' ]3 P. r$ i; I

5 w' r$ ]: C+ b0 T- T    }5 |9 @; k: {4 I; }& m7 R; t
0 X% f1 [( A/ I! ?
    /**( E4 y2 K" \, Z4 J
! M: Q% C1 x1 K4 s
    *@dev根据_tokenId返回对应的资源URI
! }6 ?' Q# g/ J  _9 n# F* {
: [" N& c7 e" [8 W( ^% t; r0 M' F    *@dev如果token不存在异常返回空字符串. w- `, G( e% X7 K* j; h7 v! k
3 K: l( b1 j# O- Z% e, G1 }; x
    *@param_tokenIduint256IDofthetokentoquery
( g) Z6 q: [' ~$ }7 C( ~8 V& t' e2 \2 N9 E
    */
2 `3 C+ n; `/ c( v% C
; h. o* B2 G1 y    functiontokenURI(uint256_tokenId)publicviewreturns(string){0 g1 u. h# @7 l9 W
% |3 _0 Y" b6 ]
    require(exists(_tokenId));
% v% ]+ A1 C* e* i
) ?& U3 E/ j  u0 \1 K4 P    returntokenURIs[_tokenId];
7 x' O6 W4 D$ A$ V) ]. c7 G+ j; I0 R5 i! N9 U4 h  a" ^1 ^, b
    }  j- g0 L: u# x2 h  [+ C
( q8 Q; K9 L9 q! H
    /**. W; P) T% `* d$ B

" Y; A. V. o8 J4 D, O3 L    *@dev获取tokenid通过给定的token列表中的索引
/ \% ?: y  u. o9 h
7 }; L2 a( C- ]' W. P& _+ s- R    *@param_owneraddressowningthetokenslisttobeaccessed
: x8 n3 B5 s7 l2 `; Q& }
7 ^, a, P/ ]& S' d1 i* A, S    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
" K: W- K( @+ f8 H5 m! x6 e1 A5 P1 U- ]8 h
    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
- r9 p% x' \& b* g3 W6 ~3 i) Y- V: l$ q: ^% j3 z1 R( C
    */1 y( S+ h8 Q8 ?1 R

0 A6 d" v9 l8 Y+ y& ]  c    functiontokenOfOwnerByIndex(
# X$ A+ R; W* ^# n  p! u2 R
1 b/ z$ ?" m# E# p& R; ^    address_owner,' x8 b6 q# W4 n9 w# K% A
. d$ M$ e# }2 K/ O! H7 H- D$ h
    uint256_index" c9 ?, w; |! |1 F7 B5 \( ?1 K- F2 e
- y# T2 `: l" r: a% V( Z! G
    )
7 Z, W2 g7 n! e7 G4 I5 c: ~0 I0 e1 \. z& A) W- N
    public% A+ V* \0 ?5 W' ]

% m" M( h+ Z3 B+ v8 ]    view
# P0 e0 P, J4 P6 o2 V, o* ^- r4 \* v* R
    returns(uint256)2 t/ k# r$ d2 o' L5 L- \5 u

7 k! C( p% e0 O/ g    {
8 a, @) J- f4 E. I" G; W; p. ~6 L. K% J  R9 V$ S2 n: u
    require(_index! L2 L! o/ W; f: f
0 m2 j1 w& R& [4 l& G4 p
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。2 ~5 U+ H; j, Q1 F
  T- b, _/ U" h! Q2 m7 I- Z& I8 @
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2