Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2497 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。1 A$ r1 N; g9 x+ t6 s$ l
' s/ z+ U1 _$ i4 e% f; A0 q
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。9 ^, L  V' h' G, ]2 B
1 I' u. ^4 |$ j
    ERC721Basic.sol% O* l4 @. _, Q$ U3 l/ k$ }
/ ]) ^- n: \  j: [6 D5 _
    pragmasolidity^0.4.23;
* j& p# Y$ k+ i. s" }& B, l7 U
7 D" V7 s8 ^% h7 T% g4 \    /**, o( {, R$ K5 U8 |
5 Z" r2 ]* _3 P7 i3 d# L
    *@titleERC721标准的基本接口
" O$ s& ?! ]8 f3 H% Q+ ?7 y
; w2 s! H/ d# g3 r  W    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md( Q* [' V( _* Z. j! ~: @

# E7 ?7 q) a7 A" s) V    */
, Z; V8 s: G" b
5 x) f( [& {4 y) P% {3 J: X. Z    contractERC721Basic{
1 J1 h8 z- r, z5 k! A5 K# k
9 Z. k9 j( v) R# _9 i- y- m    eventTransfer(
0 p4 K  j7 b* X$ G8 |# w* D& k* [; i( d+ Q- f4 I4 X) \8 G" G* C
    addressindexed_from,
: c  A$ h/ E% b1 U; @
6 M, A/ _. r) |# j9 L    addressindexed_to,
/ y8 Q3 L% [: F1 F
. _4 u  L7 {4 O* f2 d6 A. i6 ^    uint256_tokenId% N6 v3 @" B5 l# {9 ~
3 W4 ?9 g$ J5 ?- o" Y8 \5 r$ k4 }
    );5 Z  Q1 \9 H- O  V+ e4 G3 u

7 L: a5 S) D& h3 T; V1 Z+ w7 q    eventApproval(
9 a8 `! U4 ^" P3 ?) E. a" S! v& V' V( `' S( w
    addressindexed_owner,
: d) G: f7 C8 E. i8 r# P6 V1 G
8 Z5 ]! v# w0 L8 j7 k. f0 e" U    addressindexed_approved,
1 C/ V3 z' @# ]& {- f9 F; z
+ a% k7 Q. e" e2 p* q0 o    uint256_tokenId7 t1 p6 ?) Q( C* K6 v% \

) f1 p6 C* k. L3 D6 ~! b( Q    );
4 Y# X) h4 b( l& ~# q  n4 g; z  m1 x
    eventApprovalForAll(
  W/ T+ v( }5 K$ i- ]. E9 ~7 v" l5 }4 v+ k, d
    addressindexed_owner,; T7 \3 [- g0 q) U  c* C# ^0 w
9 P  v- r7 }; G- {( _
    addressindexed_operator,: K  M2 f8 g' c. @
( D+ i7 ~! s( e- K' k( W
    bool_approved
) `) J- z1 Z; ]  K, i
4 h, \6 m- g+ U: e6 M2 S' E    );$ h7 B! u7 c# C' L8 W" `

- R. ^4 Z: ]1 u( }  K' Q2 ?% O" x    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
/ t: B7 C: u/ d$ E5 F( _3 }+ J: G6 o8 j% L1 b
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);
4 e) ~, F; `. f7 j  [
/ I; j5 `" O' Y3 Q7 l! N    functionexists(uint256_tokenId)publicviewreturns(bool_exists);# {( x( O- G3 A+ {2 t
3 g, s7 O! v' j- u
    functionapprove(address_to,uint256_tokenId)public;
( N- M# [6 b6 |9 T! M" O7 k# O7 L1 p0 l& k9 C
    functiongetApproved(uint256_tokenId)
7 R0 [9 B  a6 e8 _- Y) B; z, B4 G
    publicviewreturns(address_operator);1 C, d! F& [- L/ p
) Z* Y! i7 I% C$ y6 p6 _
    functionsetApprovalForAll(address_operator,bool_approved)public;: c6 W, n, s. c' j! k
+ }5 A/ X( C8 o+ T
    functionisApprovedForAll(address_owner,address_operator)
  [! m6 e; S  p/ M0 ]
; S' J& Y$ E) o0 P    publicviewreturns(bool);
, I8 x( l* a4 t) t& n8 ~6 L6 _& ~# i/ j, f
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;; \* v1 e  ^5 L- r$ E& C8 Y+ u
, A& ?3 R' {. `1 R* K- O. a; }
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
! _8 X+ ~; m" Z+ E6 O1 e; o
$ s$ C% p. B( w: C+ Z3 y. X) T    public;
  K5 x! [, b: Z) j2 }/ b; {! j$ d( Y
    functionsafeTransferFrom(" P3 O0 C6 ~2 Z, V- g) ~% r; J
2 E" [. Q, u; v; c: i7 K& P
    address_from,
. M6 `7 s: f. w" p  N5 ?9 ?7 L
' }  c+ U6 |- w  W& m" G, w    address_to,* b5 ?+ B& Z; A8 [4 |% b# E2 r
) |' o. H' v2 c* ?$ C" l+ H
    uint256_tokenId,( j: y4 j0 s, o- u
+ ~4 W5 E# ^8 C9 \9 V
    bytes_data
$ d8 e2 O: s- |8 }1 X4 M
4 C% E+ z. `& G6 p    )
3 \& {; D* u9 w0 h2 N# K
! h6 y8 @% o) D: l: x    public;
! o' V7 {' X6 r
' _, Z% x8 n0 N    }! J3 ^7 b9 h0 q  k; _1 w
3 b" Y& i( K8 O  W5 Y* O
    ERC721Basic合约定义了基本的接口方法:
$ W0 |0 j; ^! w& M2 Q1 u' x8 J  l7 `9 [2 v; J% d$ [* G4 i
    balanceOf返回_owner的代币数量
, q  S! g2 t1 K3 x4 Z% k) T4 V# ^
    ownerOf根据_tokenId返回代币持有者address2 a5 P, r' m% L1 ?
" V' e( m+ X/ R- r4 C
    exists_tokenId是否存在3 \7 ]" P' Y+ S8 `, @% X2 ?
6 Y0 x& z. I' M
    approve授权_tokenId给地址to$ k4 k- y6 [, m, N2 }6 v

