Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2401 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。. V* V8 F% U4 H  E8 c; ^
+ @. M. `0 `' t: J; p; v
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
& _4 }: E/ V9 a( i6 m; N0 B
3 J/ D6 @, I/ O+ A3 h    ERC721Basic.sol) @/ J% ~* @" G; Z5 m; L

+ w0 F$ L2 C6 r1 }4 N; F7 z- D    pragmasolidity^0.4.23;3 Z- G& Y* N) l: H) |9 J
# b' _+ X# n9 m9 V2 R+ k! i
    /**
6 V1 H- h9 B) g7 P
( c1 n# g7 F6 u- F7 Y/ l    *@titleERC721标准的基本接口0 x5 r' v$ W: y0 \
1 w# h) J2 \: M
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
- Z2 f+ p" v9 G6 v% \' ^2 K) G8 }5 }: o8 M# \. p
    */; k% b& B& ]! `8 g! l, C

0 {& _) k$ ^) t0 B8 g% ~+ h! _    contractERC721Basic{
- Q" @8 a, p9 w1 H( Y* |' \. S' q, [  f) K
    eventTransfer(% F$ r/ f# b* F
: a% k4 X2 Z$ f" ^) D6 t: F
    addressindexed_from,
& k' c% O8 S0 t6 a% n" N( V$ m& }! t1 Z' X- S. a' A5 B2 e9 J
    addressindexed_to,+ y- T( F$ C( K8 N
& y+ G  j8 p' {$ `
    uint256_tokenId0 ^! y6 |7 a6 M9 h, J& i. W+ B5 y

. |3 t0 q( a0 t    );5 i6 |+ O1 F- E$ x8 Z4 Y% [9 O8 S
4 q2 W5 f' D+ j# M2 V9 p
    eventApproval(
  N5 a+ D( t4 E% w6 E) h0 ^: U+ k! K' U
    addressindexed_owner,
; \5 [& h( `, u# B8 J
( S' ?6 N. N/ J4 ^8 l3 m    addressindexed_approved,+ u8 U2 t8 d4 I$ `  `& y" o+ w

2 v+ u" x. n: s# D; d) X, [    uint256_tokenId' I  G4 k( Z# E

4 D4 f# y" q& q7 V& u9 Q) C    );
3 Z- g/ P0 k+ v4 @) e8 L
) p% g2 z( ^2 \- K    eventApprovalForAll(2 c# ?( b% {8 t  W

$ b" ?" S+ D9 `: U+ A6 \% `5 Q    addressindexed_owner,
* @4 @8 u- K' p- W( z7 [# [' n% c. e/ Q* H
    addressindexed_operator,3 \% G& R) d( I, g
1 K/ c% T# L; b
    bool_approved4 e  g1 L8 q3 Y1 F  ^# [4 M

1 a4 A0 V5 Y* S& _    );
3 {( ]! ~9 \* c, _2 g9 S  L0 |' f$ T) {* Y
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
5 l& j+ d5 u2 ~7 Z$ \8 `/ A1 B& ~/ w5 \) h5 c, d- I
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);! O% E9 u! k. S

" y$ B, f$ Q  T: a- H: R; V    functionexists(uint256_tokenId)publicviewreturns(bool_exists);- m( A. @8 x/ G. R. b% s

: Q8 ~/ d* _- B( z8 F    functionapprove(address_to,uint256_tokenId)public;
  Q* g$ `. ?3 ~% P* f6 R4 g
0 Q' A" u# n0 s) n; ]9 h    functiongetApproved(uint256_tokenId)" W, X/ b: W$ L  @& Z- T5 t

/ Z: [) a. L1 j, `3 t    publicviewreturns(address_operator);
) v" Q# R% C( ?  d7 I6 X- b+ Q
7 i. d7 F# b1 n9 m" L    functionsetApprovalForAll(address_operator,bool_approved)public;7 I3 o: W+ C2 D; u% W3 }! y

$ L& W, A9 u" n1 n# l# B9 ?    functionisApprovedForAll(address_owner,address_operator)
" N% s6 n- e9 x0 T* k+ x5 p! \
9 A  P, `. i1 z1 X% G    publicviewreturns(bool);" B4 B4 u; O$ f' }5 H; y
; o+ K5 E3 T; m4 n: i
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
$ U6 y- Y9 M' B9 f7 J. @
: R! M" ]! e: S! |' |. A    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
$ \8 |9 q! W$ Q) X  \( Z
! q$ R4 b8 r+ \    public;/ f& {6 E5 i* R! ^
- q) {% `: O( l* `# u+ {" T; X
    functionsafeTransferFrom(
. m+ F$ n! G' A( g5 v) f9 C" {! N% o& w
* Q+ F0 L7 u( G# E    address_from,9 n' `! Q4 B- A( \' E- g/ f+ z
# L4 I' O) c/ G  Z( v' M
    address_to,
" N- e' |& E4 S2 m' W& C/ Y( a7 z: s
    uint256_tokenId,3 `) @2 k  T6 W4 z' I2 p

6 ]3 K, e3 h9 Z9 l    bytes_data4 I7 f: C- T- w6 Z! s- z

& m& a$ p# Q1 l2 D$ N+ l0 `    )" G) N/ S, i* J4 e8 `8 j) J

# h  ^* [- j7 q( ]    public;
  Q1 p( S5 a# D' v- G  p! F& w& |) v# |' ~3 h4 X& C& v/ m4 g
    }# {2 X& |9 g$ `5 [9 g" N& S

5 S7 b& G8 N) R; @4 \: u    ERC721Basic合约定义了基本的接口方法:* [7 D' W( b' K0 _
& o) {; Y4 c% J# a3 N& Q& X- c7 d
    balanceOf返回_owner的代币数量
# _8 L, b5 v) Y$ |$ g; F
# h0 L, I. {2 [4 p" f    ownerOf根据_tokenId返回代币持有者address
" @" Q, P& X) W* {6 n" Y6 U1 W+ C  R% l! l
    exists_tokenId是否存在
, V6 Q- L" Q% p2 I9 F- p/ I; g! Z9 v" e/ w
    approve授权_tokenId给地址to
/ K0 t, E+ b' @' o
' [8 v# K' w  Z    getApproved查询_tokenId的授权人_operatoraddress% [$ E4 i) P5 u
, u0 q7 D: m3 k
    setApprovalForAll授权_operator具有所有代币的控制权2 O1 a( P4 {! U& o: Z
6 |( S: a) p/ R) {8 r( g
    isApprovedForAll# U9 {! W; R  a  C

8 ^9 T* L2 |) `7 A9 _$ v    transferFrom转移代币所有权
' M3 A$ l1 s6 u0 P
* ?. Z, L! D; R7 F. D    safeTransferFrom转移代币所有权- V/ a! `* k* V/ u

. ^0 y( J6 r+ W4 I9 F& _    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。/ i6 p" U) I0 `; P. }8 h$ ]: m( {- A

) k) m1 C) @) d. J; J    ERC721.sol5 Z: G: d4 I1 C0 p" i0 F+ s
. B( r) }* m+ o
    pragmasolidity^0.4.23;
1 r9 |+ Y" l  g) K+ F/ L- I1 o# Q
    import"./ERC721Basic.sol";; D& d; y. j+ Z4 Z& q# R

& D* K$ ^# Y, Y5 }) G    /**( h3 y( U! `  J/ z/ `" q
; a/ w. S3 \# B+ w! }  J' J
    *@titleERC-721标准的基本接口,可选的枚举扩展5 w2 ~- V+ l* @2 t
7 Z( y. ]- _3 Z4 Z6 j5 R2 i- u, e& c
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md  ]7 V# g) W  N. Y

5 ]$ t. z  N- N! r4 r8 k9 N1 |# P4 h    */: {$ m6 R4 h1 a2 \- h6 v+ W" q
, O$ R& Y4 }! z( }8 a
    contractERC721EnumerableisERC721Basic{
& ^7 m# e! |' R# E. E& R: k  n( G7 @8 a+ Q; u
    functiontotalSupply()publicviewreturns(uint256);
1 x& r  n% i, X. i
" m6 O; Q9 D# D% r5 w2 j  @3 V    functiontokenOfOwnerByIndex(2 j9 n' S6 A9 }2 V; S/ h% g1 u

# W6 q8 T/ {3 o: |) x$ D6 [2 z    address_owner,
9 b1 W+ k% P9 I  d1 r3 J& q
) A$ ]; w0 f6 x! N3 _    uint256_index
- U! ?$ o: ~  K3 q7 l
+ Z4 i* }2 m* h# s' {    )8 }1 g, J' M" M) W, q8 I
& W9 s( a7 Y7 M9 Z1 W& _" u( v
    public
( b. Y( S9 Q1 u6 {) i& w7 }' |! @  ?) a( c! x' L
    view
1 e- x! j+ R  }6 K& z6 d7 o$ n( p- c6 N* J7 c
    returns(uint256_tokenId);" v+ S. u  i: _7 J

1 B$ `, r. [" X: r    functiontokenByIndex(uint256_index)publicviewreturns(uint256);/ @4 b( ^8 n. v- U

: G  @) A" Q1 D1 ]% Z    }
; v3 J1 d7 A' R3 L, r/ G, |8 Q; B* S/ L% t
    /**
" }+ @8 U) c! F; O& w2 t* k$ A7 W
2 J( H! D3 B' c: m    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展
! p* i2 Z2 |' n1 D) `
- _/ u( ~8 g8 G3 O) K    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. N- e* K1 B8 o% e
8 g* o# X- k; M! V6 H
    */- f( K& J$ e7 M2 d, ?
7 l1 [2 d; k/ [; ]) `
    contractERC721MetadataisERC721Basic{: l& s! @; p, J# R. H" D- J

' E) m! W- P& ]3 p% w3 y. ]    functionname()publicviewreturns(string_name);
( @7 l9 w+ _9 t& W  r
! t$ U; F& E5 W3 Q- M! J: f    functionsymbol()publicviewreturns(string_symbol);; k# x1 ~2 A, _- I* [3 a
. D6 W9 `8 W9 `# x* o- d
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
4 X' }3 T+ w2 R, f
4 G3 |1 i3 @$ O2 z; ?  _" U    }7 m4 y; B) k) x- S

' T/ \9 @) p! B% U2 w$ x, Z    /**# p4 `; |! V2 x9 n

* z  Q% X( V* ~    *@titleERC-721标准的基本接口,完整实现接口
) H* t9 }4 C+ c: X
1 y; J* M4 T/ l4 [5 B! p0 F    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md8 |9 A+ ?! Z$ G3 M0 P+ ]
, o, w* i9 k6 @
    */
9 r- j- R; v% i" Z1 i& j1 H6 f# Q. u  s
    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{% t5 L. ]/ g3 W
; O' u' {1 c: Q# C& n# g
    }. v! S5 A! _* P5 H4 Q5 f
7 I$ {: B6 I. J  F( T) c. E) R# k" d1 b
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。( E9 c- W0 p  H8 B

* L$ _9 g0 ]& D8 s) v% \) }) u% g) Y* Z    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
) ?$ \: f$ P7 N* m- ~# _2 P. e+ F4 C
5 x8 j8 h2 [% A" B    totalSupply返回代币总量& E2 {( b; i9 @, `  X# E* g( [

4 H) |  r4 t2 I  N! w    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
  F! V; `; B. G; G, c- M5 p6 O2 k4 _; p; `
    tokenByIndex通过索引值返回tokenId
