Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

OpenZeppelin ERC721源码分析

杨远枫冠
2477 0 0
ERC721官方简介是:Astandardinterfacefornon-fungibletokens,alsoknownasdeeds.也叫非同质代币,或者不可置换代币(NFTs)。提到ERC721,一个好理解的例子就是CryptoKitties迷恋猫,每一只猫都是独一无二的拥有不同基因,有收藏价值属性。ERC721对于虚拟资产收藏品领域会有很好的应用价值和市场需求。
4 k- C' a3 o& `( L( B: {" {+ d2 b. _! G( u
    它和ERC20有所不同,ERC721最小的单位为1无法再分割,代表独一无二的,针对不可置换的Token的智能合约标准接口。从ERC721标准草案中可以看到,兼容ERC20的方法有4个:name,symbol,totalSupply,balanceOf添加的新方法:ownerOf,takeOwnershipERC721还重写了approve和transfer。
0 t1 R0 r! u% F3 J1 W" f& Y4 M8 q. `" R: e
    ERC721Basic.sol
+ i7 |' w2 S) m. L" M) H- e8 A; C% T7 i; l. }" M, J/ }# l
    pragmasolidity^0.4.23;8 l0 O, r4 ^: [, G- m/ b" P

1 M: l3 {: z0 M& N6 h    /**# q$ l; ?* l8 g+ N& l
1 N' A% l; \0 V5 S- l4 I$ ?- ^
    *@titleERC721标准的基本接口& I1 E% }& ]3 [# _" n1 ?* G

; w, T  u/ d0 s* `    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
" q# Y! Q9 f) Z0 E4 l
+ O( u* {2 [5 W/ t$ o  @* u7 i    */0 Q1 G: {! n% r- {, s

0 n7 k3 s: L0 P    contractERC721Basic{! m* T2 ]9 I+ s1 w8 [0 B- R2 b
, c; ?+ K; M" o, m$ R
    eventTransfer(; @( }2 q  ?4 d
2 j9 E5 T, [! R2 g) Y
    addressindexed_from,$ A; j' }) G9 s) j
: o4 r  \) f/ y$ m* k
    addressindexed_to,
- t5 A0 q7 Z8 n
. N- U9 w8 u- p" Z    uint256_tokenId
3 [& K8 t  f5 M1 z4 `& t; B  a9 y
0 @, D& `4 _; A; B) o6 u' L$ y    );1 l" a7 v. A  E- M0 f: D
; c6 Y& N+ k# @- {8 u% X' e
    eventApproval(
6 I% b3 I5 I# h* r! r; f" B$ u, P/ s* b' X: d4 t* s0 q
    addressindexed_owner,! |( q  e. {$ f1 S. }, @$ N" S. o
/ _4 Y/ y+ Y# Z5 ?& ~
    addressindexed_approved,
2 q  F8 \) ~/ P" v: o6 g0 z
$ C+ t4 K  L# g% Y3 j- s; L- Z    uint256_tokenId
" |" S' m3 B! \7 e
+ `& W0 `8 l+ P    );
! L: U# r# q; d3 e* n! w# ~! t7 H3 w5 b* f" Z
    eventApprovalForAll(& T( J$ _& M! x- {
1 j9 ]9 u/ y3 U0 ~
    addressindexed_owner,
- S: k1 E6 \  i6 w! J6 X* A* k+ i1 r" P! }6 e
    addressindexed_operator,$ o+ ^: U9 P  e3 U# A* `& n0 P5 u
, e% j9 o( X, I, v" M1 U
    bool_approved
! S3 z; O8 n# D& W( Z! C9 m1 y, r' g% j2 Y( r9 \- M0 I7 r+ f; `
    );# r4 m! k5 N+ f+ {: _

$ F. R) D0 B, j2 `* b& l    functionbalanceOf(address_owner)publicviewreturns(uint256_balance);1 O5 x- N+ n/ Y1 d
+ ~) ^0 @& k0 T& v
    functionownerOf(uint256_tokenId)publicviewreturns(address_owner);5 h* q9 S/ |: X# B' \
' u1 `! z  n& y0 X9 F( c
    functionexists(uint256_tokenId)publicviewreturns(bool_exists);
& x: n" e% C: J  _
. r2 h- `4 @1 T9 j# l    functionapprove(address_to,uint256_tokenId)public;* j( L! U6 x# y( }+ B- A9 Z  [- d

+ F$ V$ r( {% z0 _8 Y    functiongetApproved(uint256_tokenId)' A3 q) A; y) s
9 ]; d" L5 y  F8 {4 `- ^3 e
    publicviewreturns(address_operator);
: {$ e9 m. ~0 n# o3 Z8 q% Z* v# P7 j  z
    functionsetApprovalForAll(address_operator,bool_approved)public;
1 |+ ^# ^6 E* N4 H2 a! ]- D# I) c) o8 d
    functionisApprovedForAll(address_owner,address_operator): W: h8 w( h! i8 z$ P

8 u0 u; R7 b2 l7 s; c* J0 B    publicviewreturns(bool);
  @* s$ B) y3 P* a: S7 s% @# C
3 V" H, @5 q3 {1 k7 ^2 r    functiontransferFrom(address_from,address_to,uint256_tokenId)public;3 N9 ^  m- L7 `

; R' |2 v' X+ g2 f. c# K    functionsafeTransferFrom(address_from,address_to,uint256_tokenId)1 c: d2 b/ ^0 @$ u! _) w

  r3 C" b' O, C: g% J6 `* k    public;& E6 {, B1 Q! V* j
/ ^8 T4 j- \% V# H# z' ?- e
    functionsafeTransferFrom(9 G( O9 H* p6 b+ F( ?2 l1 F  [+ T- c
% C& n  W, M3 h9 c
    address_from,
7 M  R) |  [  x" T; t, u5 w8 C4 n  S) k+ L6 i. y: }# {
    address_to,
6 c$ ~  w( P" Q) @$ p
6 T" m/ f; i1 \/ w    uint256_tokenId,  o( `. a( `% w  n4 H# x3 g- I" ?

# Y1 [$ J( t& `3 Z+ g$ |! J    bytes_data
2 G9 p- N5 ?6 ~- m: d3 A( J0 x' y6 J* Y8 n
    )% b0 P$ U" \4 c0 w; N
9 [; q, j$ k4 D+ b' V5 P
    public;* K" L3 z6 V$ [. l' G" v- Z) O; y
9 h, A& O$ G$ i
    }
" E7 `8 m) |: d/ a3 `8 i  i
5 u! b4 r# M7 M5 C    ERC721Basic合约定义了基本的接口方法:# \! T% ^; Z) M% ^' v1 u
- h3 d3 f' J. O) b) E  B
    balanceOf返回_owner的代币数量
8 ]7 {, x4 f( K! |1 _9 |; O) R) p  Q1 s) T6 x, [; |
    ownerOf根据_tokenId返回代币持有者address
5 K2 ]# k5 A" Q8 d: s( v7 r  x2 D4 i  J& v) L$ v
    exists_tokenId是否存在; V, N. w' T% D% [+ z$ u
2 g* J9 r8 c  N# ~
    approve授权_tokenId给地址to' I* H; |! q7 B6 Z3 z
/ c$ U4 F) ~; G5 r+ y. y
    getApproved查询_tokenId的授权人_operatoraddress* n% [* s: p9 f0 n5 Y/ F5 V& x
  @5 `/ x; f% p$ V2 }
    setApprovalForAll授权_operator具有所有代币的控制权
/ ~2 b3 l/ Q* `1 z) v9 m" z! Q  a4 J& y, t  K5 E% t: V$ w, J& N
    isApprovedForAll2 I9 G4 ^. M2 L) s( B1 v5 w
5 k; F9 S, L4 s1 e, F! i
    transferFrom转移代币所有权  a9 o6 F7 D1 |$ b$ Q% A, c4 g

7 e- _( u* d1 h% d% x4 {    safeTransferFrom转移代币所有权$ ~6 W3 N% n. o& E( q, e
4 J1 p/ ~: e* X
    同时还定义了TransferApprovalApprovalForAll在后面的ERC721实现的代码中再来看事件的触发。& y* O6 ^7 D* J, M+ d
2 a- Y2 ?. N/ S+ y2 k5 O
    ERC721.sol8 U+ _$ t  x; `. \. A% Z
! r  [7 G# Y# ?9 f3 a( x8 f2 X
    pragmasolidity^0.4.23;
! y4 O" l* Y6 B  k( B& ~
! D0 O( h  l# {' \    import"./ERC721Basic.sol";& n9 p" x8 G. D, M) F
: B+ u& K% Q. b% ]. m
    /**, x) h; [; p, ]/ U" \' N
/ b; h) @* @8 S2 D4 I
    *@titleERC-721标准的基本接口,可选的枚举扩展0 |- e. I) H$ S  s
! ~+ R: }  v" w' O- K
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
8 s5 }/ k+ g+ u9 n% y: W
" t! Q& ?7 O" P  c$ J: s    */
# `3 H) R/ G5 J) g) J: Y+ d9 Y9 i
    contractERC721EnumerableisERC721Basic{
- V5 P, [9 ?8 ?2 p4 l$ ]) Z0 ^9 d" E" _3 d/ v
    functiontotalSupply()publicviewreturns(uint256);8 j  |9 i4 o$ p' G# z
9 H6 ?7 M) A5 S1 C2 J( ?8 z  Y
    functiontokenOfOwnerByIndex(
% y6 }8 c8 a- I! C
$ Z; Z4 }1 `$ o6 _/ s5 a    address_owner,' N* ^( C; x& I6 ^( ?* M5 n+ Z4 G

5 X! }3 @8 \0 e3 x9 h    uint256_index
$ Q5 Q  P1 @3 Q2 X$ X: N& J, K; T5 A: [: a: C' n: l5 M4 Z
    ); [" y0 Z: L0 t+ y3 @' N9 G
, B0 t- a& a; w4 g* m3 A! k
    public
* W; u" @( N& Y( S& l
( l0 T' y9 A  d# a2 r( w& @    view  c4 v9 |& S5 X& D2 }1 f- q5 M

4 h# m8 l& S1 `; O    returns(uint256_tokenId);
) z; @7 d* }- k3 S* N5 @) T  g
' E* A% G# o2 J* L5 ?! ^    functiontokenByIndex(uint256_index)publicviewreturns(uint256);
+ E8 l+ Z: B2 E
( B( b) \& _" s# j; }2 d2 I2 C    }" c& }6 e, T! p+ l9 w
9 x0 D1 z5 Y$ p1 H, r
    /*** c; W9 W! \9 F

" L4 F( p* `/ z& d. P5 D# M% \    *@titleERC-721ERC-721标准的基本接口,可选的元数据扩展6 S, P1 H1 O/ D$ t, B

0 }  _; J3 J# E. u" D- `    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md: i2 }( n+ |; X5 K- n. C

/ x4 C3 ]5 Z; V% P) {    */! h( @* ~: U# Q/ y! ~  n

0 _2 X- J3 Y2 `+ O    contractERC721MetadataisERC721Basic{6 R) U$ Y  R+ H+ |! C

/ Q! x1 D$ e2 K& a& g* e) n    functionname()publicviewreturns(string_name);
/ I0 h2 A  V3 h# y7 y9 j5 e. T' D5 h+ D& x! ?7 L$ w
    functionsymbol()publicviewreturns(string_symbol);
, N2 E! F) a  G8 B2 `& W; H8 r
1 C4 X, O. {6 C4 ]) _8 @    functiontokenURI(uint256_tokenId)publicviewreturns(string);
: t" M- |# W( Z( h: ~; Z
1 i+ r2 e0 r" p$ {    }2 ^$ Y7 @( q9 H4 B- q
' r- i. H6 w0 w
    /**, c8 |3 \- M2 \5 T8 d' J2 y1 n

! ~% C1 J8 k$ P) y* b    *@titleERC-721标准的基本接口,完整实现接口
2 n7 z7 {+ U3 P  I' v) K+ Y* L: r' t1 a7 ~) l& |
    *@devSeehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md4 {  V. l3 k. u2 w, j$ Q

+ j% ]: o. P8 c) ^" \    */5 l; _: \* ~+ K! _$ v7 b) n

- U( J% T; z9 P  a    contractERC721isERC721Basic,ERC721Enumerable,ERC721Metadata{3 H, O- e& a; Z0 N2 }* `9 ~

3 C1 M0 {$ f& E    }
* U) @2 C8 C9 F8 W; C( r9 k, q: G3 l4 b8 z8 f
    ERC721合约继承了ERC721Basic的基础上,添加枚举和元数据的扩展。) e; R0 c" y( b1 Z# B6 O7 K. ^% c' {; O
5 E/ k9 n2 P  g" j0 K8 A& W
    ERC721Enumerable枚举扩展可以使代币更具有可访问性:
/ D, u3 E1 {; |! Z7 B) ]) |. b
! b2 L# Z5 }3 `* E    totalSupply返回代币总量
% [/ A3 R' J6 t: e4 M
' ?& F4 k4 w; J; g  x$ c    tokenOfOwnerByIndex通过_owner所有者地址和索引值返回所有者代币列表中的_tokenId
, |1 C. T" Y; \
9 I% {8 [) \' D- v    tokenByIndex通过索引值返回tokenId
2 w/ C# k+ O! `- N
8 P0 A. T  [3 n4 s    ERC721Metadata元数据扩展哦用来描述合约元信息- l- [" C$ W( c) E8 U
! m4 R7 e- m5 i; v* T$ }& s8 P
    name返回合约名字" Y3 p3 l) w: }8 s! G* ]1 W+ d
8 K9 a7 X. ~9 C$ Q& s( Z
    symbol返回代币符号
9 F: s! D  S7 G1 [/ s3 C% B
- [( x% I% d2 r. {& V! T" b) e0 z    tokenURI返回_tokenId对应的资源URI
$ A, \$ b8 d5 R! Z7 l4 ]. V' F- d: l: n% Q4 Q: r. R/ Y
    ERC721BasicToken& ]" j! ~* n+ s5 b' k# a

' q) h5 Z+ n$ n5 K, x' N* m    ERC721BasicToken7 i! m$ _% d7 u: J3 C  c  A3 ?9 b4 h5 P

9 e* ]" z, r6 S$ O' b4 H8 M    pragmasolidity^0.4.23;
. z' `1 e! G& \! w0 l2 c+ U$ l2 @/ x! r# F1 e- j, Q, ^
    import"./ERC721Basic.sol";5 k' V% X- W9 Z5 s0 w
  ?! J% A- }/ R0 p/ w
    import"./ERC721Receiver.sol";2 b% ]$ ]# R1 k) g- B& X0 T

1 Y* K% [4 k7 ]/ R    import"../../math/SafeMath.sol";
3 p. O5 m3 _" N* D5 M1 e- j; g: V5 ]
: m% P7 {- G: V4 i, I. z+ M    import"../../AddressUtils.sol";
6 W+ B9 y. N8 q2 ?2 W9 q9 [; }! @' G" c/ W7 o; `8 Q, Q; i1 Q
    /**8 Y+ V/ F- A0 ^. j) v+ O0 T9 F

" {1 E& p; ]5 b& F- z+ T9 g    *@titleERC721标准基本实现
. b2 p  R: X8 ~# ~( _% n! \1 [# V4 q" O5 m% {
    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
( r; c* `5 E: K( c9 X
+ J4 D, B* U( O; g3 s4 e    */
1 E! _% N. w4 Q8 v1 {, {: b  ^  `4 `* e- w$ @
    contractERC721BasicTokenisERC721Basic{
6 w. p, M, k) X# `. }& I) ^' X, W/ d: `% ]  n
    usingSafeMathforuint256;9 m- i1 I- C8 k' o- }3 Z7 A

$ ~+ Y4 K# y' ~0 P3 k1 p; W    usingAddressUtilsforaddress;0 W/ z* i3 n. q7 S' b4 B

) C" L0 E- @5 @  l3 x% l    //Equalsto`bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`/ q( q# q' R' o) Y  R- a
" O/ [4 a7 W0 _
    //whichcanbealsoobtainedas`ERC721Receiver(0).onERC721Received.selector`
; Q1 ^& t4 D2 u; R- L6 `8 g8 @1 G! `  q6 R" M  d+ L) Y, E* q
    bytes4constantERC721_RECEIVED=0xf0b9e5ba;# U8 f8 @1 M1 ]' |  v

$ d7 C" n4 j+ W1 w0 r* K    //tokenID到持有人owner的映射
) F2 s5 B0 R  D6 L; U2 j5 U6 W
9 j( @1 B) j7 }# G' y    mapping(uint256=>address)internaltokenOwner;
7 F" R5 k0 P1 u# l; u/ g4 P% {5 L1 w+ l0 ^9 N& p$ X) ?
    //tokenID到授权地址address的映射8 n, @6 x3 D2 S1 D
: k, ^" C2 g1 J' {" L
    mapping(uint256=>address)internaltokenApprovals;: m0 C, ^2 p: x( N% x4 P
$ b% M& p* S; _7 m
    //持有人到持有的token数量的映射, }" F- a  Z  z6 |
( k! N: F7 g* e
    mapping(address=>uint256)internalownedTokensCount;6 F) a5 F" J2 C/ T5 d
" b# W4 s3 M; H* q  P8 L
    //持有人到操作人授权的映射
9 t! W. P, o: b5 K
& j& o% J+ h. f* h0 w3 o9 E, y* t    mapping(address=>mapping(address=>bool))internaloperatorApprovals;: \: d/ z8 P' n" z4 b

) a0 Y0 o- a# G. M9 W) o5 |7 A    /**
( h/ x, Z& n) b+ X' r2 K/ m' U" E! _: }& u' O% m
    *@dev确保msg.sender是tokenId的持有人+ ^0 O) M. ~0 X/ f* e) }: e1 s

, _! x% Q7 W5 n    *@param_tokenIduint256IDofthetokentovalidateitsownershipbelongstomsg.sender3 w7 A" F" ^2 t; e

1 b6 h/ W7 F6 ^( i: G# P    */" x: R+ L% x/ }* n% y$ J. f

6 c5 e0 H( {/ n    modifieronlyOwnerOf(uint256_tokenId){
6 e: D  R2 r2 D8 P; {
3 F. v* |& w3 t" S* l# N    require(ownerOf(_tokenId)==msg.sender);, q  @3 b7 [% L1 ~+ u% ~
+ u( M7 z  f9 u/ n7 E
    _;
; Z( N, k' M! n1 v% D& d4 d& e
, [4 i5 B  Q5 c* @  Z9 [; |    }
8 \- R6 h5 L5 x+ Z4 a7 H# n, `& z9 T3 h/ L5 O9 r# S0 K  G  ]
    /**
/ o, O$ t$ O7 Q2 v
; m3 n6 [6 y' n: [    *@dev通过检查msg.sender是否是代币的持有人,被授权或者操作人来确保msg.sender可以交易一个token
, i% K  i3 Y5 q
& i) g2 w8 A9 @) J2 g0 G    *@param_tokenIduint256IDofthetokentovalidate' }8 o8 K; Z7 l7 x, u- `; {$ B; G+ e

2 v8 h3 C! O; n4 f    */
6 B' p$ p, a1 H" I0 P5 g& b$ U& ?
& U: ^4 p  B8 P) Q    modifiercanTransfer(uint256_tokenId){: n: D8 L; G. t3 X) L# P2 h, W' g7 m+ R
$ @6 }+ j! o% b* \
    require(isApprovedOrOwner(msg.sender,_tokenId));+ Z, X  N* F' U/ ?% F
$ y7 x4 R" ?, M. \+ U. b& Z; B( a2 g. B
    _;
/ x" S# B" F6 S, C8 `' Z. G* [$ W* b. c0 `7 w2 H2 e. y
    }9 E" c! U" X9 Y; Y
/ }! K* m8 y4 K" F6 h
    /**7 Y, p, Q5 l+ i0 u# x
$ Y8 _7 T1 U+ l: W
    *@dev获取持有者的代币总数! ?# T, d8 M; O1 x$ r  k1 S
2 J3 M( O# Y5 v- \+ }7 Y
    *@param_owneraddresstoquerythebalanceof. h7 X* K; K$ A0 b

) O6 {5 p. X  W) \# S* ^, O    *@returnuint256representingtheamountownedbythepassedaddress
) [/ |; S; q& I$ a) n7 d3 P- ~) k+ G& e" R' R9 a7 r. G2 S
    */# L6 z( \( t6 w
0 B( u/ L" G# k2 D, Q# m% r
    functionbalanceOf(address_owner)publicviewreturns(uint256){
- W5 J5 q! \/ r
) c) Q1 x. S& K    require(_owner!=address(0));
: }$ O9 U* ~3 w
( p& _5 f+ K: z+ y2 a3 q8 ^- T8 |    returnownedTokensCount[_owner];' _  r% ]: k1 n& ?0 n) I" V

5 c) z8 U) I, M+ A7 _    }' F& c8 X, U+ ~/ A# @& i
- K( X& }, f- B. ]
    /**2 [7 Z2 W( i8 n+ C: F* t  ~& Y' j

3 P$ h6 N4 S4 ?# o  T3 i    *@dev根据tokenID获取持有者( H& b3 O# Q; i- O) f- I

" C; z. [, U. q9 _1 y- P    *@param_tokenIduint256IDofthetokentoquerytheownerof
+ V7 x5 l2 x3 c% q% x1 ?: f% @% c1 O) g
    *@returnowneraddresscurrentlymarkedastheownerofthegiventokenID
0 G7 i9 Z" s  D. Z9 P$ t, E" I1 G% h; w: ?! d
    */
& M' v4 K" m+ s7 p
' w) o$ h9 G% f! q3 T8 i    functionownerOf(uint256_tokenId)publicviewreturns(address){6 q* J! _( ?3 ^8 z
+ X( h6 ^& T5 w! V
    addressowner=tokenOwner[_tokenId];
% o& b' g1 f" l3 `, k' J: J3 |* U; C" w/ f( L
    require(owner!=address(0));0 V. j' M/ I, {- i4 m' K2 z5 v: P. w
0 }1 |7 `" |, N4 M2 G
    returnowner;! z8 l, Q/ B# b" }6 f
& }3 Z- R7 I/ x  I. I/ O
    }' R" ~$ [1 U7 I& z1 ?& P! ^
( i# v1 ^7 I2 n! P
    /*** j: ~/ e( f( R! f7 U) r; J

% J, N( G( N' G, ^4 Y    *@dev指定的token是否存在
) }* [5 D( e* {* ~% K7 \5 k% m) ~; h- `% ^4 N7 }& S
    *@param_tokenIduint256IDofthetokentoquerytheexistenceof
4 O; }0 G) a  B4 C( G+ z4 g1 E( F) w* @2 F+ m3 \4 {
    *@returnwhetherthetokenexists4 n* {. q' g' o/ X4 D4 Y; {

6 @) a7 [# N  e    */
3 ?& a0 I4 c5 u% t+ |
- b' l7 _- i3 _1 m) ]+ j    functionexists(uint256_tokenId)publicviewreturns(bool){* o6 Q3 v; I. P, h
' V7 I1 g: c# v+ Q! b: g, W) P- G
    addressowner=tokenOwner[_tokenId];
6 a+ \& v1 q' d6 J% n1 Z2 ]: _
8 v  @  [* R- @+ |! }" c  Q8 I1 C    returnowner!=address(0);) U& |, A6 i3 D5 y" x" i0 b$ H

& Q1 m$ \/ H4 a2 ]7 r    }- F/ y$ m7 M% [' ]8 O
3 _: v% m/ U  d+ y
    /**
& j9 \+ }& _+ }& i" }% M% Q2 X1 y+ p1 ~9 e8 K- l( K: B
    *@dev批准另一个人address来交易指定的代币; y& N* q, n' A4 a$ R- ~4 `
7 U- B/ ]5 A! o" C6 x* }
    *@dev0address表示没有授权的地址
# t; |6 p% U6 H7 r5 M* o$ ?  K7 C3 b, N9 w& ?6 \" R$ k
    *@dev给定的时间内,一个token只能有一个批准的地址
0 N/ ]& t8 K) V+ p3 X; ~3 ^
! W+ |" `- @1 A, F& K: i; M    *@dev只有token的持有者或者授权的操作人才可以调用
/ D$ E$ B, ?+ C1 {3 h. A! v
2 @! }$ g) V- J8 [    *@param_toaddresstobeapprovedforthegiventokenID
5 `0 @* a; P5 O9 T/ V
9 M$ X! x, F: C: i5 _% x- O% {    *@param_tokenIduint256IDofthetokentobeapproved) d$ {9 s: }& _0 b! o8 U0 [+ t

5 y& G. _1 n! q    */. }% i2 O/ }6 ?+ y3 d  d, @
6 `! k  U6 W) @0 z. a
    functionapprove(address_to,uint256_tokenId)public{# j$ ^% B) s4 i8 Q9 n" P0 S

8 k+ |5 Q9 [$ W* i4 h, p! s    addressowner=ownerOf(_tokenId);
% J- o( z0 E3 e% J* U& R7 N. Z+ |6 C% Z' W5 q* m
    require(_to!=owner);
3 _& F3 E3 z& V* |0 J
! `/ d: b6 s, V. G; ]# k) _    require(msg.sender==owner||isApprovedForAll(owner,msg.sender));! A9 y$ W2 B# T. {" C; B

