Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2481 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
6 g. K# C5 a# L+ @, q2 |$ c, B- H! M
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
1 U- i& D/ t" @1 z% e! p: h1 ?  q2 M& a/ t3 q1 V
    ERC721Basic.sol: k5 L. z2 G- C9 b
) Q; Q. F0 w, u% I# R
    pragmasolidity^0.4.23;
5 o3 v' k; g/ H1 }# e/ F  j" n9 q/ }+ u' c$ ?
    /**
8 h2 g- F+ d! p% K! F) e
5 R/ n# r; W( T; V, J2 [    *@titleERC721标准的基本接口0 N! n$ I# s0 p

. C5 M: q$ m0 \! y( Y. |" g    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md# c  x, {* _8 y$ b' Z
6 S9 [) W5 B- k4 U
    */  q* j$ E8 v+ V# ?9 w: f" Z4 ]
0 z. U" |) f) B
    contractERC721Basic{* r) |+ k4 X; T6 W, z. E
6 {3 |4 F' E/ A" ~) o; n% a4 ?4 M
    eventTransfer(. H. \; B* ~5 `  t* u* k; s, V

0 ]; B! C, n- R/ S    addressindexed_from,2 Z5 ?, G0 {) E8 C
% Z( x$ Z9 V& Z) R* r5 p/ t& `
    addressindexed_to,
8 N. x# L8 w) Z- v* U' I
; D$ w8 ~: g! m, `* T3 J    uint256_tokenId) a1 F, v, }( X6 a  c! N

- c/ I1 U- N% A( s! d# N# K) e9 D8 S; R    );
" \0 K# y* f8 R* F7 C
0 C0 }+ r) E! `! S/ ^& d    eventApproval(
* f' [( m) v& q/ S) X2 F" w! O$ |
    addressindexed_owner,# v8 _3 _: j% q. Q
1 i( e& o- B/ _: V% C5 V1 j
    addressindexed_approved,
. G$ ^- ^- m$ `- X1 y1 w2 g& r$ G) A4 B+ }: E- m- r
    uint256_tokenId) X, h5 N' O9 B1 @+ ]: H% n
& k/ Y& Z; H& O, b# D7 [7 @
    );
0 Z2 d+ ^' S5 ]: f6 j# `# U2 O
& \3 T6 ]" ]$ u2 K+ h    eventApprovalForAll(
  z0 V" v! B( X1 `1 f8 _
' w9 r7 u1 A' S5 z    addressindexed_owner,5 k! G9 g' |. C4 R+ c7 ]
- r0 D2 M3 P9 L/ O4 o% l
    addressindexed_operator,6 d5 r. n' b# t, J3 F9 H. Q$ O5 W% w

4 e# a0 ?6 p' h8 d; ]6 e' m    bool_approved
! N" `% O8 K- g3 L, y$ u  Q7 ?6 T  `5 Z# I% f$ U1 H  ~: l; Q) S
    );8 I; |) N) I1 X; F0 M$ ~5 A

* Q  W9 l- t3 ?0 n  s    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);! Y% V  X* D5 b2 x  |
/ e: n3 v6 C$ q3 i) s# c
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);+ c$ t" q0 d  G1 l2 O5 y2 u
6 k. f+ N/ E  O; |
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);4 `1 d5 k- z: M% x
6 i2 W* `. P( y  e! w' O2 T
    functionapprove(address_to,uint256_tokenId)public;
3 v$ ~* T/ J! n
! H; _2 m- e- i5 |0 e    functiongetApproved(uint256_tokenId)! h4 b; X. A) [; C; c/ @0 ?& M; ~
& s6 A9 w) X% m( \
    publicviewreturns(address_operator);5 ^. U" N1 U+ ?+ r

9 E! F# X4 Y* P3 w- w6 s    functionsetApprovalForAll(address_operator,bool_approved)public;
' q5 P2 I: P0 Z
4 i4 Y; \2 k' a; y+ l, [  H8 O    functionisApprovedForAll(address_owner,address_operator)
  n1 c$ `$ o* H4 l
6 B0 Z0 `% I/ H/ A! h    publicviewreturns(bool);0 v5 _( j# C3 p& ]8 ]/ ]

  L, m+ k3 C) ~7 I# C$ g    functiontransferFrom(address_from,address_to,uint256_tokenId)public;- k/ O' Z1 B  r
7 u) K2 d: f/ I( H
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
8 K' _7 R* D" [- A0 G# n7 [. a2 f6 t: F/ |' e: k- R
    public;
7 J) _2 K1 ~& e- T0 S
$ @$ n  z' M8 j    functionsafeTransferFrom(# F& Q6 b0 d& k; f

! n9 g7 [# I5 A9 @" _1 b- A    address_from,9 T4 ?  t  A& g2 O' v; E5 ^
' R+ Z! N" s' R
    address_to,
# e' l( F/ f; W! k( m8 f# ]7 Y0 f8 @0 W+ s4 N
    uint256_tokenId,; F& o" T9 ~; s: A

, i) Y6 `. H5 A) `    bytes_data
- M  y! V0 G1 [
: C+ P* y5 m( ~    )
- t' Y- G6 F. g* O2 h9 T7 j
) |% A9 K1 k9 ?" t    public;
' z# h. r1 X% M& q+ R& j/ `: G! _2 W, a$ K1 D. G
    }9 h5 _, c# S' t/ H; l  |

1 O5 L: L* @& q( y# M8 k( n6 Q  u    ERC721Basic合约定义了基本的接口方法:1 `& s$ N7 V9 c: W% q
& U! M, _5 p, J5 S1 }. E
    balanceOf返回_owner的代币数量' B, f- s# s2 y' ~& ]0 j3 D' a& b

9 ?* R4 X5 G% {; }7 W8 ]; b$ W    ownerOf根据_tokenId返回代币持有者address
  V5 f$ F$ M8 g) x6 f
  R: v# Q" j. x' V& ?9 E1 F% Z    exists_tokenId是否存在, E2 _1 k( T# P1 S
- o" d+ D# v  V0 C" X
    approve授权_tokenId给地址to# u% E4 Z) r) N* C# a5 r

/ _. u) T6 N( l+ N' A' m    getApproved查询_tokenId的授权人_operatoraddress
0 a& m+ j5 @: l% B0 ~3 E. f8 h& R. T! E; ]
    setApprovalForAll授权_operator具有所有代币的控制权
