Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2476 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。/ R% N- }( x0 o) p3 G/ E% K
" B) J0 h* {/ N1 ~1 }
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。; S) w; S$ _8 l; {* X% J/ x% a* b# h

: M* G" z( ^; W    ERC721Basic.sol/ C4 k! z- w$ A, T! V
! m, q" ?1 ?6 O
    pragmasolidity^0.4.23;/ ~* S) W7 S# d! [

& J( i1 m2 r5 c) I( n) o! A    /**
6 f+ L' B0 I! `% t' e
* k+ J3 C7 D$ L% E    *@titleERC721标准的基本接口
8 D' A# \. b* m6 t7 x2 G6 [+ G' S# ]# v2 m
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
( {* W: j0 N5 p7 N# i
& X$ H0 b9 F, |$ ~    */0 l- K, r: Z6 ]% i/ v
6 I9 ?5 {, u; e: v
    contractERC721Basic{" \8 G1 J/ ~' V7 I- O

" D2 Z$ e% R0 }/ W- c' n    eventTransfer(! D" J) N, P9 d% ~7 A/ x" b0 Z
. x$ A% m2 g0 E" ^0 i
    addressindexed_from,2 E! J8 v% N) H
# K. g: D: D2 V- y+ Z
    addressindexed_to,  P7 `# W) g# E6 w/ E* Y6 ~4 o( L

0 m! w+ i4 I) w    uint256_tokenId( _4 u6 E% S, h
  B) C% A) N. j. l
    );7 r- \2 [& g9 J" I: {
- }+ E% _7 {+ z. D% G) r3 V% M
    eventApproval(6 J- t! {. X! e! P
3 Y) o+ f* ~; A- }- A" W
    addressindexed_owner,. l8 |6 ?4 y0 D. l" B7 s
8 c! s) T; I' y8 U
    addressindexed_approved,% W/ X( F% t0 B; [9 k# D
$ [* y* E. t1 D
    uint256_tokenId+ q1 Z) N9 \7 R
' v6 p; D: k) N1 F- B  f
    );! b+ N! `: ?" T7 g& ^4 O6 M, f

$ B# y+ _  a+ @0 Y    eventApprovalForAll(
! n3 K, Q! z/ J/ _8 n0 u" {6 G. y2 ^( l4 R
    addressindexed_owner,
4 j7 ~- r1 t: ?; Q3 b
! A1 F$ \2 |, @2 M* Y  Q    addressindexed_operator,$ I( c" l: o, C1 X

$ h0 n3 k  W/ ?- F! \) q    bool_approved( g3 E4 q/ s4 M. T& \

3 T: w# M) m" o0 K. p  f: j    );
% n. ^+ t" {) v4 Q4 \4 b; A; s* v  t  u& [, w6 w4 I2 Y
    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
6 k. F* f+ |$ K9 a' L* N0 r) V* w% b1 m+ e- q3 e
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);3 Q- T$ g5 k4 C  k
& }7 U! b. P  H6 Y9 O# x
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);9 }6 Y) X& ?! ^' ~
( l& z* Q0 G* A
    functionapprove(address_to,uint256_tokenId)public;, }/ Y3 p5 `7 F- O: T  p7 `0 D

' U9 S* y9 p* U" d/ A' z- W    functiongetApproved(uint256_tokenId)
0 r7 F  B! [0 W% n3 j6 a
" R( S$ s' E" _" _    publicviewreturns(address_operator);
7 _2 _& a; Z/ v! N/ ?! m9 R* D- b9 E4 m$ B* C. E
    functionsetApprovalForAll(address_operator,bool_approved)public;
. y( Y) w5 X/ N+ Z: u2 U3 D+ y5 [$ h* G1 Z6 e# a
    functionisApprovedForAll(address_owner,address_operator)
% H# g. o; w! W4 {  k' P
: y' |2 Q0 }  q; d- o% }+ p    publicviewreturns(bool);
" v0 M; k6 H- P: r2 W3 a  i' F/ a5 g5 s- F9 e
    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
- ]8 x! `- Z) X  X  f6 M; ~0 D% P5 A
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
6 s, ~0 m' Q* q' n6 h. D
6 ~( y6 v! Q0 b  B    public;
0 N" g3 T& @1 P
, V# U. r! V( g7 }    functionsafeTransferFrom(1 b8 D  F0 I7 e& }. n

& D* {3 m" i$ E6 C0 a: v. m    address_from,
# ]8 U$ T( ~/ j/ T0 z) v2 L% i: J" l; Q  t4 H1 N. G
    address_to,
5 \9 @; O8 u$ W; e: I  G$ k
- g! n9 C: f6 N2 i# m! `1 B5 [    uint256_tokenId,
( \5 s* k% w6 k8 u+ h' i
5 N, y: T- E2 y    bytes_data8 Q8 @  c4 N( K! Q

7 ?* x3 w8 k+ d+ F( c# C    )* o/ m% g8 }3 `9 L$ ]
) s" a2 h$ v& y  p" C
    public;1 q4 i) k$ n5 Y2 Z+ L3 p  W, b+ F( Z

1 I+ D6 l: _9 R2 [7 e    }. y, m- I* s% X0 z: q
- k& ~- ~0 C% U/ F/ j( |
    ERC721Basic合约定义了基本的接口方法:
5 d7 |, g0 G6 u8 o" [- `4 U( \0 F) c
    balanceOf返回_owner的代币数量
, g: x) E/ z8 R
5 J9 k! N( J4 V4 }2 R# q1 |    ownerOf根据_tokenId返回代币持有者address
/ G& |. Z. H5 Y  Y, ]8 ]9 w1 k4 n
    exists_tokenId是否存在1 \7 Y' A8 v6 U& F

2 ]/ _( i1 k: z; w1 n    approve授权_tokenId给地址to& P9 E2 E6 C: [; ^7 M) f
. S. f  t: z. \6 N" V
    getApproved查询_tokenId的授权人_operatoraddress
6 F3 \% w$ s+ I. t" W# @3 F( Z4 L) c1 W5 F5 ~6 u
    setApprovalForAll授权_operator具有所有代币的控制权' B. y* {& y1 a" E! v( t9 f4 `
' T& h" V; l. S* l# R8 R1 t
    isApprovedForAll9 i  ?2 o) j9 v' B

7 }( V; Y8 t$ c7 g* m    transferFrom转移代币所有权
5 m) Q; Y& O! C# _8 P' \+ H- _2 v" F( o) q
    safeTransferFrom转移代币所有权3 n8 w' j- z1 b% T% X

' u: C1 s; ]0 C$ p5 @    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。$ t, X$ W1 I) k! F5 a( p0 U7 a

% x- y5 I+ y7 t% l    ERC721.sol, o: K, @- L: j
4 T+ O5 y9 G' C% S+ E8 P  X
    pragmasolidity^0.4.23;
) R- O7 f) X% x4 o% A$ N# K4 s- p1 I9 ~2 W, }$ q5 j  k) k, g
    import"./ERC721Basic.sol";( Y, p2 T0 Z: j0 i

2 B5 S; P' e, [9 v    /**
  h$ b, K# q+ [( B& B  R. r& O4 ]0 m0 l" A7 G; A- J+ l/ A: Q
    *@titleERC-721标准的基本接口,可选的枚举扩展
" a. R% R" W' M, @7 z8 ?# j" D
* X" d1 u6 b/ W/ {6 f    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
; L) H$ }, Y9 \# ~% y5 K0 s/ N# k% \. g5 f9 Q
    */- E- C: F5 h& m: w