$ n0 }/ l2 x; Y/ |- t    if(getApproved(_tokenId)!=address(0)||_to!=address(0)){
" F8 U1 O9 P0 U* }# p/ `$ q3 O' I5 k+ F5 S! I4 E' X1 L2 _
    tokenApprovals[_tokenId]=_to;! Y& A4 m# e" j& w
7 ~: L0 i: j9 r! D% d, d
    emitApproval(owner,_to,_tokenId);
! x8 n# W  q# F4 B
- Y* p) P6 Q- |9 b* ~  b    }
5 w# P! g, ^+ R7 ]& X
  \- v) x# Y0 B9 U) \6 u    }! x' x$ W+ u( A( h2 c

+ P# e* N" [) X    /**
/ w1 K6 t3 B. G
) @8 p! s/ @# P/ }$ ~& v    *@dev获取token被授权的地址,如果没有设置地址则为0
- {  S+ W% Y& [. O0 q8 ^  [+ ^) J- {$ i  W) F0 \8 ~' E) v
    *@param_tokenIduint256IDofthetokentoquerytheapprovalof; X/ p4 |% d3 }& V" s' D4 }$ ^
: x+ B; V6 U. H: k  m2 j7 N
    *@returnaddresscurrentlyapprovedforthegiventokenID' m% ]9 _- S* p4 {
# m7 P) c% y/ P7 u
    */: M* K. n# _- K/ Z1 }
1 n3 ?4 h( r1 I/ }2 s" }" k
    functiongetApproved(uint256_tokenId)publicviewreturns(address){. S3 z0 {: D+ l( C: T" r5 l' b
: x) ^" {6 A' a) }( Z
    returntokenApprovals[_tokenId];
) _% t- ]& z0 w$ A, \" M% Z" F  r: \* f9 d
    }7 o; h+ G4 ]: f: C# A