& z  K3 z* d( X; `    getApproved查询_tokenId的授权人_operatoraddress$ Y* F% C- _( V; a
( c% @& Q; Y& p' V, u
    setApprovalForAll授权_operator具有所有代币的控制权
) o9 u9 Z, r& C# k: ?6 w& g3 d: c9 w% }5 ^
    isApprovedForAll
: `% W/ V! u& a5 b$ y3 U# h, a: G/ J
    transferFrom转移代币所有权
$ J, b/ o5 C3 C4 f5 g* q
# D0 o2 E+ N) n# e. ^    safeTransferFrom转移代币所有权
  Z4 `$ m6 H! D5 r; }8 v; O" j$ t' C1 [7 P8 A
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
9 n2 p& T1 @& S2 R7 J' w6 M6 p
2 }/ T1 K9 Z+ R$ a  g( n' ]+ ?% `, u    ERC721.sol
; T: y1 R- h3 O4 Z& s
4 v$ B' Z* `: H' _* G    pragmasolidity^0.4.23;/ q4 ~# Z2 X0 c

( |5 i1 q$ }" l' g' i3 q% I    import"./ERC721Basic.sol";7 K7 ^: i  _7 E
9 D3 Z$ k' F, @5 ]
    /**
8 X# }# G5 b  O$ Y! x% e  r8 q1 r+ J8 B; R+ I* I, I1 g
    *@titleERC-721标准的基本接口,可选的枚举扩展
8 _; n) G! {7 A- m7 a3 ]. c* G& D
" Y5 C9 j- U: [, R3 l/ y% A5 C1 ]    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* x$ Z$ v/ b/ n. k& U( _) D3 y( E# T; T( F  b/ T
    */
, m+ c2 J( i& {+ N: V  q4 ?
/ ~- ]7 A5 U1 V+ k; h+ N    contractERC721EnumerableisERC721Basic{
$ b! k' n6 ]3 a  p. V  f7 D4 o) r: _- A( x! i- b; D' Y* r5 {
    functiontotalSupply()publicviewreturns(uint256);: I6 R% b$ Q  g7 t
% C8 W3 T- m, d/ ?
    functiontokenOfOwnerByIndex(
) @, \5 C* M* J; S% B6 H$ p* p6 A$ }
    address_owner,4 {$ c" b; R# F+ G  v

% Z9 d$ _+ _+ e! E1 J* h, `$ d    uint256_index
% N0 q2 x. Q! S# e3 D! l8 U
' W5 i8 ?% d6 i) q$ ]9 P    )- y2 B$ n0 `8 ^# \
3 }9 `# _4 r4 K8 L) ?3 p- k
    public
- H, A* H0 _" z3 c3 i0 i  e4 u* Q" B1 _8 J5 G) b
    view+ k5 O/ |! V3 w( k  N2 r& b
- |2 C9 I$ P4 G! S9 o1 H- B0 I
    returns(uint256_tokenId);% k. T: K9 U+ b! K# B3 _

; O# j0 L$ I* J; [0 A+ v    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
: w3 G" X' h" G- e+ i% t! ]
/ r" ^: i; V3 V    }
1 z) u2 j7 W( P& e4 Y7 q
/ a! p1 K/ H0 Q3 q    /**. k$ }# s9 k3 R& w6 C
/ d  z% V4 r/ G0 I5 y1 Z) j
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展5 J- n3 o) @2 V2 p( h& |" O, @
7 n4 a% Q7 ?) h( l: s
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
9 G! }' \! H! `1 h+ I  f* h9 `# n
- N$ A6 K$ Y+ h$ e% R    */
7 s, \: S  X8 }  M- W2 e3 P% D! A2 D5 ]- ?/ P: `
    contractERC721MetadataisERC721Basic{* X# C8 b5 N6 q" {* ~
+ E; s$ a7 H. s9 V% l
    functionname()publicviewreturns(string_name);6 c5 u4 \4 F  ^' n% R. B$ A6 C  P, S
4 Z' f' t9 S9 T! @- N; w
    functionsymbol()publicviewreturns(string_symbol);4 v( m% [, {8 |' ?. m  F

2 [0 x9 [! U/ l% \+ S    functiontokenURI(uint256_tokenId)publicviewreturns(string);" N3 r/ y' R. t8 X, h  d/ F

4 J& q8 T" C/ I7 X/ G5 l    }
" R3 m, w. s/ X8 |" L, Y$ S
2 O2 X4 H# ?) V7 g    /**
9 [- F* `  u" G* Y1 w0 L- W8 t/ A$ S% x% k/ ?1 ~: g
    *@titleERC-721标准的基本接口,完整实现接口
  D; K' i  u6 ?6 L3 J6 _- y$ [- I% d7 k
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
* X8 a% m8 \6 c; U9 v) L
/ K9 s( X: w1 t/ Q! ]! o7 `$ i! R    */* I4 g" n/ z' V; W( |, q

4 Z* g6 y/ h; q2 M, |    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
. I4 r& N# g0 h! a7 Y# u
) A; x" Q' ?/ ]$ u  U+ q    }5 e$ q6 d9 d6 E( f( J! d! b
2 C- |4 {: F6 G% J7 N( f
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
4 \- d) [" \8 w9 f3 Y1 I# `
+ ?+ u) y& {& \* F8 k  O) z, z* K    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
0 O9 M0 x# C9 H$ F% I7 E( }/ B: n/ n' _' {
) B. u: T- p8 P5 [* F7 Q    totalSupply返回代币总量
9 f2 k9 _/ o1 m8 T# L
# f$ u; U" T: h2 J$ {    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
3 \8 F1 t8 _. D  U, g) o) F. F+ A# k+ t9 q; k$ ]! K- l( p
    tokenByIndex通过索引值返回tokenId" I4 h* S3 r) K5 q& J
1 {5 c* g7 n" f" m# I: K
    ERC721Metadata元数据扩展哦用来描述合约元信息
, W5 v& }) p) u7 N  s/ b. W. O2 g# P2 l7 W9 j2 x# F
    name返回合约名字' l# y. T) S9 B3 ^
) l% m9 V$ d% M8 o  k# Q
    symbol返回代币符号: [; ]) m8 S# g* f! \

" v( Y1 r( w: r  _7 t" n6 }$ `1 O    tokenURI返回_tokenId对应的资源URI- j0 x* A% Z# z5 l( L
- o5 F/ G/ S8 {9 E; `% S% Y) R
    ERC721BasicToken
( l6 K) d% v$ [' X/ P; W9 d  `
6 N( b& V! q8 Z    ERC721BasicToken+ P9 f7 }" I& x# ~

1 I. D: m% R2 |; |    pragmasolidity^0.4.23;
+ V" v3 }! b- c7 @9 `* q  V0 ?( k. p/ J5 J6 H: E$ J
    import"./ERC721Basic.sol";
5 `; `4 W5 e9 Q5 s: q5 P  T; {2 E; p2 z$ I
    import"./ERC721Receiver.sol";  V* s' v. Z6 v2 }' S! ?# @

2 l. k2 h9 `$ r  x( X( e+ D    import"../../math/SafeMath.sol";+ t, y3 X* O) w

7 ?$ }1 E6 Q0 l. `8 e& H    import"../../AddressUtils.sol";6 K- T0 s& F0 J+ o6 c: L% a  n" U

" W. z6 C" w3 J5 ?    /**9 J0 J2 t% @& J

3 K) d9 F7 Q0 O8 g) h0 ~    *@titleERC721标准基本实现
* k4 r- I# J+ R# i% s/ W4 _# J9 _% `2 B. M) _' X) v
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
! {+ ^$ g( y2 u# m+ P0 |# ^# ]5 V( }8 v
    */
: {, ?  g& G. t# Q' A3 `; [, E
% [+ l0 |% O7 v1 C    contractERC721BasicTokenisERC721Basic{
# @' M0 ^; o' C; h* W+ D5 t  L5 Z4 \# }( z1 E( r6 x
    usingSafeMathforuint256;/ q: N9 F9 V1 M+ w3 ^3 F9 K( M
; t+ g1 g1 }" {4 u: g2 x
    usingAddressUtilsforaddress;, z: ?$ R/ @0 G' f# H8 H, }, g

* n; |6 \2 E; ^2 v& H    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
8 N0 }' V' [' u% [# o
+ d( N( m/ Y  r( |, V    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
5 D% L# d/ E+ k/ W" N: @& a) B4 Z9 s2 Y, k6 z
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;% W3 G6 o# x( y6 G. E, x* s

. ?% }; _" G+ L# [5 z% M    //tokenID到持有人owner的映射, _! g0 M! @7 A/ t4 Y2 B* l; N! _

( h' Q( K- V8 c7 W) E2 W    mapping(uint256=>address)internaltokenOwner;' g' N/ N( t0 \5 q$ C/ h) w
6 T& W. [' i, k' B4 u
    //tokenID到授权地址address的映射$ O  m& {( Z  T8 a

# n% K, y% t" w, @8 v* r" W0 U    mapping(uint256=>address)internaltokenApprovals;  `, w, H: ~  x! p. @

7 J2 d7 O- A) N. T3 D( p    //持有人到持有的token数量的映射& {; M+ i& E; J7 {
2 w! c5 B6 u0 B  W, C
    mapping(address=>uint256)internalownedTokensCount;
% v; l# i6 O0 s* x8 P) n& c  x7 J1 ?% w2 O6 A
    //持有人到操作人授权的映射
  Y  ^) g, k: \% m# D$ [  Q
9 X+ S7 a! ~/ h5 x0 `+ L    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
! u  w/ h# {9 l$ F! z% e" p! {% e/ T6 d5 P; M
    /**
9 G- R; P) A  I  c* n: @' _/ l. p/ |. @6 U  |0 n  ^
    *@dev确保msg.sender是tokenId的持有人
. ~* @- ^# ^' ^( \& W5 q
8 E. P" Q; y& y3 q2 Z- t    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
7 d$ B7 ~( x3 S  u6 ]. a/ U8 v; M9 h8 {' r+ ^9 L
    */5 g+ ~4 K$ T. ]9 R, n/ }; x

5 W# M$ s. j% u+ k9 x    modifieronlyOwnerOf(uint256_tokenId){
* o, d5 q6 |8 e; B9 D7 q2 m" B0 x) V: u/ [2 Z
    require(ownerOf(_tokenId)==msg.sender);
+ F( H# C' `. ?) s% m
7 J5 J0 c! g' w/ t7 j8 A    _;
$ l0 u: y$ X5 Y5 u  D7 Q2 m% S: Z+ x7 W% _6 ~4 e( i
    }9 O# D% E# |2 |2 Q9 F% f& z

5 Q6 o1 j* v3 C5 X4 o' x- G    /**
3 M& I1 H/ `( i& p% J1 d4 D9 A9 I! T
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token! T+ D: Y* C& N8 }" v  @

' S4 T9 ^/ i! x    *@param_tokenIduint256IDofthetokentovalidate
9 d" M% c2 D( E7 K' M! _% g* _$ U+ Q4 M, @! T0 Y% _- B9 I+ r4 r5 M
    */( A+ M( E- O6 l* i

9 g0 k; V! ~" t7 P* X) ]* O0 `& d    modifiercanTransfer(uint256_tokenId){
" x% _) V6 U! W& k* O; |$ \' Z( g
+ p, h3 H& c9 h; N* W    require(isApprovedOrOwner(msg.sender,_tokenId));
( t# K- J3 j6 V& [8 {2 a8 F5 t9 {- [' {% b6 _; i5 F
    _;
) t3 F, h5 @# a: Y
( W- Z7 v# D9 \' W% E    }" z+ Y' o* a( t' L' _3 w( D

. k2 I% C% y) _5 ?' H" P  S    /**
1 Y) {+ a  Q6 d# E3 a7 d' G
3 V8 r7 e  G% t& ^1 n    *@dev获取持有者的代币总数8 a& W' b5 c; B- g$ _2 {. [, x
) e$ W  O1 M% ?- g
    *@param_owneraddresstoquerythebalanceof% R: J5 x. n, Y" `8 e2 ?5 Q

/ O' W( e  c" C+ U3 l; }    *@returnuint256representingtheamountownedbythepassedaddress
8 {# |* z6 u" x9 \& I7 j' J
  k# b, |" ^, K0 P: H' y, i    */
" n2 a2 p0 ]$ s; l3 ]! C3 M6 e
. H* b$ s/ p' }. \' ?    functionbalanceOf(address_owner)publicviewreturns(uint256){
; L! f0 E8 h0 E, ]* Z3 L+ _
6 g0 w0 G: v$ ^    require(_owner!=address(0));+ h; f5 l( k: N( L
" ]1 A. ^/ [8 [3 T$ V! E
    returnownedTokensCount[_owner];/ X9 Y' S" a, E* ~3 Y' ]
+ w( r6 H$ _3 I# v
    }; d* b* J, B3 x9 B$ i7 }

; x4 }6 H, R4 {! U7 W    /**1 u( m4 x, _- i8 x1 z
' I0 A7 `& H7 n
    *@dev根据tokenID获取持有者; U( I4 y+ ?- ?  J% m' \8 Z

5 u- J0 S$ r0 O$ e( N, _    *@param_tokenIduint256IDofthetokentoquerytheownerof
. O1 R. x4 I; {9 A& K5 v2 ], \. q. I
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
9 l" G: A7 l6 h8 t  f( l6 q" k/ h! ~7 \
    */
4 [  `! d4 }# X: w6 q! p% ~$ ^
# L" Q% ^) D; e! p4 q    functionownerOf(uint256_tokenId)publicviewreturns(address){- T+ g: ~$ {+ U9 C' k' L
. i# L3 t/ C5 N9 `
    addressowner=tokenOwner[_tokenId];! _6 e0 p6 {0 Q: O- H( X* T+ m
  j7 D$ Z+ ?, D, M/ J' v9 U
    require(owner!=address(0));
4 h+ R2 p) s* L" z$ r2 q. l. B
7 @+ f1 S  u# g* S  Z    returnowner;7 I; j! y/ M) z! M- y

8 @8 f9 r& ^6 t* v8 ^+ I. h    }
+ {0 |( `* x# d! T6 ]! w5 u" G1 d& b# I; ]) i  Y- f
    /**
- ^9 |5 F- I! d4 f+ L9 O4 {: t- c* ?: [: B! @) M3 F
    *@dev指定的token是否存在
; l7 S* @4 Q5 a- {+ D* V7 q; m+ a
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
, H. s  z; |) I+ D9 K; r
+ U& o# I) k4 |2 A4 }    *@returnwhetherthetokenexists
" N. Y# i9 H3 s# v/ h" ?! V& i% g9 {! E1 p& f6 i4 H1 A
    */
" ^: @. C' `7 Z% i  N. f* h0 U5 `0 J" R' p2 H1 y) g/ ~
    functionexists(uint256_tokenId)publicviewreturns(bool){) P& C! a4 R& R$ N% B( @
, F3 R; M) K+ K6 Q! Z
    addressowner=tokenOwner[_tokenId];
0 I; T) i; f9 a0 |# ^# E
5 L) T! ]: T. `9 [5 B6 S: o( i    returnowner!=address(0);
* U& x6 Y8 w( y, L( L
/ J# s0 o- K! r  y. B0 p    }
) \, X5 P) N. i' w( [: C
8 |7 w+ c0 M( m( s; ~' d8 H) G    /**
0 K9 c) e  U. L; H" e1 M
' B8 B( f6 [* C( B    *@dev批准另一个人address来交易指定的代币0 U' `9 R9 b0 S

% o- {4 _3 L2 J( ]    *@dev0address表示没有授权的地址
1 T& q2 L$ m  U# L6 A0 C/ q
- i- B+ |5 c, c) m& |* v    *@dev给定的时间内,一个token只能有一个批准的地址
/ V8 G8 @  s" M* c
) r1 G( r4 n  ]2 ]( d' O    *@dev只有token的持有者或者授权的操作人才可以调用: Q' Y- ]* A+ z0 @

6 I  B8 k0 {- B+ }    *@param_toaddresstobeapprovedforthegiventokenID2 O( E  S- z* _% \

. ^9 Q3 Y/ e. n: G- s4 U5 [    *@param_tokenIduint256IDofthetokentobeapproved
( `: k  d. N: t# C' U0 @3 F6 N
# J& E" x  Z. h. @. J/ D, k% n    */
+ c# N; t! g0 z/ u- V. D! i+ T3 l( I: [' k
    functionapprove(address_to,uint256_tokenId)public{/ f$ ?  T! G1 C# I. u' m& T
8 Q+ {! y6 U6 ~' i$ I! z
    addressowner=ownerOf(_tokenId);
1 e% ^& G1 R% M, g) S
, J& t7 ?/ q# M% Q7 m" }    require(_to!=owner);
- t4 D0 ^! r( b- q0 }3 c* Q3 S) e- ]/ v& \+ l9 F5 ^( W
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
' z/ U, E! v0 v4 h5 w% m. R& U% Y3 Z
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){. j9 a3 ^$ a1 z* i0 p

, A" E! M) G1 H- V  Z+ g    tokenApprovals[_tokenId]=_to;7 x# u* K4 i: e# a. ~) P' [5 u( F

2 A2 N9 U; A7 u/ ?    emitApproval(owner,_to,_tokenId);
4 b" I6 B! y% J6 S* _0 S8 `3 n; R2 Z: @2 U( B
    }: x0 k) j! ~9 K9 v" `
# `- t7 u/ a8 s' U2 Y* e3 R
    }2 ]7 Y5 z+ w3 {2 [7 e5 T  G( Z
1 E$ n; e" J* V5 l6 ^
    /**, S  k, u+ \2 ~: M

4 X4 h9 _1 `! b    *@dev获取token被授权的地址,如果没有设置地址则为0
9 o1 q% y* }" H' G/ m
- @8 E( s; ~0 N7 q    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
/ i5 E' C% \8 n2 f" V, [
8 O9 S+ _8 ?4 P3 \/ C6 e    *@returnaddresscurrentlyapprovedforthegiventokenID" ~; l4 m1 h9 E  f! W
0 d/ A$ K( g  A8 W+ o6 S
    */8 N( B* y. Y  n: U$ |# \
: ?1 J" [% B0 X3 q- _, h
    functiongetApproved(uint256_tokenId)publicviewreturns(address){: O; ?3 |3 `( b+ j9 X# [

  J1 W- j  a3 F7 X    returntokenApprovals[_tokenId];& d) A& a) z, p% a8 n  ^" ]3 r3 v
8 Y; e4 `* n# e
    }9 |; o0 b, i% n1 i+ n7 E' I
+ \3 H. k: [6 u. D
    /**
# f5 C1 k- V4 t, T. @5 g, N: h
4 j6 r3 t+ l* r    *@dev设置或者取消对操作人的授权
4 c1 E& Q6 Y% t; v) z% x4 {- X
, ~% l- d4 k6 M8 ?8 I    *@dev一个操作人可以代表他们转让发送者的所有token1 H6 k/ Q$ R' o  [

9 B1 A# \2 r: k  N. i    *@param_tooperatoraddresstosettheapproval' V4 {6 s/ s5 I" w$ o
/ W9 g  o$ i4 P6 D
    *@param_approvedrepresentingthestatusoftheapprovaltobeset& V/ W, n, y- x( ]8 X
9 k/ ^/ I+ Z% q- z
    */; B; a4 O0 q0 _- Q$ x+ S0 ]
$ f1 j0 K# }. A! f; i
    functionsetApprovalForAll(address_to,bool_approved)public{
0 [5 q/ x- y  s1 c, X
: ]$ l; O& ]: g8 }- ?% Q- S5 I8 w" i1 r    require(_to!=msg.sender);
+ W- m5 }* z% o+ }" v+ {+ i. i5 g
    operatorApprovals[msg.sender][_to]=_approved;  c: d6 W2 c; h% n

3 ]( E# {  k- ]    emitApprovalForAll(msg.sender,_to,_approved);# J: F, V, V0 m0 ]1 u6 a- {3 i
6 l/ b# C$ j4 a
    }
9 S2 g! z8 V, b$ O
& u8 z% H% J, @) M    /**
7 r5 K; [) m5 N4 S
/ Z* i0 ]/ j6 C6 n0 S4 B( Q    *@dev查询是否操作人被指定的持有者授权+ F+ F  k: ]' n- I. S5 ]
, P8 N( o$ B" J( C7 o8 d
    *@param_owner要查询的授权人地址8 U: e; O& X3 I$ j9 N* D; M
* ~) R. E. k* E
    *@param_operator要查询的授权操作人地址
. Q, m# U, }" t& Z) i) y
; Y' c! {3 |* a( t% q  o" e( g7 y1 }    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
2 N0 t: B7 ?1 F% _' F. n; P+ W! R# K1 `" ^7 D9 @* ~! t0 h
    */
  @( T. V( P4 a5 ?: A8 |4 z  t' ]2 A; X: ~$ M7 B2 f* l
    functionisApprovedForAll(8 w, Q* a9 ~: A9 p; q* k/ D
5 a1 [/ N% [% s3 a8 D
    address_owner,
. S7 _" O9 Y2 q( N2 s
+ s% |" _) Y' t* S. a    address_operator
2 x* G% x( G4 X6 x$ A- s8 b5 q/ E7 i/ W3 y8 a
    )
' r5 ]( Y+ [& y5 H
$ g2 `% j3 N! I7 z9 u. f- Q3 M    public
7 Y& |9 f. f4 o0 c8 [5 B& Y" J9 t# _& z
    view
! [( g1 Z; k0 ?$ n, e* F1 q. x- h4 ~" {3 ~, M. c! o
    returns(bool)
3 p3 y' B$ f/ @8 s' J7 `# ~" J
6 R+ N7 \* [2 L0 L    {8 {" \* T. R) V8 b, l: ]" B: o  j
& F$ I4 ?4 ^3 l" D# o3 v, z, v
    returnoperatorApprovals[_owner][_operator];
& \# l9 H- q; k( |& \( O, D( U7 H5 o. }! R1 a6 ^# U
    }2 w/ I6 b+ t5 }

" t$ a  O4 G, n# O$ [    /**& P! W" z, D" m& ~9 P

/ o/ G* C4 A7 Z    *@dev将指定的token所有权转移给另外一个地址7 H7 G# [: N% z2 t5 J) _+ M/ B' L1 [

8 ]* w1 _- b+ W& Y% h3 L! R    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`5 J' i5 P% j6 I% w5 c( l

9 a# |# l: B' l/ d+ f2 g. B4 E    *@dev要求msg.sender必须为所有者,已授权或者操作人
! [# j7 B6 T- C% C' C' w$ w& o/ x$ z! d: M9 j. `6 D8 m/ z( O
    *@param_fromcurrentownerofthetoken+ ]1 Y; o; \- }5 _1 {% A# M3 Z

' K3 B8 v% C# f    *@param_toaddresstoreceivetheownershipofthegiventokenID
# Y% L" }) ?, J, }9 m+ {; E; W
! G! S& {/ O( M* m    *@param_tokenIduint256IDofthetokentobetransferred/ N6 X9 S/ Z) z6 o  k* b
/ [" g# T) H% D" ^4 q
    */* u3 K4 v  q6 D$ A8 D
& F- O2 d" i% u0 g
    functiontransferFrom(
5 O% y1 X; Z$ r* {7 O; p: }' Z4 ^; A* z# {( B
    address_from,
: A, D9 N  c1 n% p: T7 f$ U2 O! K" Q: n3 _5 Y3 r
    address_to,$ ?' q3 ]. c6 v" o6 r

8 g4 Y/ }) e" t# y8 i    uint256_tokenId7 g7 f5 x: b/ x) B

) Y) q% s$ _, z& \    ): ^# j" V: Y: M
3 |! w- K8 Y: M8 e# v2 R$ D3 s# s
    public9 i6 T2 n' l3 t" p: Z6 P. ]  r4 P5 C
6 w% K  ~: k* V* q2 P; v3 q
    canTransfer(_tokenId)
! E  n. h+ J, w/ _  K: C; l( \  ?/ h+ I* D: D
    {
: J5 Q) U$ C5 f5 j1 m( P
  u- ^) ?( w3 F# S    require(_from!=address(0));
2 a" C1 `8 v3 S6 P: K* ]
, V5 s$ y' t2 |$ E    require(_to!=address(0));
8 w) y5 Q: L/ U* ~- w* {3 p9 x2 z  V) j$ D5 j) j2 ^4 \6 s
    clearApproval(_from,_tokenId);
* K! Z9 A3 Q) s0 h# b9 V/ s5 U) \/ M6 @
    removeTokenFrom(_from,_tokenId);
8 O" k$ |, j! n) M0 U' k8 e& V% y& r& ^" @
    addTokenTo(_to,_tokenId);6 T- `8 A" ]' c2 |

, W# e% g/ p7 r    emitTransfer(_from,_to,_tokenId);  _4 G: R- e4 j, B

- T  Z* V& A( R0 Z7 x& k    }- v7 x$ g/ m& Y; I
" c5 e( o  e" J) T$ z: a
    /**
' D# x3 X$ y, W. c2 S" [( O
+ j' B: ?$ w* ]( [5 m    *@dev更安全的方法,将指定的token所有权转移给另外一个地址9 c% X, L8 d( |) H0 X, ]/ O

1 G" m; h! x: `+ I. H    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
! @3 n& `! @9 g, o3 ]5 i4 d
+ \5 x3 e2 r! E3 m    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
+ V" {+ z4 k9 x$ K9 v
# c' m9 v) l& X2 h- M& g3 f2 F3 t/ Y    *@dev要求msg.sender必须为所有者,已授权或者操作人
) P- m  K9 ]$ l( O- E  W! c' r  M  o7 o6 m
    *@param_fromcurrentownerofthetoken/ ?; H$ s4 n& e: w  g' Y
# \0 E3 U- O5 \7 e
    *@param_toaddresstoreceivetheownershipofthegiventokenID
, x" @4 E! y( X1 M! l/ z4 r  K4 d; t7 m
    *@param_tokenIduint256IDofthetokentobetransferred( y9 B0 t1 z, E

( x# q  O, n' j    */
5 m! N/ I- u( [1 G. K4 z
3 @5 l0 p3 k4 |8 g# j, ]% |; a    functionsafeTransferFrom(
! y# @; E, |' e& _' f7 i
: E7 N0 P9 \( ]" ]    address_from,# V5 t: z0 B# b# a4 K% X2 m
# w  Q. T9 b; _
    address_to,) J) D! {  Z! \5 i, G
8 j) c+ ^& K9 n" A7 \' h3 o
    uint256_tokenId
  n8 e1 o# b1 x0 `- l8 L+ B. g- P' {
    )" z# C* E: g# d9 w8 p9 C+ ?

- x" U& I. j; ~8 W3 P0 D& I( b    public
/ ^. L" l% ~$ v+ |  s/ Q8 V
) _, @9 j. o$ H    canTransfer(_tokenId)
  A+ i) }) ^' Q/ P# t% N" A3 z+ k+ A! A7 D8 E7 {/ D) S& }; R% h$ D, a
    {
1 X  G0 G9 d1 r* ?; E8 ~% P" x/ y  X0 n% u! @2 W; p9 d* N: f
    safeTransferFrom(_from,_to,_tokenId,"");
* M% q9 d. S& v/ N* w- I- A) Q$ p3 p7 _
    }8 |9 ]( H) M2 Y
* E+ l7 x/ a4 s9 _& x- U/ u  L8 @7 z
    /**5 T, A# m+ Y2 C2 h
+ S# h3 u: Y. P4 ?1 g( A
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
9 `- p: f1 x& p0 x
. {4 e# ~  `; Z' ]6 N: v    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值' S. a) j: D8 h5 `/ x
" U* S5 w+ x/ t4 d& A* p
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原) y" U2 S5 Y  K* v9 A6 ]* t# V4 t
% b; v8 h- {. ^0 V3 u2 O8 p; F
    *@dev要求msg.sender必须为所有者,已授权或者操作人
1 `. ^+ W1 c$ q6 X, Z* y' T2 b8 v; [% k7 r& V6 P1 M# [9 o
    *@param_fromcurrentownerofthetoken, V* v% u9 ?( H6 y5 ^
# T+ A* T$ w4 e2 ^
    *@param_toaddresstoreceivetheownershipofthegiventokenID
( k. {9 ?% U2 a$ g) k
  l6 Y0 ~8 @7 K5 S: Y    *@param_tokenIduint256IDofthetokentobetransferred. a+ R' o% G- [
8 U. Y5 T; M' G' `( W4 F4 |- `8 s
    *@param_databytesdatatosendalongwithasafetransfercheck4 V0 s( s$ j7 f. j0 q# y
0 b+ k: ^, c. v5 x8 s
    */: G( V/ Q7 W0 g( b( K

% K; A! \$ ^5 D    functionsafeTransferFrom(5 v1 H3 d# w& @. i. r' e

: e' k% g& b4 h( U* P0 ~/ Q! T    address_from,3 B' @2 F' P4 G+ a

0 k; k' P# {( ?9 m8 g! ~9 e    address_to,/ h& m3 A+ q- P; _/ `$ \5 o, V$ V
- m; P9 K  c3 N8 Q
    uint256_tokenId,
" H" ]: C/ ?+ I. g. N$ V  K/ [8 A: b# j9 x8 E0 ^
    bytes_data2 k/ q1 f$ C: O; l, Q

0 t0 P2 B" O1 |    )  p8 }7 V, M4 ]% A/ l+ s0 F2 Q' q
5 |& d) I, ~) `: |" i( n
    public( a3 ?' g" f: `7 x2 ^/ d

; H1 g2 @( ^* }9 j/ N1 p6 ~    canTransfer(_tokenId)1 \( V8 J! r/ q" d
& q" Z+ ]2 y* N" X
    {- _& `, ?0 M8 `# }7 J
( v1 z; F, ^+ w& |& s
    transferFrom(_from,_to,_tokenId);
+ p+ M) ~* ~+ e% J; h1 q0 o$ q  k. f6 c
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
2 Y' r/ y6 B* C! X# ~2 a5 m
+ Q9 n$ f+ \! z( ]# x    }
9 U4 J% _- q& k# b) d# N# y5 ?- y2 h% q2 S" X
    /*** i8 |1 e# ^& r  O( d

7 E1 E0 x6 ^& g8 J8 Y$ m* U8 q1 y# f    *@dev返回给定的spender是否可以交易一个给定的token5 [8 {; N& g6 r4 n+ y* N6 \. X

+ H! H& s0 |: T& _) R8 w    *@param_spenderaddressofthespendertoquery7 e4 V2 D6 b. w+ _1 i" n' P# C! R
, A- G% |4 @* M; D; H' R- P7 K
    *@param_tokenIduint256IDofthetokentobetransferred' ^3 i# r+ v  U* C, Q
  l6 E8 p; C5 e- O% ~2 z4 r7 {
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,9 E' y8 D$ `* B) J6 r

! q+ P3 k) ^1 T$ y6 y2 j1 A2 m5 w    *isanoperatoroftheowner,oristheownerofthetoken- f( t7 W/ _. U9 A  U

/ A0 ^1 l1 n+ e* i    */
2 {0 }. M- C1 L! S( y7 f8 X# V$ O" W% _# y5 j
    functionisApprovedOrOwner(% {8 C. j' T5 {3 _) J
! t0 t: s4 L) I- @
    address_spender,
) ?0 s3 E8 m& w7 E' T5 s  V' f! l
) X" e: |6 P4 T, J1 ?; a: V% j    uint256_tokenId5 s9 A- P# C5 ?/ d" |0 Z
% \, D. c, O7 }9 `6 D
    )$ Z* R1 f7 P% }- g- T  D

) ]5 P0 U2 i5 S  Z    internal
6 e$ |% F9 D/ Q: n! u3 l9 `. M* ^! z3 j' j; Q
    view8 _) @8 y/ n! }- h' @

" R' a6 q4 O6 F6 y    returns(bool)
) e0 G2 f/ V4 ^% X" t; J% k( R* x, q4 C. T. e) X
    {
6 `. W4 G' ]- z: e/ B4 q9 O8 ~7 O- \3 P' f. u
    addressowner=ownerOf(_tokenId);
0 M0 y3 |( [) Q
  `. `) _2 z. S! z    return(! j8 c) N5 l' B

9 R: A- j  N8 t0 L: v2 S    _spender==owner||
( a  r8 n5 j) j9 R8 O5 E# H$ N$ y4 E1 K- B# P+ \
    getApproved(_tokenId)==_spender||+ {' J* j9 }) a) N! A7 l' l6 p
9 M/ `  h# K# r1 P4 X/ f/ q( F
    isApprovedForAll(owner,_spender)
8 ~( W& Z4 v1 W- s6 v" F: x% x4 }" q8 F2 B
    );
: X" Z# O7 G8 _& y% y/ s9 T+ n' k! Y0 r
    }& Y4 z9 B0 }1 R8 {

/ b* C$ K9 s1 R; v7 u- I9 r8 Z" ^' I    /**
7 v2 J( o9 @7 Y- _
% A/ `8 P7 j( _5 d    *@dev增发一个新token的内部方法
& F4 U4 j- j0 |3 E9 M) I: C; u9 F+ y- W, ?" A
    *@dev如果增发的token已经存在则撤销+ t' J* W3 L$ ]! _
! s) _0 @8 M: e8 a& |# k# @
    *@param_toTheaddressthatwillownthemintedtoken
  T7 t; O) o2 y
3 n/ V8 p" q; N4 [  k1 m& P3 I    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender
! b9 I' C2 q+ {) n$ }  h+ a
/ R5 u8 X- t4 M7 O8 X0 @) t    */
5 F( z0 L& R9 G" ]# @2 @! A8 z. s; i( ?7 [; _5 E
    function_mint(address_to,uint256_tokenId)internal{+ O% j& q' J, f5 o7 l

& p  h3 U- e* U7 j0 U    require(_to!=address(0));
3 l9 H7 ^* r- X4 K* I. n; ^/ c+ w
, R& s3 g: O$ V0 K    addTokenTo(_to,_tokenId);. E, b/ X9 L' g
% d6 x( k/ N$ {: d
    emitTransfer(address(0),_to,_tokenId);  q4 t' c/ d0 C; Z4 B! L
1 p. x. \) g0 J- F5 `& x
    }
# z) p  S6 U6 C  u% d
% q% ^& F; J6 N/ i) G: i8 `    /**2 X6 W, A3 Z2 A  d7 t' N
2 \/ g7 r! N4 \4 H+ A6 Y
    *@dev销毁一个token的内部方法, w7 n  h  s& t: c+ h! l

4 ^' Y$ z, c0 c! x4 W/ O: v    *@dev如果token不存在则撤销
* H/ p' `! F5 \' a
% ^+ V, T; e/ L- {    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender. ?3 z2 V, e$ P) Z! d  @

  c' T+ X6 x+ s( U& w) B$ E; @, O    */
6 w, U' q6 E) I' B+ d- e) F3 A: J+ T! `: w
    function_burn(address_owner,uint256_tokenId)internal{
, a: ]0 ]+ F) [  F& e, u+ g, J: }% S2 |; X
    clearApproval(_owner,_tokenId);
  L, o/ r7 z( u: Q0 n- I
% g6 w( H. C8 B2 ^    removeTokenFrom(_owner,_tokenId);
- h  p: U9 R2 ]6 W! s1 B& Y- [
+ [- \0 I6 p# F: `* A    emitTransfer(_owner,address(0),_tokenId);
( S4 k/ M8 l* z8 s& g5 w# V
0 @1 f& r+ D: V4 b- b3 _    }) |# V  p1 l3 I$ L4 @/ v
9 B# V- ]# T' D! C
    /**. v5 W; G+ W$ z' A& R1 e" I! g( n! e

9 n# ^0 `, M2 r1 ~    *@dev清除当前的给定token的授权,内部方法- P3 z$ V5 n. {0 `

6 u: i. D" |' D$ h, H. V( C& |    *@dev如果给定地址不是token的持有者则撤销
0 l+ M7 V, L' }: ~% z
1 L7 ^6 N* N6 A- g    *@param_ownerownerofthetoken7 j3 t% |7 L" w
9 E+ f, f7 `- [" u) O
    *@param_tokenIduint256IDofthetokentobetransferred0 a$ k0 {  l! S+ b4 s7 m- W! j
2 }# q, \& D& L1 R3 b6 F+ V9 c+ `
    */6 N& c: [7 @) L* I
# X/ Z1 H) P' l+ u
    functionclearApproval(address_owner,uint256_tokenId)internal{3 }  ^& Q. ^2 c
) `9 r% o% f$ R  `, i
    require(ownerOf(_tokenId)==_owner);8 o5 {" T3 k# J/ F0 d

" s* G  ?" d% x  T4 a    if(tokenApprovals[_tokenId]!=address(0)){
0 T4 G, W  y, M) G0 F4 w  r  q6 v) |. O) P
    tokenApprovals[_tokenId]=address(0);
- A, b3 u& y* ^" B0 L; m7 m* A, R7 C! r% b3 |  h0 H
    emitApproval(_owner,address(0),_tokenId);+ X$ F, V) I: j0 \: {* J
7 L; c5 u; g& O& K
    }
, Y( J& p; y* L% Z! f8 M$ z9 Z5 u8 Q) a% b/ \
    }
  w! u5 K- a: C7 i% N
* ?/ C" O! e: U) g& x. E    /**! p. O' n+ `% i% M6 c3 C

& Q$ k+ Y0 f( e3 V    *@dev内部方法,将给定的token添加到给定地址列表中
4 j4 ^" M0 A( `
6 |  f- c1 n& `    *@param_toaddress指定token的新所有者: X% L! j1 L/ p: s

/ [, r9 `6 R- R( H8 [1 u  ~    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress
  T, k' q, p/ m" E! Q9 k( s4 H9 v9 I# [7 R& k
    */
5 C6 {' X  K( E' j0 h. i
2 ^" o2 R+ h4 f    functionaddTokenTo(address_to,uint256_tokenId)internal{+ U' Y' o: |0 b1 Y3 H5 Y! n
" ]4 o( t1 Q, u0 ]  F1 q8 }
    require(tokenOwner[_tokenId]==address(0));0 l5 ^/ d! @! n( v* A
# ]- G0 L5 U" x3 K( w
    tokenOwner[_tokenId]=_to;1 m0 j- ?; q9 {1 m' ?6 ~

+ |+ y5 S  o8 L! M' D6 ]; V" y    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);4 _7 y* ]4 t7 l/ Q! {
& w5 a, \( F- Z2 @5 z; G
    }( T4 L; o: s- }. O, p8 o
% y* q5 v; M; r* ]
    /**
- |* f5 E. Y' |/ I' A) T& r
* `/ f& L3 T1 U) i    *@dev内部方法,将给定的token从地址列表中移除; {0 |5 R3 J1 |: ^8 z

# G  j- h2 ^7 S; P$ G: E    *@param_fromaddress给定token的之前持有中地址
; }" x. a" C. {6 y1 r& L9 s/ v
3 L. Q0 P! T1 x9 s) e    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
4 V1 b0 k1 B- u! K3 ?
$ ]+ V1 k3 S1 k: t2 E- ?    */3 {9 s3 F/ `; [& R* O$ _( t2 a, V

5 J0 |5 y# e" q# x4 ^) Y    functionremoveTokenFrom(address_from,uint256_tokenId)internal{
) t6 k; p2 s: G# t4 N5 E: Y9 k" b) Y$ ~* v* ]" A& n
    require(ownerOf(_tokenId)==_from);, @( i9 A( X1 n2 y  `

% S7 a2 F* E9 S$ Y- W    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
3 [0 S7 g9 U# x+ A
; C; m3 @1 d7 o2 K" b7 U! U    tokenOwner[_tokenId]=address(0);8 W% C) [4 g/ h# Y8 P

4 _- S0 k/ L7 M6 [# C: i    }* ^( U' P, ?2 _

. E/ }- R! M3 J* Z7 q, d0 p    /**
! V/ g) h3 _" f( t0 ?/ k% ~! W1 u/ g  T4 Y$ z
    *@dev内部函数,调用目标地址上的`onERC721Received`
2 g. Y: F0 E( A& W$ v) K9 h3 J+ T3 g: l8 e  S' {/ }+ p
    *@dev如果目标地址不是合同则不执行调用2 }1 W1 }! R9 Y: y" f
- ^$ t' A: Z. U- c( w8 v
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
; O2 e- H! m' Y
' A" Z) ^2 j7 {: p    *@param_totargetaddressthatwillreceivethetokens
$ q, O2 ~5 h3 A1 h! }( ?" r$ c, h; h) ]: a
    *@param_tokenIduint256IDofthetokentobetransferred
, s5 n6 ]5 J6 O* f7 U# Y
$ @8 z# `# T& r' x7 B: ~    *@param_databytesoptionaldatatosendalongwiththecall! g$ @' k$ E+ `- n) `

6 Q# j6 [" y" d* \- p    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue4 k2 M7 Y) l8 E6 I: e

1 Y$ z$ L6 b9 j! Z2 S: G; z    */; A+ j" e% {  k. Z5 B' V
" t# Z  Z% N) S! w  t: ^
    functioncheckAndCallSafeTransfer(
, H1 T! z3 r$ ?: @
$ B* O* y' w6 ~    address_from,
$ e! \9 N: f7 z. _. ]4 j: j0 ]0 R1 R. I/ p3 q; ?% F
    address_to,
6 Z6 w1 z, w- o; X
. l" u/ M# ?# r! [    uint256_tokenId,$ K2 x9 M! e" \* f
% q  u! \- X) g4 I
    bytes_data
5 R$ U5 f5 o, O3 Y: ~' C! @. W1 N* _: r- j
    )
  u8 g/ w5 Y; F  d$ ?" C
/ U8 D* o# ]* R: Y/ R    internal
" T3 [# o: k7 Y; w/ t
  H- g) j  ^) x, m0 l) U    returns(bool)% U' a( ~( b4 U, Y, `

3 ^4 P* d# s' W) ^    {
" F6 `) ~" p: |3 \5 ^  V! P" h# }0 x) {& {7 U
    if(!_to.isContract()){
4 W1 C1 S& t/ E, n' G. I6 K5 U0 N8 o+ m5 }
    returntrue;
7 u0 w8 D0 X' v/ o! K5 [; C3 e3 ], U7 ?* {7 Q& {# B5 w5 ~
    }3 r% }4 n, d' `( B% k2 Z9 k
+ n3 O7 M5 A% m8 i; m, t: p
    bytes4retval=ERC721Receiver(_to).onERC721Received(: z- W; A" V8 C: b# j/ I
, P' h" j( F4 a# M0 l) h
    _from,_tokenId,_data);* {+ L5 p! N" |. X6 O( H, b3 M( \

; q. j  N% C6 t$ o    return(retval==ERC721_RECEIVED);
9 i. G' s5 R& @/ }
+ f- J; A! A& W# g    }* Q  J% J* Z$ r: b

7 U' }% L- F- A3 m" \    }
% u6 M$ H) X- g: v' \
2 T+ t3 [6 ?' ?/ l! Z    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。- X  q9 _  _7 Z/ V4 L; p+ m% I  s
6 e) i9 J' q# Q! ?) L- k& J
    ERC721Token.sol
; n% R7 m6 P! h. J% S- X; e# i8 X+ {3 H
    pragmasolidity^0.4.23;  w! D. v$ ^8 w; W5 n

+ F, f% n! g4 \. z7 `( t    import"./ERC721.sol";, Y( R; F2 ^5 ]  r8 d5 I+ N

, Z) O; v; S3 V9 n$ ~6 g! J    import"./ERC721BasicToken.sol";
, O, w' m+ C& W* m/ U/ w4 k" b" \+ s- k2 x9 F+ {& E; l) L; }
    /**) z; m$ H+ a, e5 F- N5 m" E
) T* l3 c. Q* e% O0 |) R
    *@title完整ERC721Token9 T0 C1 i& |. S( K- V( X
) I9 |7 A, m9 T1 t0 _9 F7 V5 j- J
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
2 ]0 }/ h% ?8 y7 E6 e4 L
0 c+ s! w3 C$ @* c6 w6 L. w    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
# G' m! j. K' V/ `0 J" F) R6 g& O- t
    */
5 M# N  `! W; d* W' X% Y6 x  S) _
    contractERC721TokenisERC721,ERC721BasicToken{9 o. T& o/ A# K" }
) u& d4 K! x( d( c
    //代币名称8 {6 B5 k3 G  ~' `' M+ Z. z# {+ }
2 r) c- D9 a- l4 t4 a* H( _! [- [2 l# q# V
    stringinternalname_;
$ U7 r: Q5 i) |3 m' _0 L3 _  |' ~" t; t& K6 W, d( e9 x6 o
    //代币符号. ^( x$ f9 `' l; t0 C) C: p

* V- ^6 e. O6 v: G& ~% i    stringinternalsymbol_;
% j* f. X; v+ {4 q' M& d% x7 n% v4 c! @5 y, p) X1 r
    //所有者到所有者拥有的代币列表的映射; k$ M. P' n/ P  ^! K8 L  ?

  z2 y2 `+ h1 C) P$ b1 a: b. Y1 i9 }    mapping(address=>uint256[])internalownedTokens;
5 N# I# ^: w6 r6 I. u6 z3 f( r0 ]$ [9 F9 Q* _) y; W
    //所有者代币列表中代币ID到索引的映射
5 p5 X- i+ A* g. s; @# A6 b" [7 t& k9 e7 z/ m
    mapping(uint256=>uint256)internalownedTokensIndex;
3 y# `1 H' B8 l* X( b' e
9 M1 }* Q- r- }9 }  u    //保存所有代币ID的数组,用于枚举
$ J0 h% V7 [: w3 b
2 {/ m7 b% t: |3 |" `4 f1 G( P    uint256[]internalallTokens;
2 Y+ x& ]1 g5 A; {6 f* p# g- Y) U4 Q3 p# W7 }
    //allTokens数组中代币ID到索引的映射% v6 U# P4 j7 r2 ~
. x0 T$ a( R8 [' \( [
    mapping(uint256=>uint256)internalallTokensIndex;- r( ?1 ]) |% J) G# c

' h+ {' P  i, g; e7 ~    //可选的代币资源URIs映射
( A1 E4 I# G: H* t+ T9 o# U
. D. e1 f% U3 x7 L  I    mapping(uint256=>string)internaltokenURIs;
. V4 p( N8 q9 U7 C7 E2 ^# Y0 {! P6 }
    /**
  o2 n' x" T! S$ x1 ^& }8 _* {; @$ u* M8 O" w
    *@devConstructorfunction5 R% h3 G- I/ ?6 n
5 t8 T# x+ O% J) ^( z. F/ p# r- K
    */
, N7 b2 A+ u4 v3 A1 [+ r3 j
& |7 G# v3 L( C! u, @    constructor(string_name,string_symbol)public{5 f( ^6 @, v/ H

8 e4 g. B- |# V, B* I    name_=_name;
) x! i- B7 r& t. }. j3 x
% P1 W3 R- @! g- W4 d    symbol_=_symbol;  e% f+ }% o- ~" O3 ]) q: W* T& O
+ C; ^" e0 Y2 Q: X8 n6 b3 E
    }4 E+ O8 l8 x' e: [. y* T1 x$ f9 N

: g9 `) o% L2 S' W    /**
7 D* h6 ]% i  }7 \) Q- A) K0 Y" }* D/ z) p2 w- F
    *@dev获取代币名称9 x' b+ g4 j" M. C: c5 I& F7 e
$ `$ s) w8 _2 |$ b& I# p
    *@returnstringrepresentingthetokenname
9 n( P' C3 ^+ P9 r7 b) _- B
  p6 ]) \8 B  o( Q8 C    */
: x0 ~# ?2 G& r+ m6 }
* f7 G( J7 [- m  R    functionname()publicviewreturns(string){, _) @) P. J/ O$ a
8 @8 a' C7 v& i0 w0 ^
    returnname_;9 S& U; y" D# m* R% S9 E. M" D0 O& _+ p

4 Z/ A0 f/ a1 I, g+ z    }: |5 a0 x# _4 b+ ^2 q- i

$ [2 F9 Z* f- |; O. _9 k% h9 ]7 N    /**/ s2 ?& W  F0 Z  l$ H; @8 F1 r0 B
5 n( I' m$ d! W, j: _
    *@dev获取代币符号) R- r1 ?: z7 T! |/ G: d. y" Z  W  `

6 }+ p1 ?( g7 n* Z$ E& N: v( w    *@returnstringrepresentingthetokensymbol
3 T- {! ^7 u$ Q. ?1 o  V/ c7 e* x) y) D/ v
    */5 o, x% `! }3 m. P1 d

9 H+ u) ]0 p- H& w0 [3 n    functionsymbol()publicviewreturns(string){5 c' G3 L$ F: l% g
4 o* }+ O) Q; @0 r5 P- a- t7 a
    returnsymbol_;
& R! z5 b2 o5 ^& u8 @+ J- }3 y- }6 L1 T+ \6 R" L! \5 N2 z; c( f
    }
* M; |! b0 z3 ]: S7 H$ Y& a
' \7 i2 z% o* t5 ?    /**/ y$ ^- O6 }/ f' e. {, d; `) c, W3 ]
' C- K4 z/ o) u* w# b+ c
    *@dev根据_tokenId返回对应的资源URI
# _& I, \' b+ f5 k9 g
( c! P- ]( X1 d+ \    *@dev如果token不存在异常返回空字符串
3 D* s* w  b* e7 G
; Z, r1 S/ Q$ E* s* C% L" s    *@param_tokenIduint256IDofthetokentoquery  b$ n/ M" G; J( u7 c0 W* w8 D
' U2 k/ x* h8 \, |" J& p# y$ l
    */2 V1 O/ R! D: q6 z! L0 ~

. k2 D5 l9 K' S+ u    functiontokenURI(uint256_tokenId)publicviewreturns(string){9 z1 s  [3 q3 ?* j

5 m5 c& `: W' `2 C9 o    require(exists(_tokenId));- k/ ]5 {9 m% ]+ }

' V$ }# B" {1 D8 A    returntokenURIs[_tokenId];
7 l7 h5 w* q/ T. {+ ]& l2 y8 {' O5 k7 e! x
    }
& S8 ^4 w% {! u8 W' I2 a
: k& O* u5 X/ q& S) ^    /**
/ r5 i. x2 c- o( T0 q7 |$ l/ |$ Q" u7 @
    *@dev获取tokenid通过给定的token列表中的索引) ?3 c5 I; U$ ?  i5 q) v, Q
1 c9 k" t! L% `7 e, a0 w+ c
    *@param_owneraddressowningthetokenslisttobeaccessed
2 [- B( X! I1 Z* p6 M$ M( [
' D$ L# u( K9 [8 R9 [* R7 H    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
# J* l' B/ D, M5 W1 Q5 f3 n
8 h* x: c0 K5 v    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress! d( w6 W7 M, M: O' z. \  U; J

- E; l+ t& w) q( m. c8 k) }    */. w  X+ c# `: ~9 C; x7 M

3 l+ u( `& n) y" N+ T" a8 X    functiontokenOfOwnerByIndex(
5 v' c( ~, r  z5 C' D2 z* q( g3 N( a( R: ~/ l' V! Y: N
    address_owner,
/ D& r; j& N$ @( h0 l' T9 X- o+ A* S: v2 g% v
    uint256_index% G! {2 Y! F; r; q4 i) r
0 A8 [# }1 P/ Z9 X) ]0 @8 F8 H$ D9 d
    )
0 _' t# _* x' M  N4 R/ y0 a9 {- }  ^7 s# [
    public
8 j7 R& `$ b: }% H$ u
- E. E: p8 y# y8 I    view
. v1 n9 Y0 ~' a; _& b/ w& M# f7 y2 R  I' C# }" T1 Q
    returns(uint256)
% x  K  H; a9 L- o( ~& F5 [
1 e: e6 Z2 q* A. X" R4 o    {
& Z" k0 q% P* _9 ^! W) {4 w; w" j4 o0 }
    require(_index7 V* C$ J; q/ y- S$ ?$ ]- Y/ P
: W4 @9 G" k% L. ]4 [6 ^
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
3 K" |8 ]* j, B! F2 D, `( v& g" G: _, w; n; a- f
    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2