% P  _7 I' W7 b: @" m9 ~! i' C: A0 F( A6 Q. X% z8 L" S2 _
    isApprovedForAll$ a0 W# O: h  S. B9 o

) a" ~  x; D9 K% t# X, x    transferFrom转移代币所有权+ f4 I( W7 ~7 Y' f5 x9 Z
; Q  y' Y9 K( L% V+ ^
    safeTransferFrom转移代币所有权3 c. K5 T+ A+ ]3 j( q

% f" ~/ w4 l1 e" X    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。
* R2 T9 |2 ?7 j9 E
2 T% p+ ?1 R9 I4 Z    ERC721.sol
+ P' q- @6 ~2 A# l  p. k. e
4 ~7 D9 {' e! u) H    pragmasolidity^0.4.23;
. p: B( P. W7 D) P3 `1 q7 f# T2 a/ T+ Q
    import"./ERC721Basic.sol";& i2 l* k' x$ h8 Q7 [8 m' `3 D+ `) y

: g( U6 d5 C4 B7 X! `    /**
) Y- E( V6 j( L& O' h( e; X: [- }4 k) i4 y! [; T4 B+ F
    *@titleERC-721标准的基本接口,可选的枚举扩展
+ m; F! }& t1 q5 C$ G. z* a" N; h+ k; F9 P
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
7 m' [  k$ Q/ K
4 e6 {! s2 P# S% f5 [    */
5 n/ t( d' X, X+ F! M& S. a7 j) y: |. Z: F% V7 w) }- ?6 K
    contractERC721EnumerableisERC721Basic{5 P$ {) h+ n& i8 l  [) O  i- V

9 m# ~% e( J) E. d  |5 d    functiontotalSupply()publicviewreturns(uint256);
; W, y" {2 A7 H( ]% b* @5 f8 W2 ]" [$ W7 s
    functiontokenOfOwnerByIndex(  U) \- Y6 D- Z3 K! e

+ k+ h) u9 K: X: G    address_owner,' U1 i0 ]6 G6 G8 Q5 W! L. H2 p6 e
& w& r4 F; z! U
    uint256_index
$ ?) s/ }2 y$ r; G; w; Q
9 o. d  H) |( X; ]- S' k3 n( K( m    )" t# F& a( t+ b( \& \% v
. B* x* L+ u- i$ F
    public
9 ~( R8 ^0 P" _! f; ]- h0 E5 v  V! _+ j/ y% b0 W4 Q
    view
8 r. [6 u0 v2 A- z/ m
% e$ k0 L. \$ v5 I# I8 c    returns(uint256_tokenId);( n. c9 d! o9 m7 o. s( y

2 d! L* g3 Y! L% y% R% ~    functiontokenByIndex(uint256_index)publicviewreturns(uint256);) ~+ h( ^" R: J: t

* c7 O0 o4 m$ N. J: ~    }
6 c  u2 r# S1 B/ x6 a0 @+ s9 i, x9 n; x4 Q
    /**
. [' }' T  M& [9 p3 i/ c- }  _; O1 ~: U" ~& A8 \/ r0 @
    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展; C' \1 U7 H( l
  C6 k( h7 }: w# ?
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
! t- X6 F7 Z- w& H/ p4 p
1 |* g  U. o+ q% P# P    */
2 A2 R# F6 }  U' M( ~, \! b3 r! F* K
    contractERC721MetadataisERC721Basic{
- W$ t5 Z9 ]) _/ T; I- i2 }! b1 z2 N0 R2 s* {
    functionname()publicviewreturns(string_name);
& r5 u6 a# D& U$ }$ ]0 |$ i* g! y( D# k2 V! m8 l: l. y( `0 u
    functionsymbol()publicviewreturns(string_symbol);
% N, B/ U0 ]( Q+ t- w0 x/ O: A+ b
    functiontokenURI(uint256_tokenId)publicviewreturns(string);- m; @; l) A! I" s. d

  ~0 W( N1 i: j' w7 [    }- D$ H7 r0 n0 k  T
7 v  w) n& U0 [$ p
    /**2 L; `8 t$ {, A3 u
* l, {! ^# `& I( W  ^
    *@titleERC-721标准的基本接口,完整实现接口
! ~8 M! _. i. E4 c* i+ V/ W- i2 x
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md3 b& `0 F; w, G

/ u) f! l/ \. w  f5 [9 z    */  U" Y0 f2 B. q& r; n

6 E  E' f* [& H7 m* m    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
6 ?9 \; R" y$ a* O, G' C: N+ F/ \3 x$ {( K' b" p
    }
0 ?6 Q; g" T! g+ Z
7 y. y" g$ K" s9 x    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
/ ]& M6 _% P+ Q2 F
9 }. P+ _$ O5 n( s8 ~" c/ n1 ^    ERC721Enumerable枚举扩展可以使代币更具有可访问性:2 y* {. B4 I/ B: |) u, L- z

1 W2 K( x" n; e9 A* `    totalSupply返回代币总量' J2 M" e1 [6 ~+ E' N2 h

7 C+ p5 J$ ^& v6 I; }6 a    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
$ M& X. k  C1 M* `# N9 J! q9 @! Q, j! w$ v/ n+ f1 @
    tokenByIndex通过索引值返回tokenId) K  j" J. a7 K
5 s- \5 j3 I$ Y; g& i7 M, P
    ERC721Metadata元数据扩展哦用来描述合约元信息2 l8 p1 D. g: x5 x1 L

- a6 x: d% c% d: q9 r    name返回合约名字6 K: g5 J8 w* F. o

$ h6 U; f, d( l/ Q* F    symbol返回代币符号" q1 Q. p+ E6 q% L

$ U2 J, |  h2 X& F0 y5 d    tokenURI返回_tokenId对应的资源URI
  Q7 z0 b2 _* z: e4 y8 g) K) Q; t4 G  n* Z$ g6 B4 n( Q& t
    ERC721BasicToken$ K% i% K1 |4 \! E7 ^

$ o. d) o0 R( \% D    ERC721BasicToken
: X/ U! l2 R" Q3 h; f" c5 X& t1 n& g
    pragmasolidity^0.4.23;
6 Q- p0 p- B: H6 g3 J( S* K! }) H9 Y
! u4 V3 A& J1 U3 F, f$ R, w    import"./ERC721Basic.sol";7 N& s2 \/ v/ ^/ a' C8 R1 W

2 @: N5 D% E6 h( O% P# ^+ a0 P    import"./ERC721Receiver.sol";
' y' F* _  Y" y8 p$ Q* X2 X
/ l) U8 \( K' C: y) F2 a4 G; l    import"../../math/SafeMath.sol";: b6 U, N. M& }- f( K3 [& ^1 T5 q2 D
$ q6 Y1 G; n, g5 h7 I; w
    import"../../AddressUtils.sol";
% U1 N$ [9 L( g$ q5 n& A; P, m( P
    /**$ G$ p/ O* J7 D, H; @+ i( W5 h: G
& W. u' ~5 {3 y: F
    *@titleERC721标准基本实现
2 a3 U' r+ c7 \' ?! D* o7 k! U7 O% J! ]0 I; H1 Z; B8 r; H6 \
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md: G# W1 n- ?; y8 v: b+ [0 c

( x9 p9 \3 C# ?, O* O    */
; U' P4 K1 C0 n% L1 i) Z9 J6 `2 n# |& n7 `1 E
    contractERC721BasicTokenisERC721Basic{
3 ]& ?" o) ?3 J( U5 G: _; [/ V/ K$ W: @9 u  g; Q, F
    usingSafeMathforuint256;' R( A* M5 T. c% u1 ~6 N
( c  d& F5 z' A$ U0 J) u
    usingAddressUtilsforaddress;7 T: S3 m- e+ K
. n' Q1 ~  s# J+ K
    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
/ y& N& Z" s7 k3 ~! J$ r: U3 ]1 J9 D  U, G- ~; ^
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
' _, `) R5 C, z6 `; t3 Y% I! |  c' i4 i( d
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;
. E+ V$ o" x. K! Y7 q5 ]5 O* X' m4 c9 J& S1 K" i7 a
    //tokenID到持有人owner的映射
* G7 m& [4 P# o$ y( Q% l( c# F3 C3 r0 _7 f9 b/ B  m3 ?3 q6 W
    mapping(uint256=>address)internaltokenOwner;
$ w' X0 w2 c+ J+ f( R$ o/ Q1 ]/ @  R* i# s$ d$ f. A7 `" M
    //tokenID到授权地址address的映射, }- M8 z% G$ S; }8 V1 M' \

% F4 p$ u# U+ d& }- R. P6 @    mapping(uint256=>address)internaltokenApprovals;* u. a. J8 T9 P5 Y3 f% r1 D, G
9 k0 X' A4 x$ S
    //持有人到持有的token数量的映射
$ J7 J# t5 [1 K% I7 v. j. u6 g8 ~
- @% r$ X/ i+ o, ?6 y) _    mapping(address=>uint256)internalownedTokensCount;0 ]$ Z! o6 k( J6 b& @4 k
6 P- C% y8 c: H& v
    //持有人到操作人授权的映射8 [# P: _$ j5 G8 h1 P4 h, c1 x
5 Y  `& {- m/ t, E
    mapping(address=>mapping(address=>bool))internaloperatorApprovals;
* Q$ x% H- }  F8 M" [5 {2 q& g: n1 i" v
    /*** S8 P3 v. d* f0 Q. L3 i
. ^# e% q# z+ s) M# f% [8 H
    *@dev确保msg.sender是tokenId的持有人
5 b  h0 t$ ^# s9 R/ k9 O! N
9 E% w  b0 I* B; {  N: Y    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
6 f% c2 [% [6 R) _1 S2 s% j) v% o( j: n1 Q% s
    */" H: T% g& A" ?; d8 W& W. ^5 F* u
+ A3 l# L$ f0 _
    modifieronlyOwnerOf(uint256_tokenId){7 H; G  ^. ^( p. D
; S+ Y2 }: a8 V& y& c6 h1 i
    require(ownerOf(_tokenId)==msg.sender);& X, |0 y- m: P- E' i/ P

; d+ W& D; m3 A# a7 T% {6 M    _;
- T  Y& K* ?* x& y% S6 B" J; E4 f5 R% }* n' B8 K
    }
& n0 z4 v4 W" S" P0 k% G( t: F4 y6 I1 K- A9 g( C
    /**9 P" R3 y3 \8 x! O! ^# F. \- k8 M3 i

: i$ y, N/ _3 S5 F( Y: u    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token( v( q7 _. W+ e
2 S. T7 F' H- x4 N) c' X
    *@param_tokenIduint256IDofthetokentovalidate& a' n2 E+ W! h
. H. R- l! ]: B* k+ |& Z' o1 N
    */
. _. ^) A' v3 J  y( K+ o( w& g
. M$ X! M* a! O  G( V    modifiercanTransfer(uint256_tokenId){+ o, x& z& `+ Y. F

" [9 q. j* B* ~    require(isApprovedOrOwner(msg.sender,_tokenId));
& j/ _' |$ O* n5 L0 l4 C
% G, v; q; ~  Z    _;
; N2 @3 i" p5 W
* B0 u4 k) B# q0 h$ M+ d    }) ^! ^2 W9 A2 l9 h* X7 V/ F' B+ k4 h
2 }4 ]" M% \8 h4 `* s& _' [8 K
    /**
5 X: N) [! V) ]5 O; j2 V
7 t8 R# m7 n, F0 _" R    *@dev获取持有者的代币总数- H/ ?( V: r' |4 t

& Y/ `2 Z* V5 a8 I$ d) ?    *@param_owneraddresstoquerythebalanceof( ?- h  N. ~" T6 Z6 q. C- _1 L5 C- V

' ]5 {3 s& [9 D9 s. h( P* b    *@returnuint256representingtheamountownedbythepassedaddress& X9 V9 C, b! ^6 k: A* O5 K2 ]

; ]2 L6 l+ u$ v( N- g* F9 w    *// [1 W" u8 p- `1 O
6 t$ b9 F* k1 M2 \2 R) y7 M+ q
    functionbalanceOf(address_owner)publicviewreturns(uint256){5 K4 b4 m2 D' Z  w: o4 g

+ X0 S  u1 r) ?3 S) ^& H% h% {    require(_owner!=address(0));2 s( ]7 k7 W9 j+ B9 G  G. p; X1 i
& w; W& S) ]+ b
    returnownedTokensCount[_owner];: v7 ^7 H, w) M$ d