: `7 C3 A9 z- A5 M    /**' a* H# s& @, z6 H! D- R! f9 j
* H( h+ j/ J- e, Q) H% l
    *@dev设置或者取消对操作人的授权" e8 _  x- c# f9 J. K
6 O' e5 |! d) j1 ?2 G: t
    *@dev一个操作人可以代表他们转让发送者的所有token# A( s( |* @. w! Q" ]( G9 R
& x% v0 S7 I7 g1 M- z. l. e
    *@param_tooperatoraddresstosettheapproval7 R0 o' j; B6 }

! q0 L- p+ I9 Z. W" }. m3 r    *@param_approvedrepresentingthestatusoftheapprovaltobeset
# I; q- \' d: _$ Y! i! q
2 Y6 w3 n& p- u- q1 ?    *// U1 M$ h  |4 x7 c

, h* |7 j* D2 @/ Y6 ]3 K) k    functionsetApprovalForAll(address_to,bool_approved)public{% P" c4 C! {: t- `2 A* ?7 N

: H2 b; Z+ l* W$ Y    require(_to!=msg.sender);3 k) s) }( t; B: J" P* l" g9 J

$ [0 x' W" W- X. i/ A    operatorApprovals[msg.sender][_to]=_approved;5 O  C$ A. b" Z2 \. W6 U$ }
5 a) C1 g1 j9 w
    emitApprovalForAll(msg.sender,_to,_approved);
. e* |: ]5 r' B- U" S8 q5 t% V% q, z% c% \  `
    }
