Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。( W/ r  D; G, }$ i$ {% X
废话不少,先上完整代码:- \; {( m5 e- |6 g, m5 S, E
  1. pragma solidity ^0.4.24;
    8 V8 W3 ~1 R. L- j! @( [" g( f. |# V
  2. library SafeMath {  /**; H  e7 h- k! h# S. m  c
  3.   * @dev Multiplies two numbers, throws on overflow.
    , {% |/ e% e- O0 m( g
  4.   */
    # F7 r+ x+ b% R
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)/ b! A5 ]6 |8 Q# e
  6. {    if (_a == 0) {      return 0;3 l" C: c2 C( V  A, _6 W
  7.     }( [- Y1 j0 b* o6 h* x
  8.     c = _a * _b;) Y+ ]* h8 a% i* }
  9.     assert(c / _a == _b);    return c;
    + I/ x  j3 L0 K! u, x
  10.   }  /**1 S+ w. Z3 `3 q, Q  h
  11.   * Integer division of two numbers, truncating the quotient.5 I1 i7 {# K$ ~, U
  12.   */
    1 ~& U8 @5 U+ d# N0 L8 ?/ X, r/ M
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    % v3 G& W/ T5 q$ l
  14.   }  /**
    ( Y7 N4 [0 ^. @- Q1 h, y! H; {
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).2 [5 H7 h" b9 _9 d; Z5 _3 Z
  16.   */- D  I( W  W0 p- G* g9 q2 j
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    6 c2 `! z- q9 [5 U# j0 z9 v. h% G9 V
  18.     assert(_b = _a);    return c;
    1 i1 y. P- j1 t# E8 X# ~
  19.   }
    % i2 p- E/ i% ~& ?
  20. }
    8 D: v  B/ a3 w
  21. contract ERC20 {& R3 j7 [% K' i3 X( O4 m# M6 Q& ^
  22.   uint256 public totalSupply;  function balanceOf(address _who)! P( X. b8 Y4 n" e( }; b2 F
  23.   public view returns (uint256); / W' S; D# v: E4 D7 w7 C
  24.    function allowance(address _owner, address _spender) public view returns (uint256); ( d1 Z( }. z$ A1 C
  25.     function transfer(address _to, uint256 _value) public returns (bool);  9 [2 h4 i6 ~( W% S# r2 |
  26.   function approve(address _spender, uint256 _value) public returns (bool);  - ?$ F4 m3 x8 t/ R
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  : O7 P3 q9 E) G& L" {3 F& U, L
  28.     event Transfer( address indexed from, address indexed to,  uint256 value); $ |- l9 o, f' A# K2 f
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    ( Q0 f0 P+ e: G1 A- J
  30.   event Burn(address indexed from, uint256 value);+ O) l# R& p9 D. N1 u7 z. A
  31. }contract StandardToken is ERC20 {% S8 V2 }; M* I
  32.   using SafeMath for uint256;
    " m* d" F: \" Y. m8 a' K
  33.   mapping(address => uint256) balances;1 N8 g% b" c& D" Q
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    ( I1 d: a% t9 b1 A
  35.   * Gets the balance of the specified address.
    & M& \* D5 W8 G! D2 _, ]
  36.   * @param _owner The address to query the the balance of.
    0 \& }' `( n  {, V2 W
  37.   * @return An uint256 representing the amount owned by the passed address.
    : d, `( \% a8 `% ?+ U8 k
  38.   */
    4 H5 i. \0 j9 |+ h. i) N* f" L
  39.   function balanceOf(address _owner) public view returns (uint256)
    8 K0 g9 R) Z- W4 L. h3 V9 S
  40.      {    return balances[_owner];: J! T+ `3 n! B
  41.   }  /**
    5 z) o4 }5 I; k9 p# y; L; E) S
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.
    9 F6 \! w) X- `! y
  43.    * @param _owner address The address which owns the funds.
    . |+ C! k' T4 H! W1 x
  44.    * @param _spender address The address which will spend the funds.2 d& ~4 c. Y5 E9 V  p
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.+ i3 l/ K  C7 l" D/ o9 C
  46.    */
    . A6 r1 @- p( Y
  47.   function allowance(address _owner, address _spender) public view returns
    - m4 \5 \3 E& m& e4 c! |
  48.       (uint256){    return allowed[_owner][_spender];. K# w6 z5 J/ ?+ H
  49.   }  /**
    - z5 h5 f" |! y; P) e
  50.   * Transfer token for a specified address
    6 ]- o: S$ D, l" C: Z4 V
  51.   * @param _to The address to transfer to.; v5 s- I# |5 h
  52.   * @param _value The amount to be transferred.# ^& v( a' E1 s: Y
  53.   */0 j. G- n' Y2 m* R+ P  m2 x
  54.   function transfer(address _to, uint256 _value) public returns 4 I1 c1 }5 H. {: E
  55.       (bool) {    require(_value = oldValue) {
    ' Q6 ~1 v1 t+ s# t* ^
  56.       allowed[msg.sender][_spender] = 0;
    6 B0 `: a6 A& y3 }: X' _
  57.     } else {
    3 u/ i0 b  g( a0 C- ?
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    $ w2 X6 L/ c# G# `4 b3 G
  59.     }, ~; \$ X" _9 H5 R
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;8 e" s' I. U8 n" e5 q
  61.   }  * @9 e9 M: ?( Y+ ?& J  \4 x! c, [
  62.    /**
    ' H$ {, j" w$ e
  63.      * Destroy tokens& \, w/ p$ X) ]- n) [
  64.      *
    / O  h! H) {6 m: @
  65.      * Remove `_value` tokens from the system irreversibly
    3 v. k) x- S5 o! N' n
  66.      *
      ~/ {) V3 P4 \; ~1 G- Z6 l! b
  67.      * @param _value the amount of money to burn3 y6 S% g) p6 {  P
  68.      */
    6 ~4 j2 i7 `2 h) m6 q
  69.     function burn(uint256 _value) public returns (bool success)( W  ?5 E% R, |! p) c: A9 S
  70.           {        require(balances[msg.sender] >= _value);   
    + b* Q& q: X+ V3 v! B  W: m3 `% J4 w4 f
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);         
    9 o. r0 C/ n9 w* J% n8 v; o. S% c
  72.         totalSupply = totalSupply.sub(_value);                     
    ! v* @  [# n5 ], k: e
  73.         emit Burn(msg.sender, _value);        return true;
    - ?; q; i/ g& r" x
  74.     }    /**8 o1 R6 P" F+ A" |
  75.      * Destroy tokens from other account
    , L7 g: C3 b: k$ y) v4 P. ?
  76.      *; j) x1 i- D" y) b/ Y# R
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
    1 u1 z3 W: N& Z' Y, w& ]
  78.      *
    $ i$ F8 b' X1 e: V
  79.      * @param _from the address of the sender
    & i" }) @+ {& ~6 g# h6 _- U; W
  80.      * @param _value the amount of money to burn
    & P. e' {# \6 X: {$ ^4 S
  81.      */
    ; H* |" u' L' T; o/ a5 F2 r
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) % Y0 ]1 [* C# K
  83.           {        require(balances[_from] >= _value);                * H7 `# E7 E9 Q2 X" Q
  84.         require(_value
复制代码
' ^0 {4 e# L# R- j, t; ?
这些代码是什么意思呢?' q2 N3 C0 R/ ^5 A( b$ Y2 v
一、ERC20(EIP-20)说明3 R% E( r6 e( K7 I3 @
ERC20是一个标准的token接口规范:A standard interface for tokens7 b/ }5 J6 ?7 i
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md/ D; m5 R4 ~! p+ h" E
我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
( H/ Z/ R! s4 `; P9 ^- P9个方法包括:
4 a* O2 l. _+ P; H' D" O返回token的名字
* j: U" |' F, s# A! H2 i; W, Dfunction name() view returns (string name)* v3 i, v- k( T5 O# Y# h) }
返回token的代码  e* o- o$ b" }: x, m
function symbol() view returns (string symbol)
" o8 F/ q, G" d2 x返回token的小数点位数& K- s9 D" H0 o+ X3 _2 w6 ]
function decimals() view returns (uint8 decimals)
2 A& q. w7 b9 A7 ]返回供应总量
2 @7 z5 Y2 \% p; U/ d! @unction totalSupply() view returns (uint256 totalSupply)
; J+ o9 a( ~) u* b3 F2 l查询某个地址的余额& C( }$ t$ w; R9 T1 D2 m
function balanceOf(address _owner) view returns (uint256 balance)' O. b3 [" o: j
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false8 g1 `& o6 V) F$ t
function transfer(address _to, uint256 _value) returns (bool success)
' o. ^6 O5 x- \2 c3 H1 U* l8 g从from地址转账到to地址,该方法用于委托给其他合约代理你转账
' @" p; @0 e. Z* x5 Ofunction transferFrom(address _from, address _to, uint256 _value) returns (bool success)& |+ Y: k9 o- S1 y+ y8 B+ y2 n
允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
3 ]- t: j. R& [1 H5 S6 kfunction approve(address _spender, uint256 _value) returns (bool success)
" [3 a4 y  E: P返回_spender仍允许退出的金额_owner
1 f* i9 N- K2 {: C) a. Cfunction allowance(address _owner, address _spender) view returns (uint256 remaining)
; ~' f3 j7 B3 \2 e3 X2个事件包括:! x: s2 R7 x' Q
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候( U6 }2 R* k, t" `9 ~/ s* N8 z
event Transfer(address indexed _from, address indexed _to, uint256 _value)
8 f& e3 t2 h' A" R9 y委托转账必须触发+ \7 h- q" L* q# T! l* q% m
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
$ }' d7 u" W1 R; E* ?; K# H- d$ O* F
4 c% D9 C& U7 ~! L8 ~* }8 z- [6 |) z* O& g
二、代码解释7 W. s) K6 d& Z
4 }) k$ @* }, I8 r3 D" P7 ~
代码包括几部分:& A  o  Y! O1 ]& D4 o$ |
6 Z, D/ V, Y! Q/ [1 i2 g% \. X( v
安全的数学计算库8 }. T' m8 o: m: s; {: Y
5 W( |2 G+ }( z7 v1 C4 t( x
contract类 ERC20,主要针对ERC20规范定义方法和事件
) V* f( V5 @- t' ^9 J2 }' f/ o6 k1 I
contract类StandardToken继承ERC20,定义具体的方法实现
; m, u' A9 Z) D1 L  I7 n' {( o: I
% M; g, c( q' H) W/ P/ R: [2 Econtract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5