9 H' Y% |% m$ W0 G; |8 w% ~& f+ I+ C) E
    ERC721Metadata元数据扩展哦用来描述合约元信息* n3 F! ?4 r9 M! r3 S, [
! w+ D# `' p1 D+ z* |" l$ C
    name返回合约名字* C  e9 c5 y3 J. A, r4 m: r
: F2 a5 u5 U3 I! s
    symbol返回代币符号' v, i# K4 Y+ U$ s( @' q9 c
) L6 B3 J1 G7 I3 O; _/ Q) G- I
    tokenURI返回_tokenId对应的资源URI& v# z* ^+ ]9 g! Z5 F
, R  l9 C! h4 j" L/ |* p$ u
    ERC721BasicToken
/ F& y" ~- }5 t% w" r! `
0 J+ w1 d  |9 y5 [& w7 ^    ERC721BasicToken4 X* w% t  x& m& y) y, }  c; t

5 ?6 r$ p$ p5 ?" M# V, ]    pragmasolidity^0.4.23;1 a' H% s+ g6 r  e: K% |0 e* {
1 ?0 E' K. _' }0 y* n$ f
    import"./ERC721Basic.sol";4 G8 K7 H6 q6 y1 {. J$ Z
6 Y0 j% C& I& c9 y4 u) T9 u
    import"./ERC721Receiver.sol";
# W! S+ n: E( T/ }- x7 V8 T* D& D6 Z' `8 Z
    import"../../math/SafeMath.sol";' @8 x/ ^9 F- v: O6 N, ?1 l6 o
" f2 ]' [& C- Y. x, a% X
    import"../../AddressUtils.sol";& ^$ W% l% z7 c% s$ |8 e  K9 b5 [
; S- ]: K5 L/ \; N( r; l( q8 j
    /**. w6 a) Z) M. g5 a9 i% M9 \
) C$ Q4 C6 y4 I
    *@titleERC721标准基本实现
# a) ?5 h- ?+ N0 M- g9 e- V. |* k" W1 S" T2 B% d3 V
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md6 T0 p) Q; p, v% L, }. |

7 g$ H/ [) W# z2 S' Q5 B    */
4 ~" v! F" K, Z6 ^
6 w5 h+ f; l; @) h6 K2 _9 P- c: N    contractERC721BasicTokenisERC721Basic{
! i; D, O# U0 T9 {% K
2 X' ]0 W3 O; D3 }    usingSafeMathforuint256;) Z9 M% _, i, {. Z" `5 r5 N( o
$ g0 f9 X1 W& U* u
    usingAddressUtilsforaddress;9 `/ l0 X; Y. C. Z; I$ W4 T

  s4 P1 o- c' A2 F4 s    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
7 p& [* V3 m; I( s: l# l2 J/ n; B' W- r/ i- y
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
) c7 N5 O7 }$ r1 D6 k
+ a. q7 S9 Y8 C$ ~    bytes4constantERC721_RECEIVED=0xf0b9e5ba;8 G; |( x4 ]7 w5 }+ q/ f9 C
: L) \! s3 g+ U4 h; ^
    //tokenID到持有人owner的映射! U% t7 m2 G7 C" m' @/ |

, G0 I( U% h0 O2 |; L4 a    mapping(uint256=>address)internaltokenOwner;+ W5 l3 m5 p% L5 e4 P5 y5 c1 C" R
( r' o0 X3 v' o
    //tokenID到授权地址address的映射
7 t, s( [  O: O4 h
0 ?3 P' Y+ V4 t  R6 I7 c( X    mapping(uint256=>address)internaltokenApprovals;
% l6 z& n/ ^# F+ D+ G) `! S9 e: ]$ a( y+ Q
    //持有人到持有的token数量的映射
6 b) J- F8 y5 |/ J! p; Z6 u" o: ]  u) ~* H
    mapping(address=>uint256)internalownedTokensCount;" m' X5 }# K" z0 ~
( t0 d# v9 Q+ u( F4 M+ d, z& L
    //持有人到操作人授权的映射
% a# p* x: x' e' ]7 ~8 |: z
. ^8 K0 W& t* ]/ v    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
' R1 z- Q2 B" @; u" K) l. }5 Z5 Q% z( s
    /**
0 N7 r$ e) u4 v( U! ], r
5 Q* }( ?& _5 X" D0 ]9 R    *@dev确保msg.sender是tokenId的持有人" R+ ^, ]' c2 W. O9 ~
; K1 N2 `& x) \1 e4 t1 ?# p
    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender8 f( g4 P! b+ N' c
" }, W1 G* Y; i+ S
    */
# @7 P5 J$ \$ W6 G. l6 ^; M& F5 N# }1 D% W! u
    modifieronlyOwnerOf(uint256_tokenId){
) L  G2 O8 d8 x* a
& t* h/ q) K  v- L9 Q+ u    require(ownerOf(_tokenId)==msg.sender);
( O- M% l& p5 t1 ?/ v5 J8 w: F+ d4 {+ ]. s- D, y% x: X0 Z9 K
    _;
0 O' O0 [+ y( }0 P, E% O/ {7 L! H: K' ?, z* Y1 r% M. i7 j
    }$ G- S, c" i9 m1 u% k