' }7 A5 [1 v. X- a7 j# z    }
' K' k2 ?' r' l3 I
5 Z6 |3 x$ e7 z& u# m# ]! N    /**& |: p: W7 P8 z3 N- U
2 Y% ?6 n6 }7 i1 r; O8 ?
    *@dev根据tokenID获取持有者+ t, E5 H& Y+ g' j( r: g  J- `3 [: Q  h
. x4 X+ _4 H4 @' D9 A
    *@param_tokenIduint256IDofthetokentoquerytheownerof# n0 M7 i' U( O2 T1 p

" S, p# o9 a4 d8 X$ b- _1 V% j/ c0 e4 U    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
! Y! b) N, j' x# N" A: d
" b5 J) R+ m$ B% Z* v3 B4 l, R    */6 V% v( X1 p4 _

) Q& k* E& `6 i8 r/ Z    functionownerOf(uint256_tokenId)publicviewreturns(address){
/ H, q3 I$ J: C9 g: w" @/ @7 @" U; \3 |$ H
    addressowner=tokenOwner[_tokenId];
  p- N) G3 a, H/ p4 O* Q
* u+ n3 u' R( b( o& m    require(owner!=address(0));
' f7 A( F4 ~" R: B
/ J( |9 M5 M9 H0 E1 h, ^    returnowner;
- W1 H: |8 p" x) [6 M! x
; h! ^: z, H$ P    }
1 f/ P, i  r! Z4 q$ f/ \: X. b4 L/ q! h4 c' ?0 s/ H/ W. g' `
    /**
1 q4 D% |& A- N1 _; G" l8 u4 r2 E5 U' g* J0 i
    *@dev指定的token是否存在
7 r, Q7 R3 l0 T4 U, M
" n/ U) N1 D" J3 [$ L$ l2 x    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
2 R" |3 z8 h8 g7 c8 ?& l
  t  B1 \; h0 s' G8 T; K2 `    *@returnwhetherthetokenexists- M7 {7 H, z0 i) m( O+ I4 _6 T
* x# |" b' y* H  q5 g
    */
' A: ?0 F6 p% \) L# v0 G, T% [- s6 ?$ ~
    functionexists(uint256_tokenId)publicviewreturns(bool){" H6 B7 X1 s, n. d

* E+ Y- D  W  J( X" s( k* h    addressowner=tokenOwner[_tokenId];5 ~5 k! ]' {9 \8 x' f! r0 I
# t5 g# M1 D& n. v1 U( c/ b
    returnowner!=address(0);
# q& f' [1 M: Z
5 ], d* K4 s: i2 F/ z4 z& C    }# k" V2 }2 u% K! |
, [+ s* T& d+ q5 `
    /**
, [* i% X- Z, Q" T9 H4 A% i: R! i6 z/ j' @. D
    *@dev批准另一个人address来交易指定的代币0 k: z9 K3 e9 h; j

  [% p( t& Q3 o  L' Q9 S; f7 _    *@dev0address表示没有授权的地址
4 U/ {8 t& q0 r8 |3 L3 X6 {7 }% w; x1 B- m. I
    *@dev给定的时间内,一个token只能有一个批准的地址2 s5 N3 W3 D8 b. y1 k  Z4 O6 T# |
2 d5 z, k  U4 U  l& a7 o
    *@dev只有token的持有者或者授权的操作人才可以调用' ^+ `8 }6 s+ h2 P' B& P