$ i; j6 r$ k- j$ u0 \1 \- c    contractERC721EnumerableisERC721Basic{1 I1 j6 N# T% I9 ?- {3 O8 U* e
; ~. O, e! R/ G& m: u+ n
    functiontotalSupply()publicviewreturns(uint256);$ _" I1 e% h: V( s" A3 M

! p7 e3 N" E. j; b+ I    functiontokenOfOwnerByIndex(5 u& F1 O% H: o

' g$ H5 M9 r8 _    address_owner,
! x0 L' d% u1 v* W+ |& K, }3 b' [5 a4 ]8 ~: q: Z
    uint256_index
' h/ b  q8 |( W; J" s2 R
$ {% f4 Z( _2 y% l/ v" \" {1 d( o    )3 H: b3 l2 W5 q  X# @" E6 c- f

8 S/ [' J; Z1 l/ Q/ G( T8 ?    public6 G! G* t  `. n

) M2 |: g+ x) K3 `3 x    view
$ ]8 D% q  ~5 M6 S3 g7 Z6 _5 s( ^& e! y
    returns(uint256_tokenId);
  Y  ~3 _0 M5 _6 w( O  j& p* A1 `
4 r" Q! p# M/ I" ^" [3 r2 A! G    functiontokenByIndex(uint256_index)publicviewreturns(uint256);+ c9 b, ^) O' I% }) h6 ^
/ l: v4 v3 [+ J0 t" z
    }
; s! k9 P6 }" v) [
* T9 U% P6 L0 J) _3 L! i( G# t: _  v: y    /**+ s2 f. G. M6 t, i* t8 K) w

+ ^2 q4 c( _3 g    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展. G, H0 s3 e7 H0 }, `1 ?
: x. Z; T! T! N1 X1 o" C, g' y
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
% r% k4 d/ ]' K8 [; `
" A# \2 @: a' S5 e8 A* s    */8 v" `( X2 o2 S" E6 `
1 Q0 ^: b: s2 `. P7 W
    contractERC721MetadataisERC721Basic{, J  ~" n3 Z9 k5 j' `! M$ U

2 }0 H' I% O1 l/ Q    functionname()publicviewreturns(string_name);
7 ?' X0 [7 r$ q# ~" k, O; B( J* ]) e/ a0 K1 F4 x
    functionsymbol()publicviewreturns(string_symbol);
; b" c4 t! ?/ W* T7 d2 M$ X. p; v8 C: b8 }2 X6 W, y$ `
    functiontokenURI(uint256_tokenId)publicviewreturns(string);
7 t3 E1 y" X& N& H, N
) W0 h9 C7 B# |, {" M( A    }% `3 Y0 g" u: P* M% y0 P6 b

+ s/ U3 p  G- Y; V9 g) F) j/ m    /**6 N7 H8 s+ _: x( O, _8 Y" ~. |( l

# z. B. E; m& h5 b    *@titleERC-721标准的基本接口,完整实现接口
3 ~  A  y6 V0 q% y8 Y$ G) U  w9 s7 t/ D. R' |5 j+ q# l
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. P7 ^" @, \0 T; Y

/ ~6 V( A4 K" w/ {7 Q9 F    */
+ y5 G/ @0 ^' z9 U
+ r- ?. T$ o. d* @% M5 s7 }    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{
7 g, l* t7 w8 m5 p: M+ o5 @- b* z1 M2 I5 d! C
    }
7 h$ {" M; N7 L7 h
5 Z4 u) N2 j* x    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
( r: Z; Y' y) V6 q0 y5 V- Z- Z4 l! A, [0 \8 O4 p
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
' `( X+ b0 G1 w# b4 C4 d) q1 L
& y7 f  ~  n5 h    totalSupply返回代币总量. P) V6 v* R! i) ?$ \
1 H4 _7 f% t4 i& f
    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
+ a8 S+ ~; c9 Q! F5 ~5 y) w
' t+ e3 }; }5 N/ I) J% ^    tokenByIndex通过索引值返回tokenId
/ X# H* e0 x$ J& E2 C: T3 K% H% U# a" H+ Q
    ERC721Metadata元数据扩展哦用来描述合约元信息
2 w( Y) [$ l$ j, Q, X) l; X4 c0 T5 m; A1 @, ^6 [( }
    name返回合约名字
( {3 K, i  M$ [5 ?6 {! k( C. `3 I7 G# S2 F- j4 ]) I; U# a, S
    symbol返回代币符号( _, f3 _7 E! g7 r7 f

5 q: [# u2 k- u! u, j5 Z9 D    tokenURI返回_tokenId对应的资源URI
% k+ g2 M$ R; o8 R/ W& y. P1 X6 y$ p6 I2 G
    ERC721BasicToken: ]) ^7 @' D4 @9 t- g/ o( b( q

: `0 m% U' B: E/ Y1 l    ERC721BasicToken" h/ N. o- X3 p6 e7 ]
/ l: e9 H+ N) j3 t# U' W: I
    pragmasolidity^0.4.23;% q$ p2 J; ]; @* [" h1 t
- u% i- E0 E* g' g# }
    import"./ERC721Basic.sol";7 y- f: Z; ]9 n8 Q- O5 }- a' z, a
& V) K( `5 ?2 \) V! B7 x8 p
    import"./ERC721Receiver.sol";2 z8 x+ N; S+ g/ T( U/ @( B
: t' S0 F$ h* L6 @$ _* M
    import"../../math/SafeMath.sol";0 S8 c3 J) z8 E+ u3 F$ S, J( F
3 v$ C- I2 ^  W$ j) I: H% N! q4 ?
    import"../../AddressUtils.sol";$ _- i$ S0 V; a$ z
* q4 S. Y& R8 q, ^9 ^5 q# Y
    /**
- Z1 X# i- b1 T+ R7 S
2 ~2 E( {3 S3 `; n( `+ _6 G9 c& |) Y    *@titleERC721标准基本实现
9 k1 @- D  j4 t. K; h2 R; K) L$ b
! m8 q( W$ b) P! v) o    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
' H6 t# M7 p! A6 Q1 g- E# T% z% V0 z* I# O$ _3 v  e' K1 E
    */1 V2 \9 B2 w* H& r  C; \( {: D

0 E( ^( ]2 F' v+ N# p- _% N    contractERC721BasicTokenisERC721Basic{
$ D; D' u& f5 b2 S  ~2 U1 B
; B' Z- |  d1 m0 s    usingSafeMathforuint256;
, C# g5 D  Y6 x' w" Y) }- X6 X0 j
  i0 p% s  A9 h    usingAddressUtilsforaddress;0 U2 _3 B6 _$ c* Q0 O

5 h% O* l+ L# A- G" X7 M    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; I! x5 [7 B1 m! `6 e
  p' q& b! P; X* [5 j$ w$ V) g
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
5 P4 c) V8 b) r. L
) S3 l8 U6 M& D; [# O    bytes4constantERC721_RECEIVED=0xf0b9e5ba;2 ~: }4 K' e3 h- X: S2 u% R

, H- D' Q0 L0 H: y  v8 x    //tokenID到持有人owner的映射
$ W0 U0 r2 w; j: h6 }+ ^4 ]( H4 ^# ?4 Q- u4 G. E
    mapping(uint256=>address)internaltokenOwner;' m" G* N6 F. B/ _: q% Z7 U. Z
( f4 F0 o+ ^0 O# R
    //tokenID到授权地址address的映射( g) C; r, t+ v1 v, x3 i& U

' L; v" n, a2 V! o    mapping(uint256=>address)internaltokenApprovals;2 [" V* z# V1 a$ _6 @% q

" I; F" C( }/ K  m3 W$ d" ]    //持有人到持有的token数量的映射
1 {& ^. y# Z- v3 r0 G3 K7 x; X! I8 |/ `2 S4 r6 P
    mapping(address=>uint256)internalownedTokensCount;
4 b- e) ]$ y* B/ M1 U) ]
" F0 V4 l+ ^% w    //持有人到操作人授权的映射
$ H5 x" Z0 }$ x8 I% a5 N# v! f
1 Y+ s% u5 n4 ^2 R9 o    mapping(address=>mapping(address=>bool))internaloperatorApprovals;7 B; h, o$ [5 n- w1 R0 H
# s' R. @6 o4 c9 v: F
    /**
: m( Y4 ?5 I) A+ `" C* ^  `6 c) H8 o# K2 P; d) c7 |
    *@dev确保msg.sender是tokenId的持有人
5 y6 y2 i" s5 B) ?
; ]0 x9 f0 g3 z& F$ V- w9 [    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
9 Q* k" d; b/ i  W8 k* v3 y; W6 g! }9 f. Z* _4 t
    */
* J" l2 D2 {  s! g! O" J/ w" V( A6 j- r$ D( Y7 `; V3 }. l2 m! ^3 L! N
    modifieronlyOwnerOf(uint256_tokenId){
3 b; n2 l5 P. L1 r1 j! }7 u* h1 }$ D
    require(ownerOf(_tokenId)==msg.sender);