; t+ I" \( O9 E* ?( J
$ L' T5 j) }' K' N5 n9 @6 A    /**
, i$ ^% e$ ^5 A. X! \! O: k' L+ p
! o7 L1 I+ G- C    *@dev查询是否操作人被指定的持有者授权5 M& S  t( e& c; P! o& D$ ]

+ B7 d6 @6 D; b0 {4 m* M2 k/ X    *@param_owner要查询的授权人地址5 C( b; \* M- r2 ^4 V9 G
# i) K& M/ T% Q9 B2 p0 x
    *@param_operator要查询的授权操作人地址; i& p- z2 ~- ^* Z: E* r! L: @* p. T2 v

4 `4 @3 e- H. ~0 m    *@returnboolwhetherthegivenoperatorisapprovedbythegivenowner5 a1 L# L3 k" L. T0 c
3 w5 M! K# H" i
    */2 {2 x) M0 d3 L* T; M; T9 ^

# Y: Z6 P4 R& {( O! d    functionisApprovedForAll(
+ d2 e! L# @, N; T7 |0 _$ y4 E; [7 h- T! D
    address_owner,
- [$ s$ m  T. [3 t
0 K/ ^& A9 m  X9 f* ?( q    address_operator  h! V6 S. @4 }

# P, M" J4 C7 S* X) E! b! t    )7 k' ]% u  w$ _) r1 D0 k

2 g" y$ A7 |2 L. Y7 t* x& P    public
0 i3 U5 u3 q+ B0 ]0 P$ @
, L$ \/ P+ }6 r  }4 t    view- i% C7 o; A9 r
2 m5 x& x% s) A  l  Q2 B/ e
    returns(bool)2 s* @( X* c' A7 W
" G2 P! W. P- S0 k& T/ j; N
    {# m3 b( K' G" v# H9 [6 u! I* {

- q7 b5 }/ H( X    returnoperatorApprovals[_owner][_operator];. ~1 L) B- {6 X/ @- x

# j1 V/ x9 p3 b) I% e9 }    }7 E* h- @, y3 _6 w9 n, P

/ q4 Y/ \! f( ^- I) v- g0 f, f    /**
! m( d/ }6 U- \  W
4 @( E4 ~; [6 u7 I0 S, y    *@dev将指定的token所有权转移给另外一个地址; s4 w7 T$ ]% h7 c. y3 b  t
6 g7 ?2 q/ W2 j) }
    *@dev不鼓励使用这个方法,尽量使用`safeTransferFrom`
: k4 u. j) g7 m+ y
6 S$ b8 U$ l6 t4 j: `    *@dev要求msg.sender必须为所有者,已授权或者操作人
& x+ f' P. _" E: f7 C: V( A# D2 ~7 e, l
    *@param_fromcurrentownerofthetoken
. R1 i7 g0 C2 x% U- m  D* M" k. E$ j7 I; ]
    *@param_toaddresstoreceivetheownershipofthegiventokenID
- N0 O8 z! [: k1 a6 \* o$ o6 y8 Z5 `1 E
    *@param_tokenIduint256IDofthetokentobetransferred
/ F" r: J/ F5 y4 [
4 s- h: Y  M6 A/ A; r2 }- l% j    */% N& o& _  v- E
& K% }# r) D& b- Y6 X5 g
    functiontransferFrom(8 b7 k$ y, Z( S" z8 `

) j) v; B$ N: T8 c! a0 R7 Z    address_from,- I1 D5 k0 u4 E% B2 `0 Y% S! k+ V
0 \8 v" M3 M$ \5 K3 y$ W
    address_to,
/ t* A1 Z5 o+ s; e1 H: }' T/ J  W* U6 x: s6 `- @9 Y6 `, e
    uint256_tokenId
4 R' n* q) T0 `. ^2 Q- {
( K$ X1 M: y0 z1 ?- ^    )3 T( T# O6 ]1 Q7 y

! V; R2 o7 X! I* C/ P" o    public
$ n8 @' s$ g( w4 s/ B  d9 P$ l% x) X: s- Y% b% T
    canTransfer(_tokenId)
0 `- G# R' ?; z, q/ i
' U8 Q2 v& _* |) k) S    {  s# F9 c" K) d4 V
9 ]7 P! {/ Z9 n; q0 g
    require(_from!=address(0));
0 h$ B7 i1 K+ b0 E$ c
! [9 W/ R- I: S6 u! A3 f: S    require(_to!=address(0));
% K5 `- A) v/ u' T1 v- Z+ b, f5 \& e9 {) D3 @2 Q, K$ |
    clearApproval(_from,_tokenId);/ J5 B/ u2 g* y8 i+ H1 ^
+ p. H- d6 k+ [. u
    removeTokenFrom(_from,_tokenId);0 f; Z, ], B. Y) U# m

) L! `% p$ F; d" |    addTokenTo(_to,_tokenId);2 W( Q( a1 A+ x

+ R0 b7 W9 t1 Z; x8 X  l# U0 V4 r    emitTransfer(_from,_to,_tokenId);$ D0 p/ `  t) r" L- ]1 E: G2 l5 z
# R+ K4 V1 k; r5 s! d7 N% Q
    }& M1 z$ i: X: E* Y" ]* N0 J0 |