' l, ]: a$ t, c. U" a4 n
    *@param_toaddresstobeapprovedforthegiventokenID( t, F2 }. y6 L  g/ P

8 y0 i& g/ [4 h! x. c# `9 J; ]    *@param_tokenIduint256IDofthetokentobeapproved; B* L3 \0 n8 y( p

. D+ B1 \) d" H( D2 r. `5 U    */3 @2 d* F+ k; Z8 b# i- O1 o
! J: n2 L! L0 g( q3 o" J  V
    functionapprove(address_to,uint256_tokenId)public{, F5 r5 p# J% e9 `( a  N1 ^
* G, H. F& T9 c" c$ b  V# r
    addressowner=ownerOf(_tokenId);% {! X* J0 }8 j! }) T# ~8 W! a# ^( K

9 z  _; K9 `- w  w! s5 i$ l, F    require(_to!=owner);
) W2 h8 @/ R( u; U% \3 q6 o
5 O" K) f3 B$ e! T    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));, U+ C% U% A; u( N4 ?9 w6 |; b! M
7 ^, h' T7 v# J6 Y; e6 |; j
    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
- u3 F6 |+ Z4 H
, s/ Y+ j( z( A8 F/ W    tokenApprovals[_tokenId]=_to;, W5 S/ {# k& j: c5 L0 F
" {) ~5 i; R0 L0 t0 @
    emitApproval(owner,_to,_tokenId);
. `' n5 o3 {$ g; M: Q- B, K
' o  h- A3 v+ d    }. x. R; O' A; ?

5 O* k8 F2 i! m& v& |. Z6 }    }5 I4 c! f. z2 w9 e' B7 i. d

& [6 c+ h4 f# u7 Y" r    /**& [/ `+ F$ i; W- w5 c! E2 ]

* O' h8 B" h% a  e$ H/ W6 x# D4 ~% ?    *@dev获取token被授权的地址,如果没有设置地址则为0
7 ~* ^! n' K1 [1 |/ C  \6 H3 t1 ^2 X, [3 Z3 O9 y
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
6 t8 ~% u# N) V* p; `' ?3 g: z7 l" C, B& ~: [
    *@returnaddresscurrentlyapprovedforthegiventokenID3 D0 G! @# d  e9 ^# P' {( i

% n7 R$ T1 E8 m5 G' X4 z    */. R8 }; v; z8 X, \
7 y, p3 t4 S1 [- f! j  N" q! o
    functiongetApproved(uint256_tokenId)publicviewreturns(address){* I% g/ @, E* o% q9 D

; j) e* u3 k4 L$ V8 b" p    returntokenApprovals[_tokenId];8 B+ y  O! j2 l" O
; r6 N+ {3 J! k" j* g
    }
- i. Z+ y/ e0 T& k6 ]( o/ I' l4 n! w3 V
    /**
" {& O9 L0 L' e8 u, j1 w
6 E; m4 c' |* E! B    *@dev设置或者取消对操作人的授权
: \( M' u& l6 n3 x3 s0 ?1 b- A2 _" }& p! U1 d) N% g
    *@dev一个操作人可以代表他们转让发送者的所有token- g' e- f% |0 P/ R# w: r& z3 C

  t9 t* {6 C* r# t0 B    *@param_tooperatoraddresstosettheapproval6 i* v; ?3 K6 L; ^/ w7 ^# }
/ L$ l% {' ]0 b2 Y- A4 Z+ g
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
1 U# F! e' O$ p# n+ Y/ @2 N4 a! }) ?9 l2 _; d
    */+ D0 E( k" h$ z

, m, M: D2 W! f9 i3 @4 @, z    functionsetApprovalForAll(address_to,bool_approved)public{
" Y) G- c+ T" S2 i& q1 B; X" C6 ]1 i$ j2 Z
    require(_to!=msg.sender);9 [- u3 W; Y7 a

1 p, J: ~( P$ ~* P! y    operatorApprovals[msg.sender][_to]=_approved;
3 B, s% W0 e& B8 J" }+ |" h- @
' ^6 v8 D8 A' E) D1 J/ D    emitApprovalForAll(msg.sender,_to,_approved);( z6 L2 _2 u7 {' O: C4 z  P# ]: C" n
4 o* n6 J1 D& Y
    }9 I. b* }* X1 I

# {  @! U* ~8 t1 H    /**
5 J4 d) e2 h9 S% P1 m* d" R8 t
- x* b' ?; A; W  k& g8 S# Z    *@dev查询是否操作人被指定的持有者授权
: m7 H3 s. r8 j  d' E
% ~. R3 r' B( z4 @% [    *@param_owner要查询的授权人地址
6 ^& d- o" Q( d& }- [. L4 Q( A6 Q, l( Z
    *@param_operator要查询的授权操作人地址( K* f: M" @7 B/ \  L1 O) Y
$ B+ m* @' O% S6 n
    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
/ G0 J* o% w  |) j
# }# i9 P0 k: i  q    */
9 a& M7 d" F( ?( l, Y+ e$ t* W( F) ~! e* U; h% s
    functionisApprovedForAll(9 W" \" J" _; h4 z4 e- k

* ?* H$ Y( H0 S. W5 E8 ~    address_owner,
3 _7 Q. x: B# P8 A* M; i
" Q9 z- A) V4 H# m6 X    address_operator
0 @3 N$ {2 Y- V, k+ r4 r2 p4 E# H/ k: C) K* I
    )
# F  g- O" W# Q) h
* l2 B; W' v# p7 O0 A+ r" e    public
+ i& @4 n0 k6 l, Q0 N8 p+ K/ `2 g' D7 E0 w& k  c
    view2 O2 d, b; P& ]' F; ?
# }  X7 y2 r5 m) i! A: E7 l; M' U* O) |
    returns(bool)
" e! B: a) \7 V6 |) S; P# R% t- F1 V6 V
    {
( g8 ?  x& j6 [# Q/ j3 h% a
* ]: ]6 x6 l+ w    returnoperatorApprovals[_owner][_operator];
/ v3 W( X6 \) ?4 I" P: N1 e+ S; ~& _% E0 U
    }2 W' l" P2 W$ Z
8 A1 ]) f; d! a  k
    /**
5 r$ |$ Y; q" n2 \! x. ^4 U3 r; v+ \/ P5 {. C4 G& o' S
    *@dev将指定的token所有权转移给另外一个地址* L# g) T; y9 v8 z5 M
3 }9 R! F+ H7 T
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
& n6 a* r0 _% Q& O; F- d' U* i; u$ Q2 l& v6 z# R; U3 U. l
    *@dev要求msg.sender必须为所有者,已授权或者操作人, \7 t! \& f* F( A' j: L; {
& Y- b- N; z% r+ L" y( C
    *@param_fromcurrentownerofthetoken
# B. h$ Q9 A/ o4 ]9 R9 N5 w5 B8 U& H5 Z  d7 a
    *@param_toaddresstoreceivetheownershipofthegiventokenID; c; @& l$ N! N& b: O9 _  T% w9 M
/ N( K, l5 c7 ~- L1 |8 d
    *@param_tokenIduint256IDofthetokentobetransferred
/ i& I; }5 F( K
, m$ ]% J# m4 ~0 |$ Q    */
" t, J5 `! f6 \  z
7 a( z2 W; q3 c  w, o    functiontransferFrom(
8 n' v$ a7 ]$ N( M
, u0 |8 o3 [8 a; W    address_from,
  _4 C& G! P/ m- I2 o/ g7 N
% j* v9 q# n' {" N9 G) I( P. `    address_to,
) H" a; B3 ?4 M) a8 A% h1 J% z2 }2 T9 J: X$ T! u
    uint256_tokenId3 H) @. e0 ?0 }

! n! u3 t+ L3 |; [1 c, a$ N2 `    )5 E" A; n1 y- M& \4 l
9 X- R! G; }7 T) E( Y9 }
    public
, Y3 j% a6 ^+ F: P2 x0 b( j8 z% B# _
    canTransfer(_tokenId)
+ M9 e4 j- G/ a8 M' h
! f: h" J( y+ I4 ]% H8 M, a    {
" m: D8 q7 S5 V, b- o
8 b* e  g# g: ?) X    require(_from!=address(0));5 Z' Z+ v8 R$ @& ^5 J
" _$ B3 J6 H# Y7 |4 G& \" J. w  d5 r
    require(_to!=address(0));/ R% {  o. b1 a- A9 f5 }& j* U% t
. o  O( I/ ?; ~& T
    clearApproval(_from,_tokenId);4 Y8 U5 W- f$ K( r2 p
9 q- q5 E: i! V
    removeTokenFrom(_from,_tokenId);
0 s+ _" K* M9 c; b/ v* |5 W; r  R! I1 e1 }% R8 W) R
    addTokenTo(_to,_tokenId);* x) g0 `: E- a% x/ a1 p2 v
. }8 C) c3 o0 X( U. p; R
    emitTransfer(_from,_to,_tokenId);. e9 p3 P7 n6 A7 T* \4 }6 k0 Z

: l* r. ?) j: d* g4 h$ K( Q    }8 V% X+ O: W0 }" ?4 J- l. ?

3 T" ]- w9 e* t1 x    /**% J# j' G" G9 N9 e, o
- e# W9 C# s! q
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址/ m! n0 S& U  L9 e! Z" v' F

( i, V0 K! C+ A* Q/ E; J3 Z2 L0 o    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值: V" O8 Z4 J, F

% r0 q) h1 \) @) L1 ~    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
( r) u* l. Y/ I9 [# d" \/ ?
4 D1 l: r$ T. u( a; T" l    *@dev要求msg.sender必须为所有者,已授权或者操作人# S- D% N, Y& l* e/ d

- u9 e8 U/ [) K# V1 |    *@param_fromcurrentownerofthetoken- j+ V/ v" x* w( {6 R4 d6 g* p0 w+ e

, ?8 R# l6 q0 L7 I6 E* ?/ Q    *@param_toaddresstoreceivetheownershipofthegiventokenID
- Z, _8 x& |1 x9 x
" J# n- m1 J* ]4 }" b$ T% R    *@param_tokenIduint256IDofthetokentobetransferred' L) C8 f) R$ I9 V- ~
: o" T8 F2 J+ R& j: h
    */
! ^- a: F4 R1 b5 g0 _, S1 ~- G. n
    functionsafeTransferFrom(5 x) Y+ m7 ]1 S, ]8 Y4 _; s