. D" ~8 j! x7 y    /**5 e7 l. l+ V; |! j8 {
2 R+ A+ d4 p1 E. |
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token. N" L7 v) l9 ?: ]* S  C& V
8 G  Z. H5 i* d- f7 P" a/ ^
    *@param_tokenIduint256IDofthetokentovalidate
+ Q  u* Q1 i3 `( O1 C6 M9 K. f  A7 J. m! f- O  m; k
    */  O4 N4 m+ e  p+ ?5 O

5 P. o7 Z1 W  D% U6 I9 K    modifiercanTransfer(uint256_tokenId){; I2 ~! ?8 Y7 d7 H1 ~

( E5 R& k  d$ D  p" M* _9 R9 n) e    require(isApprovedOrOwner(msg.sender,_tokenId));
2 [  J* K" f" q& p% J% Z# S
. V) R* l) C8 R! C: j+ p" j    _;: ^* l/ ?: U7 ?1 @( o. s/ h2 P

" V0 M! C# v  J8 ]    }
- |: d: K; P) b- G/ G' G
2 w0 c) Q0 S6 G: e    /**. u! u  `3 M0 P/ U& W
, D7 d0 W& W1 [( l, P
    *@dev获取持有者的代币总数
0 C; M1 l' \) Y, O& R. f5 [& T7 m$ z' g1 s( ~& r
    *@param_owneraddresstoquerythebalanceof: ^, |2 M6 B2 X& N4 c% A

8 U* y/ O; x0 a, g2 h$ J/ G    *@returnuint256representingtheamountownedbythepassedaddress
7 k. s4 m; Z4 G2 a
1 [2 j; k# v/ [' {2 T    */  ~. z/ s$ |( \- Y( @0 {

1 q! c; A2 x$ Q    functionbalanceOf(address_owner)publicviewreturns(uint256){! w! m3 Z, ^5 t/ Z( e
' v1 m5 v8 f' [. O# ?. B+ K
    require(_owner!=address(0));
9 G" Z1 ?: W3 c( x) R* p4 S* g. b
3 N1 w  }9 b' U    returnownedTokensCount[_owner];3 m& I9 t9 p2 T9 y4 I
5 x1 D& X6 u& e
    }
4 C( U8 j1 Z' {3 f) k$ ?2 X, [2 i* ^0 O9 C. h. k# T) z
    /**. O  a2 A8 p5 J2 @; M4 i

3 |9 Z6 s; J+ c6 d, }& d- l" W    *@dev根据tokenID获取持有者
- ]: r8 ?7 T% c( y: t, m# C( [. s3 ~2 {
    *@param_tokenIduint256IDofthetokentoquerytheownerof) S( J6 w* h/ G- \3 o" R% w

5 }: a7 }' O7 F3 L* s    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
% \9 k4 t. V' \9 i; i
* h8 Q, G* t- N! I$ B, I    */
0 L0 n" o. d( W; n! }# n
  ?( c& U+ R% n. H$ F; {: a& n& T/ c    functionownerOf(uint256_tokenId)publicviewreturns(address){& C$ H( ]8 x3 s5 I7 O9 ], q7 r

2 A6 c% m' w* B    addressowner=tokenOwner[_tokenId];
8 }. I/ r' H" T1 c! j$ U6 T
# X7 b; f, O0 s0 F8 r' K    require(owner!=address(0));: E& b) L7 J- m) k# N

% a, s2 v  j% y" _# m, x1 q/ t) [: [    returnowner;! S6 ^$ r# F$ X: ?7 |
- Z, n1 t) A5 \& e) ^
    }
: g: B# }5 q: J- c
0 }  c8 N  L- F' u. S' E. U    /**
6 F. H; w# y: M  i) H7 {( m6 W# f1 ~; |% Q2 N2 n
    *@dev指定的token是否存在
* q1 B, v# o% u7 h& y- g, Y
1 M. ~' M4 N4 @% d2 e, l$ z: `0 ^1 Y( D3 \    *@param_tokenIduint256IDofthetokentoquerytheexistenceof0 T2 I  D* P5 y3 y
& f5 [* V4 W) d8 k
    *@returnwhetherthetokenexists
( d3 T  }5 D+ j  a7 o5 w5 G9 K
4 T* m1 g+ D4 i- G- Q! m* z$ j3 n$ I    */
7 m- p: o4 n8 i& z$ A8 d: d- o- D) ?+ q: u9 p. q" f; ?( Z
    functionexists(uint256_tokenId)publicviewreturns(bool){
) N. u( l& s' s+ M7 I8 b
  h/ B* m- L( q# Y9 {0 k    addressowner=tokenOwner[_tokenId];0 H) w+ y7 K0 z1 R. [5 C, ^0 V3 _
6 j' S+ K1 g# I5 E
    returnowner!=address(0);
8 w3 ~: [) ]9 n, W  |7 t: K( [* A' o# R7 J! ~
    }4 K$ z0 k; y) i0 N. X

/ h. e0 l% [! \; N5 H5 W3 ]    /**- K$ C) G$ ~3 e# @( e% Q

# M, H, S, W. u; o/ O% `5 R. s4 ~    *@dev批准另一个人address来交易指定的代币, @: {1 {& s* i- ?- z

8 {2 \& S+ j9 q9 _8 H    *@dev0address表示没有授权的地址
8 f9 e0 j4 y: g, P$ O) @+ u( T  L
3 m4 y% i1 Z/ v6 J3 w    *@dev给定的时间内,一个token只能有一个批准的地址4 Q/ b. T. \, q' [# V: ]3 g
, }4 ]! J- k. Z4 h8 B& ~9 q0 l
    *@dev只有token的持有者或者授权的操作人才可以调用5 T2 P) S- I0 R
& }+ k# w( C& M
    *@param_toaddresstobeapprovedforthegiventokenID
% A3 g, k, g" ]4 i' }, q0 x0 p) i8 l+ ]  K7 Y4 ^3 F) d8 \( W) a. _
    *@param_tokenIduint256IDofthetokentobeapproved
- |9 v! `8 {- o7 O. B& e# ~0 n$ G% r8 w7 Y9 |! H- a  _
    */; k" d$ e: L3 i: p
; b9 ]0 l# l7 N. y% [# r; j2 l
    functionapprove(address_to,uint256_tokenId)public{! x: c+ C2 O2 `( D) V2 }3 k
. c, _! r7 k" F% x. L. @0 I. s# O
    addressowner=ownerOf(_tokenId);
5 y- y" p; D% i! D* ]4 W" d2 B' w
& \8 q$ @+ H& j7 J! o  e$ a  w: M    require(_to!=owner);. r7 H5 c' p/ \: f

: M7 P5 z3 Z6 S$ v9 Z; S: \    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
3 N2 p* g( ^+ }4 @3 ^5 D* {5 h1 |2 N& \6 ~& e4 p) j
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){; i; y# f  q$ P5 I
4 U4 F6 @! S( x; B! M0 G
    tokenApprovals[_tokenId]=_to;0 k+ t4 I& m% n4 d! }' O
, H( ^8 I3 ?( M' K4 p
    emitApproval(owner,_to,_tokenId);3 ~& b' X* f( l  ~$ a9 Z& x
, n: e( f" J: V+ K
    }4 |7 R4 x# L) b4 y8 o

  B( Y/ x' C; K* T0 j    }
" t7 I" Y! i/ }/ e# Q: O
# o4 W/ G# j/ R" R; I# r2 @* U    /**4 r# X1 X8 E* c4 S
  u% v6 F) y8 k9 Z8 j% X  P" H" ?
    *@dev获取token被授权的地址,如果没有设置地址则为0
  g7 w3 I2 n9 r$ ?; }) L; p2 u# S) w( Y7 }
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof2 I! c) H) k7 f, T3 A) y
- G0 n0 ^. K0 w
    *@returnaddresscurrentlyapprovedforthegiventokenID2 c7 L/ G; V* _9 _: c$ i0 O

/ e' K* M+ Q5 v! H( M# Y    */: D* }  [; m2 B& F: U, V& O

( g1 h# Z2 I: W" D  @. i    functiongetApproved(uint256_tokenId)publicviewreturns(address){
1 a) l4 o( f4 i* p: e# M( o$ G
- e: _; s: r$ a4 h  c0 j    returntokenApprovals[_tokenId];% A* P6 i' T" x6 T% J* x. Z; w
- _3 A/ m, J* F1 C
    }
  }% M; f! e) B5 A: ]
& q1 K3 u7 }+ g0 Z$ `$ w  `' s9 ^4 Q4 l    /**
' v! {6 x5 M8 y. r! K& d8 X3 v9 ]/ Z* j- U
    *@dev设置或者取消对操作人的授权
4 I$ U# [! S) ~% q2 \2 I4 i$ a6 l& Z% V; E
    *@dev一个操作人可以代表他们转让发送者的所有token
8 H% s. F# f% o7 h$ m8 X$ U$ S3 d) `( ]0 m2 x8 K3 T
    *@param_tooperatoraddresstosettheapproval0 k( n& W+ v$ C' Z" {
) a+ Y, e  p  _0 V/ k
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
6 K7 o2 i8 H: Q9 _8 {9 f
- `+ d0 y. |. S# @" v    */
8 ]) g6 L# z3 W7 x6 v! ?4 T( k6 Y# h) M
    functionsetApprovalForAll(address_to,bool_approved)public{6 R8 m, h7 [( n
% C) W7 F  \: j
    require(_to!=msg.sender);* g! L) @! C) [  ^

, @, b# |# R* X7 o0 C1 ^4 C8 D8 p0 G    operatorApprovals[msg.sender][_to]=_approved;; Z0 z  a/ K% ]( k. T9 c& r, D* L8 b

' J1 Z6 Z- D0 H; a    emitApprovalForAll(msg.sender,_to,_approved);# p& B. D( I5 @4 W
' _6 P9 [& \. a
    }
$ |- k  I1 {/ \( w
7 I: N+ |# _. P    /**
: {! `! F, z- P: o, E+ |9 g0 e
: [5 K5 Y  @* t, G' J    *@dev查询是否操作人被指定的持有者授权# V0 C- t6 `3 ]5 `" `/ I

$ H# j' n0 T- d    *@param_owner要查询的授权人地址9 u  u  ]/ j! I; C

6 {" c- h* D  P: ?' W  ^1 x# u    *@param_operator要查询的授权操作人地址& a( j( R( Q# f3 |5 g9 O4 u

! K8 d- \4 I" Z* h; j$ K7 W: Q9 u    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner2 `: Z" {/ y9 q2 t8 l4 E9 q; A

3 f4 Y/ o, R3 v: O. W& ?% {    */# G$ k# H. _+ W3 i" ~$ w. y

" g3 H  t1 ]: t9 Q9 Y) u    functionisApprovedForAll(
7 O4 {5 Y9 z* f. |, [4 Z' O; C. Z' z8 m, L; v) Y) G
    address_owner,
, v& i. S+ h+ ]' X- _. F8 \3 k3 c
    address_operator
) x$ D6 H1 s4 p) f2 c" b
" z9 v$ O0 g! `0 J% e& b    )
1 M( X" Z* N# g3 ^4 y: y- A
3 {/ a* ~" R" q) _. \# ?    public
. L1 d4 T) q' C1 z0 L" W8 m% g
4 ^. C2 D! Q3 H& d% n    view+ m# C8 r* X2 Y  W7 o2 N* R
2 j$ ]( N) A0 R. r. k) `" z
    returns(bool)$ i4 u. u+ l) r3 d& E5 x
- v! j8 S$ x/ H. ?* I* }
    {
! E1 f; F7 ^! g8 E# O+ [: x/ u* G; c
    returnoperatorApprovals[_owner][_operator];7 W: O: U; o" N2 }8 m
5 J7 `) w8 k9 i6 v$ e$ |
    }
" A; h5 l0 g! t& E8 b' e4 R; g( J
  B/ u1 V5 k" f. p    /**
3 q: j3 Z9 J4 E4 {2 |. j4 u: j" v0 C$ e6 z6 }; S0 w5 S7 [* _4 J
    *@dev将指定的token所有权转移给另外一个地址( x2 K$ Q! g( y

& @. P) v; Y1 A* N, E7 r    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
  p! T" G8 g% U2 x
1 ]% `$ Y" K0 B+ q    *@dev要求msg.sender必须为所有者,已授权或者操作人. Y/ f& H) s( @: o/ F3 u

8 P6 w! M( V  Z- ~" q    *@param_fromcurrentownerofthetoken+ m; A4 j/ x6 U7 i5 g

$ v  Q* K4 ~+ ^- \6 w1 m; r: Y& P    *@param_toaddresstoreceivetheownershipofthegiventokenID
) b5 f3 q) b9 t" ]5 v
: ~1 Z% s# d2 L    *@param_tokenIduint256IDofthetokentobetransferred7 N' I" d% i" e+ H" Q" P
2 W& A$ J5 M( v0 C
    */
2 m) u: Z# B' C- C8 N! c. b1 g( X! q5 C6 C# v' S
    functiontransferFrom(
4 F! }$ g" K$ @# j& B+ k% i/ E
# Y9 z* S# ]7 |    address_from,5 d( b; {# `+ O+ j) g; T( [
! J$ L+ f- S# c( X
    address_to,/ P. o7 U- E; {

+ B6 I& I; ?/ v2 b* p* C* |5 q7 F    uint256_tokenId
4 ~* l- \2 b6 a( r! ^5 h
2 q5 o! P+ \2 G# e4 G1 n    )
" q& `4 ?; s% Y7 E" F* P3 }
" O) r$ Y" I- M    public9 j  H; L4 D( i
6 V6 B6 b% @% M) K# g
    canTransfer(_tokenId)8 c3 B9 \5 @1 _6 c5 D& Y
. ?$ l6 w* _5 e! D/ I3 ]
    {) y! A9 ?2 c# j& e0 u; V
: l! k" ^( Z% I1 J7 P& e" m8 v
    require(_from!=address(0));5 p7 h3 X: s5 B8 Q4 r4 e
" ^  ~* ~. f( ]) a' @, d8 }2 G
    require(_to!=address(0));, }8 |5 g, U' `- X6 m8 Q1 C; K

( \) F3 O3 t1 Q% `0 W    clearApproval(_from,_tokenId);
3 {/ ?. b- q1 u5 _. D) t. F
9 L2 V* o. z/ J3 ?* u4 K  T    removeTokenFrom(_from,_tokenId);
, a3 R. E4 v  S- d
# S9 V  u  k- J( }; o    addTokenTo(_to,_tokenId);; |* r1 E( ^* i1 E2 A* k" z6 l
" [1 W$ w& ~% K2 E. |8 e
    emitTransfer(_from,_to,_tokenId);
1 @" p0 W, |  m, ^0 p6 o- x3 Y, `, v7 D5 q1 s3 A
    }
- a2 `* A9 u8 ?0 n7 x" [; |
. x5 e  w1 A6 ]( ?, r& g, y3 s    /**( T# x  |& [7 e
8 V  v; |% a/ {4 k; m
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址, Q, A- q) N! w( Z
  K$ U: e0 a4 J. b- a, y! k
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
6 e  c: }; S$ p! F) M9 X' Y. k4 y4 w# p- S' V  `
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
( [% S2 @) x, w; o: n
# b  E/ f0 A* o6 N    *@dev要求msg.sender必须为所有者,已授权或者操作人5 M7 s6 d0 J6 t+ ^. r& p

. T9 @' E6 t' N/ Y: R. U    *@param_fromcurrentownerofthetoken
3 Q3 H# }* z1 ]) m, ~+ G* z
+ t2 X  H5 v4 j; f1 l: ~9 P    *@param_toaddresstoreceivetheownershipofthegiventokenID
4 O4 D7 [3 h3 P1 h
% d* u2 K( S, ~' d    *@param_tokenIduint256IDofthetokentobetransferred/ }. p3 b0 Y& `9 t, c

7 S8 a" J: i8 {: F% w7 L. T' I; U( y    */
7 Q  w  G' s3 _* ^
( @% I& L( d% E+ l) M, r    functionsafeTransferFrom(# c+ ^( I; l, X: h( J* U
( G0 V. H4 k& q1 ^: G
    address_from,
& v- \2 |3 k1 t  v& w. A$ H3 C# b# |7 j* i" m4 x
    address_to,
8 T8 |) d  E' _, X
) t  j" ?* _! ]+ S% x    uint256_tokenId; V3 f% r0 e+ U' r2 r* \0 {" |

: W, s2 E/ d5 B/ H    )
+ x- h2 k* j6 ~
2 G, I. s+ C) O" j6 t: [& x    public8 E1 Z. V: L  N9 }( V% S3 _3 o3 T
( j2 S) u; L# N2 }* h4 c
    canTransfer(_tokenId)+ O: [% W  q$ }2 T/ c4 x
& X% D7 R2 O/ e8 C
    {: ?! I& _2 e" V7 l" W# U& X
; I$ z& D4 P% w2 @1 i
    safeTransferFrom(_from,_to,_tokenId,"");
" \: h/ J  U7 h" ~0 L7 Z) |$ X( R( N
    }& B$ Z; ~$ W5 H3 V0 {
& V% l/ Z' R# K* ^
    /**$ C. J: X3 \& ]/ {, G% U/ A

" u  {0 e( B* s; w9 h2 k, }    *@dev更安全的方法,将指定的token所有权转移给另外一个地址" T8 s+ X* i5 G" C3 Z# e
2 j7 b. h6 \9 F9 \0 q
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
1 r/ k3 t! g, Y8 C
! A! ~+ k, i; e% D    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
( Q0 |* S: _' U7 u- ]: l; |
5 e+ K3 d) Q& n9 |) a$ w    *@dev要求msg.sender必须为所有者,已授权或者操作人8 y; i/ S6 H. E( R0 _, V3 c

; a" k3 Y$ i' I" ]! `" H    *@param_fromcurrentownerofthetoken
1 g0 g' `. Y2 T- S8 z; d
# W; {% ]% g8 z    *@param_toaddresstoreceivetheownershipofthegiventokenID0 s  z  Z/ |+ k3 l; h, g5 o
5 Z* l/ w0 g# P1 g1 E& L
    *@param_tokenIduint256IDofthetokentobetransferred
, i+ b: x0 H6 |" o4 X1 a
  X* H9 l, S$ B. J5 J    *@param_databytesdatatosendalongwithasafetransfercheck
+ e( Q6 {4 {5 ~# g3 y0 @; \' G- p. L" ~8 M7 W5 Y+ o: r
    */1 {- E) z+ O5 }- B4 i
$ B0 B! j' J( v- K( c! I  V  D
    functionsafeTransferFrom(3 o9 q: x- \% @
4 p/ x" k+ E5 L# \$ v: ]( s
    address_from,
6 M' d3 Y, q- M
6 |) _  f$ P) Q; z( `    address_to,$ ]0 y0 @# L! W5 T( O9 m  a

! i) \' ^1 d+ b, G$ h4 R    uint256_tokenId,
9 {2 R3 k7 n5 _0 U7 C0 J
! d1 G! u; s% ?/ x* O0 {    bytes_data7 W" h$ J" a# t" g

  E0 B2 D4 G- Z) E! u    )% B% l5 R4 v# e  ^  w
$ w$ d* O  E" w8 E# H9 l) ^
    public5 X: }  _! s! w2 [8 t% Z

& K. v7 ~+ S. G7 G* J8 i# X, N    canTransfer(_tokenId)3 q) L' p$ w. Q! a
; d8 S! \' ?; S, i2 w2 M
    {
, J2 Q1 ?  U4 K( h
7 M4 l9 M$ t0 H2 j0 i; Y1 i    transferFrom(_from,_to,_tokenId);
4 V: i9 S; P2 {% J  a" Q( V& v
- i9 n5 u: s, H1 J& Z    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));- F5 G. r8 @& |, i
7 A& e+ l( o: K# f0 S& c
    }' ~( e- G( v7 A/ [, c

( T. M" ]8 M& @8 H7 y    /**3 H% P1 b( q* P+ q. Z3 h2 V
/ ^9 f# a. R8 l' K; ?8 C
    *@dev返回给定的spender是否可以交易一个给定的token
8 e$ x  ^8 |7 x& Z6 T7 v, \: h/ g1 G- G# G0 ~, `( ^% e
    *@param_spenderaddressofthespendertoquery
' H6 L( q* N, H
# K& Z4 V1 p; L: x    *@param_tokenIduint256IDofthetokentobetransferred
/ b+ ^! u8 l( O4 t% x- `
* r6 j% v: [1 u" \2 x* e& |* U2 |# i    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,& m, a3 r# I% V

$ P2 e2 n9 r' i' E( }5 V    *isanoperatoroftheowner,oristheownerofthetoken' j( X7 m- H" F: `

8 O0 H2 E5 R6 `    */
1 ^1 [) O7 r) `4 i; H- w. k1 A' O1 L5 r# ]9 `6 V' w
    functionisApprovedOrOwner(
# R; D3 J3 k. o1 p" \; s, e5 @8 ?& S9 Y+ a. M
    address_spender,
" @: j+ q1 a) j3 ?# |( Q& g  ~" G2 W9 X" d: ^# Y0 _# |9 C# g& N9 P
    uint256_tokenId
- |  X% H( Y" ?& |( n6 ^; ]
4 z4 P5 ?3 X; |) p    )) l( y1 r- d: t, _/ R6 r# n

/ L+ _7 p+ z0 R: i    internal2 Y4 S  w! y* a9 }. b0 X( p) ~2 R8 [2 q& m

+ k+ b( H- I* s    view9 Q+ T( V( m/ ?/ K

% Z$ p# y3 A9 W. Y( \! [    returns(bool)
4 o! c5 W3 r9 {, }: x1 ~8 A3 Y0 e6 Q" I
    {
+ A0 Y4 q9 x  f
( p9 @! @* ?/ o    addressowner=ownerOf(_tokenId);
$ _5 `" ?1 k/ Q
% W& i# R6 q# ]4 ?5 Y8 @    return(( F* a9 `5 I, {% I, m

1 a0 p% r* V% K2 G6 D& w    _spender==owner||
6 E  y* ]4 ^% l. K8 L  a  K9 Z/ F. e- n2 [' u- B
    getApproved(_tokenId)==_spender||/ Z9 ^# s4 {! E: U2 m% K8 A

% D, C9 R- G3 x, D3 r    isApprovedForAll(owner,_spender)  m8 c' x! t+ R- c0 H
3 Z* S$ |! L, r; ^$ K+ F9 \
    );% X3 {, X: Y# ]5 N6 m

# t/ A7 Z% O% Z( W4 P    }: L  {% r2 K8 N6 X8 U( N

9 n8 l, x/ j. O0 h    /**& w6 s! N. o% x; q6 f7 P$ v, s/ m

' l1 z) r0 k0 r* {9 r# h& w8 i    *@dev增发一个新token的内部方法- `. A0 x% ^+ K, ]* x2 E% @
/ _) [* A" V( @
    *@dev如果增发的token已经存在则撤销. H, x" j( y- O% z1 F9 }% v

5 \2 s; W- G- Z/ T    *@param_toTheaddressthatwillownthemintedtoken" Q! a: ?$ _- v) W5 w
1 A0 s0 r; l' s8 A
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender
5 g7 s0 J6 x" ?+ j; n5 X! M0 t* y1 a3 K0 ^; K$ I
    */3 @8 d7 o8 k. l9 [
& _: }. A! E4 N
    function_mint(address_to,uint256_tokenId)internal{
2 h3 c  F) W. a( {9 ?+ b+ v* b, f$ U9 q; T( h5 l: a: e1 W
    require(_to!=address(0));( F. |9 q# z) C5 P5 N: ?* y
" i7 Q. i- j& U! V, s
    addTokenTo(_to,_tokenId);; }# K8 `1 b+ U, v- A( s

$ T& _  {4 x; a) ?    emitTransfer(address(0),_to,_tokenId);
2 Z0 \6 h  W) |, `8 q$ ^. w9 ^% A5 Z+ w, c5 m1 F
    }
' w7 k9 T. N, }! d% `6 l' S. _# w3 T& d' A
    /**
/ E9 J, l) ]( V5 O- }7 x) \4 [' k9 u# Z( E" P' B0 `7 K. _
    *@dev销毁一个token的内部方法+ B* b6 ?& t& F

' l% \/ w, X- m2 i  M9 ^    *@dev如果token不存在则撤销
( D+ a2 y2 A. Q# _8 ?
0 C3 T* }" g" ~    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
  K6 e8 K. e! x) B" s. y7 n; B; F- ^5 a3 E8 g, {. C
    */7 [9 Z& ]& c5 @. x* ~' t1 q4 g! g

+ u9 T2 V6 C9 O3 v. h' @8 O% y    function_burn(address_owner,uint256_tokenId)internal{7 K8 o7 J( [. K4 }( J( k

& v& |7 i  u2 c0 V& |* P    clearApproval(_owner,_tokenId);9 u7 z* d3 y) j8 H6 m' |" m
, m- [/ |2 J8 H( P  o! Q$ y
    removeTokenFrom(_owner,_tokenId);' e! |# g! t0 K9 T

& `- j0 \2 @* @. Y% {* F    emitTransfer(_owner,address(0),_tokenId);8 ~5 [' a+ D; G' y4 B
- Q& ]: u; `/ ~' r+ y
    }
* r( E8 t! w4 u0 W  c2 n0 J- N7 M. Y+ _# H4 p5 E& V7 T, c
    /**& U5 j) C, Z2 y4 N

& L1 e0 g1 R! g) k    *@dev清除当前的给定token的授权,内部方法
$ }* \1 T6 H. l: w3 @, a1 C
' X6 c) W  `* }6 i    *@dev如果给定地址不是token的持有者则撤销
4 a; X( n. K3 F# s" v
6 l! g& d3 N  ?3 [* A" Y( K# P    *@param_ownerownerofthetoken
6 I! w6 i; R2 w* y- K5 O4 P/ j4 X0 }
    *@param_tokenIduint256IDofthetokentobetransferred5 }) ^' J0 T7 U/ f' M
7 r1 p4 J( i+ Z6 I* Y
    */
9 W: S9 H+ G  q/ h9 e. g
$ J/ m9 Q1 G& V' Q' h    functionclearApproval(address_owner,uint256_tokenId)internal{" U& O' O- u1 J2 h9 x
3 o5 o4 u4 ?% q3 o: K, G* u
    require(ownerOf(_tokenId)==_owner);% d  o& |/ a- o% t
$ y* J/ V- ?" P4 b/ z
    if(tokenApprovals[_tokenId]!=address(0)){
$ e: D# X$ N' ~5 j% e3 m
. U0 j. T: u1 q7 u& [% M    tokenApprovals[_tokenId]=address(0);
0 p* V& E/ o1 w' X9 u4 B* y. O) f/ \- k
    emitApproval(_owner,address(0),_tokenId);9 D% S  y' f" `9 H9 f0 O
% ^% J( z4 N# C! l9 H0 \
    }' V% d1 |+ z' M/ c7 k% i

* \; q" `# ^5 R" m8 x    }  |3 h8 Q9 R  V, J, ]

4 M& b" Z) k6 y+ d1 ~    /**
. m; h1 E; t3 V4 K% Z" ^9 h- Z8 @- `7 t* ^( T
    *@dev内部方法,将给定的token添加到给定地址列表中
4 ^6 {. \; z. W/ o0 Q& P$ z7 g! r
    *@param_toaddress指定token的新所有者- R/ Q2 a+ }2 {
- W% e. _7 o+ u' a! Z2 n
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress; Y: ?, K. x+ `; V) L2 M4 w
" j( P0 ~6 d( w  R$ v. O3 |
    */
& g/ d' ?3 R+ m; ]) q: m2 |% _" d9 h" d) W3 r- y
    functionaddTokenTo(address_to,uint256_tokenId)internal{
) a, Q- Z5 W0 N& Z
1 M* M' ~: |; d: D8 @7 T9 O    require(tokenOwner[_tokenId]==address(0));! v" J  I* G2 B$ l" R! Y
1 {+ ^; P% o& T4 M2 ?5 b
    tokenOwner[_tokenId]=_to;  X* R# U0 `; F/ r- @/ {5 ^. j
, |- c2 l# ]: `
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);2 R7 ?; m8 I: Y+ Z" a! W
* ]* C3 `. x4 H, ^
    }
- k& }  _$ w  T4 w
6 w/ _/ T5 A: G6 X  A! Z    /**
4 \! x% ]5 ^' D& ?) {7 M9 k' m" _7 `( T1 D$ _
    *@dev内部方法,将给定的token从地址列表中移除
: M' w- U3 W, D/ d3 A) ]8 p5 c8 J' g: K# K
    *@param_fromaddress给定token的之前持有中地址. C# a; H; m2 V5 |
+ y2 k+ G4 p; W, n; U
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress! n+ u1 m; v2 l3 V, R9 g1 t

7 D  I( W1 z9 h    */+ V7 c8 f: C0 @8 h
/ i" R6 _+ P+ j$ L
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{% M/ e& ~6 o* T7 |

3 S! x" L! k; c5 k! S    require(ownerOf(_tokenId)==_from);
+ M1 N, i. j- P9 ^5 u6 `
& T7 w' p5 z3 b: b% d) W& J    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
+ I; N$ o1 p8 @% g2 y$ |" m3 i: M, c. V/ _& L: L
    tokenOwner[_tokenId]=address(0);2 X. ~% R/ o: ?1 ]+ U7 n

! L. K: n0 Q& r    }
& [% M6 P* n6 C1 p  D$ V- T8 y+ _" E) B  W2 U. `
    /**
3 t( W& w* {6 d2 w9 B4 U! e' [
, x6 K- `5 V* ^7 f    *@dev内部函数,调用目标地址上的`onERC721Received`
5 H( E7 R+ X/ Z) G( A: C% d. V2 |: y7 ?
    *@dev如果目标地址不是合同则不执行调用
: |+ J, b8 W' l* K* P+ C7 w2 Y7 ~  S3 h
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
8 ~  e# X3 l: D1 n) L
! f4 ~5 A: ~' ^" W6 h# Y  e& u    *@param_totargetaddressthatwillreceivethetokens
; A# J7 e0 T8 A# t/ s% m4 W9 v0 U& e3 {- T
    *@param_tokenIduint256IDofthetokentobetransferred
( Z% E, k3 y. H. z
) I% T4 J5 \' X# i6 {    *@param_databytesoptionaldatatosendalongwiththecall8 `$ F: s2 U& n. k3 p& ^1 p3 A) T

6 G/ I5 d' e( r' A' j8 F9 Z    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue/ F$ K# d6 q# u3 m" _- \; k. q

& }- C8 i: [, x: R) @5 t    */( ^. q: |7 ~" J" f3 H
6 U' i8 X, b2 _3 S1 J" n  i
    functioncheckAndCallSafeTransfer(
7 u6 j- ^/ s( o& Z
+ a0 v+ ?& T* y$ V( Q/ `! i    address_from,. J+ S- J( W/ B' `& U

8 @$ w* k% ^" c0 S0 H* ~4 {8 [$ L6 [    address_to,, a# }% J( Y( x: {2 F4 H5 l

9 X" L: D  ~! o. i    uint256_tokenId,  p: T1 ^5 t9 m' O$ |/ g

4 d1 i: `2 I# w8 R+ |( c" x    bytes_data$ @& ^8 B9 P6 W
4 Q) N' ~; ?. K7 B5 Y7 H0 q
    )- ^5 p# G3 L) ?) R% J, O
  e4 h9 i5 I5 K" l" m/ H
    internal
* a8 W( x' {' q+ q" V$ Y- |" _
. Q6 l" t; Q0 x0 ?+ y5 s. B! Z    returns(bool)  Y4 D; q5 C  f! V
4 i3 ]; @1 t* M* ?: O
    {
' L' Q% N0 J# ^4 k3 Y& @* h/ L$ X: n0 i* e; n
    if(!_to.isContract()){9 e9 ?) e" m$ a: y3 F

; S4 L: t2 [4 ]- a: ]' t/ t    returntrue;
, T' d2 s' Y7 J& G0 o7 E, e* L  P6 V' @3 f0 J5 Y- e7 b
    }
/ M8 Z+ R( H% j: e2 g+ q
7 C# L# W/ I; I) w& K    bytes4retval=ERC721Receiver(_to).onERC721Received(( V8 g: w% P8 k" j) I5 n) @, T2 c& g9 h

' h/ V) [! H6 n8 p6 f    _from,_tokenId,_data);
2 O5 G$ g% Z% v0 P. P5 r0 Q8 A0 g2 j8 i7 ^5 ]
    return(retval==ERC721_RECEIVED);: N- N9 Z: K. C4 [; j: b) c# C

' x. \. A7 M8 I$ y. \3 Z    }
8 V# g; p6 s/ Z
. a1 k( U( H8 p    }
8 ]# b" o/ _% S: k3 e$ L; R7 M; ^
( Q" _  z7 ]/ Q/ J+ x0 k9 w9 p) l    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
" V3 \% q  L( L& y, I, M6 ?6 ]+ E* q% w, h1 Q
    ERC721Token.sol- k: |3 u' F# F+ J3 w% F% F, t

3 q3 ]$ Q5 s" G* s- L    pragmasolidity^0.4.23;
4 j2 B* i: Y( ]4 f  m: A
+ V( `* N- I- X9 ]" P- l2 {( E    import"./ERC721.sol";
+ {6 A- E' s: p9 q. _6 K6 C5 F* q8 j" _! i5 {$ t/ |
    import"./ERC721BasicToken.sol";
9 I4 F! I: R+ i# x) ]7 \. a
1 O- F7 k( {1 V, K    /**" L4 U) V7 [/ H% Z3 I% s0 _

2 Y" o9 ?3 ]+ l& C  a    *@title完整ERC721Token
5 `, ~6 A; H0 t) o& q
( Z- g5 o: O$ z6 W    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能4 F0 R; Z" `4 R% }: j

7 \: h- O  Y; I! E+ v) y  d    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md; d! I/ Q+ Q, |4 d

/ D' r5 U( j' U, {$ |; e1 C2 k  o) p    */
# A6 X' y( V- `. `5 f
3 [; F+ J$ n8 Z9 M0 W6 J$ F; ~# h    contractERC721TokenisERC721,ERC721BasicToken{) m& F+ H  ~7 N+ Y  |, J# W" B

' ~6 G4 l3 N7 ~: t) p    //代币名称
+ Z$ K' y6 `7 G4 `5 k4 I3 t
# n/ ]4 a  N/ L    stringinternalname_;6 b" \% K4 u. D" I: I4 d

/ q7 c/ Q3 z8 d% q' d    //代币符号2 s0 b8 W* B& O# g
: x4 n, N/ P9 T+ z2 \; e9 s) l
    stringinternalsymbol_;
1 D) \7 h8 d. b1 _9 d/ W! \, V& m: R2 g
    //所有者到所有者拥有的代币列表的映射
7 E4 z- Y# `7 K, T0 @  o# P6 ?& k/ J9 c1 K" z9 N$ e% a6 {
    mapping(address=>uint256[])internalownedTokens;
% ?3 b8 e+ E2 B: B' Z. K9 `8 F# |, }# }, q, }, C2 R
    //所有者代币列表中代币ID到索引的映射
# N- Y+ q- d+ A! {, F4 S/ e) z( a. C" g. G$ E% ]
    mapping(uint256=>uint256)internalownedTokensIndex;& Z6 V" ]' T% D. a" d

" H; X2 ^5 C7 P0 t8 O5 f0 @; H8 J9 R    //保存所有代币ID的数组,用于枚举
2 z( D+ d4 t1 Y, _. ]
/ b+ N! M* D' }$ w2 r/ J    uint256[]internalallTokens;
! ?  K3 z% M- A1 r) g9 ]8 z' ?3 h
    //allTokens数组中代币ID到索引的映射
: X4 r, m* w# |: M) Y3 ]1 R. j# @1 z4 _2 I+ v
    mapping(uint256=>uint256)internalallTokensIndex;; O  }% K" h2 Y
& |5 y( ~8 m6 s# }) q% e1 p+ E* Q
    //可选的代币资源URIs映射
# ?; z% g% H4 E
! Z$ @4 k  ]6 O/ e: `- w/ _4 \# h    mapping(uint256=>string)internaltokenURIs;
& J( N3 d% y! j& D9 H2 J7 k' k1 |# z4 O6 e
    /**3 f9 S  x  a5 g& V( `
! n0 v; t  i% f# {
    *@devConstructorfunction6 Z& n& j- d! x" c

6 E# R  g. m: X2 h    */
* h! B4 p) P) \+ u8 h  w% r: J  D/ w1 l  @6 g
    constructor(string_name,string_symbol)public{
% q& R+ P, \! W& ^. Y
# N( w# v& j; o# S    name_=_name;
6 ~& L! h$ ?5 Y, v8 }0 }- y, l0 C) C( J, s! p! Z3 r
    symbol_=_symbol;
2 o0 l5 c$ b" g
0 i. q5 n+ n, d5 K. Q2 I6 i    }' H/ P  \; q( k$ G) q
" c8 T9 t! S) W* p
    /**4 ]& J8 h  K5 Z6 {( m9 x) h1 _5 I/ w
; N! B7 Q& ?- S$ O
    *@dev获取代币名称% n1 z6 ~6 y9 F) p
9 W  a* Q# W0 p- P9 G
    *@returnstringrepresentingthetokenname& a" r% M7 `2 B6 [1 u' l" Y4 |
1 @4 Q5 m; T6 m! k) F
    */4 s$ M, U. ^+ K+ [% U6 X

; g# q0 A) d, S1 l" ?+ K9 V$ b    functionname()publicviewreturns(string){- v4 |& ?6 x! h# W5 ]  L

% H' _- W( b  |8 y    returnname_;4 c$ ]' }7 Z( k

' J* |, T3 s  P0 G4 m9 T' b) p8 A6 V    }8 a# r0 A% z: B
( k3 E7 _, ~2 S$ |3 [
    /**
4 c* N9 b/ N# c! }; |8 q" g) n- X! j) [+ Y5 Y0 e
    *@dev获取代币符号
& N$ n1 u$ o$ a6 p, V- n' [; F  [* }  U/ s7 F/ C7 o1 [/ `
    *@returnstringrepresentingthetokensymbol, z/ C* i* ?/ V& Q) F+ x* d0 ?
; e! c; R! V6 M4 R
    */
" f  p* E5 K* N7 J3 D+ ]8 h
2 h! a6 Q9 P/ L    functionsymbol()publicviewreturns(string){) S# ^' |% V5 s; X9 H% W
- {/ S7 ]4 x& ?, [1 i
    returnsymbol_;9 e* `# @% G0 z! k# r# f
) L  Z/ W9 [" D
    }
: |( Y2 D# g' Q, P& L! x, q3 P) \, c. G; I+ B
    /**
, s3 r& _8 r; h- z7 m$ U+ z* i7 h( J
' L( V- V6 _. X8 j2 w9 {% O2 r    *@dev根据_tokenId返回对应的资源URI! c' C& S  V5 a, S3 A3 B$ Y6 S. r

6 m& q; g1 v+ @% B  W: M    *@dev如果token不存在异常返回空字符串
& Y; n4 j6 w5 C8 i
. \4 S: _  H/ \7 ~9 J" [/ m8 t1 s6 N    *@param_tokenIduint256IDofthetokentoquery
$ W1 c- g/ M; f& @: ^" j! Z! {' d% |* \7 a7 X# Q" b
    */# A& j1 f2 L2 X# T8 h
; K( ~! e. B1 X( g+ Y9 ~
    functiontokenURI(uint256_tokenId)publicviewreturns(string){; V" s5 t7 P0 D7 Q3 Q
1 C! W, h' b+ J) V/ J% R) J
    require(exists(_tokenId));! I  X) N! O+ V/ H

  o. A4 M, b9 u, D7 K    returntokenURIs[_tokenId];) a( N' Q( s$ P% J4 s' H
) [8 h  t8 e6 E2 N* B, I! p! J; M
    }0 b1 {$ x3 D3 T/ B1 T% b  Y
* o8 _2 g* l$ T+ k  J9 L
    /**0 j  `& Y: R) c! z7 T6 a* b
4 [% G+ J! _& ]9 g' m5 f  L
    *@dev获取tokenid通过给定的token列表中的索引
" `) P/ t: g- P# t6 d7 Q
( [5 @! M* D/ R2 j    *@param_owneraddressowningthetokenslisttobeaccessed
- |* {  p; q/ D7 E
6 o3 _& e$ a) K* R    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist1 Q& }' o2 g$ k

7 j/ @6 i' \: e+ P7 [+ U    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress- t! R5 _0 T* I' [
& e6 R# a% X# n/ h
    */% W# W0 H! J0 u$ S) e

2 {( l) c! A* O: {    functiontokenOfOwnerByIndex(
$ n3 d% X$ K7 w
5 y- f6 r. _' g' U0 K) s% h    address_owner,
8 _' u% s5 ~6 y9 U: S4 ~8 a( Y3 y, L( G  j0 f
    uint256_index
. Z" y. q; O/ s  ^+ S% N; \4 d% X) U, G
    )
" {0 y! ~4 Y, R1 s
2 I# h9 c; b; R4 p" ?    public
# i2 y% Z8 D9 S- C7 b3 j: ]5 j8 S5 l$ _2 |: b% m" p
    view
1 |& k1 W8 p9 d7 u  m9 V$ M0 _0 Y8 A# x; `4 L
    returns(uint256)% W2 |. b8 N  P. Q) J* a2 I5 k

) N$ t" `8 S! \, Z0 ]# W  Y    {
; |$ ?/ S  X) z
& o' ?* m* {1 Y3 F0 B0 H/ B    require(_index+ Q4 F* J. V8 T; P

; D$ y% x$ O0 R" x7 l6 }. T    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。2 D: Y, w4 M' F5 v; W0 S+ W! z

( A$ M# L: g6 J$ A" {0 ~' F0 e    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2