6 |5 F' L& T2 T; l    /**# D' N5 W% L, Y' B  {  d

( ~: t$ {; D5 [2 t4 X2 h) o    *@dev更安全的方法,将指定的token所有权转移给另外一个地址
$ h% ~. t+ }4 w, a7 V" Z
6 [# G' G+ c7 v6 B, H    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值
/ J4 _0 o: A# K) ?% c
$ [: q/ ^! |' r0 [! ]4 M! U    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原
: H; e& J& x% a2 ~+ x- |  x: [; o" y
8 n0 J* X, c+ e. ]1 e    *@dev要求msg.sender必须为所有者,已授权或者操作人
# _, R0 M* ?) V1 c9 l5 x: {& N
    *@param_fromcurrentownerofthetoken% M" ~2 G4 Z( r' g# f! D* {' d
$ i+ \, `5 Y& W; M( }' p
    *@param_toaddresstoreceivetheownershipofthegiventokenID& v3 z8 q' I% V% ~9 s

- ]# r# \/ L' P3 d) l2 s' N    *@param_tokenIduint256IDofthetokentobetransferred6 y# ^9 ^1 P9 J- z& K

' ]! x5 ^; `* ^  K1 \) P5 d    */
+ |: i1 W7 Y8 y  ]8 t; }! V; z5 @, X) N! w
    functionsafeTransferFrom(# U) V% X+ e, c" x1 P- D
! b: C0 N5 X4 T& |3 a" L. ~7 C$ Q
    address_from,0 S& q! i# Z$ T. ]( d6 ?
. P4 L/ C- j- F* Q; T; b" ]- l+ s3 ^
    address_to,
4 A" b% u6 q( D. k7 q* f& C+ _7 |
. x& @  C. r% B5 ?! N    uint256_tokenId
/ R5 p& [/ @: J; E
' ^. L) {. r% j: m$ E    )
; Z/ n( n% A. J
) m* B/ b6 N7 r) e0 G3 G    public2 X* b0 C. t2 u
9 p: m5 p; A: u( w$ j" g  C
    canTransfer(_tokenId)
5 p4 ^& y2 V/ O7 O3 D& V; R8 C9 y8 z) Z: u
    {4 E' l# E9 ]( ]2 E! E: B. m( H, K: k
; V( ?) d( A; Y* d7 X
    safeTransferFrom(_from,_to,_tokenId,"");
/ f; G- r: j% _" Z9 b: n) N6 y8 M% m; Q- v$ G
    }
- X( j* j+ a8 |" v4 x8 ?
; U1 X: F3 X* q9 O) n8 b    /**, S& a! E" p' B# {7 }

7 S* [6 s) ]8 Z1 P$ H    *@dev更安全的方法,将指定的token所有权转移给另外一个地址* @) j( d4 S2 `

3 Z0 a9 k8 G1 r* s* G    *@dev如果目标地址是一个合约,必须实现`onERC721Received`,这个要求安全交易并返回值( T( n0 p  W8 _/ X2 D# L

- W0 Z- e: w( Z( k6 D! P0 k    `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`;否则交易被还原$ U" Z" m0 [( D1 k# h

5 _3 P5 K7 Y4 |! A) h    *@dev要求msg.sender必须为所有者,已授权或者操作人  K) `; t3 p9 t% k" _) o

7 D& }  }/ U/ Z+ H# s2 @# _0 T; i    *@param_fromcurrentownerofthetoken
1 [" O2 p& @/ Q) q, y9 [! e4 O; F/ v, ^( |
    *@param_toaddresstoreceivetheownershipofthegiventokenID; Q; b, {2 M5 s) j: u& Z& n

3 V3 g" `% C5 H    *@param_tokenIduint256IDofthetokentobetransferred
$ ~! \0 c. M8 g
, k' F  t- V  }% q    *@param_databytesdatatosendalongwithasafetransfercheck4 c7 |- ?7 K- [/ e- J* p
3 M& [/ ^3 @8 y  Y* p
    */
0 \  H8 t8 J3 g" n$ ~2 a+ j3 O
! O6 w4 e8 U: b  P2 `$ o% m# ?' C    functionsafeTransferFrom(5 p4 A8 g, |- Q! T. w  z5 k

: Q' h+ w% `6 a" \1 ^, d2 V9 N" v    address_from,6 P% ^1 @4 Q4 a2 y
" p1 ~) v8 j5 p( R  A! {; w) b3 P
    address_to,
3 }5 b3 w5 L$ W9 \2 R; b0 |* ]! M- Q8 X6 p3 ?4 S/ P4 f
    uint256_tokenId,* |/ Q9 c% O: n+ C1 o8 y5 K
7 E" X. u: w' D4 ?' s! _2 k
    bytes_data; S, b6 Y: p$ ?2 @4 ]( e
  u/ C  ?" p- F( Q2 f- V
    )% O  G! N7 T0 `3 k" v; B* |6 l

8 r  I3 O) Z$ J    public" P" n. J' D7 d, h3 c; s( G
9 z/ x% S' z  e7 E
    canTransfer(_tokenId)
! H0 F* H/ d  {9 o
; ^$ M$ e  Z0 l) j( \( G. b1 u7 g4 A    {& C+ {0 g8 Y4 }* o4 K' b; y$ r

) w8 z7 b  }# b    transferFrom(_from,_to,_tokenId);4 y' o3 n8 m2 F7 X5 m

3 i& p6 w/ d- F$ g# J9 Z, O* y* c    require(checkAndCallSafeTransfer(_from,_to,_tokenId,_data));
4 R, ?9 K9 b5 e
' H( _8 b8 |- ^    }% G- Q- {: m1 ]5 x1 J4 j( }

* A* W8 w2 V1 f9 d/ O3 k( s    /**
0 A0 r  C1 u' T$ ?/ o0 P
, u0 R/ ^# D2 n1 j    *@dev返回给定的spender是否可以交易一个给定的token
7 s4 X2 |/ B0 d2 ^" v+ t/ d4 U4 P' R( j: Q
    *@param_spenderaddressofthespendertoquery) w: z0 U* t% h  J9 E' D' U  S
0 y3 p+ p  `6 N* W$ H4 }
    *@param_tokenIduint256IDofthetokentobetransferred