: C# ?. @* q1 t' [    address_from,6 H6 L- j& c# [9 [

3 B% G$ B( p# Q' O0 v+ w    address_to,
: j9 B1 C0 o% N: z" K' q
. i7 D: t! n3 e    uint256_tokenId
' z$ Z% e+ x& c* F5 b4 \1 ?- p) y+ A
    )6 C" S# V" I; e! D" D, ^8 J
* |8 U" F! C0 m0 z0 i$ u" e
    public0 f( D. R  Z, @* V2 T, k- N
8 m, n, i& `" Z( @& n1 ?- D
    canTransfer(_tokenId)
) T3 }" D9 V' r- d3 Z) A
- _8 m, y7 h! k; G5 x3 S8 s  Y    {1 ?4 ?. T1 V$ O( W

3 q/ k9 L, u/ m8 T. B" }    safeTransferFrom(_from,_to,_tokenId,"");
3 X# ]  u* M5 d  S0 w4 Y8 [' m! {/ w
    }& S4 e* x6 N, a3 z/ g7 v& L/ c/ G* K
  K7 h! j2 j: o% c" N) \9 @
    /**
$ x: E3 v7 _  |6 @$ m2 M& b- M' }4 G+ z
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
! `  S4 W, j" c6 E( f
( b- M% g) X7 G" x  ]    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
/ n' W! R0 l: @( \+ ?0 a6 ]; `/ [0 ~) }
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原; G' ]2 {+ [- y

! W7 w( l9 X( A* a/ _; m+ H* r. U" A( v    *@dev要求msg.sender必须为所有者,已授权或者操作人$ k+ S: I3 _% z$ ^6 o  C  P$ Z
8 S$ H6 t8 f$ C
    *@param_fromcurrentownerofthetoken4 _( b# b% R; `; S4 `3 s* f) O

. h# F7 B1 l) [/ H' Y# [    *@param_toaddresstoreceivetheownershipofthegiventokenID' ?* `8 B1 S. B6 {6 Z6 x

" Y' B- z2 p+ J- l0 p; R    *@param_tokenIduint256IDofthetokentobetransferred& m. e; {5 g- x3 q' t& A
5 E  A  {* N3 R/ i/ h- y
    *@param_databytesdatatosendalongwithasafetransfercheck
* {% u' l' ?' ^* ]* C/ f0 {' Q: g8 Q1 V3 q
    */
* P- n# m/ [6 F. e, s6 w9 v0 b% G9 B: r& _2 e- }1 J5 a! m
    functionsafeTransferFrom(, A5 v( y1 h6 q7 I+ ^6 T+ z* X6 U
! N) k5 K5 k# I7 m1 H% B; z5 w7 P
    address_from,( d; i$ o9 n4 {

4 @# M3 _6 a7 y' B  T7 z+ P    address_to,# y1 a& n8 k9 y( U) n# E
9 h! y# C7 c' k) K2 ]
    uint256_tokenId,
6 |2 [4 S% a/ U$ m7 f0 y% _% W6 ~2 C) P# m. s( p6 @: b- W) Z
    bytes_data6 `& A! r) X- V" v. R4 p0 c

8 c1 `6 K/ W3 |5 q8 g! C# I    ): R0 l/ l# H4 k9 B- N6 x$ k
& O5 z" S- b, Y& k' E5 |, o" a# y7 x
    public* Y1 Q9 H8 h  I# L2 o9 s

7 x! W7 A  d6 [9 g: L    canTransfer(_tokenId)
% H' O6 |) g( [% c; ~+ E3 ]( f# A! R& N4 O' W7 ~
    {
% y) e" x& S( d: y, {2 C* L0 n) s3 U
    transferFrom(_from,_to,_tokenId);
1 _1 P9 W# w" i6 c8 W- U
" k# G% g6 r& ^6 T4 G' c5 N* i: X    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
8 ]) ]* s7 d& ?9 ?& A5 Q. X) Z: ~9 W
- I) E+ ^* _0 S7 j$ \    }% b+ H; u8 q- E5 _" ?

( g; j$ O' K! Z; q1 Z    /**# c7 f, {5 s+ u) Q4 f% K8 F: p, e# e% ]
9 t$ ~0 j  E9 p: _4 z; B2 U
    *@dev返回给定的spender是否可以交易一个给定的token
- F% D) t0 N/ X3 g
) ?% l+ |/ q: I) T; \    *@param_spenderaddressofthespendertoquery
; x; y4 `8 ~1 O: X
- ~! k/ Z" C5 G    *@param_tokenIduint256IDofthetokentobetransferred
# F* i# {) P) b1 S2 X0 H1 q) M3 E2 `6 ^  M. D3 i
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,
. j# O  i5 t$ |, _# v; U( ?: I' b) K
    *isanoperatoroftheowner,oristheownerofthetoken
. X0 S8 j  l, L% z
, v2 \7 m" u# V5 K3 m1 w6 R+ l( p. r    */# H! d% D( p8 H+ W- {
4 n- U* Z! _* [& Z" ?' H
    functionisApprovedOrOwner(
/ y8 w3 z4 \, E; A# Q5 b9 i/ g1 o' t2 R7 B" Q& w5 `8 d
    address_spender,
6 w0 T" K( g1 s6 J0 S0 C7 T$ {5 i2 `/ |- V* t
    uint256_tokenId
) I$ l1 m, h0 j6 F* |' W  t4 y9 K6 G9 p" h( L4 d; i/ H
    )2 N, e" ?! @' c* \! a2 o( U
; ]: @6 B7 l5 L- F9 U
    internal  r3 j( J/ v0 X5 h8 ^# Q' V3 G

, y% I  N) ^' e0 Z% U$ n    view$ W# N2 q/ s9 p, W7 Z
4 Y5 f4 B* p1 m7 y" }
    returns(bool). N+ O- }& x+ \1 O$ [. Q

, N4 `- R* R" k/ D! y1 A6 O    {8 S0 R% X& A  P9 a/ _

+ a7 d0 G0 Z) {  S' A% e; o    addressowner=ownerOf(_tokenId);. ~/ V7 q+ w/ _: c. U/ l, _
- A9 \2 Z! Q) a4 L+ r% L8 F
    return(4 F4 G8 Q/ `$ {! ?+ d
- X& [$ P0 B1 o- A; w: q+ D  W
    _spender==owner||
# S8 w. k: b9 L' t; _4 |$ |( c5 M6 q6 W% r2 C
    getApproved(_tokenId)==_spender||
, d$ A2 h; s1 \# H1 q$ z$ {" v) M( C. Q1 B3 c/ I
    isApprovedForAll(owner,_spender)
, w8 \8 {6 B  r" N1 D- \
) [0 g6 n1 ]$ {2 r6 ?8 d1 ~    );
7 k2 t1 P/ x! o% |* I* G1 D! N4 B/ Z' i0 n$ [# h
    }
) W$ l0 C7 q8 I* l; K, y4 U9 N4 t+ Q8 Y$ ^) ]
    /**
) n* q( {: w1 k# U
7 C3 b! G' s# t7 ?! h# n0 V    *@dev增发一个新token的内部方法" |# ?9 {& t5 X. i+ Q
2 r! R1 N2 W0 R& K% c5 d" W8 w
    *@dev如果增发的token已经存在则撤销9 K, ~$ r9 ]3 e1 T
/ V" d3 Q, {2 E/ e
    *@param_toTheaddressthatwillownthemintedtoken
$ H' ?' _/ P8 ]* V6 A+ S4 N
6 b1 P+ |8 a. \    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender* x( {+ q# W( z  O

" t: V* S7 F5 u1 }6 E, z0 ]- t    */$ P6 e; D# U- }* ?9 Z

