Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2402 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。. u- i- t1 s% g8 E5 |4 H
5 W3 j, T& j- J0 s0 v, h6 v/ f) u. f
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。6 r+ Z9 E( b) S5 `" t& t

/ w/ B* n2 x$ k$ I. y    ERC721Basic.sol
7 l7 b* p0 V, p# N1 [1 M/ p
/ n- `& p3 ^( H: ]6 U    pragmasolidity^0.4.23;4 W# c1 r; T) \( e

2 Q( p% T# x) I3 @0 y* W    /**# [1 m  D. p0 d) [

. X7 ~3 B6 F! e) {2 k* t* M& s  ?    *@titleERC721标准的基本接口
( l* i. D0 k' ^! c, M0 x
2 p* a6 f  q* G$ T1 l/ k+ y    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md; |- {5 W) X" f# \6 E$ M

1 k; r' u0 s% X2 R) D4 \( T6 z    */
# O) I. Z8 x5 d' P6 h+ U4 K8 Y8 h  x# ?& P6 R' p
    contractERC721Basic{
, _4 }- `" }  ^0 B7 H& t! O5 A- R$ r7 V5 D5 u9 Y# u
    eventTransfer(9 d: b; @' o9 M( C3 V1 ^
7 v+ o* [" x( g2 e
    addressindexed_from,
1 ]7 P  B: J" L# }7 `0 n: ]1 g* g5 b* q& @% ~, H
    addressindexed_to,
  M9 l4 Z7 w* Q' q0 E. y  L" O1 k- M( Y" N& R
    uint256_tokenId
; S1 U- @4 i9 d6 H. ?2 s) W% d, r# e* Q3 M" g
    );
. D. s/ J0 W- h% N; W! P& N
5 ?6 @6 e/ W+ ~$ B1 p( j    eventApproval(
/ A- O1 ~; @3 i# N2 q' y4 Q( E$ v
! X$ ]5 l' \1 h" s) D  U# m    addressindexed_owner,
! A# V/ x) K' b% r! p7 r2 S+ {
. X# f: {) R0 a! j    addressindexed_approved,. b( e5 t- W4 e7 H- K! J
3 G1 z5 D% k7 v7 W& G% y3 U* v3 X$ ]
    uint256_tokenId
  X4 w8 }% W% L: N% u3 L9 |- [" D3 f: R! H5 V1 G6 Y
    );
5 U1 `1 I3 h& F# q
  R7 B- w8 h3 G    eventApprovalForAll(1 r; r1 |; Z3 f& T% c9 d# j
) c5 R# H# J- S* I, g
    addressindexed_owner,  p$ J) t- U+ L7 _" P
  a+ n" ^6 z  f+ C( }& G+ ?
    addressindexed_operator,8 D$ D% F* \  F: V. @6 z7 S9 d
$ V3 A9 u6 Z) T3 l
    bool_approved8 X: X  D3 G! B6 f3 b2 V  M1 H
9 e1 n, I1 {  E5 L, ^9 Z# p
    );# K1 F) u- s3 X8 U# [

% F! n. r8 A8 T7 e    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);
3 C1 L  A# F7 V; v) b, @% d2 o
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);" x! J4 u! l: o

$ o/ f! H: g. g! f# i+ I" K    functionexists(uint256_tokenId)publicviewreturns(bool_exists);% F, g3 O7 f7 m
& p0 U0 [* z% }5 Y
    functionapprove(address_to,uint256_tokenId)public;" y. E6 e/ u% s- w3 Y, s: z4 {

2 n9 P9 i: Z+ j3 e    functiongetApproved(uint256_tokenId)
8 B  l. B  C% t7 O
; |/ |) x3 K$ N0 d    publicviewreturns(address_operator);, _$ ?% @  q/ _+ p% Z# \/ N
: G' L- p3 X) A1 C0 H
    functionsetApprovalForAll(address_operator,bool_approved)public;
& G0 o1 `- s, i0 P5 K1 d+ z! H4 B* D; ~; E! Y
    functionisApprovedForAll(address_owner,address_operator)
, t; K9 W# t: k( P3 d; Y2 F
$ C- l: p* m5 H- l& x    publicviewreturns(bool);, s/ n* C; ?" S; C0 B5 T, G  Q

+ d" T& a# f# c! i    functiontransferFrom(address_from,address_to,uint256_tokenId)public;
8 t3 x3 N; h% b. o& z5 l4 o7 i9 W% g* A; M
    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)
/ a" q+ \( o7 M4 b2 @  H5 f1 u# }+ Y/ `
    public;6 s* f; M9 P; i# z, M3 f

5 N  P+ `# t0 y4 }$ h" {5 y    functionsafeTransferFrom(
) c5 b' s/ |7 }( g7 a! K7 T. Q
  @5 [- s+ h* {% X, c3 L    address_from,4 c/ J" D! n7 a

  d; Z2 g8 i' n; ^. b* v    address_to,# [8 M  Q# w  b* |. g4 s

' v$ H6 G1 O$ g5 C    uint256_tokenId,
8 s/ w& B6 X  O9 v: }3 h
. J9 v9 o+ s+ \  J    bytes_data  |& X7 @5 R2 L- A8 Q
, B* U; T# ?# w2 X0 L. d8 v
    ); n% _( [% i# k3 w# O) f; Z

& u3 ?: Y& ?0 E+ |, _2 Z5 w    public;+ u9 ~, q7 M& V5 [0 p6 o
" ~6 }. Z: Z- ]3 v3 X
    }7 T# I/ @1 m  r0 @
$ z" u% ?# G) G1 i  F% v- M
    ERC721Basic合约定义了基本的接口方法:
3 F0 p" S) B$ U5 Y9 M  X) x# l5 D9 i' m" a( ^  W- f. m$ g
    balanceOf返回_owner的代币数量, v6 b. D8 i1 i# C/ ?0 T# d, K

4 M, I! Y$ M; u8 ~- o    ownerOf根据_tokenId返回代币持有者address
' Z  q1 G, s6 L
! f! F% a4 I8 ?9 D" v    exists_tokenId是否存在
. n- A) ~$ Y1 P5 G( t& D* E2 J. x0 l( t0 F0 T1 ^$ y6 R. {- Z2 o
    approve授权_tokenId给地址to
* Z5 a7 u- M9 G: u0 a2 r0 U9 |  x
    getApproved查询_tokenId的授权人_operatoraddress
; p) e4 G! f2 d) i: R& u/ ]- B; }
    setApprovalForAll授权_operator具有所有代币的控制权
0 c1 ?7 _# c; r" G& Y! s3 G  t; z. ]: Y: a4 i
    isApprovedForAll
% m$ B5 F' w% @1 V1 \, H* I
& I( P" \4 m, H  Q- j/ B    transferFrom转移代币所有权
. M( i1 ?$ }& J) Z* j! N% ?
6 z8 Z! s. i$ T. J; x9 r1 T: W: j    safeTransferFrom转移代币所有权$ z- h" F! d6 d1 @6 i2 l
- v; V, M$ X' L& t; H
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。, B9 s" w! b) k+ H$ ?$ G
! e# q% A! S3 o* e; [' y
    ERC721.sol* m) Q' H3 H1 _' K

- ^0 |' c7 F) N! q% W0 b8 o    pragmasolidity^0.4.23;
- J/ e7 T7 R. [/ ]$ j: M+ ]* O) P' T
1 B& k0 a6 X; \- }' T/ k" h7 @8 `    import"./ERC721Basic.sol";8 r# _' Q9 w2 F* u5 m( a