. D2 z1 \8 J, ^% T( P
$ g0 F' ]0 t) I4 i5 u" K- {    *@returnboolwhetherthemsg.senderisapprovedforthegiventokenID,( s( Q  }/ d6 p- F6 ^4 {% J
' y5 a" \- n" T# E1 z/ j  f( g: ?
    *isanoperatoroftheowner,oristheownerofthetoken3 q( p* Y  Y" R
5 P9 e; I- Z7 Z+ E) w9 J* m' O
    */
* {, O# r7 G5 g* r# a) f) Z. \3 b4 ?9 g8 {8 m3 j
    functionisApprovedOrOwner(! e$ {  Q. l: Z! {2 D+ t8 U9 `; G& t

  {# ]* a" y, c! U% K( i    address_spender,
) c  E6 Z: h" o
# M# b8 ?/ |# o    uint256_tokenId) N9 s# f; @! S" J2 s4 \
' e, h; H8 Q) B0 y# M8 ~
    )
7 N  Y# I" k5 f% J5 n# Q# r% ]( O- X& R) ^
    internal
; E; `7 v+ X2 C# R4 f( ^2 g4 d  ?! x- R# {+ U
    view: }' X+ y! c( i' q5 l3 ]7 m1 _
7 D: q2 C4 x& y6 o% J6 d
    returns(bool)6 O4 @! A. s2 B* k% u/ a
+ q1 @/ b1 O" y+ H+ |5 a
    {
) ?# G- f2 |1 f; k5 K7 \: B6 M
* r# y  _. F6 L/ k( V2 {+ V    addressowner=ownerOf(_tokenId);
; h1 {3 s& z/ Q1 }/ X% g
) u& ?7 z  S* q) r0 t( q    return(6 [' O* u! N& Z
7 u- s  @3 O5 \
    _spender==owner||
: d4 ^- s& U: l5 E5 ?4 B/ w! ^- A3 T3 p; E$ l9 i% [
    getApproved(_tokenId)==_spender||9 c3 k2 y& x* @; v
  f5 o  R' f6 B$ Z! [8 O( o
    isApprovedForAll(owner,_spender)( ~, v6 f$ |& k; @2 `" k6 g7 {
/ H- ~. J. S+ q$ [4 {
    );( [$ H  N7 g9 o: n

* S$ c: n9 k8 l( K" L* a    }3 J* c- @; t0 Z4 l' J4 f
! }$ X4 F# R- @2 t8 j$ A, [
    /**: J* a( S( c! ~

6 M  D, k, }' `3 N    *@dev增发一个新token的内部方法
4 y$ A! q- N: @# v
% W! r; f' A7 C- ?. m& M    *@dev如果增发的token已经存在则撤销
5 _: @6 b. U: P5 M
2 v8 ~2 A3 B1 q2 w    *@param_toTheaddressthatwillownthemintedtoken+ Q2 p7 M6 c7 L& A* B! h7 H
# @) b2 w- ?# D. z7 o5 L; ^1 U
    *@param_tokenIduint256IDofthetokentobemintedbythemsg.sender% w$ w. t4 L3 ~. C$ k  Z1 e
; H  M9 x6 V, \! v3 l. M
    */+ Q  Z; z6 Q0 w5 k8 H; t
4 A4 t7 n" M* V3 t( y& j
    function_mint(address_to,uint256_tokenId)internal{
( o* F' b; H4 L! [. l% j+ W2 F# F* s( n4 Q4 j3 r
    require(_to!=address(0));# L( W4 K; v# D# Y# M

/ }8 s5 g3 `8 g/ i    addTokenTo(_to,_tokenId);& e! U' Y& \: \( h3 O( c5 @+ _, c' q
8 j5 L" A( N, s( _/ M& ?! u7 T; N
    emitTransfer(address(0),_to,_tokenId);! z9 I# q: v' v) ^  L$ k

" ?2 i  c: y0 W2 J1 [    }
) J) a" f: s  U- l
" E. ~+ k  G" W! Q, u    /**$ [) m9 o' `4 ~1 Q# _6 D! @

4 n; I) \/ m; k/ d5 R; h+ g    *@dev销毁一个token的内部方法
. M0 V8 }: L) U: V
" ~" T6 K& B) |' ^5 u    *@dev如果token不存在则撤销
5 i6 y( J. S2 ^- E3 ^" g$ C' t9 }' `/ I; B% H" _0 H
    *@param_tokenIduint256IDofthetokenbeingburnedbythemsg.sender9 C$ s0 ]/ i6 W; N1 J$ G- y

$ Z/ j$ u( z; r+ V$ f' Y4 X    */' L8 b- l; u2 _
+ O, x; W, y9 S- z* v  ]: J
    function_burn(address_owner,uint256_tokenId)internal{
' F* y2 U" O  I" h( R& \8 y% I1 D6 l8 b1 C
    clearApproval(_owner,_tokenId);
% f' B' m! \: i: \( o: b0 I$ R- ]. _! N; ^; A9 o
    removeTokenFrom(_owner,_tokenId);# _7 h8 u9 x& Y0 G

: U+ g+ k' V6 S  s" B    emitTransfer(_owner,address(0),_tokenId);$ k9 X: a3 \' n( [) m+ l4 p

" z- B$ @" Q: g  {$ x) u' D, w    }% Y) V  A% J& U# f
, I" Y8 }8 E: x% A
    /**
3 p1 F* \, l9 {
. p* C$ W+ h/ ~# M( b    *@dev清除当前的给定token的授权,内部方法
# r/ [9 S" _9 m; p7 _" \' \  G) K6 Z! b* ^: L7 s: q8 }7 N
    *@dev如果给定地址不是token的持有者则撤销
' ^. Q' |5 L  A8 y. h$ l$ d5 g; f4 O) c% S
    *@param_ownerownerofthetoken" T& {  [9 x5 x5 M/ |- ~* k- D) A
+ e# n2 ^- O" ]- [9 e
    *@param_tokenIduint256IDofthetokentobetransferred2 B8 \0 g! U: S; ]" t

7 z! P; H  a, ]; k# g* q+ U    */$ Z) J5 y: y1 t5 E+ [6 f. m# R$ J

) r; r% O3 i+ y, u: N# x- w' L    functionclearApproval(address_owner,uint256_tokenId)internal{; h1 {6 Z) o0 a9 ?1 i" w+ x

! P/ e! M# I* u+ I0 j5 D" J    require(ownerOf(_tokenId)==_owner);
: F2 q3 D" U+ c/ T9 i( F! Y( [( W6 C  Q+ _8 [1 |" F# V
    if(tokenApprovals[_tokenId]!=address(0)){. S1 n- r: U! J3 l

$ q  Y* N% a$ p& f4 n    tokenApprovals[_tokenId]=address(0);
, }' U2 n; w7 T1 q" x4 X! e. S, b6 O4 [
    emitApproval(_owner,address(0),_tokenId);6 _  n0 |, B. R+ R
: I; N% x+ a' g: r/ n' g7 i% J' ~
    }
/ }9 d0 g* j8 Q8 ]0 R& \8 E
2 C. Q$ l4 z% F6 ]3 O/ `    }
# @) u& I7 @* T* a3 S
: D- U; w. i- M; t, u( X$ P    /**
' b# {6 I' L: C3 G+ U" a- K6 [+ C4 H7 j8 p
    *@dev内部方法,将给定的token添加到给定地址列表中5 X. {& Q- T1 c* `
. C/ e1 f) c3 [. R, F# A1 X1 k' I0 p
    *@param_toaddress指定token的新所有者* k& ~2 z) Y& U  F; Z

! E! [3 P; n: J2 P4 e5 l    *@param_tokenIduint256IDofthetokentobeaddedtothetokenslistofthegivenaddress. k+ ~& ^* ]/ a1 l9 V