" b0 m; J: R1 w: h    function_mint(address_to,uint256_tokenId)internal{4 h) U( H4 Q0 r8 i" P
9 V' b+ M* i% g& d% t
    require(_to!=address(0));% u& q: F$ P3 V. f/ Z
5 p7 a7 f5 H. g5 i" C/ r' E
    addTokenTo(_to,_tokenId);  a3 a6 n% M& u$ j7 }$ V

  ]# D; W; G3 }$ @    emitTransfer(address(0),_to,_tokenId);9 ~/ z# r7 {- F! \( N3 y  u

7 m( c: p' J" q7 ~$ j    }7 Y' o, g& ?; @/ P5 U; K% ]9 ], _: i

/ N4 C, z, I- U$ G    /**" U4 |* Q, R- t0 K" z8 X, H; A
; x4 Y4 I8 q) i2 X$ C
    *@dev销毁一个token的内部方法
3 P; r: r) H; X7 [+ F) p
; u3 ~+ D" S% P8 S* ]" M    *@dev如果token不存在则撤销- f* c( \/ l# S
7 A5 Z* z- {( S9 @1 O2 m
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender9 _6 F& Y. r1 S& X  Q

2 q8 B; u) b) r/ d  P    */
+ i, {' V7 a* K& C( m
+ r- ]5 Z4 l1 }* {4 m  z/ [    function_burn(address_owner,uint256_tokenId)internal{
! m- Z. A6 y+ `" f7 j6 S8 N* K9 Q" m& m* _2 L: `/ W3 r* B
    clearApproval(_owner,_tokenId);6 W5 |$ a; z. n( S+ X
' A5 n; k9 w( i8 w
    removeTokenFrom(_owner,_tokenId);
8 V4 Y% W( G, Q& w1 B9 v# q. W0 O/ Y5 T* l5 r4 z( x/ L
    emitTransfer(_owner,address(0),_tokenId);% q, `. ~) V8 {' r7 ]
: [3 b5 ]  v2 N5 [$ ?$ y
    }
4 s- e! a5 Z# Q2 y& m; A2 x# x. l- y2 m. A6 r
    /**$ W. a7 @# r4 N5 e, u) t# o

4 Z0 p7 r: [0 F  F    *@dev清除当前的给定token的授权,内部方法
" L; h. o- Z4 h/ M) M
% {. {& Y$ F( L    *@dev如果给定地址不是token的持有者则撤销- g1 p& @0 G. N: v
6 C5 _7 D" P4 Q
    *@param_ownerownerofthetoken, s" F' ~- N, ~  }

3 z. u/ P, s2 Z  b    *@param_tokenIduint256IDofthetokentobetransferred# ^* J. u% o+ M9 R0 z: F4 G7 v

4 d0 ]4 {8 P' F  G7 Z4 p    */
- f6 E& Y0 I  h5 e- W
5 O1 s* Z2 K2 `" L0 D# x    functionclearApproval(address_owner,uint256_tokenId)internal{$ \  N% j, t2 J2 z' _; V

  }( C3 K; D) R+ Z$ L6 z( X    require(ownerOf(_tokenId)==_owner);
" i6 P. u2 B! v, _/ p$ B: T. p: D( c  w1 J# e
    if(tokenApprovals[_tokenId]!=address(0)){
" H% v& M$ h. D# Y  {( B  k- Z# V3 W. I4 {
    tokenApprovals[_tokenId]=address(0);
' p4 g" F! g0 [
* ?. _: |6 h+ S) p. }5 k+ h  k: W    emitApproval(_owner,address(0),_tokenId);
5 S# q1 h/ N" _' O1 O* A- f  h! D3 L7 Z" T- |
    }: l* G  u3 X8 t, }
6 z4 H% ?, p4 E$ x# k9 K0 @" T/ E' T
    }0 J' g1 V) a0 L; _7 Y

- g2 I3 x! f2 W! B8 `/ P    /**: p* s6 u8 P# S( d+ z* F" M# T/ q
, d) b; d  ~5 w6 U
    *@dev内部方法,将给定的token添加到给定地址列表中
+ t( x* B" X! U+ H9 C
$ @- `- g6 G. j; C. D" S    *@param_toaddress指定token的新所有者& R! Y5 v8 p% N! I' X; ?1 l) R
' t; Y9 S% q% S, r
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress' D* j/ j7 C, w4 n
4 y" v9 B5 a7 {' B$ Q: j
    */( b5 l) f# g% P$ W4 h
, l$ U( O# B$ v4 D/ N* _
    functionaddTokenTo(address_to,uint256_tokenId)internal{
- q# \& F8 {2 I( A: r: ?) U; L& v0 `7 H
    require(tokenOwner[_tokenId]==address(0));
! z# Z# \: X9 e! n  Z2 b5 ^. z5 N: }' C4 E; g3 J8 _; Y" M
    tokenOwner[_tokenId]=_to;
0 x+ r1 I' G" I/ U, P" ~# l* R* b4 v! U) ]) Z
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
! `# `4 w% k7 j( H$ \' G/ G- f6 u1 D) J0 E  N# w0 x
    }
2 q1 q) Y1 }) `( h
2 @* E) D$ u$ i& w    /**
( L7 ?/ `/ b! l9 M" \
, W' R. g6 Y0 Y8 j    *@dev内部方法,将给定的token从地址列表中移除
5 R& w# ~9 ?' \6 F- a; J" Z+ b1 |: x8 @- P: j0 `
    *@param_fromaddress给定token的之前持有中地址9 _+ q4 q1 i7 l4 v9 }# ?