$ f! D$ X2 @* X! a    /**% @) h$ f5 D  v0 k5 H% t
; P, R1 |, L& k) I7 a
    *@titleERC-721标准的基本接口,可选的枚举扩展5 {: E  a" f& |0 ^% e1 o
* s7 [6 Z2 U" ]6 i, K
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
5 ~2 ~, Q6 V2 p) o6 U; X$ z  G& }$ B% H: k7 V( W% C
    */
/ i* S( N; k% ]' c/ M% h+ i0 `
6 Z3 {! L( z* ~* z5 q/ D! _    contractERC721EnumerableisERC721Basic{' Q& P4 K3 f  O( }7 `- l1 x

2 c  W5 }* S/ Z& t8 N    functiontotalSupply()publicviewreturns(uint256);
8 k( J! T1 F# E* g4 a9 w: Q4 ]  y
    functiontokenOfOwnerByIndex(
, \- ?& G$ x3 Y, L8 j7 i/ L6 V8 T8 G3 y3 }% C2 V/ i/ a
    address_owner,
1 U7 p, G+ M) i; f$ x# k
0 M( e! r4 o' i8 i* ?    uint256_index' f% o; W8 ~7 f. q: \7 r

2 K5 A5 m& l8 }  k/ k, O2 s    )
' m# `; D$ n' I. I, q  `5 r
6 c* z! E$ y2 k- M9 r4 N, T    public; L2 n( ~8 k* E( U
1 g7 ~1 x( v2 u* D' V" Y5 |. [
    view
2 I- u# p2 z0 |6 c# l4 P: N
- _2 G$ F3 R' ?  H    returns(uint256_tokenId);% j' `0 k1 U2 E, S% ~( [  d  u

; Y3 c- c7 ^$ ]+ X6 U) A    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
$ z( z0 @( L7 X1 G' J! h8 h/ ?/ v) E+ d4 R' \- p  I4 D
    }- b( Q+ V1 P% `2 q% _. p* j3 H7 q
5 q* l* J+ u" O1 J) D5 s( S( \
    /**- f- I7 }$ x0 b: }& }2 g$ A. k$ Q

/ K) _) `' b$ I# b    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展
- O! d/ v5 s1 X; D  |, ^( {6 H8 I! D
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md/ J0 j# m+ {; H
! w1 Y6 C' @8 X$ ^; A* s
    */9 y6 i; m) @1 u  r7 F' s

, F/ U; c2 ?6 g- g    contractERC721MetadataisERC721Basic{
+ z( u3 [+ Y9 T4 c
5 w) `, o4 l# U% }    functionname()publicviewreturns(string_name);% H" a  M, L: _5 d4 |& F/ R0 B
( k* J# B' C: ]: [+ t0 B3 h% n! \, r
    functionsymbol()publicviewreturns(string_symbol);& b0 q. b7 G0 r8 x7 J* L6 t1 J

1 j3 m& ^/ ^/ [( \" {    functiontokenURI(uint256_tokenId)publicviewreturns(string);
3 }4 O) {* f" _; G
& s# `6 B! w* B5 l  d    }
( T" H% T$ B( W/ I- \- u6 U- E
5 W  ]" H7 k# e9 D0 b5 L: v    /**) C& ]0 ~) Z, X2 Y: s' c$ M6 A

+ p1 s0 v0 B0 x" f! ~$ q    *@titleERC-721标准的基本接口,完整实现接口$ p5 B( I5 x* f
* i; A' Q$ ~+ t
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
0 f% ]- F9 P# `! S! i/ v6 s$ r2 j  V! G& X* U9 w# `* f
    */
) D# f1 H  C/ c$ x
6 y! }' M% y' T& ]6 v1 i    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{! D! z+ H' c6 b5 m! B1 C

5 T9 W( j& i8 p% N9 z    }
1 x  d) ~- i/ f* H. q6 |, g5 {
0 s& r1 U* _) U4 R# G    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。
) _( ~& X* z4 [' S3 a+ Q# [9 N6 Y1 q  z; M( M* l3 I0 V& \
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
2 J2 g* A3 d( G- a0 Q2 ?" P: `- c) K/ o# t
    totalSupply返回代币总量* R+ h; T& G6 @, Z) h" T% A! t! E

) K3 e5 L; U" _# m1 d3 ~* I    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId( b3 g  n8 z, B1 i
) s! U; U$ K  L* G- g4 O
    tokenByIndex通过索引值返回tokenId