3 z" a7 B- |7 h6 R! Z    */% J! W" y! l" F2 o" N  q
6 }2 G- _" _( f  l& h) V6 d' c
    functionaddTokenTo(address_to,uint256_tokenId)internal{
0 p; C) o& U# H  x
% ]% Y% I6 \0 j. S: `: @    require(tokenOwner[_tokenId]==address(0));
0 d+ a  p8 F8 G8 g( Q8 U" Q
" n  ~$ }2 Y; Z) q8 b2 y" E& K* F    tokenOwner[_tokenId]=_to;4 C0 t7 k  B/ l. {

4 P+ t4 A! a4 ^9 x    ownedTokensCount[_to]=ownedTokensCount[_to].add(1);
# U2 ^" f$ h. t8 f0 ^) v' _8 q/ k- h* Y4 X  D
    }
/ D2 X# x0 g7 ?1 D$ n6 u! f
1 L$ f# Y+ Z+ Z% N5 u    /**
# E8 U4 V. j3 u
, A% }0 o* z# Y% ]" c) `    *@dev内部方法,将给定的token从地址列表中移除
5 d( x( [( ]5 M: s$ v0 j, W5 S  g# K1 M  M) L7 ^
    *@param_fromaddress给定token的之前持有中地址  a9 a" d" {3 T3 _  R
' q/ b* S+ P! `- V
    *@param_tokenIduint256IDofthetokentoberemovedfromthetokenslistofthegivenaddress
9 G7 a3 M/ U  `  L3 Z  N3 I1 u
/ ^) r8 a8 k# g( r) M    */+ ?' z& d5 d! Q7 F& m& z
/ U% b2 y$ F% e; i( ~0 k/ ~
    functionremoveTokenFrom(address_from,uint256_tokenId)internal{( w+ l" b3 ~# q) t. F# M
- ~+ U3 s) h9 z, x! H
    require(ownerOf(_tokenId)==_from);" n' b; ?+ C1 n: n' J/ ]5 ]
( K$ ?, ~+ ?5 k9 H  }
    ownedTokensCount[_from]=ownedTokensCount[_from].sub(1);% c! A: E! I; T2 N3 ?

, o4 f* b( L* T( R7 r    tokenOwner[_tokenId]=address(0);/ U9 }) \/ h- {) Y6 z
! i# R6 J( c- q& H' @9 M3 r
    }
9 h4 S/ i/ A, ~0 {/ n$ `% K0 a: C6 q, g( l0 Q- n# W
    /**1 [" q- I1 |7 g  H
3 I& m) ~6 D4 L/ Y: x' H% f, X
    *@dev内部函数,调用目标地址上的`onERC721Received`# ^9 ]1 }. U+ Z) d/ i+ I/ o

0 x. f  @! L9 ^  `! P    *@dev如果目标地址不是合同则不执行调用
: l3 Y1 I' ^, p3 M4 E. G5 T2 b# N; q3 E
    *@param_fromaddressrepresentingthepreviousownerofthegiventokenID" u7 f8 {& ~# Y' I& }& {

- A3 G2 Y1 T8 K% @' _" x# M+ g    *@param_totargetaddressthatwillreceivethetokens8 J( U: y4 u$ G) e. F3 P
  x- @( A, R! }! J2 `
    *@param_tokenIduint256IDofthetokentobetransferred+ ]) c# b' N: `/ a: ]& p' K% W
8 Z8 R+ I( m* ]% ?  I! i
    *@param_databytesoptionaldatatosendalongwiththecall+ q" k% D8 f" `8 c" p6 \+ \* A

" k% e2 v1 S! L& L+ k    *@returnwhetherthecallcorrectlyreturnedtheexpectedmagicvalue
  @+ `) W' P( \: }
+ b' S$ N+ z' }0 Y% k7 |* C  X    */
1 U0 d6 e( q0 _4 ~: Q
; y* U' v# }/ t4 G% V    functioncheckAndCallSafeTransfer(9 A7 X; F/ I. ~5 [* P0 w8 u

. _2 ^% p$ \+ Q    address_from,# ^9 G' o, n/ i- b  |9 t5 Z5 @

( o0 l- B3 G/ r* P: A5 D    address_to,
4 P  o9 l9 y/ J' y! D6 Z, g  ~7 }# k; P5 i2 f' H
    uint256_tokenId,/ f" ?( e3 J  j0 d) @7 B

: x, ~, `+ H' C5 {/ W8 F7 z7 }0 d0 N; y. m3 e    bytes_data; |, h! b5 u$ {4 i" {1 ~9 F
& L& @3 ]4 L; F7 d
    )
; O& L- d/ P& U* p8 L0 H9 ^! r* ^$ V& ]" O3 M; r& n
    internal' Z3 {$ X. _2 K' O) ~1 P) A
' N$ H& s, `% ?3 |; z, k
    returns(bool)
1 A0 C% K9 Z. i! d6 ]" o# p
2 S) T/ K" p" y% x; I! s    {
( m. I# G* ^5 {) M
! g, M2 z. q0 Q, D5 S    if(!_to.isContract()){  f' l" n6 t1 C1 |& B

8 L( _8 u& v/ B* w) U/ h  j8 e    returntrue;
; o; W; q5 k' o1 G. I& F' `5 m( t; d- C) @
    }
  [$ M" F% ^' ?0 X3 c9 R& ]- H6 C5 x+ W
    bytes4retval=ERC721Receiver(_to).onERC721Received(
6 i1 I7 S: a- i& |  w' a. `$ H4 t
8 F  v% u# T' n& \    _from,_tokenId,_data);; K/ L; a: R, o1 C% b1 i
. D2 s( A% }3 j- D# N& S1 q' j
    return(retval==ERC721_RECEIVED);
* b0 y- b9 }& I; d3 G' u9 ~
; r& V- y( E+ b8 u) y- Q4 B    }8 M$ n' b! s! |" m
# w" X1 v9 P( U! p
    }8 p( U4 e/ m; |  ~- K
- t: ?) P9 l) A7 u, K7 i* G5 y8 @
    ERC721BasicToken实现了ERC721Basic合约定义的接口方法,主要对token的持有人的一个添加和修改,以及授权和交易的管理,实现了基本的非同质化token的业务逻辑。具体方法实现并不难,就是对映射的公有变量的管理,但是对于权限和安全验证值得关注,比如函数修改器还有require。
2 f- A  z# @" ?
( I( \( x% ~( i, p7 R0 v! u+ ?5 f    ERC721Token.sol7 T# K/ k4 f+ ~/ s: o

! B/ }$ x" G( _9 `% f4 }    pragmasolidity^0.4.23;" ~5 L3 W+ j# W  X- S

& t3 ?' U6 O; B. q! E. o4 r    import"./ERC721.sol";6 Z/ B* V+ n  [! k3 @: d! D

, Q/ w$ z" p. g$ g" Z    import"./ERC721BasicToken.sol";
3 \  u" h$ k9 Y
7 s* b: x" d% O. U, s    /**% V. |' _7 t/ Q7 E6 W5 e. a
% ~% H% d8 c, z
    *@title完整ERC721Token& l! `( \& j5 c) {
& t, f2 H/ ~1 c) d
    *该实现包括所有ERC721标准必须的和可选的方法,此外还包括使用操作者批准所有功能
. m& ^; i2 [) L6 X8 l
9 y& a4 b0 F6 _5 k" n1 y' e; a    *@devseehttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
2 ]. [; H' C4 X" ~/ U; s5 |- d, E) |4 v7 i/ Y
    */. e9 G' @7 C  U4 ~" G
$ Y- r* T1 `4 r4 [3 C: I7 H
    contractERC721TokenisERC721,ERC721BasicToken{' s; J* O, D" i8 i5 M' \7 O
% @$ u+ w/ o& Z
    //代币名称
1 r( e% h+ C& b( T
8 d8 D$ ?: G" m    stringinternalname_;3 ]/ r: q# r; ^5 j* h% H( I+ _+ U' d
! ], U2 o) x( v9 }/ m0 h) R
    //代币符号
' [5 {; l* x& k0 v8 R! G2 [8 ^/ ]
% M8 E3 B! T. \, [8 L/ u/ @/ b) A    stringinternalsymbol_;
( P% Z* I; }& i0 y$ F& j( d6 y$ K% d% U& F: l
    //所有者到所有者拥有的代币列表的映射
3 b. T9 C8 F8 A1 V4 ]. R
* M& H: u% W1 l3 t( q6 M1 T8 J1 ?& e$ Q    mapping(address=>uint256[])internalownedTokens;; S5 g" Y. A& ?0 Y# `) h

- z+ D1 e  s8 L0 C1 M% u# X    //所有者代币列表中代币ID到索引的映射. `5 Q5 e+ i% I/ d  j
0 G+ R5 \3 X# A4 ~0 v* Q/ P
    mapping(uint256=>uint256)internalownedTokensIndex;& |% `1 w! k! \9 h

( m8 |  [: m6 q    //保存所有代币ID的数组,用于枚举7 S  t% r) Q. N+ g% e+ X
7 _; O9 B& G# ]8 R; i
    uint256[]internalallTokens;
) m. ^6 j: b" {2 Q9 a
0 U" [- V( h. ?    //allTokens数组中代币ID到索引的映射
# V% i' l$ p" X0 g6 @
+ h# E$ L) k! Q" R0 Q4 {    mapping(uint256=>uint256)internalallTokensIndex;. i' R0 u& R9 T6 A$ ]* _

4 t* P* I7 ^3 U+ ^% B    //可选的代币资源URIs映射
8 n% i2 R$ x' R1 n9 ~1 V2 \4 J
    mapping(uint256=>string)internaltokenURIs;! d$ \! Z( r# k

4 s8 E0 i0 c; a" L$ z) Z4 [( R1 c    /**
: D! n0 @7 A9 a) k# @- ~$ R) V9 c! w! Y( `" \
    *@devConstructorfunction
3 c+ |! d) G$ S. u4 O) V0 V
/ l/ W1 }1 o* e2 R    */7 y) ~* [7 s1 U& T5 }
$ E; s2 X& q1 C' D* _# S+ j+ n
    constructor(string_name,string_symbol)public{7 K9 u: e; H8 S

( K- G( P# e# T7 u    name_=_name;
& z$ F$ B) v* p, I3 `# ^9 x9 v5 c5 b+ }  @
    symbol_=_symbol;
0 k/ ?: H' V+ g' K9 C  G- [5 M
+ i% r& o# }# I: N$ {# e    }5 U: u- c8 e/ @; u' `
, A! H- z$ r5 W2 @6 o
    /**
! L9 D. k+ Y5 S9 C: N8 \. w3 S! E3 q4 j9 }
    *@dev获取代币名称/ q4 F# u9 [$ J7 h. }5 k8 C+ T' n
% R1 l; D2 F- x2 h: h
    *@returnstringrepresentingthetokenname
2 J. g. @) ~4 V& d, L6 A% {8 B) C2 k, E+ U9 k
    */
" E2 g& h# {9 d! D7 Q" @% ?1 v# A. a" F, t" ^) u3 f
    functionname()publicviewreturns(string){" Q3 C7 m2 a/ U4 a" Q. X. B
$ ~5 ~% }/ P. A* Q0 V& T8 t
    returnname_;
* B, X/ C5 {0 R1 U
$ v4 @1 X2 T. r8 U1 K    }
) ~. x8 v8 s* m3 L% K' G  B. T% J+ A: g" K6 `
    /**
/ O, R0 R4 y8 ?3 x8 V/ ?. G
5 k' \$ b: c8 ^; x# B( o2 ?  P    *@dev获取代币符号! a; I. d" i6 t! C5 g! v+ n) ]

/ a( v; g0 \; m+ J    *@returnstringrepresentingthetokensymbol
5 a; B" t6 M( T( M' L  f5 v, K/ P/ q5 }/ X% l) a/ m/ A8 T
    */: R* w1 T' ?  a, [4 W

8 y2 I5 E  V* F1 k0 Z6 g    functionsymbol()publicviewreturns(string){& A1 t% P. n/ ?% M

: }" n6 k! o' [1 B    returnsymbol_;
  i( l' ]$ t+ H& x. X: n1 [# F
( a6 ?- X. ]! T& k3 n    }3 ~; W( Z/ b7 x% B1 A8 [7 W; I
3 `+ ]# U$ v5 H/ v' G
    /**: J. `6 x, _" v) A  X

) [- |2 w1 I2 H" c7 `* b& L/ g    *@dev根据_tokenId返回对应的资源URI# K. d% f/ w8 M
; D5 Y  D* n$ R. x" \/ N9 S) |6 ~
    *@dev如果token不存在异常返回空字符串4 {% E2 H% X3 P! j# l
0 Y. V6 H, ?: s, E) l
    *@param_tokenIduint256IDofthetokentoquery( F) E8 E4 }7 Z+ w

- r3 U) x" f. k    */: Z6 S+ g4 b$ @
$ h) t3 b* G8 y6 ?  {& l$ e1 l
    functiontokenURI(uint256_tokenId)publicviewreturns(string){
/ l2 a7 H; f) y# X' H; l* W- V% b$ P; P$ G7 o( i! Y
    require(exists(_tokenId));
2 e* E" D& m) A5 A8 F
+ c' T: Y) m! E# x' X    returntokenURIs[_tokenId];
/ S% y+ ]5 G9 b$ q/ S9 y& b+ N4 ]9 I
    }
1 i) ?* Q# H* P& G' y0 G
& e5 |+ `: H# r  B3 ]    /**% w, N0 p8 r4 B( ^- l

- @  a) X$ ]; L/ f' {. h$ Q    *@dev获取tokenid通过给定的token列表中的索引
  w5 H, v# ~8 G: ~" R/ m+ u- X7 V! h3 `. T2 c) u; B
    *@param_owneraddressowningthetokenslisttobeaccessed
! e' w+ d, P  A7 R5 o9 f3 }3 e8 ?9 ]: P/ x4 Y8 J
    *@param_indexuint256representingtheindextobeaccessedoftherequestedtokenslist
+ D% f. L5 r1 w9 Q( a9 R' v- b5 A
4 |5 Y5 S3 c% M    *@returnuint256tokenIDatthegivenindexofthetokenslistownedbytherequestedaddress
5 ^. C/ x) Q9 D3 r0 i. k( E( X- [" g( J8 ?
    */
0 k' U  a, D- n: `2 Y1 ]; {3 {# [; k8 R1 Y
    functiontokenOfOwnerByIndex(
! D( ~: N/ Q, E% N0 x; j
! P! v/ h. m' m3 d/ M9 [* H! Y    address_owner,% p9 }+ {6 E9 W6 m: L3 G$ l

' n; R5 a# Y& F0 r; b& J4 Z    uint256_index3 v8 X$ F8 w7 h( [$ T& G9 _5 o

1 I/ r( H1 f# E" M" B    )
' A' B8 D+ y+ R. ~8 m7 V
. b- c. e% V4 a8 m3 \8 x: d: K$ z    public& S: {) y8 a* ?5 }

2 _$ `2 X0 Z% L    view7 _( S; \% [8 c# w2 f
+ T. i% Z7 l% Y4 @5 u. y. S
    returns(uint256)# U# j4 u2 Q% ^8 l) I
( M) v1 k& B6 `* R. X$ T
    {
  ~; y3 i# Z/ C6 Q  G5 z2 D/ }! ~, v3 _
    require(_index
  J" q7 d4 e* ?1 R- r8 e4 r2 Y2 J+ `. _; b) [: Y8 \- t" C
    ERC721Token实现了完整的ERC721标准,在继承了ERC721BasicToken的基础上增加了一些token的操作,主要在包括token的元数据,资源URI,增发销毁,还有就是token索引的映射关系。对于具体实现我们根据实际情况通过继承ERC721BasicToken或者ERC721Token来添加自己的业务逻辑。. ^+ H8 ~1 K0 {. ?- h5 D

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

本版积分规则

成为第一个吐槽的人

杨远枫冠 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    2