& K2 D- L7 _" ]/ {; j- C, l
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress% Q/ H: F5 G$ z

5 J( d0 z( h9 A    */  `+ B( |. P; m9 x

, L: a( ]1 C# L( S" _+ c    functionremoveTokenFrom(address_from,uint256_tokenId)internal{
# P% b+ b) m/ ]2 x6 Q, r
# g2 v# x5 {7 _3 I. c5 v    require(ownerOf(_tokenId)==_from);
& C" p+ p& D& Q" y  Y" l4 B4 t$ L% r/ E5 ^+ C6 e
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
0 a  v" v, W3 A& j3 I6 @
: c& b: L0 N& I( n+ u    tokenOwner[_tokenId]=address(0);0 J2 X3 _; _# _0 e
$ y9 ?: u8 ?& x3 D7 Q& _
    }9 P; ]. @; Y: V0 H+ Q1 J

- Y, g- d3 {. H' y8 M" I7 H! I' W- B    /**: S& o* T  z- _# Y
8 A; l/ K5 W$ f
    *@dev内部函数,调用目标地址上的`onERC721Received`3 @6 W, T4 B4 |. M( _

7 H% q; {0 Q! g: C( `    *@dev如果目标地址不是合同则不执行调用
2 x+ N  {3 Z6 k+ |8 y) L- ?4 O( }* U5 @! r( t" I
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID
1 D  \. f% t+ A! Z" a! s- X
# s: S; z* ^* ?' M5 ?    *@param_totargetaddressthatwillreceivethetokens
7 M* d& d1 m) V, _/ e
# j7 I7 _  H; P' R    *@param_tokenIduint256IDofthetokentobetransferred
8 ^2 U' M' k8 i- P8 K5 U6 p' T: ~7 ?6 |  B! |
    *@param_databytesoptionaldatatosendalongwiththecall
$ C+ X5 S: ^( v/ ]/ S  `+ v$ H$ {+ @4 j0 i3 _( }
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
6 Y' k7 E6 z7 r) p6 `1 F
7 Z1 Z' v5 T% x) F! Y0 h    */0 W- b; @1 f1 T' S( O& l& V

: S# X- n/ m+ `: |    functioncheckAndCallSafeTransfer(" D2 P! A) W4 @) N3 w9 ], G
/ G. e$ d3 W- {9 j8 }
    address_from,
( f- X8 }3 N" ~. o9 Z; f# S
, g6 j: T$ `$ O$ @/ A* v( d" b" g    address_to,7 b: A5 K; r6 r6 `& U8 L3 |

" B; W$ U, J+ W3 [' R    uint256_tokenId,' L2 Y. y' m) Z8 o% X9 x1 [
, V6 o$ A' v* ^+ e! A. }* k. X
    bytes_data; e7 f% E/ F8 Y2 x, h# T+ O
  r$ ]1 G' g2 E, l, b$ [6 I
    )
# U+ A7 y5 _# D! i
4 ~0 T; c/ u* X  U, q    internal( R' X+ s  n+ c1 j
9 r0 a& r# u5 ~3 m
    returns(bool): h3 i8 t9 k2 @
$ |# z$ o5 v3 j, [) u' s- L
    {
2 X8 m& x5 H; g! e/ L$ T/ ]4 F: ^7 C7 K" s  }3 R  [
    if(!_to.isContract()){
1 Q2 h3 |8 p. P) i+ }
' l, I6 l: h$ c- f    returntrue;3 w" k4 s. V* Y4 ~# e

, w6 Y. S6 w3 b$ a6 h9 I. l! o, [2 D- S    }  v- A6 H5 m- ?
" A0 X- Q. f( T& l0 D
    bytes4retval=ERC721Receiver(_to).onERC721Received(( N' d7 g9 {; M
! K% M; {8 h$ U# j0 Z% k6 R
    _from,_tokenId,_data);/ P8 O& A) L$ m1 ~' A. H" a+ c
! z3 a3 q/ a0 {. {/ H% r7 A
    return(retval==ERC721_RECEIVED);) r( y4 \2 n7 d. |

6 W8 k: g, S' N4 R/ ^* O    }
4 C. \" p0 _+ d4 z! r/ u
3 N* v( W2 p$ a9 c! f6 ]) d    }+ i# {6 r' `8 @7 Z4 }  V
* G) P8 t- K- _9 h+ e" O' `8 e
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
  s$ s" X+ o7 x
, u$ d4 a$ \1 a    ERC721Token.sol
, |( K5 ]. U8 E! {; b6 u" o/ e- Y7 t' ?* H: R2 f
    pragmasolidity^0.4.23;
2 _% S9 k* `! z+ i  ~. |; g2 H7 e
. w1 O9 v# `8 V8 J5 {    import"./ERC721.sol";- D" b4 X% p; y; N. D* E# l
# q2 v# i0 K$ R& B4 |4 i
    import"./ERC721BasicToken.sol";! P1 k" t/ f: F/ I. O- p4 j: x. R6 H

% _. F) T* ]: u; w; N    /**8 z8 M6 v9 g) o4 J

$ w1 f  D2 x5 A. j, R. M1 l- G    *@title完整ERC721Token, u/ Y1 g; X" {, [6 @, [  J" c5 U

4 V& R' W% W+ Z7 q, P" t    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
/ [; O" j9 u% T$ L
6 q) Z/ i& p5 l) n2 p! A4 q- P" ^    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md' I5 m: r5 E$ R" p. a
5 `3 V5 Q- Q. {* i. w
    */
; P+ D1 ~2 @7 N0 }
. [  t+ h% u: a    contractERC721TokenisERC721,ERC721BasicToken{
; A/ k# P1 l- G3 ]- e% f1 _0 l* W5 Y# V- _+ x5 A: l
    //代币名称* ?" d) Q) q# s5 T$ `
% p4 ]% t' {7 O5 p
    stringinternalname_;) z# J# z+ m) M. Z0 y
* X, @- b1 O' q& B+ S8 O
    //代币符号" g' M$ W( }8 V4 ^4 u7 ~3 T" a