; x8 J& ^* [* |* Y- |& X; U- u6 m& Q6 x9 x4 k  z
    _;
6 m$ m$ x( ]% d, `) }: J  k7 i% c$ q, }' h8 m" Y
    }
; b8 `9 k  r# ~; {7 z2 ^6 z% a7 y4 B$ K& U" E! n
    /**
5 R( v! |# s& O+ j  d' G. A7 c  [3 G  ]) S, h4 u* x
    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
& `6 j: B; C2 l3 U
3 {9 `$ I8 U# M    *@param_tokenIduint256IDofthetokentovalidate
, y' D+ H7 m( R  g1 E0 Z* R! n+ O& o$ ^) y( t0 _6 R
    */
/ }( H8 J4 ^! l! h& A7 H1 p  y' Q5 _4 S- f8 k9 v
    modifiercanTransfer(uint256_tokenId){
" Z1 Z  r, E* f0 v3 D$ M' F
6 y7 V0 g5 F/ Q' I8 g    require(isApprovedOrOwner(msg.sender,_tokenId));
( u( B9 b8 B6 U8 ^+ N8 T3 P# I$ S% f6 [/ P  P+ F
    _;2 `( n3 R( \: m' d3 a6 ^/ z

: F3 t4 |9 H) |$ R8 O2 M5 v    }/ e9 [7 S  y8 {* V4 g

9 r" M% s: D+ c+ ^8 ^4 r    /**) G9 M+ L1 G- |, n/ [2 K; P. r
% ]4 E( Q/ J+ b: i7 P
    *@dev获取持有者的代币总数% i  W. N7 I4 L0 D5 |

! G, O% \) A4 g5 H    *@param_owneraddresstoquerythebalanceof
; B! z% P1 n( X" m) j% f
! {5 ?4 y( o  G5 E" L7 z3 X6 k    *@returnuint256representingtheamountownedbythepassedaddress# e8 E/ l" n; K

  v7 k$ T7 _4 B# p0 D    */7 I- X, D7 ]+ T/ T/ \

& Y' V6 t, |' A$ k7 P! L    functionbalanceOf(address_owner)publicviewreturns(uint256){
. r0 q2 y# C9 u$ V/ {* U# Q6 T$ T, Y$ Y# ]
    require(_owner!=address(0));
; U4 g- }; h1 P# d
3 Z" ]/ J$ J" \& ]# h( M    returnownedTokensCount[_owner];$ K5 m7 n7 {; v

4 |4 @* c4 T* j5 g    }& ]8 O' p% R) ^+ r  _% a; u

8 |9 |: z6 B# O, D$ f2 _    /**
: Z2 d7 c+ B/ i# Q% g. B- |- a# j  J
    *@dev根据tokenID获取持有者
, ]1 @& e0 z' }9 b% r0 \/ b
1 V# }# H3 H( K6 ?1 @    *@param_tokenIduint256IDofthetokentoquerytheownerof
! ^/ A+ A# s& S3 P* @
' |' E7 k7 W6 _* b: ?7 B    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID* O" m' Q; R+ |# e: D: Y

$ P& t- H+ X- l    */  O  D! }. ?, J4 J- o% z  P

$ n6 i* C% E5 j& o9 e+ K! e; H8 E    functionownerOf(uint256_tokenId)publicviewreturns(address){7 Q; b, W8 S# N
) c9 A- P1 y, O7 _+ _3 l/ L
    addressowner=tokenOwner[_tokenId];$ e6 T4 L7 |7 O1 P7 |" p- E" ~
* O6 N* v! \! [$ X
    require(owner!=address(0));9 J7 F* B7 @5 i% v2 ?) Y, y
8 C/ ^- }& Q2 N; n. w
    returnowner;6 U1 W- N+ ?% U9 a9 S

$ c$ T# \# M& i# v    }* Q% ^+ s  T7 v# ]; N1 d8 ^

& d# \% J: L, e' `# ~    /**$ o' Q  G& V( J! t6 e8 X& z: J4 N, C
3 o% W8 D' N0 e
    *@dev指定的token是否存在! P7 t7 w( A$ W/ W
5 a) [! C0 I# G* v7 ^: i" U
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
( p2 {8 t8 D6 z- B, b9 v- V! c2 \3 M5 s7 S/ \6 z" e
    *@returnwhetherthetokenexists' Q3 m) `, }' M& @6 T/ z
! b( z, B0 Q; R
    */* ~6 J( Z. r% I6 G5 }6 X9 {9 p! P

: J1 ?% |# b& c    functionexists(uint256_tokenId)publicviewreturns(bool){2 {8 S8 ?) D+ X5 _+ @
+ d, y$ m# @( l: w" r* Y4 k& ~
    addressowner=tokenOwner[_tokenId];. u5 `) U  \. l2 r. u( A0 v$ u; a& l" ?8 A

  b1 T# C6 j; j8 s- R. o& B    returnowner!=address(0);
: \5 r  c& y: l7 Q# I# [( ?9 \. L# r0 s9 U8 S* ]. ^2 ?7 _7 }. `/ K
    }
; @4 r, t+ X, A3 m9 Z  L- h" _0 {8 c6 ]
    /**
, S0 e7 j9 ^* k- V( x6 S( N7 G, z) {6 z' a7 g+ N0 x' P
    *@dev批准另一个人address来交易指定的代币
) @& ^+ h  u% q( C. i9 v" e( T0 @( g: o
, u7 Z. A$ U2 Q: e    *@dev0address表示没有授权的地址( x/ O( |3 t1 Q% K  s* q

: S$ ~" e4 {3 H  p- U3 w  t    *@dev给定的时间内,一个token只能有一个批准的地址& T7 P' D+ I5 Q! ?* ?" B* D
! p: D! H6 W( m# t* x: N3 F5 [9 c! t
    *@dev只有token的持有者或者授权的操作人才可以调用5 S" V* k; l" k

9 |3 G  p  }0 v    *@param_toaddresstobeapprovedforthegiventokenID
) D1 [( i$ e9 Q5 D8 v0 f( G4 _8 R& d
    *@param_tokenIduint256IDofthetokentobeapproved
4 Q5 {" V( q: |' l/ [0 L6 j0 m# K! S
' G0 U7 Z* R5 g& P) T1 d2 W: f    */
  X$ b- u1 L$ ?' C  g+ [- M- _2 W% D6 q% B$ @
    functionapprove(address_to,uint256_tokenId)public{
( }8 {( j$ L& A% t+ w& {
& l$ J  ~2 R1 G* W( U9 T# c" S    addressowner=ownerOf(_tokenId);3 L6 W- I4 @4 ^5 P) L) p5 h0 O; @
% P. E3 Q. K" m
    require(_to!=owner);! n: J5 g& |* c5 O. Z
3 H4 g; l" Z2 F+ A) c
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));7 v$ p5 X/ V5 Z$ {& \

6 k  T/ l+ x+ I$ q% o# V" n3 j    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
% Q6 e/ j3 ?& W9 u" D# z! z; k) r. \; X4 q' R$ F- J# v4 k9 x2 ^' x5 d( g
    tokenApprovals[_tokenId]=_to;* E  h- k* j" i& S

3 E/ G9 N! |( R    emitApproval(owner,_to,_tokenId);! q9 Y% X7 ~! {! @0 G' D
+ C0 g6 a& S" R! Y! x% Z# f
    }% I. T$ M7 @, ]( w2 d
* s8 k  e* N* M( m3 u' u( N7 X7 i% T
    }4 C; L! E0 x* c8 Q& Z" w
+ n! z, H* L, j* p7 Z* A+ V
    /**
- U4 ~3 C* |- O; b  H5 h3 R. L) N8 Z9 o8 z* ], N* u% C9 L
    *@dev获取token被授权的地址,如果没有设置地址则为0
& k0 a; w+ y  X
& d! j/ h' V3 X5 {    *@param_tokenIduint256IDofthetokentoquerytheapprovalof2 n! v1 j3 f' l
1 Q  d2 Y" S2 D# [/ A
    *@returnaddresscurrentlyapprovedforthegiventokenID, e! I0 T: x2 M: S2 [) n0 Z- X4 I

! J' Z, T1 ^4 u* a/ i* M! D* q2 U5 _    */
0 M* D: k5 z, P% B# Q5 [' C1 b$ P5 \* L. @% o
    functiongetApproved(uint256_tokenId)publicviewreturns(address){
2 J, n: f; g$ ~& u3 O6 c+ D
# D5 i3 R5 A# l: ]8 o3 H5 G    returntokenApprovals[_tokenId];
! p) J' F- W: m% J$ }
" X6 |# R; b% ]    }
" t0 y% \/ H; |& y6 t- I* a$ U( S: Y6 a$ d8 ]
    /**
0 C( ]/ f- X3 W* H7 N6 z0 |' T* e( L4 m3 ^% a6 S
    *@dev设置或者取消对操作人的授权& o8 r! c- \, @" e8 r
# `5 q/ C9 r* A- x& v0 a2 j, f+ |
    *@dev一个操作人可以代表他们转让发送者的所有token; ?; ?6 n5 l& M2 Z7 m2 r

# e/ F( M0 w8 k    *@param_tooperatoraddresstosettheapproval, C- J  I0 a# T- Y" f" I" V* X6 _
0 l/ h; X- P' e/ {6 d
    *@param_approvedrepresentingthestatusoftheapprovaltobeset
" R" i% [5 }% k: ^' f4 J+ q/ t3 u! J" C8 B
    */% s- k- x$ b( {
) h) Y6 R, R! b6 \. V3 v: Y
    functionsetApprovalForAll(address_to,bool_approved)public{
' A0 r1 W8 P( M; V- D- m
) }; H4 [2 ?! l1 q    require(_to!=msg.sender);
( Y/ r% X) f; A) Z2 d6 Q! X- C9 c( P# g4 ]
    operatorApprovals[msg.sender][_to]=_approved;
  W5 d$ H3 Y7 f( i5 q: S2 ?* b9 v" C6 K* s1 O9 Z- }
    emitApprovalForAll(msg.sender,_to,_approved);  W# T$ e% g5 D- B+ d5 _

3 Q" Q, R. h- V( B& A    }6 P4 H$ a6 X3 L) P+ {' o0 L' u

) c2 u$ l: q3 o    /**
  C6 r' y! W# n$ `) ?. L
- M6 ]1 s) |' f    *@dev查询是否操作人被指定的持有者授权& |9 B8 D# X) R* i% J

1 e# Z: u# t1 S2 B% M    *@param_owner要查询的授权人地址
" V! k1 V1 G9 f; w; k
! m5 H7 @4 ]: S0 t4 R    *@param_operator要查询的授权操作人地址
3 Y7 d; [1 v' Y" a* X
4 a6 Q% O" @2 t: \- o5 Y. J    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner; z  t& T6 X) m% l/ W0 Q" A. o4 U

  p# V  C+ ~. q, q. e/ {  G    */
6 ]( h7 Q' |* I$ m* y' h/ e  C: @' \2 _
    functionisApprovedForAll(
" [' y3 `5 E$ G( H% L
- ?  c$ C$ I* A( d' X  l% n, g    address_owner,+ i' I- q) a2 g/ @3 |8 m1 X
7 d4 I$ G& j& a
    address_operator( ~+ t: m  `7 ^9 U$ Y; l9 O
2 S" ]1 [. \, C! d$ @( B
    )
) X4 f) d: d6 T- X- p# [: a
; g4 \6 J2 {  D    public
$ ?5 }, l2 ~4 [5 g8 v( W5 W0 A  F  [' A
    view, E) V# `! K- [4 c
* ]- x2 m' h: l; Z3 `9 t
    returns(bool)
# I9 D- z7 D0 F* c! v8 y: p  T4 |* E: [, J- f9 p* s3 a& o
    {6 U6 B; O, z; i

  t* ]5 e2 t) W3 w    returnoperatorApprovals[_owner][_operator];
/ K+ x$ @" w( x8 Z5 M5 K7 e
3 e5 j3 C+ F- f* o3 q    }
2 m0 Z) E8 u; L# T! ]. f
+ {) F. v6 E% d  _6 C9 h+ n" ~    /**
$ ~& }; |3 y% W) S. S* S& b: h8 E5 T( k
    *@dev将指定的token所有权转移给另外一个地址( P0 W: ]( d' h7 ^

" D! i' t& o( X. V    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`6 H& p' Q4 s3 ?4 g
! B: Y0 G+ \* A7 P9 V  u8 B  x
    *@dev要求msg.sender必须为所有者,已授权或者操作人# s3 @3 q$ e9 a2 f  ^+ k: p' u
. S3 j: J4 T3 y, h- |$ C4 D
    *@param_fromcurrentownerofthetoken
! T1 c5 k! e; i8 X; u3 `- b
/ n) t8 V0 E# U# d    *@param_toaddresstoreceivetheownershipofthegiventokenID) ?" p+ J, i0 E+ C8 |: v' Z7 I

: l( I* T% W% e% X    *@param_tokenIduint256IDofthetokentobetransferred' M: I. }, T1 C3 ^" r" g

3 P7 ]: P# t& P  x+ D5 |; Q3 Z    */
( {' M9 }& H& D3 S( C
% v* p# r3 Y; q3 k    functiontransferFrom(
8 |0 G+ G# N* ^$ H  N2 h, t, e# Z1 S2 a9 p* G3 v- A. J  W( ]
    address_from,2 K4 q: b- \/ l2 b: P* S5 E/ ~8 N1 t
6 O* G2 G0 o1 X  _  Q' E% [' ]
    address_to,. i  G# P4 T* C
( e% Z/ g0 J" ^1 ~* Q; e
    uint256_tokenId
* _, u3 j" E% V, A! Z
/ j6 H5 ]8 e$ x+ E2 I    )+ M- [% h: X5 i: D; C
& y$ x% z, K( N! r3 L! b
    public
$ a7 a5 e; K1 L+ w1 I- }, Y, d( f% I' J$ _  K0 J
    canTransfer(_tokenId)# c5 }( \  A" S3 U9 n
+ b3 o, n: A, n. g3 p  f# Z+ ?1 y7 i
    {" P3 N* z4 G5 F2 T, u8 I1 D
+ l/ k# }! z, B2 T$ x/ ^& O( x
    require(_from!=address(0));! P) }- t, b2 ~% }! J
. Y( G0 z+ p% ~* W' @' D
    require(_to!=address(0));% i0 z: W+ K0 c9 p( C) }2 j6 a

0 q* @; N& Q: A8 h) ~1 S9 \: j    clearApproval(_from,_tokenId);
* u" \/ k! r( b- v& i
% h) c( h+ j; [4 s    removeTokenFrom(_from,_tokenId);# o4 p5 w5 Q; N5 G
$ m/ e4 j' f/ H* x- e  q! M7 {
    addTokenTo(_to,_tokenId);
# _  y# y: A$ W0 k2 ]
7 `( z3 {) Y) L6 j9 ~* ]0 B8 D    emitTransfer(_from,_to,_tokenId);' e( K) x/ _2 i# q- s0 i5 H' N
3 x2 `& p( Z& f& @7 e7 @. e' d% D5 E
    }
# W# X2 ^7 ^( B" `! z2 W& o
& `. p0 [3 m! C9 D, ?    /**
, s" y" E- h  g. d# C/ ^2 Y9 ]- K/ N( [( i1 q! s- j
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
; K0 I2 M" [/ v- _' B# K6 d1 [& }# A* g  X4 X& K3 ?2 `
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
2 i8 J* m- H5 w# _3 p" H5 |0 v# V8 t
    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原! G1 n# S# N6 t8 [9 @. z9 f0 |2 P

3 g9 Y; p3 r# U$ u( d# \1 z    *@dev要求msg.sender必须为所有者,已授权或者操作人
2 ~  M* T1 `* D( U9 O; N- z% d' w6 X: s8 O! `# B
    *@param_fromcurrentownerofthetoken
* f; i4 l8 o5 `" a9 n/ T& C" z( b6 `* Q% t8 @" q! P- Z
    *@param_toaddresstoreceivetheownershipofthegiventokenID. ~4 Y5 x  G0 _' N6 ?8 Q7 i9 m) @, P
9 q" c+ u& N7 _; s5 C9 _
    *@param_tokenIduint256IDofthetokentobetransferred
% L4 l, @9 J/ U. Y% ], x7 q3 o
1 S9 S; W- [. Q6 _4 B8 E8 E& j    */3 Q  k$ [1 l! ?; M8 W7 k" x

" q7 E) J/ E$ V+ G- l! a; ?8 z6 X    functionsafeTransferFrom(
$ E7 e, T- R+ T3 p- b, @) D
6 S/ K' M; p: b  d    address_from,- e1 m3 M) w& Y: \; i/ Q. y2 S

% ?' ~+ F( F8 v/ H) W    address_to,2 p7 Y) J" l+ I9 o
( l+ n4 X, o6 ~2 a; W
    uint256_tokenId3 \) g( Z- \+ B, y

% p2 m4 F  t2 V" v/ r% v# U8 y; o# O    )$ ^6 K- y2 b1 J% n( t0 r

/ R+ {8 W, H& }3 b    public
( h3 e! @& q1 I2 B* \% ~: W' _5 ]- X' b7 y0 ]+ @
    canTransfer(_tokenId)
% S" Y- I  X0 ?* U" z% _5 q* F' ?6 }( P* t& B' I+ t4 \5 I
    {$ b; v1 P. u' ?) v

8 d; d# O0 ~. E! N4 N+ h+ N    safeTransferFrom(_from,_to,_tokenId,"");' W+ |( o- p3 s5 ?+ }" a; C! w

6 s, Z0 I6 {: M: `8 [. N$ y) c    }1 c4 g/ b) L' e( d% x! \( F

% S; _8 D: h8 E( F9 `5 V1 K    /**
+ P4 p) a; Y* Q& w9 q
5 `2 K) @3 }3 L- F% j    *@dev更安全的方法,将指定的token所有权转移给另外一个地址! Z/ p: Q& P' F: M4 ?. k2 X

& g8 r+ n+ ]  d2 \* O' b& E; q    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值# i  f1 W8 R# d; \$ X) r6 q$ ]

# v% v0 N, R9 ?/ }    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原) s# O, d& s. e

- }# S; y. U( M    *@dev要求msg.sender必须为所有者,已授权或者操作人9 s$ Q# u: Q+ o( I! a- O
% W3 y+ ]' _# K) K' z# r
    *@param_fromcurrentownerofthetoken
8 ^5 i0 N1 e, ?) Q5 S
- s+ N7 `7 Y/ M# E+ r% P2 Q: B    *@param_toaddresstoreceivetheownershipofthegiventokenID
  f7 S, O9 y. Y5 y) ^* h
8 ?; @2 o7 k2 V6 [, l    *@param_tokenIduint256IDofthetokentobetransferred
( V1 w" W' w+ q7 V) a' z1 U: _6 U4 @
    *@param_databytesdatatosendalongwithasafetransfercheck
. ^2 {1 P9 X& C7 N. [1 n) s$ D" Q; l0 h6 f1 ]
    */% @( p. h# N! @8 ^7 K) @
, R" w. [4 V& E3 |
    functionsafeTransferFrom(
6 Y9 ?/ h& h1 [  \! s& C6 H: h% Z( Z* }' _8 [, b- L
    address_from,
  L7 G+ H8 b# g/ s% d$ n; s! s* W% j6 ?2 o% h6 d7 F3 a
    address_to,' r* r7 p" N. ?0 J: @
! `$ R- f; h2 y
    uint256_tokenId,
0 t9 j+ [) t. ^3 K1 r8 t7 b5 S
* ?2 h* P8 c0 }) ?% m: J1 f    bytes_data
/ @1 E  A2 \7 F0 |' _9 D! A3 x* @1 J* F
    ), m) ]1 i) ?& I/ ^4 R3 N
7 A* e6 J3 z- m5 K# }/ l; y+ X
    public4 n4 y; q# f' X4 q
  q7 r: l9 v$ ?+ ?, j  w6 P
    canTransfer(_tokenId)( G9 U4 F( }% B
  w1 d9 y! U* _1 o. V6 h' f: S
    {
8 n( D# e9 N+ z) p# w0 P% f) Z9 K) p$ U7 \' w& z# w1 A
    transferFrom(_from,_to,_tokenId);
  Q  Y! c# W3 v5 p& t# G* L6 g# x9 |
6 X& U2 k  O$ X1 M    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));7 P; l+ X* T& P' ~3 [( y7 g

5 X+ `& ~1 P; l9 w  G3 x( `    }7 ^% g3 B1 P$ u' o3 K1 A5 u( Q9 f

/ {4 M. v1 l# V6 `' h3 l0 F& z    /**
" d3 w# Z9 N7 T9 v/ W9 `
) U3 x9 ]8 q  j# T  G7 c# }    *@dev返回给定的spender是否可以交易一个给定的token9 X6 l0 c7 ?8 J9 Q/ I; |7 X
6 K1 J7 X% H3 S1 b5 I* {4 J
    *@param_spenderaddressofthespendertoquery  I$ S- u7 _' Q' X" _( M* f8 }

6 h4 r6 [" B1 N' j" x$ K# K! D+ S    *@param_tokenIduint256IDofthetokentobetransferred# \% ]: T# a2 f7 p9 o
, r; o9 Z, ]& ]" q1 ]
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,
% f8 x- o9 u5 i1 C2 F5 }
0 i$ u  M& g1 x# J    *isanoperatoroftheowner,oristheownerofthetoken
1 f; g% E) `. M4 R1 H! K) E% A
: d/ C: W0 J! s4 Z  H    */
0 L+ p; [% ~, K( c( y$ C
+ Q. @; u! x2 U    functionisApprovedOrOwner(
2 C5 ?" H' ^0 I2 R% L4 u" M' x1 ]
( g4 z/ i5 U6 `( [4 I6 F+ D  B1 I    address_spender,
" v9 z, n6 R, B/ @! L( w  L% r" B0 U% ]5 u# [" C, Q
    uint256_tokenId
6 o; A% g& W. K- D. H  N
4 E. t8 h; G: q( j+ N; ~    )
* O+ @: ]' t. n& e/ J' {
0 g: R' w4 n" {, Z! V  I    internal
" r% Q- P% T; g6 a
! N8 P+ w2 p$ d1 V    view8 q$ z; Q( e# Q: I4 J/ W; g

& h, ]8 W# Z' J% L    returns(bool). ?6 T* i/ _' a1 A- B
/ H/ m( g0 p- x. b
    {1 c- h: X4 i  s. Y* W/ b

& e* @! C! h) p$ }# ?    addressowner=ownerOf(_tokenId);
7 Y. E$ h, k: {) A. r
5 _  `* E/ I4 a" t  @8 g/ e    return(
9 F/ d' h5 K9 |7 P1 h/ V9 E2 P* c  d" G! q6 J$ D1 h
    _spender==owner||
- |+ Y3 w1 m6 Z, m, d
$ _+ D/ |. f0 _8 o9 }    getApproved(_tokenId)==_spender||& E2 f4 k, L! \
1 }3 `. o- w& g8 Z1 j! h/ n- O3 G# P2 u) s
    isApprovedForAll(owner,_spender), {9 x7 t: {' B# j# C9 b8 M

2 I" w' R+ T. B. e    );
  N5 U: w7 f( N. Z7 {" b1 q# @
' g; x( T0 n- D( m) y, W    }9 h+ U, A* L3 m, k: v" ]

2 t- ^2 j- \9 ?. a" q; G. X    /**
  {: U" z4 s4 P/ w( v& i9 ~6 N* ?9 D( }+ O. l
    *@dev增发一个新token的内部方法
  F/ p5 o5 l! `( R2 f
4 G% d4 ]1 M, @% T- d1 m    *@dev如果增发的token已经存在则撤销
2 \/ z# z2 [+ T( i% o+ T% d6 Z
% Z. N' ~0 f3 ?( d    *@param_toTheaddressthatwillownthemintedtoken) O% A" Y, i- D! O
% G1 q% x, H* \4 N7 T
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender+ l( C, v, _1 V+ h
" d+ J  A6 |" _+ I
    */6 b) \. o2 q) H: H8 S" y, P, b( j( v/ @
: U7 ?: I+ `" [7 q+ O, R
    function_mint(address_to,uint256_tokenId)internal{
( Q. R" M/ C$ X( @% d* }9 t1 i' L# {7 s# ]2 b
    require(_to!=address(0));0 V% _2 }$ x& S) _8 u+ p! V
, Z- g2 T9 Y8 P8 Y: H: n* x
    addTokenTo(_to,_tokenId);$ ?1 }3 T/ ^, s4 w# ?

. T3 X# m& v4 L3 K6 f# I0 I2 \    emitTransfer(address(0),_to,_tokenId);
; ?3 j5 T! v6 r2 L. V' t$ ?( F- x' k  J- C
    }' O% a/ m9 g4 H9 J

8 Z& D7 n+ X' }  t' G' P% Q& X    /**4 |) L" b- ]. k: y8 h% \
! U8 w% v: r. n$ f
    *@dev销毁一个token的内部方法
) V! D  D# @9 {) S7 p) y
. d2 m- N7 q9 ]& ^$ r- {6 `( h, N    *@dev如果token不存在则撤销$ k% A( C' L# N, p( m) w4 j: `

# Q2 i- {% o: D% P2 i6 W2 G0 s# P) L    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender9 i! D4 X& g6 H. i5 C% S3 z& ~
/ X: l- h5 D( v0 m0 }
    */
1 r/ L/ x+ k/ f; M9 x' ?
. Q1 O8 r2 O, c8 @7 Y1 x    function_burn(address_owner,uint256_tokenId)internal{
2 J6 m: {' a, g8 ?& d& L. @
, v# ^/ d1 N- u3 Q6 \8 o2 R7 Q    clearApproval(_owner,_tokenId);3 [+ g& m% ]2 u) A3 _' C6 A

: z0 P1 ^/ j$ d' m7 D    removeTokenFrom(_owner,_tokenId);
" Y+ |8 Y) q: \: ?. m: ~1 N) x& Z  l* T$ t
    emitTransfer(_owner,address(0),_tokenId);
. W* |$ N+ r( F
3 N2 a+ H/ B8 S0 \  f    }
' q; _  I& Z# N2 G" H0 t5 A! b* q
    /**
6 h3 m+ V" w5 @6 r! j
  u7 n. ^# S6 o; f+ o    *@dev清除当前的给定token的授权,内部方法4 A1 F9 ^' d( i# E3 G* S
9 X8 q* S& g5 a+ d! }
    *@dev如果给定地址不是token的持有者则撤销
: X6 j3 C. V! t- ]2 N; h( k, K4 ~3 E: k
    *@param_ownerownerofthetoken, r* _. {) |0 e2 e' N( G

) z8 Y0 r; S7 u" F9 z. H% B( k: F    *@param_tokenIduint256IDofthetokentobetransferred. I) Z% m: k4 n. U3 _

, R4 M8 L( q( c: f0 B7 S; X9 Q5 l    */
# W  V8 [3 C7 S" i. u6 y4 G# h1 I$ o1 J
    functionclearApproval(address_owner,uint256_tokenId)internal{
1 D$ C+ x+ R1 t' ]) W3 h! }7 j4 S: v7 Y6 Z! j* A
    require(ownerOf(_tokenId)==_owner);
  c! e& s- {% b$ h) c! y( k0 {8 J2 a; Y+ p3 B, M! W7 e0 A2 Y) ~+ P
    if(tokenApprovals[_tokenId]!=address(0)){
1 V. T3 E/ N4 s  A" h: N) ?
, f! w. h. j+ b    tokenApprovals[_tokenId]=address(0);
$ L8 k4 b9 k6 Y" {0 V) ?; w$ z; z' P& J5 ~9 X* H! ^
    emitApproval(_owner,address(0),_tokenId);
. Y) l7 K) {1 z9 ]2 H) l8 [5 e+ N+ h: X
    }$ M! T& q( b. `6 n" h

$ U1 J( k! E+ K    }
+ N& M# U7 @% Y; ]' A- F6 U' K* ^- j0 N2 _7 i/ a0 k! n9 a/ y
    /**
) X) T! Q+ z* a3 ?) w2 y4 G( s- |7 G8 o2 s: V. Z
    *@dev内部方法,将给定的token添加到给定地址列表中) U. ~4 O8 {( \2 H  b7 G& i5 \2 [

7 I: @+ w) L. r! n% _$ A    *@param_toaddress指定token的新所有者2 J! ~5 I/ V$ ?3 c
, j/ j6 o% f& G# G8 t
    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress
/ S! o8 Q. Q5 r( V* @6 s
( W8 y- |1 t- J9 }2 k    */+ a- B/ b+ y; Y8 Z1 A% A' z

/ t, i3 }  \) @    functionaddTokenTo(address_to,uint256_tokenId)internal{2 P1 k, i% [+ |) Y" D

1 |, e: x- I/ l    require(tokenOwner[_tokenId]==address(0));
( @9 L1 f% x& q4 j) Z: t' ]1 q, L
    tokenOwner[_tokenId]=_to;
7 u( ?! z* ~$ t  k. X3 h  b4 ?8 k
    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
3 _2 V+ `: t: I, i  g* b: Z
/ X- ?$ p2 u9 S" [( @7 @( J0 j' y; E    }
4 Q7 M. C6 K  Q: K$ s: c* R$ _% P: C! T
    /**
0 |. w* N$ e- l/ O# I2 B3 w7 {6 P% i& F( J
    *@dev内部方法,将给定的token从地址列表中移除
1 x1 a( B+ n) g, D4 u+ B
  _; f9 r$ I6 x7 o& `9 \% c    *@param_fromaddress给定token的之前持有中地址# C' @( f4 @- {8 w2 K
3 M5 K5 q" i  K, J/ `
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
5 C5 M# \+ i3 s3 r0 u; K5 i& \' _+ ~: o$ z; R: J% [
    */
8 [5 a' K( W+ S6 a7 S5 H, }! i: A
; `4 n; x+ r" t+ y1 s/ M+ w    functionremoveTokenFrom(address_from,uint256_tokenId)internal{8 q( m1 W% c/ A$ h
9 Q- K2 q# c; |, q* W
    require(ownerOf(_tokenId)==_from);+ b; U; j6 ^0 u% q
0 x$ C7 L: U# n- b+ n' f0 m; H
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);  r( E* Z; }2 H7 E/ J! z. D; C8 i* i

- N  p! k4 {- Z    tokenOwner[_tokenId]=address(0);$ p! Z. x& ~6 O

5 q7 M( E) R# _/ b  a/ [5 t    }% z/ z" E  v- J4 \

/ J4 e8 l; W3 n1 d! E* S4 W    /**# x5 ]. h$ b& N1 B6 S5 w% ^! B4 {5 B
8 @( U4 z5 V9 |1 {1 m
    *@dev内部函数,调用目标地址上的`onERC721Received`
/ X0 T" ?% d. s& ~. R  W. L; b% l. `5 N: C3 |$ ]. ~3 U0 k4 [
    *@dev如果目标地址不是合同则不执行调用
6 s# T- m9 v& d; |" |' T/ W! ~- M
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID& G% p1 [( L( a

4 j7 S+ u' J0 H8 X, [$ F3 }+ C0 v* ^    *@param_totargetaddressthatwillreceivethetokens
8 r$ R$ X( e/ Z  k$ s: [5 k9 j8 F" }% \9 t
    *@param_tokenIduint256IDofthetokentobetransferred; m2 \$ b8 \9 S+ B1 \
4 v# s: W5 @, ^, R, H$ }( U
    *@param_databytesoptionaldatatosendalongwiththecall
, g. O0 M8 f% }1 {% X& p# ]. f( D, s) E. Z# m* L
    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue2 E2 F. e$ U* |3 S( g5 ?
- U& r4 ?, ?  s: H: O6 Z: T
    */5 m" T( k# `4 l: P$ l
# P2 V) S% m7 t% @) d, `
    functioncheckAndCallSafeTransfer(9 _0 L1 x8 V) c- t3 e
7 r$ n* P0 d- J8 o+ ?7 Z
    address_from,
" c& K5 R/ f* X3 q3 k; s
7 S: c3 {! u4 Q    address_to,
* v1 \, t. O: K& J; y' w7 m  s- w" S3 U  j5 P4 F) l3 d
    uint256_tokenId,
# n2 j9 }3 B% T, {4 z/ S! M- A) c; _7 D' G5 U% h) C6 `4 W
    bytes_data
- F7 d1 i7 d) l4 f
2 A" J6 B6 Q9 |* w    )
0 h! r5 r+ x6 \  a. q  y$ M
4 T1 P9 }8 M7 [8 w/ d0 y: r    internal, |- K( N: ]/ r$ E1 i

2 r- m( y: t9 p5 a$ d! I9 _    returns(bool)
. |3 d% q' X- H' @8 C* p- @, n- }5 ~# P1 s  r3 t
    {
9 @! ~( m* H9 d# E1 X4 d( n  ?/ |  o1 g$ T# R+ x: ?1 P* ^1 |
    if(!_to.isContract()){
9 z! B$ Z* }$ ?( a; y! }  j3 N# f& T& Y9 X" T; R  m6 G
    returntrue;8 ?  i1 t/ _& C' e" q/ a+ N* q3 E

+ [: l& G* A, {- _; m2 l1 y    }& ^6 ]6 L& _+ S

  a% g( Z7 }. @0 j    bytes4retval=ERC721Receiver(_to).onERC721Received(
: Y2 L/ j, K! _8 B5 U4 W
, v  L  A/ W, {$ W! I( W4 }    _from,_tokenId,_data);
" d/ \, V0 D8 k) e% h# B7 A# e3 h
. d( d( v" |1 m' J" M+ @    return(retval==ERC721_RECEIVED);
* Z3 ?2 ^! W; F2 f( ]; o
* e; _' P7 b' K    }. B& p2 T4 ~9 a$ ?$ z, p" ^9 J

6 a" u0 q8 h! g5 n    }( s1 d* i! s( n6 x4 c+ z) _* g

6 Y! S: v7 d8 e/ L8 B    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
3 d! r. u8 M% ^" w8 ?1 P* J. }5 D6 ~5 O1 c
    ERC721Token.sol
. A- X9 D* j. p  u3 i( g3 R9 o7 Y  s- e6 \) F1 d
    pragmasolidity^0.4.23;& p/ A+ |6 q2 l% ~6 S/ R7 c4 |1 k+ D
; S7 L2 n' Q6 f
    import"./ERC721.sol";0 ^0 W# s% `) @5 {- `

! E. {9 O; B! n7 Y% A    import"./ERC721BasicToken.sol";% W6 |( W: L$ A

6 S0 z8 D- |$ @& o+ A# M" J5 @$ i    /**
" O" T/ L$ C. ]" J# b2 R/ R; `, O8 t+ S8 f% J" B, \( C+ p
    *@title完整ERC721Token
. {0 Y! F, y- k7 r  P1 r  }9 b$ \$ y+ X" X/ b
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能- F- ~1 N8 s; A) p- L4 S

" r4 \, G' ~  G* O; U. r* t    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
0 B) l. I7 x- G% n1 H- r3 j! e* J' S
    */
# S1 @, z) @+ x! c% c7 `% o! W6 c+ ]3 u6 n- R1 a- `3 a
    contractERC721TokenisERC721,ERC721BasicToken{
- M0 {& r/ c9 K
6 F9 V' S8 @- g* j    //代币名称% V) L+ M3 ^; H( c% D  ]
" d! t  q3 y7 K
    stringinternalname_;2 _, I0 H3 J$ e: V5 c
+ ~8 x, y6 z" @/ n
    //代币符号
$ `& T! }- U1 _0 t
6 P: d. y+ p0 c! t) d2 |# f; `    stringinternalsymbol_;
1 j" ]( i( r8 h( ]1 K$ x# U1 a: y3 y' ?
    //所有者到所有者拥有的代币列表的映射3 T1 r' c6 p9 \5 }/ b

" }2 V7 [  N: L8 t    mapping(address=>uint256[])internalownedTokens;
, Z2 R3 S1 [  s6 }5 j3 z8 u6 \7 L3 p- X5 h! G7 [. g& M; L
    //所有者代币列表中代币ID到索引的映射
: X  X5 ?( N. m! b: w/ S" r; @
( A% w6 t( u" w1 O; F0 [    mapping(uint256=>uint256)internalownedTokensIndex;
3 ?" \7 x: j# ]! C9 j9 }% Z6 P3 f# o" b, T4 J
    //保存所有代币ID的数组,用于枚举
, H3 Y. n* Z( ^
! d9 E2 L+ A" r0 m8 e    uint256[]internalallTokens;7 y8 }' Y- A# K9 c6 v/ c

0 K8 Y9 b" e" O) o" `1 i2 A    //allTokens数组中代币ID到索引的映射4 L9 ]% L$ l3 `. n& u+ u% X
6 r9 J5 C* A. N  ]! x1 g2 S
    mapping(uint256=>uint256)internalallTokensIndex;. D: ]! ]0 w) m4 q8 c. [4 G

! k) \+ q! B8 N8 L% u    //可选的代币资源URIs映射5 G. ]  [! R  q( M7 I& L
" K  a+ p& W% v" \
    mapping(uint256=>string)internaltokenURIs;, H, f) G, e( G. |9 H& H

9 K2 T$ O7 G7 I, g+ z8 @    /**
% h+ ^% R' @* E, S4 ?  y& o% |
, A8 C: e  o' H& y( W4 _) E; n5 [    *@devConstructorfunction
# j& g9 a, z  o4 j4 C( L
) T9 z* D; N3 l. W! q    */0 K+ b5 p* X8 Z" d) o- d6 S8 d
3 V$ l' ]) a- n, G+ q
    constructor(string_name,string_symbol)public{% U7 I# e. E6 |  c
4 L1 p' d! Q3 p1 y" k
    name_=_name;2 W. v1 G$ }1 M/ X( s; n* g

: M7 R7 a; K. s. W/ q    symbol_=_symbol;! d1 m4 M$ l- z5 D7 z( a4 n3 e

. ]- K  h8 u; S8 [3 {3 q3 Y( G    }( P% h! E0 q/ Q; q. \  z9 K; M

) W" V+ w3 |; p$ c    /**
2 ^, r3 ^; s! r
9 f+ t- _+ a9 m! n    *@dev获取代币名称
2 O; R' V4 r3 t- b$ Z
9 q3 f7 [0 p" a1 G- J1 f* j    *@returnstringrepresentingthetokenname1 j5 n' _) l' S9 H# Q2 i
2 \/ n6 S4 F# {1 D7 ]8 O
    */0 C  c( U) x' |' t% K) e
; d  s1 T: _! J# f$ i6 h6 ]
    functionname()publicviewreturns(string){/ ~" j9 k' ?4 v8 e# [
3 @( ^0 U3 U6 {9 {9 g
    returnname_;
" f! Q4 ^7 ?8 w7 Q, v
7 I  `8 r: i- C& I" z( |2 V    }
' H6 `1 K. R4 }: m/ B6 A% _6 I
1 ]8 D0 R8 R) e3 P5 T# p    /**
/ @, |& W( |4 p# ]: k0 `' N' y1 ?0 Z0 n: h* ~, y$ m! t
    *@dev获取代币符号
# t) \8 T5 m7 K2 m7 ^0 D9 i6 i
! r5 T/ s5 i, P    *@returnstringrepresentingthetokensymbol
$ B7 n. z2 O( x7 v+ ?6 i" d8 j& I! e* A/ \/ v1 }4 j) v
    */+ @% V& `0 e: c. T9 w# W9 Q
) t$ a( H. s  r' u( Y/ B
    functionsymbol()publicviewreturns(string){& P4 y1 w! O  Y* l0 {/ z
1 V+ N3 g$ c3 V
    returnsymbol_;) I; G* @7 o6 ?+ K

# X4 W) @# l) z1 h! D    }; V9 e7 J2 o$ Q5 D

1 _6 q$ [7 P( I: G  a    /**
, P7 ?8 {* ~* a$ t3 r/ N
7 e5 j' ~% t2 k: D7 ]. S% g, c' n    *@dev根据_tokenId返回对应的资源URI
( ?# K/ o5 o2 L) ~1 Z# ?% J
* Z/ F. z; |. [/ h    *@dev如果token不存在异常返回空字符串
' g+ z# i- z5 Q8 k( ]
+ g! `* r# e) Z, P6 W    *@param_tokenIduint256IDofthetokentoquery
$ h, T0 }8 u' e4 b& K& Z+ b; A( I  C8 a( s8 O
    */& U1 |, u1 A6 z

; E; `+ T. O( d4 P" U& y5 V    functiontokenURI(uint256_tokenId)publicviewreturns(string){, A+ H; _1 Y- F
- }& e, F8 W) a" I. n1 m
    require(exists(_tokenId));% D( Q# Z2 B  p$ [% L( |0 q
6 y+ e- I) O' ]# ^+ \6 w+ ]
    returntokenURIs[_tokenId];) P. Y9 C8 X2 _8 T$ }

3 v$ v8 s3 U7 A- G& ~    }
8 ^/ j1 F) o5 c5 E+ D1 u
. I% D# v; x  X. \& d    /**: e( V- r" {$ b6 z1 s' ?6 j; g
# T; E: N- r% e& R7 j" ~* V& O
    *@dev获取tokenid通过给定的token列表中的索引
5 W) L( q5 `- o- t2 u
2 e+ x. b0 t' D; C" C  }3 X8 m( y    *@param_owneraddressowningthetokenslisttobeaccessed
1 X! n( y4 a# N+ l' ~% e/ Y. A& j
    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
4 u& _7 F; B! f3 Y7 F: N7 w1 _  k  k& Z8 `& G" C
    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
% Q3 i  m; O" `- S
1 R' r8 K' J8 h) J    */7 @" n5 M- p% q4 A0 n

$ o6 ^# R3 O5 q- h7 ?9 M7 e    functiontokenOfOwnerByIndex(8 T* z& g) O( `$ {
/ s( Q9 X: ]' q/ g
    address_owner,
- z  F; C5 l/ o& S4 L% o, A. [6 H0 e
    uint256_index
5 {4 t  Z; g' X4 e; k1 y/ n- W. B- o0 _7 e" h/ `
    )3 r: A( T. P4 o5 o% X# r

+ |9 a4 f* h! `    public2 u0 s0 Q8 X, V  @" f3 R7 a8 \

/ j1 L, m! }2 U: u2 j$ X( v    view
3 j- I7 O1 V, a8 H5 U3 |
7 J# Y8 A" V* C2 Y7 c    returns(uint256)* J  \% ], x( l& V

7 ^8 z) ?+ Q, _% m    {, S3 C# ]# f0 o6 B$ D
. |* l) G2 S9 N8 F, z/ b
    require(_index; ^* Q. s0 d$ }0 x# y# R7 c/ B4 g
7 `6 |/ i& n8 _$ h" r- k- q
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。
" ]4 o1 z: x2 Q+ |3 H( |# C
8 ^1 Y7 i0 ]" t# o2 H    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2