4 O$ y* ~9 c( C' u; f
9 z. |2 J6 a4 Z; V    ERC721Metadata元数据扩展哦用来描述合约元信息' N' G/ p6 Q6 G! [$ R5 j
7 h1 o" Z; P7 a' ^
    name返回合约名字; d" w4 Z# P1 d- j
$ [& S: L! M0 F( k2 t) Z
    symbol返回代币符号4 ~8 n5 l. V; s7 |  x- B# g0 i

2 l% x& P6 S1 t: Z! i7 c    tokenURI返回_tokenId对应的资源URI
! i% ?; @8 S$ H: ]4 ]8 L, e. a  K, R
! A" c( m. ^, q, f$ x' z    ERC721BasicToken
9 W4 m' c& L6 t/ p$ m  Q- a$ g2 O9 A0 R. J  x$ [: Q
    ERC721BasicToken
/ v( p/ u& u& t3 v) c; z1 Y5 S7 i% u& M9 c4 N0 s  G' z
    pragmasolidity^0.4.23;
, k* a- J. \4 r( i& t9 P
& R+ J3 {5 y- ^7 z$ d9 {    import"./ERC721Basic.sol";
) G( {% L' q3 p5 ~- M/ V
# \" ?3 b6 [  Y! |) s    import"./ERC721Receiver.sol";
1 w/ d. s) i4 X
$ T2 }* `% Z) n7 V: [$ F    import"../../math/SafeMath.sol";$ ]& T  _3 |  v$ H& u
; h; p  B) @( X# a3 ]2 K/ P
    import"../../AddressUtils.sol";; F! d% j1 a. }! S* U
* W, \# h7 B# ~1 J3 C
    /**5 j: [5 Y# f/ Z" ]6 Q2 R" {% ]
# [" t% E; `' E
    *@titleERC721标准基本实现# }6 D" D- c3 Y
3 S2 t' ~0 q+ M& u( z  @
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
  ]1 G  Z- v5 K+ |* W
* ~( _& B9 y& e3 |6 H5 @! @    */
6 @0 _9 T( D# ~) K( Z% o& x8 _, {& V% B
    contractERC721BasicTokenisERC721Basic{+ D/ I2 J( C- M& z  H/ P

4 @6 D, j- T( P1 s" ^. Q    usingSafeMathforuint256;4 J! X, Y3 d# p: X" q  }7 c- F
+ ~, e/ L0 b& j1 r( f7 n
    usingAddressUtilsforaddress;
' S7 _2 N# n) x7 r* W* t! o1 |4 p5 j
  U8 m5 R& _" j# R5 h4 Y! |    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`3 ?8 r: I& \. T

0 n8 L1 D4 l5 v8 k( f8 R    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`+ K# N4 ^% v" t9 D1 S1 ?, C
9 _1 n2 U5 G, o. B1 U
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;! g6 ~# l( W# s( k1 w2 `
2 @& g+ Z: j, l: k# g% G7 n4 N
    //tokenID到持有人owner的映射. T* e6 a9 M! t; u* F2 F. ]2 g! x
  G# {3 B1 h; ^; R, A
    mapping(uint256=>address)internaltokenOwner;2 _( @0 D7 D* K# w9 d

, N& x4 w- b" N1 r' A. m; T    //tokenID到授权地址address的映射; l  X  T9 q" d6 B" Z1 {& D0 X. w
5 L2 E3 x) U" O6 ^$ H2 g7 z' |; V2 M
    mapping(uint256=>address)internaltokenApprovals;
6 g) ?$ e5 w7 z
0 G9 t: n/ n0 b2 U- X- u' ~    //持有人到持有的token数量的映射
$ M8 ^. o' [$ P7 L! {% G& o# w5 a7 a- y& p7 J9 B. y' |1 _5 t  {
    mapping(address=>uint256)internalownedTokensCount;
2 U$ K% p3 P* K  g' n7 [0 U
4 A  v$ Y: M" C) p% Y' s    //持有人到操作人授权的映射
1 ?2 e+ [4 r$ L6 V7 p) ?. U8 \( b! C% D+ [
    mapping(address=>mapping(address=>bool))internaloperatorApprovals;2 n. h* G  s5 c

3 L: ~5 u; x  i    /**
  V9 u) h1 f1 L. @" k# ^) r3 m5 X8 Y5 |) V- c  J5 i- h% t& ^7 Z
    *@dev确保msg.sender是tokenId的持有人5 K; W! x8 J4 I' s4 {

9 H0 ~4 ]% v! ?$ z+ l. M    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender
' Z, {9 _; \) s- P( D4 [. K- {) P) j' w3 u
    */
  b1 q/ \9 s+ l
  T$ C# \. i6 W7 {. C0 Z    modifieronlyOwnerOf(uint256_tokenId){7 B+ |( B6 j& \  {. d

) D. B+ ~" g8 W8 d    require(ownerOf(_tokenId)==msg.sender);, n5 \2 |6 l0 N  Z% ~0 ^$ y- \
& d6 ]  ~& ?# ^$ V- x; i
    _;
# @! V) ~( \  e9 ~/ j( K8 Y" S! ]1 I
    }
3 |; F; \5 Q  O6 F, ?/ K
9 ?7 s1 _% K7 W3 i/ L3 u0 `    /**
- s( d' S$ d1 H2 G& a
" S- R7 Z4 q$ Y) M" C/ T    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token# q5 E& o& ~2 o0 p' y; D( ^! x
5 A/ V6 b: ?0 ~8 W  N/ u
    *@param_tokenIduint256IDofthetokentovalidate
# Z6 H: ~5 B5 `) G" l$ \- E: a9 s
    */, ?* s( Y! W# v% K
! G" |% w8 R" J5 X% m- i6 {+ D
    modifiercanTransfer(uint256_tokenId){* \- f! N0 N# A$ _  `4 T6 q
# \2 Q  L; G. l; e2 z9 [
    require(isApprovedOrOwner(msg.sender,_tokenId));
0 x, J. Q* ~7 H6 A; _3 B, q
# M, i) X: F! i& U" ]$ ~) C7 X& @    _;
% ^" ~) W: j5 x) L7 z
, l& m; |0 Q2 X    }$ q$ U* Z: o6 R/ M$ o
1 j; F( k8 A* F4 P
    /**
+ d: W( o/ H1 W% y. n# i- c3 I
* u' L5 u% d- U8 L    *@dev获取持有者的代币总数7 {  K7 `! I% q: C# g' C! L- ]& P
9 X# f+ {1 @& Z" s  P8 c
    *@param_owneraddresstoquerythebalanceof$ F( E! u0 [5 x

3 m1 i  H& Z, l" C* c3 ?( i: O    *@returnuint256representingtheamountownedbythepassedaddress) B  C0 C% T1 ?) w
2 B* h; k+ p# q+ J) S/ w) [
    */$ n9 X7 p# {6 u) z% Z* k  s
4 y; T4 r0 D/ L/ r; e& y
    functionbalanceOf(address_owner)publicviewreturns(uint256){
- y8 v' Q1 x9 M2 V- C: y5 i8 I, k
' t$ c5 C& a# t; }4 H    require(_owner!=address(0));2 i$ ~* j5 H' r6 g
! {9 r2 e/ i0 F
    returnownedTokensCount[_owner];
" ?! Y6 g4 X; o: V6 K; F, i$ {1 Z+ j3 j& r2 v8 Q6 H$ U2 A
    }
3 A2 J( H4 V/ n2 L# y" }7 W
8 s  t# k0 l! M& Y0 S, [    /**: ~, F; b' L, x" z7 F' X) D
! ?0 I% A: I0 ]6 p9 |
    *@dev根据tokenID获取持有者
# [1 m+ {# ^0 t% u/ F  O; k
+ d9 y5 l- t) p2 D4 H5 ?    *@param_tokenIduint256IDofthetokentoquerytheownerof7 v3 b- K1 V4 i& O

1 T# Q( i) V: W, `. H6 n* ?    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID- }* _8 c9 V& x' `( x) S# {7 N0 }& s/ f

5 B2 h9 d- o# l; U) G; `- J8 T  C    */9 `* D/ c! B! i* D  y6 `9 ]5 N

* Y7 k" G6 m( x3 \# [    functionownerOf(uint256_tokenId)publicviewreturns(address){
" _4 [3 }$ k) T, }6 Z
5 o% n. g9 M9 B+ B( }5 m+ T    addressowner=tokenOwner[_tokenId];, c- }- q" [% M- U

% s3 B6 f) a' f8 {+ `% G1 V0 l& f    require(owner!=address(0));
; k% r4 d( g, N( p* x4 ^3 D( e* i; i/ q: U8 j
    returnowner;- u! e5 F0 x6 d3 |( c: [
; W3 N( h0 ^$ u
    }& P! X' J; ?2 k* U

- P' N% u, G$ K+ e% j    /**! w' ~" J3 j% M0 h

. ?7 i! P* L  B0 }0 F% o    *@dev指定的token是否存在$ M. x$ J& N/ P  D% Y% B
% f2 I* `8 L) ~* H
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
* S  e. m' k0 [, h8 p: P9 J3 w7 S9 g* _6 Z  s" s9 W4 E. n' z) G7 d. o
    *@returnwhetherthetokenexists
, Q$ t4 X+ @, c+ ]
9 B3 X$ I; Z/ U    *// K1 t7 A3 A0 L5 Z% G

7 o+ i- J5 W. k0 ?* S    functionexists(uint256_tokenId)publicviewreturns(bool){
  y1 s2 r$ j2 W' X5 X
, R5 ^5 i7 u5 i( @    addressowner=tokenOwner[_tokenId];
( n& z& E/ t4 H! ^9 u$ O, ^0 f# p' ]. x2 T
    returnowner!=address(0);6 {& {; ~, e7 j9 P8 j( w) T
8 Z4 T& P8 x8 Q3 e
    }5 U/ |7 u' g* A. X! E. H

* z8 K4 ?# A: m- o/ e' H1 U2 b    /**9 ?; b' L% T' B2 W! a4 F, G1 w' z
4 t6 Q) c; K, g1 D0 @1 x
    *@dev批准另一个人address来交易指定的代币
0 \) g% G' R  X2 s& Z$ ~. c& }- V! ]  O3 ^& n) D) |5 p! c
    *@dev0address表示没有授权的地址
1 l1 o/ D: i. [: ]- M( X" Q; `/ d  ^; D5 R' G
    *@dev给定的时间内,一个token只能有一个批准的地址
# _( G# ^9 i7 D  ?7 @
5 I5 K" w* M# a# n* ?7 k    *@dev只有token的持有者或者授权的操作人才可以调用
3 L( p" X3 A# S6 g% j; \4 s( @
! i  e9 n/ F% O$ z/ G" g    *@param_toaddresstobeapprovedforthegiventokenID: m5 h, E% [( a7 b2 p: p
! l( Q. Z* X" j- C0 }2 k
    *@param_tokenIduint256IDofthetokentobeapproved
% A3 X: g9 }) m, k3 y9 }/ I' l% k! I5 O( b! Y+ J% x
    */
! L3 `9 t" o9 V* Q0 x, Q6 \5 E
, r# P+ f: F3 ^8 x/ |7 Y    functionapprove(address_to,uint256_tokenId)public{
7 j4 a, X5 d' A+ E8 J
8 h2 S$ n9 N; v" ~# l0 F0 X    addressowner=ownerOf(_tokenId);# N7 Q( h( w9 k% `1 i9 y

6 b$ J/ |6 o5 n) J1 |( `, u2 u$ m    require(_to!=owner);# \' z: K' }) k$ l3 q. e9 [6 q
3 }4 k; Z8 r% m" e3 ~3 f$ ~
    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));
* }. |6 G( k' [6 e2 ~0 w- Y
- p+ `& f5 H  z/ O2 p    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
1 H( U+ T$ b. o1 k% L
$ `) M% A) Y6 m/ u1 d9 x7 c    tokenApprovals[_tokenId]=_to;3 Z6 K5 z. W  B  |. s' V2 M

3 m# K" X3 C7 W' q/ [    emitApproval(owner,_to,_tokenId);
  E! n- d, y' }9 n) B9 I
9 `3 V. t& A( u3 w4 G0 z4 m% u    }8 V+ a2 V+ {' q5 H8 z" D: R5 C0 L* v

5 _0 B4 ^% i7 i1 D0 A    }8 P/ o$ `5 o* z

& X! r& i( Z7 q7 B0 b    /**
: G4 Y* ^% Z% t6 c1 Z4 G6 w! b0 ?3 o" u  s# ]
    *@dev获取token被授权的地址,如果没有设置地址则为05 q# k/ a! f! e( D. p/ n, u
8 X* `4 P% |* a" @" V! Y
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof
; m4 U; _2 j/ B0 X' g
( N0 {) h$ `3 |2 O0 w. V; _" ?    *@returnaddresscurrentlyapprovedforthegiventokenID
! J  _: u5 e' S( h, q6 S5 n" A: K, r
    */4 R2 @8 o; }( N4 ?6 z8 u

* ]7 }( x: s& n7 \    functiongetApproved(uint256_tokenId)publicviewreturns(address){) N/ D' J4 S3 i# B9 e  T3 B
; u/ U. L, m6 X
    returntokenApprovals[_tokenId];8 P5 J4 {3 ]) E1 {3 ^4 o

+ r5 i4 P! E% D    }% U! o0 K: T% \3 Y' L* I

, E+ F  J& J0 ~8 l    /**
( h4 v$ c7 y8 O4 Y( J5 t
3 u& F- J. E3 L: G0 U    *@dev设置或者取消对操作人的授权
, o* g, \( L- i$ [6 T* J$ a# Z2 Z/ U" O) B) J) Z' l* D
    *@dev一个操作人可以代表他们转让发送者的所有token8 o8 b/ I  A7 R. ]% N3 Z8 [, A

0 o' K8 R# Q" d' k    *@param_tooperatoraddresstosettheapproval. ?8 R* c1 p4 A! I5 N+ U

4 h; _+ ^: F! i9 q' _, t6 k! Q    *@param_approvedrepresentingthestatusoftheapprovaltobeset  K( l) p; v: b9 Q4 V  m

( w# J' }! W+ b* M# L: v    */% x9 X5 Z" ^; r- ~' g; }

" h5 {* S5 p( t" n; H3 H* q( m    functionsetApprovalForAll(address_to,bool_approved)public{+ J8 o* U1 A/ Q8 r* ]$ e4 |. r

; x# z5 z; i  k9 O% k    require(_to!=msg.sender);7 v& d2 D5 q, b' O1 h

$ H" I4 P/ O. r; L7 g& m+ c$ _    operatorApprovals[msg.sender][_to]=_approved;
* _' l- g1 B2 R- R0 z% @. W
, P! H* Y* u# \3 @/ p    emitApprovalForAll(msg.sender,_to,_approved);
, \+ Y  R6 |( g/ |6 G7 y' C: @
1 j- E7 H* X* u+ r7 j    }
5 A5 B* C2 W" U) L: D8 v# d1 l9 J# g. l. G! W: M, b4 z
    /**
# x! L5 I/ s' v: T2 [5 R' _, Q' Z6 _' s; ^* O0 h
    *@dev查询是否操作人被指定的持有者授权
- P8 x8 `! y* F3 h* e9 \) a! R! W. \
5 W: s8 V7 I1 b2 b3 O! M    *@param_owner要查询的授权人地址
4 ~5 G, A; G; n- z& m( ^( Y/ u
% w6 i0 z$ x3 o9 `% k    *@param_operator要查询的授权操作人地址
% K$ [9 t4 ~$ h) h( n7 S
9 u* Y5 z' F% y' ~    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner
8 t2 _2 ~7 G! n3 v& Z$ M$ X* X& T# w7 ?) u
    */
2 |7 B; x* [& Y& R0 D2 y$ N6 v0 i! Y+ t3 x" e
    functionisApprovedForAll(
, y" B4 r  C1 @; y4 m0 @* X% i* _% y5 J" p( e5 z6 {8 X
    address_owner,
0 |3 B: c3 }' c+ L& S
6 q& [4 H/ e9 |, \! I5 }    address_operator
; X5 [9 X) H, o! N8 }  `7 r
1 z' C' f% H$ s0 b' n# j. e& d  ]    )7 J: t% I; {3 Q1 Q
+ O$ k* G7 t8 F% K, c
    public- P2 M$ \. u# b5 l# |# a
" s" R. ]8 V6 N$ d- ~' W2 S
    view
4 c% x' S/ d0 S; ]0 a! ^7 W3 r- @, a2 {$ I7 x' v
    returns(bool)
6 D* n/ l7 q" f' g- `9 N4 |- ^
5 p1 R- }- y6 C. _    {
6 z! M6 [9 Q" g; ~
1 x: G/ T6 Q% x& w3 ~7 d    returnoperatorApprovals[_owner][_operator];. B0 I! Z* }2 i
6 o9 |; \& ]) f- x: {" q
    }
* n% D# }$ d" p: A8 m
- K1 s" s/ S2 ^! z    /**
0 h" y5 i4 L0 y" O" |) c5 n' K4 v  F/ @
    *@dev将指定的token所有权转移给另外一个地址- `7 y2 A" y) b" i1 n' M* I5 Z

" p9 n6 l+ s9 @- W- f    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`6 D+ j4 a! d+ ]9 a
0 c3 L* Y2 J/ Y' M
    *@dev要求msg.sender必须为所有者,已授权或者操作人3 W# q$ m/ C. P' ?7 Z5 ^) ]
% [5 d2 p" z  V: ~3 |
    *@param_fromcurrentownerofthetoken
. F; }* ~- d* d9 ?; s3 q, q# B0 k6 i; U: R& i
    *@param_toaddresstoreceivetheownershipofthegiventokenID
# N2 `" ]0 J7 g9 v; o; h6 C/ ]
% d7 n/ l8 [0 Q& a2 l$ y: w; S    *@param_tokenIduint256IDofthetokentobetransferred! k2 E; s/ L. u3 I7 ?5 `

9 _3 f( Q0 i. }% {& N    */
% {" t9 o: I: L" a6 [# }+ C5 U$ j; D* Y% R2 z2 E  a" w
    functiontransferFrom(" j' p3 L3 P! n: G! o: j8 p- p

5 F8 e2 g8 L2 w/ r9 {# l* [    address_from,
4 m: {5 r. E: u( h; G" }" i4 ~- Q- t. G6 ^2 ?) \/ e. m
    address_to,
. F% T' u" U8 }1 y- `; O# c  i3 Y
, Q* v0 {! k% R& @; i, y& o    uint256_tokenId/ o( `9 }3 o  c5 q" c, }6 O

' n6 x1 a  @& s* {/ \    )
  y+ n& ~1 x( o- B0 V6 q& ^' o% J& a8 ~+ W: ~; E
    public
+ q6 ^# Y4 J8 `- G
% G! g7 i3 M3 F: d- E9 {- D0 k  I( c    canTransfer(_tokenId)
( V( ]0 {7 j1 v9 n) o( A3 M3 P- o2 [8 R: w( Z6 G( d0 t& e0 X% A
    {, z% R7 i, w7 ~' i) R3 b* L

9 t0 F; a' E) O/ H2 q    require(_from!=address(0));6 A1 j/ `: w& n1 C

* p& y8 q9 J# J1 Q    require(_to!=address(0));
9 o* I# G" J& L: y7 h# s
8 b- p/ v7 S4 b& Q4 S. ^    clearApproval(_from,_tokenId);/ \5 y! V9 v* @- O) j

  T7 o5 W3 W8 p% s% p    removeTokenFrom(_from,_tokenId);! e0 C: @0 l9 n7 @" I5 T
) U3 \# v& L$ e' c/ x- }
    addTokenTo(_to,_tokenId);( I0 a0 q: M) C- g+ O' M$ D

, [, H5 S# U' N8 c    emitTransfer(_from,_to,_tokenId);' ?5 h4 G$ }0 C' U7 n  C, X

9 g/ D$ `6 q. E2 b' ?# a2 m    }
% D3 p* S" ]8 l2 N4 O! D
  E2 S% [; I+ s5 T6 O/ K    /**8 f& c  ]" s: ^0 B4 ?2 A
" z& H/ U% H  p3 @
    *@dev更安全的方法,将指定的token所有权转移给另外一个地址8 P+ Z. ]' N8 O3 }
. H4 k5 [7 a% {( p( v4 P" _! G) Q+ D
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值+ m; S2 M( N, ~' J% D( n

# h  N2 o6 ?  j& D" R  V2 C    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原( r: G3 |' Q  d

& V7 m" |& `0 i; N    *@dev要求msg.sender必须为所有者,已授权或者操作人& S. g+ b) X2 ^: S( C" _

: \& z4 |* q! L- y* g1 ^. y" ?* A    *@param_fromcurrentownerofthetoken
4 w3 V- Q& U! n! e6 L3 K6 }( o+ v- i$ A& z7 }- s* N: o
    *@param_toaddresstoreceivetheownershipofthegiventokenID
; W" _  J7 c  {# F. ~7 {3 v$ W0 d4 R" Y  v* \) r
    *@param_tokenIduint256IDofthetokentobetransferred& u- i5 U% W$ S+ B8 l' c: I+ d5 @- N6 a! P

+ _( t, x( R6 n0 J0 J" X    */& f  S6 y8 @0 z7 M: A' i/ S

. t9 Q$ H, ]; @6 ^# i/ z0 x0 M    functionsafeTransferFrom(; x- w" w* w1 Y2 P# r, }+ N$ C
, P6 {' x8 s" W$ O3 J6 k
    address_from,
2 w' u1 q$ K! B+ ^/ P. Z
* N) \" X8 [" }& [    address_to,
( n2 X: H: u  l& f: Z
7 W& f; j! q8 Y! Y6 w$ D& e    uint256_tokenId4 i+ x6 l, m1 F* M0 ~- \

0 a4 J5 Z7 ^* M3 m8 a' a) x5 W: _( e    )
0 @* c, n  R0 `" \
/ D% E' r; ]" c! `    public4 r( |: X$ M% ]; K$ n8 z* n/ a

* @/ ~5 z- H& W1 ~/ {5 j6 D    canTransfer(_tokenId)0 `( ~" }% n+ o4 l1 z1 t

; A6 B" L" H: n8 E; R: g9 r( d    {0 y4 _* p( G$ g0 C* t

/ h3 m4 O+ @3 |$ K4 v- N* B    safeTransferFrom(_from,_to,_tokenId,"");5 c) ~3 S( z5 e5 l- N1 p0 r+ N3 M& J% o
& K+ N% H1 q. z, E1 Z% u
    }2 C) F5 E' G+ c5 G1 j. T! \

: p, B+ }5 V! U$ @6 k" q7 j+ x7 m& [    /**
: J# S, ~% k( _" S8 }9 O
, R0 _7 P: v) s# V    *@dev更安全的方法,将指定的token所有权转移给另外一个地址0 a) @' W8 ?& B( a9 d
$ k: W) c! `8 }" K/ N
    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
3 g& x6 I5 k9 [+ ~* T1 \3 O
! v$ {8 z2 E1 l% g" p9 P    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
4 y/ ^/ F! `, A( e6 ?1 {
8 ]! C" z( t, V6 z) ^* u- Y    *@dev要求msg.sender必须为所有者,已授权或者操作人1 q9 q  Y# \  U1 {
# @9 W" _. W5 D. Y! D1 B
    *@param_fromcurrentownerofthetoken4 b% J4 n: ^" s+ Q

! J" ~6 ^  T, H5 L! E: K    *@param_toaddresstoreceivetheownershipofthegiventokenID
) @3 I4 k7 G/ r7 o% D1 s: w7 Y* L/ I  @8 B# b: i7 B: o
    *@param_tokenIduint256IDofthetokentobetransferred
- w9 X8 r* g% [$ f% g
: N) Y4 R6 m8 N3 W. W( X    *@param_databytesdatatosendalongwithasafetransfercheck" n2 X2 @' R# I6 d% Q/ X
8 y. [1 p* n3 {/ o( S
    */
- h. S0 O8 A8 Y$ D: W
' j- l) P! s1 W    functionsafeTransferFrom(+ I4 q3 Q8 e& k# U" d

2 C2 @% P5 k1 v  ~6 ^& V    address_from,3 f' e5 O& S9 m  J! m* K* a
/ G; P2 t0 F( m( F- c  \, o2 C
    address_to,
* p6 }, i% @1 ?
" u& M. k* z& P    uint256_tokenId,
7 \1 @* Y, K4 v& I, J% O4 l  K+ h
( k8 {7 ~  J9 N4 k7 x4 e    bytes_data
+ D% h9 C2 k& G+ u4 K* b! R5 [$ `8 a
    )
( Q* g+ U4 z" n
$ ?# e! C# b' m" e1 Z    public  ?) U; n) R, u6 t

- K3 r1 I- x8 m1 a1 r    canTransfer(_tokenId)
& u* T, \/ U: y* m- P: f5 K4 `3 H; l9 j. j" O" r: ^
    {
+ Q6 O7 r& y% S5 O: g1 B4 m% T3 N8 C# w8 a6 M; o
    transferFrom(_from,_to,_tokenId);) e9 c9 S1 Z" X- F1 G% _) a
6 X: a4 a9 [5 M" r' h
    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
1 v/ p; G/ H5 ]( z: ~9 Y/ _- n/ s2 m3 R* _+ W
    }
% S2 F( G) [5 o
: E, I6 a8 D- I: f% b0 g    /**8 T: Q$ B* U- d- M% G2 t" q
3 }+ K- R4 A# U0 b; Y$ c
    *@dev返回给定的spender是否可以交易一个给定的token
  h) X8 T/ Y  i, n& \4 h! Y1 o+ F7 r- @8 W5 h- Q, R. e& Z# f
    *@param_spenderaddressofthespendertoquery/ [; Z* c* f9 }' P
( O- y. w) R* ]1 W
    *@param_tokenIduint256IDofthetokentobetransferred
( }+ n7 r# e3 X( w3 B7 G0 j3 |% E! r2 _, g5 [2 X
    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,# b1 v! C6 z* H/ m+ w( k# |

7 x$ K2 C2 `7 P) Z4 r    *isanoperatoroftheowner,oristheownerofthetoken! l) n# G- A6 Y* ?; y) F

$ h: r4 K: e) z: }# S# W8 j    */- O  M% E  p: r! e: L

$ v( l! ]) U1 G; N9 ]; ]    functionisApprovedOrOwner(
( Q. x3 ?1 p' r4 s* z9 X  M% O# j8 i
    address_spender," W/ \2 O- {3 I- W, I. N5 D3 }# s
/ y8 f) Z+ F" |# {. `* |& }+ z  T
    uint256_tokenId9 x8 D* q2 X& d3 r. w

& U0 E/ X5 P5 C1 Z& t2 e$ Z# @    )
6 e- G& @9 |3 ~' t! G  {. O& r8 D8 G' }5 t+ |/ a  D8 e
    internal. W5 z( p( k% [. \
7 Y2 A/ g" [( E/ X4 a  L
    view
& r5 u; O; U* v% Z8 }+ Z8 F# R; j
8 b* E* m4 C. N    returns(bool)
2 R, s6 B0 f& v; a: H7 S7 h& z* T6 J4 Z( \: o
    {
! M; U% v# E" Q9 H. E' v
+ h: U" q- S* D& x% `2 G    addressowner=ownerOf(_tokenId);
. ~0 h! a; E+ ^0 l  K4 O
) {* ]8 G2 f' v" L; v9 k    return(
9 S, g( v; L( [
6 q2 i" n6 V9 q; s6 \$ m; }    _spender==owner||& ^4 h$ n: ^4 ?7 a" I% g+ r
3 ]. K% B, L2 D' a8 L
    getApproved(_tokenId)==_spender||. w& J* K2 J1 `# L: \( L3 C

7 \- o' X; v0 F- ~    isApprovedForAll(owner,_spender)
: f# Q) f+ ~- M' n5 W& v0 v
$ `' v$ v/ G) e    );3 K6 _+ j9 H! b. _. g4 p; f: k
* D7 [% f$ L% B6 z9 `& c9 y, S
    }
+ y, F* k: P" Y+ u2 i" q* {5 p/ X
    /**
4 b% B& M4 S$ o) t) X
! z5 e3 w8 j9 d    *@dev增发一个新token的内部方法
2 U/ h7 z/ a1 w1 [3 F8 i
' L  S3 U- d9 |8 ]4 {9 c5 B. [    *@dev如果增发的token已经存在则撤销
2 U8 f$ X& M; F0 \2 |2 Y/ M8 F% t6 b( T8 t5 r  s/ x, ^. a
    *@param_toTheaddressthatwillownthemintedtoken
4 ]3 ^$ `2 }3 K; b0 [- Y* ~0 H( H, P) c( r1 S2 B# e* Z
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender8 Y  q+ ~, K: z4 u3 e0 F, O6 c2 k: K

0 U3 [/ W+ ~; p$ ^/ u: \- e, @    */
3 W, X8 k" c2 J. s9 u
: \% j4 ]' o1 Y4 v5 t    function_mint(address_to,uint256_tokenId)internal{6 y0 u$ T& P5 _/ U; p
0 H( t# d( s# q* _" _) I0 H' h) l' y
    require(_to!=address(0));& r6 `- Z9 x2 J- V

# x( E5 H' u4 a* H) g0 F9 c    addTokenTo(_to,_tokenId);
! E! b* L$ ^& t( ~% y. c
/ {9 q7 s  P( P% u1 X% q6 `! S% i  T    emitTransfer(address(0),_to,_tokenId);
6 j- N8 t4 N6 _2 C
" `: J1 \0 l7 L' V6 y    }% ~: H$ k8 |2 C: u" b) ~

; q3 n+ P$ J# r+ ?    /*** _5 s6 m& J6 }0 `# D

9 l9 ?8 z. v& z6 G( b# m    *@dev销毁一个token的内部方法
4 q  x* e/ i1 r; n- b
* i2 k. }8 x) P$ P  B    *@dev如果token不存在则撤销( S# O( f! c! X

8 M$ e) v+ t" t. V+ ?7 ?$ B% h  G7 c    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender
9 Q0 q% n4 V% E/ M9 R# r4 A
! I* e4 h; S9 Z9 S1 ~# C+ H2 V    */
" Z! {  l* ]( L/ V7 M1 H; @+ ^! C8 D
8 }5 J+ c, g- Q& l" k    function_burn(address_owner,uint256_tokenId)internal{5 e  Q' n9 L2 P1 I4 |8 ~, A4 D
2 X! ~* p+ _7 j7 Z
    clearApproval(_owner,_tokenId);3 B' p5 A: y5 s6 m; g  d# D8 x
& E, H1 D9 e% g3 O0 g, @) v# g( h
    removeTokenFrom(_owner,_tokenId);
; R0 F+ `' \( s( u2 a7 G( t9 K6 q
: g! l) m) n6 f7 p4 I1 L    emitTransfer(_owner,address(0),_tokenId);
" W0 z+ B3 ]% X2 s. ~- Q
8 {9 h# c% u* E2 A- r    }
, V& ^) T( [' p. z: b9 Y. I+ v/ u* M% n2 R& t8 s+ C
    /**
! d7 Y& \' |' Q& _# e" }! U4 V9 [# Q5 c: V/ T5 K1 H
    *@dev清除当前的给定token的授权,内部方法
$ t1 h8 Y- M: P2 l
7 }5 X% k3 j8 X& ?( Z( N    *@dev如果给定地址不是token的持有者则撤销
- o9 o: W* y& G& u: c$ U% r8 N" a. z$ W  ~7 {% x
    *@param_ownerownerofthetoken  B4 P, H$ s& q( G2 ~, Z

# M; X0 v4 y. {# L4 r; q    *@param_tokenIduint256IDofthetokentobetransferred
% C5 T( Q* H! N' |7 Y$ y  n$ j4 X# j: {! ]- C4 A7 D
    */5 R& ^$ c: L7 F, n# I7 ~

* H8 i& j. }, o7 Q! S    functionclearApproval(address_owner,uint256_tokenId)internal{* I* I/ j* t5 F
* h/ _' D# T+ v3 s  R
    require(ownerOf(_tokenId)==_owner);
$ F/ }0 \, k  V: z- d% x
: j5 ]8 _) S2 W" ]    if(tokenApprovals[_tokenId]!=address(0)){
, I8 U$ V5 t7 p
% T* s! f+ ^) R7 R- m9 R    tokenApprovals[_tokenId]=address(0);
; l+ H  C9 L" C( Y- S
  B- p% n! M0 {) }) p7 S    emitApproval(_owner,address(0),_tokenId);
2 u; Y- M. s% F! ~/ P* ?- j4 m9 B/ {2 C# \% N8 g- ?
    }
0 Z! ^- n; k5 f& G# F2 K, s* ~
    }6 t" E! S0 g, s( A, w4 w; x

2 g/ n( H/ {9 r  |" _% k+ j: L    /**( ]3 a: G" r1 A3 K

* G7 U; b% X4 j' @. z    *@dev内部方法,将给定的token添加到给定地址列表中
8 S' y' {$ y* h$ s8 d. E7 w
& ]" H5 B9 {  D' G1 D    *@param_toaddress指定token的新所有者# C: u& o; w% D0 }/ A

6 E; u' r5 q& m, z" g    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress( f; u( l5 V! S

0 c# g" Z7 B9 U4 `9 H* h1 w& a    */
! S  _; v+ e5 P* y8 j
1 T( `/ I- ?* p    functionaddTokenTo(address_to,uint256_tokenId)internal{
# X9 U5 Q7 v6 x2 d: G' q
' T- r2 _; G4 z    require(tokenOwner[_tokenId]==address(0));* S, Q) Z4 Q, c6 e7 z/ s: a6 ]8 V

1 z7 l3 F7 s$ g8 y4 |    tokenOwner[_tokenId]=_to;+ F) h5 b  X8 _* F; I1 f

; W+ y' w7 T4 M! p; `    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
2 t: U' {% i& D
  w! f: _* y7 w    }" k. p( c4 A$ p# [/ F( K
- x+ ]. D$ I+ w' ]. W8 H+ e+ b% g
    /**2 B; y/ V7 c) H) c
, t8 W# [9 q8 G9 c# I
    *@dev内部方法,将给定的token从地址列表中移除
2 f6 \/ e4 a6 ?+ M" E& B! a) b$ w; x6 L( e+ T0 F
    *@param_fromaddress给定token的之前持有中地址
' s( z) w3 \7 O
; q. R/ p7 B+ F, o! y+ G    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
2 n( r( S" k( ^! F( e. M
; q% J+ B4 V& E, p5 L* M' O    */0 |, {4 X4 }2 |/ ~& o5 v1 ?
) B( `+ E5 L' B* R9 ]3 q
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{1 ^9 X9 i4 D1 O
& [6 U3 ?3 [) _/ w; r8 v4 _, e' h
    require(ownerOf(_tokenId)==_from);% S2 N% [! J5 `- X3 M

$ W: N5 Q- ?& B$ U9 N7 l6 ^' ^    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);
+ _# E; v, n) k
2 [, @2 s6 F7 s3 P- V; u. k( j0 a    tokenOwner[_tokenId]=address(0);
' P  C5 D, ~( y7 C  Q" E7 s& F$ a( w" B/ g% \+ Y# r  B3 g1 u2 k
    }
: P3 @1 s' l% y7 D( Q9 L5 {: D2 x/ M5 ?% K  O1 ^- c$ r. _0 j: I) V
    /**% ~0 D# a, B8 D! b4 g

! y( e: `* F' I6 M0 c- q9 U    *@dev内部函数,调用目标地址上的`onERC721Received`' P+ `% Q( d+ `; x/ M, u& V
; n1 ~3 j+ i$ s* j7 Y5 n3 s" B
    *@dev如果目标地址不是合同则不执行调用( [6 i$ U$ l/ v

8 j6 o! `/ a. M: A. I% f    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID$ J4 ~& u3 z9 Z& c
! _2 C  H5 I! t0 I# @5 }2 h. O
    *@param_totargetaddressthatwillreceivethetokens+ _5 q; ]( k$ f# ~: o2 b1 c2 u

8 h0 z7 I" W0 [% _( C8 T    *@param_tokenIduint256IDofthetokentobetransferred% u- Z' z7 E! i- t! N/ G; v
' A) S7 A  a. m: d
    *@param_databytesoptionaldatatosendalongwiththecall
+ j5 G3 Q8 l4 W* }9 Y
  |' m  j& t9 s0 j. K' `: [" J    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
! h" C3 }# b, C4 x5 b! N
1 e8 d. A) R" z5 K1 H& H; R1 t    */
' a7 t' t; B8 F6 T
) i: u( g8 u" `6 F. ]/ G    functioncheckAndCallSafeTransfer(3 M# y! X( k# Z# v0 ?) v' r, I

- s# `1 q/ r( t" Y/ Z; W. s    address_from,$ q* |& E, \# h3 @6 Y
9 Y8 a, I3 g8 M* N: f) w
    address_to,
; W* p4 F6 R* O, f+ S: g- H/ S8 o3 T9 S5 J
    uint256_tokenId,7 x7 @1 U. w. G1 w

7 [/ w9 z) w' E( R/ Z* u, _) w! c    bytes_data. f$ Z4 }2 C' t# ?( G6 ]8 S

6 f: Y: n- e/ Z. T( P6 b    )
% W% V% p! [: F) p3 U; d% o8 J7 G. k  P. E
    internal" Y& @8 q) D; d3 q0 b" h

: m+ e* |5 W' _4 u) y) E+ O4 U8 ~1 Z    returns(bool)
, `9 s" V9 d/ e
& ^: j3 h3 R: q6 M6 L' `5 m    {# U* T( Y3 s( a+ H# K' C
# H: V8 H4 @* R7 j. a
    if(!_to.isContract()){
, l, n6 w6 |" E/ L& H
! E. n0 A6 x6 p: _3 @6 B/ O    returntrue;
+ N2 S" F  U, k
0 i: ~. E: ~$ i& v$ v' f1 x, \    }) ~$ M5 S( e* T+ a" F

' {7 b  t' N; u, B+ U4 \    bytes4retval=ERC721Receiver(_to).onERC721Received(
/ c% D) C9 l1 c! q
+ U3 c0 t+ l8 g. s' {! P    _from,_tokenId,_data);
1 [: z/ W1 R2 M3 k- `# m# _. @9 D
/ ]2 L8 }  w8 n3 n7 B$ v9 t6 h    return(retval==ERC721_RECEIVED);. s" b- l9 e6 C1 x$ ~- }
2 F3 s+ _  {3 L/ X
    }+ A. q) t: U3 C8 u2 g: z7 s
3 h8 |4 O5 m1 g" d. f/ H, b
    }2 ]( o$ C- ]  |  n) N5 v
* H+ I9 O$ L4 o$ u
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
5 v5 U% s" \9 |
- l& U. j$ x; x, z    ERC721Token.sol8 u* k' A& K$ R$ D; D
. D9 o% s. R" ~* M
    pragmasolidity^0.4.23;
9 X! w8 U! {  I$ Z0 V% N) n; q
/ S9 b4 n9 v" Q3 ?" J! N    import"./ERC721.sol";: P% q3 U9 M8 U3 {. z+ N7 G. z

6 Z9 i) r- S% i6 y' ~% ^    import"./ERC721BasicToken.sol";
4 B4 k2 [1 i1 U' ~
% L) K3 U9 J. m: X    /**
7 g. \7 s! {9 P5 L, N
3 s/ ^) n$ J) B2 N' B: Q$ V    *@title完整ERC721Token
5 u: j6 Z2 V' L4 F! f* \
! D# |; q* N) {4 y4 {( l    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能; T8 H) I. R3 t, p' m0 h; K

3 C9 [$ J9 G0 @0 k    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md9 n9 c% l1 K% b. V' E8 S

+ T; r" R7 U) v$ |9 E: y! Q    */
' w8 T9 H/ f, n8 U/ \+ O# p( [" b0 X- P9 p+ L3 J4 I3 a
    contractERC721TokenisERC721,ERC721BasicToken{
$ }) u9 f; C$ ^9 S) }2 E
, q* B. c( H8 g& g. i$ L' {! x    //代币名称, r) H/ X/ |( F! Q
" W8 z  ?9 }: W' D7 p4 d- k2 ^
    stringinternalname_;, u) k, r0 M7 p9 H% o; \. }8 S
3 L7 @( {1 h. m/ |) z6 B+ o% X
    //代币符号0 m% t* k. T  S

6 W- ], ?9 p4 i! b    stringinternalsymbol_;5 q; y( q, u& F7 F; |/ i9 E' ]; _
/ Q0 r# _% A& l7 k2 }' z% C
    //所有者到所有者拥有的代币列表的映射# R8 Q" R! w( S% a' Y' U
, X4 ]' M$ N! G0 J
    mapping(address=>uint256[])internalownedTokens;
1 `5 n1 h3 @! ~3 q2 v, c1 F) U; c# {- u, H% Y
    //所有者代币列表中代币ID到索引的映射' x1 d3 T& w5 R3 Y

$ z1 G0 a  l3 U6 H" v! b+ f0 c    mapping(uint256=>uint256)internalownedTokensIndex;( R3 T  j0 \0 j% }& |! x& h7 r

, R, m, L- H2 h    //保存所有代币ID的数组,用于枚举* x! Z% f! `3 U/ c* Q2 b
4 ?4 o4 d: b9 v  Q% a. e) f7 v0 w
    uint256[]internalallTokens;7 }( P$ n- a) m) b& w4 s7 Q( @2 W
* X2 Y( g5 J. d2 x3 H! ]
    //allTokens数组中代币ID到索引的映射2 {. b% v; ?) S
) Q( A# \% @3 v9 C, V+ v, m( U! j
    mapping(uint256=>uint256)internalallTokensIndex;
- O: B* N/ s8 p% V& \7 S; ^
& V+ o* ]+ P3 `  R# v  G    //可选的代币资源URIs映射' V/ ^, C+ Q* h$ k

0 x& M1 s: b5 r0 B2 T    mapping(uint256=>string)internaltokenURIs;; H" q0 `) F8 `( S0 X/ C& p6 }
  H; m1 n, |0 R3 d# C5 C$ G4 B2 G5 O
    /**$ F; O' h, `$ Q! a& w, x
! x4 I) o/ h2 N/ }
    *@devConstructorfunction2 U: I  w" I/ l
; S! ?9 q7 _5 q2 T9 K; `( c
    */
5 F) W* u! l7 i9 b
1 j( C. m1 G8 W% \6 l: W( R    constructor(string_name,string_symbol)public{
# b0 N6 U  Z9 N) @0 N
; f4 u5 q! R' u% C6 d% u; V4 [    name_=_name;: ~5 j( X8 p# k" D! \
; ?' ^6 b+ f9 w  o
    symbol_=_symbol;/ e  u# |) g2 s, H) z) P+ {

' b* [/ G: g* M; L0 T0 L( J- ~    }
/ @( D% g% ^. d8 \0 b7 H% b2 L) n. T% O' b9 ^5 v
    /**$ D9 p5 \3 P6 L" i6 y
- L& c9 C. w" r3 A3 b  d) @  b
    *@dev获取代币名称% [2 j  z- \1 z3 C+ B

0 m/ E4 N( t0 a1 C7 x    *@returnstringrepresentingthetokenname
7 s% l) v. G3 v3 J' k) I
! A& F' d6 I6 b+ t% r1 q    */
. {- d' ?7 T8 ~0 Y0 _4 Y( E
" w* J& ?/ }1 o2 L! H    functionname()publicviewreturns(string){
! Y: o4 [6 m& N2 b3 d9 q! U% H4 m
, C( x6 o4 v# Y7 `    returnname_;
+ M% t5 h' I+ E0 A5 j6 ^8 B1 @# F- P5 v- W& j6 g* M
    }
2 N3 s" o9 b; W  p8 w  o. P6 S4 e# U' X: S! b
    /**
  s6 r+ d4 I  t0 g1 y
7 T9 r8 [- K5 r* b& U    *@dev获取代币符号
1 V1 J3 F1 d- J. S' G
! d& w9 Q- d. m. C2 o  ~( K$ e    *@returnstringrepresentingthetokensymbol
7 _2 d- t& @7 x
- x# [0 K8 L- N- {- J    */) ?) y9 t- A6 X! q) J
/ T2 b8 L( n/ y: k
    functionsymbol()publicviewreturns(string){7 o, ~+ S- M8 Q9 z6 r& o( ?5 Q2 S1 u

2 [  R5 z4 J- L* D) W: [    returnsymbol_;
+ d: \) v7 ?' C7 i5 w8 P0 g+ v+ g9 I) s. h3 p4 N8 W# ^
    }
( D2 x2 U. s+ G% j. k- d9 y* r. D: }5 Y
    /**% V/ S$ h' `0 ~8 G, @* K

0 x6 q. a0 _0 g9 B/ g- }    *@dev根据_tokenId返回对应的资源URI0 e) N0 y( O% |' E9 c+ A

( z% u) F0 y# V    *@dev如果token不存在异常返回空字符串
* W7 R5 b7 @! T& F8 z4 s* T) n% m; P4 h  [) h1 Y
    *@param_tokenIduint256IDofthetokentoquery$ `) T+ H0 k" T& D, @! j
" h! J3 ]$ R% L4 p
    */: H) R$ H# d  `1 T* F/ i7 f

: g- I5 |* v  g- [/ w; ]( d1 ~    functiontokenURI(uint256_tokenId)publicviewreturns(string){
# a+ L- l1 D3 F0 z6 W  W/ v2 w! J
    require(exists(_tokenId));* O5 F, P& h( b6 m

# P3 o; j9 _+ H) ?9 G7 A8 L    returntokenURIs[_tokenId];, c0 W: v9 l8 K: Q

3 g+ H9 q$ X( i    }9 c4 h! J% ]. G7 B9 J$ Q: L
4 w: K2 M  v. g6 l5 m, m. `
    /**; O. z: U* k: K0 n( a; g( j& j5 q
2 G6 n7 B) W, s' x8 @( [
    *@dev获取tokenid通过给定的token列表中的索引
1 Y6 f1 c/ B6 m
! R9 R  _" b, K# K% x% C4 W2 f    *@param_owneraddressowningthetokenslisttobeaccessed3 u* K& E6 E# v0 J

7 |; r" d% W* T1 J5 U. o9 q    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist2 z4 A/ ?/ _+ w  C
- I; {; h3 b% Y6 e' p9 N0 I
    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
( k: S( ?( z1 F, u0 X/ y; T. u6 ]/ L/ a" `9 v, k
    */
) A6 e* `. _  X- M9 @& s' z5 \3 ?) x: `% K1 V% X3 l
    functiontokenOfOwnerByIndex(  e* o: a! i* h( Y) F9 l7 |, t
$ @7 N4 e" Z5 g( R; _& C
    address_owner,$ f5 l- a& Q: w9 ~. ?

) ]- M( D; O, H    uint256_index
* U  w* n# Q6 S  g2 h
* A! S" B0 [7 m- X, m- K    )0 D! s% j1 a; {5 \

1 C7 h* M9 y/ d0 {    public
) o7 d3 ?) q  Z1 {. @
( f1 T! ]% m8 K# w' q  u6 S& i+ J7 j    view1 d# U: G8 {4 d

6 z* W4 i6 q) h    returns(uint256)
& B. b( w% n3 T- Y
4 C6 F- l; V5 {    {
1 {2 q( c! K: P' J/ E. H2 G! N. P. o! D. i
    require(_index
1 _" ]$ v" \6 @$ |
1 p; |  ^8 h1 a! e2 l( l8 N7 W    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。( K# Z8 a* I% I* t) [% Z

% r) T! X: m4 k5 V    OpenZeppelinERC721源码分析到这里就结束了。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2