9 h6 T! t) x7 n$ [: ^5 z$ y& j    stringinternalsymbol_;3 S; t5 h0 X1 K# [9 R7 C! k
8 u# B* V8 Q: ^* m
    //所有者到所有者拥有的代币列表的映射  O3 b6 }4 ]: o; q( t+ u
; N1 h: B5 [$ t. `" f
    mapping(address=>uint256[])internalownedTokens;* t# x& a0 k! a; U" |

" s; \) A" `/ N* a    //所有者代币列表中代币ID到索引的映射7 w0 f( `3 Y% U/ f# O/ @" `3 R4 i

. z# ~' e: G/ @" r% I    mapping(uint256=>uint256)internalownedTokensIndex;
. i; t* M/ i& f1 P# l
/ {2 M: T- s0 N1 d. i; V4 {% F    //保存所有代币ID的数组,用于枚举
& x" G: K1 t" E- A8 R
0 w. |5 m/ P4 N5 c) ~    uint256[]internalallTokens;
1 x- s; ]" }4 O3 i% u& J( U1 |) v* D; f, l
    //allTokens数组中代币ID到索引的映射
/ Z/ o3 l2 q. `2 i& n8 k- I- M, ~5 ~9 ]5 J$ W. C
    mapping(uint256=>uint256)internalallTokensIndex;
) n  C3 y7 A" S# c7 [. G2 F& u+ X  Z; e2 c2 i" t# Q% _5 p3 j; h4 }
    //可选的代币资源URIs映射! _2 S- e( h9 |( ~2 O  e
8 B$ C. v! l) Y9 P8 e
    mapping(uint256=>string)internaltokenURIs;
- _4 i3 [3 ^) I; x" @
8 `( D9 {) H, n$ S) K9 g: E* Q+ y    /**$ C, m8 g! J8 c6 l; ~

5 _. z+ z! ?8 c. h, ~' N3 ?5 u    *@devConstructorfunction" W. u7 Z  v. ~& s5 L
" r8 J* m# I% S! R3 c- x: L
    */, z) S/ s7 N9 i% \; c% a- [8 s$ C

& g4 R: T, D' ?    constructor(string_name,string_symbol)public{& s3 T! z6 |; b  h
! V) P, d" M( C" Z' a6 P3 V: Y0 [) D
    name_=_name;
6 Q" u( `/ \) R6 z; D" S1 B2 Z& ]1 y6 B4 g' V7 o
    symbol_=_symbol;  h( y3 P' K4 j  s1 A+ x
- i* d, B7 n( k5 q7 H; {. r
    }8 x# B8 g# c/ W) _
& ~- ~7 }% o) Z
    /**3 p; P; D+ u5 h( e! A( d+ C
: ~# J' F, B4 O, j" E* g
    *@dev获取代币名称
$ C6 V! T. Y; [- v4 R
, R" S+ A: U; V: I9 k    *@returnstringrepresentingthetokenname- \2 y. d& v% s, W- C% p6 Z3 H

: a0 p  v% T3 E  P' N+ ?    */
3 x4 D  Z# ^7 `; n' m* @  u% U5 ^  m' O4 K7 J; c
    functionname()publicviewreturns(string){
* i* O, d' S% u# E- ~' q/ S7 ?2 d: Y/ l6 Y1 [! G& {5 ]
    returnname_;$ U& P8 H  t& w! ?8 M
* }3 S  n# |/ p! `& s0 E
    }
2 i9 ^8 e' @$ s& x  M
$ c- w* C% \  k; n0 e7 U5 P    /**
; B' K$ |# ]1 E2 ~3 B3 b, i# I
0 W! h6 h  k. k- n7 ?5 A    *@dev获取代币符号8 K! F& L: `) d5 D' E

* q. E! m' q# \% I3 n* e+ u' u    *@returnstringrepresentingthetokensymbol
. O3 c4 j! `8 d7 O7 O# d
' p2 N* t( H; o/ Z! o. S    */9 g3 U! p6 W& |) X: c+ j4 Z/ d
, m: @" s+ g9 ?. n1 G
    functionsymbol()publicviewreturns(string){2 k: ^; G# B$ {0 m2 E
1 p& j1 Z- p5 o# n: U+ s3 T' T
    returnsymbol_;6 W- h  W; X3 Y2 X0 ]2 |+ ~
5 S+ @8 M: C+ p3 n; @2 c$ t" H
    }
! n/ V1 t4 C- D! C, l: w& \) W$ c+ ?6 U9 i, Z$ U
    /**8 i: q% K! l: C; U4 `$ e2 m  F

3 d8 D3 C. r# ?    *@dev根据_tokenId返回对应的资源URI
  R9 G! U  s- T) y$ N" ?' R7 t4 k
  X: p" p! X: Q/ ~0 y    *@dev如果token不存在异常返回空字符串, Y2 E% p; s6 i% c
. B- c) B; u9 m. k& J9 |
    *@param_tokenIduint256IDofthetokentoquery$ q$ @) J1 t( x% p# y5 y

  u; a% z! l. i7 J    */
8 _+ r! j8 o; T  V1 k& ]* W, k  X! L0 o1 i" T) s
    functiontokenURI(uint256_tokenId)publicviewreturns(string){. t6 _7 N( ~+ n+ |1 u8 p" b3 b

9 o  A" x3 ^9 H  K. \/ g    require(exists(_tokenId));; N9 P1 Q; H" A* v! `

$ w/ ]8 m( ?# H2 i& S8 k9 e% n& P    returntokenURIs[_tokenId];
. r( o1 S+ t0 N% D0 v& X3 |: e
  W/ {/ q3 n* `. Z5 Z  [! Q  ?( s    }' |9 {3 N* Q; K( x5 N0 g& `$ Y
7 A' E- J, M5 |0 I) K
    /**
/ Q; ^% n5 Z8 \
- h& X7 F3 N$ |* [; E9 x4 B    *@dev获取tokenid通过给定的token列表中的索引0 C# T& A# a/ \- X7 ?+ Q

/ B" i. O" P  l+ I5 F3 G2 e    *@param_owneraddressowningthetokenslisttobeaccessed* Y( M% Y+ ]0 F  q4 T# i. a! e/ _
7 i7 n( R7 W! b& y9 ?
    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist. l" e: T+ K7 S, P& J

3 ]$ {+ C4 `7 Y" e    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
# v6 ^, C2 Q  Y2 c! _2 _3 V) d' F6 N+ g
    */
) B2 I) ~4 Q4 k
0 c% v' J$ q5 C    functiontokenOfOwnerByIndex(
6 r4 v. s/ u/ b5 f% {" f- K) D1 b
    address_owner,- A/ }) C& B5 j# f* L6 I
& b9 ]- }$ q4 L' R( `/ v
    uint256_index4 w! X" f& ^5 ]/ a
# ~/ @3 y9 H- D- S! S
    )
8 ?( P# N4 y; |! B9 a0 W( K* Z. m$ Y! j& i: b' @
    public$ _" N' W; `. O. Y5 ?' A, ]. ~

2 a) h  T7 q- d7 Z" D    view
2 t- W* p, J) p8 Z4 ~$ F6 Y) L8 L# S0 C$ h. k
    returns(uint256)
% m' n% n$ w7 i5 Z2 e# G1 x; Q$ u3 c& y% X
    {
% V/ e6 G( U9 l& I4 N$ T! @7 @" g( C1 w+ o8 u
    require(_index
+ i: [2 h( E2 k( G6 w# }5 O" m! S# {& B- B& t
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
" i/ ^1 a! d1 G" D, s
3 k& z2 s; m6 @$ L+ Y    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2