Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。1 h! B7 }# O8 n. k
废话不少,先上完整代码:
  I. |# W: A- i. x: r! S6 T! a
  1. pragma solidity ^0.4.24;
    ( K- T& F' c/ {) v# t! ~
  2. library SafeMath {  /**2 p" H% ?+ o* Y. ~
  3.   * @dev Multiplies two numbers, throws on overflow.
    - _; M- C6 q5 Z8 \+ X
  4.   */
    2 k! j0 ~- k6 P, C- [
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)
    ( C& |- @& j( r& ^$ E9 K; i
  6. {    if (_a == 0) {      return 0;
    0 c. R  b- r7 _5 j" q) X
  7.     }
    + l' M( D& z2 n* ?' e
  8.     c = _a * _b;9 I/ N- a! U; I1 u8 @
  9.     assert(c / _a == _b);    return c;/ U: U, N7 V5 o& ?
  10.   }  /**
    + x* m$ y7 P8 r; J
  11.   * Integer division of two numbers, truncating the quotient.
    # T: D: m" Q! g# d7 H7 h$ n
  12.   */# n  |- E$ A! Q8 i2 l/ g0 p" S$ J6 Z
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;# E5 z5 m$ P' F4 T/ k& ~
  14.   }  /**
    * Q( l) ?. s' ~
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    / n; |1 h6 S- w9 D
  16.   */. f) \8 A* ~1 T: Q) d3 C" C
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {* x  R7 c1 Y. I, T( x. z7 K
  18.     assert(_b = _a);    return c;; Z  q- p) O9 d$ R# v5 J6 Z
  19.   }2 U! P, P- T# u
  20. }
    + ?* @* A) O9 r3 ]$ S$ X% |7 O! T
  21. contract ERC20 {0 ]- F9 q' R! x+ m
  22.   uint256 public totalSupply;  function balanceOf(address _who)
    , J. p7 P# b, @3 n0 u% q1 m5 m
  23.   public view returns (uint256);
    7 b/ {+ K0 S4 t# f7 Q! i
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
    5 D' `: O, V% L: @
  25.     function transfer(address _to, uint256 _value) public returns (bool);  
    - R  C* y* g. b1 }9 X$ D; [
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    6 c- I  p: U1 _8 g1 L& L
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  * P! Y/ O/ c7 t5 y2 N$ z
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);
    2 P% J; v- E% l2 ^/ v% X
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    , X* g, r7 O0 y3 B# U
  30.   event Burn(address indexed from, uint256 value);' w# B% W" q5 Y- w  H, ^
  31. }contract StandardToken is ERC20 {
    ( j9 ^) n. y) ~7 {( S2 ]- U4 ]
  32.   using SafeMath for uint256;2 `9 Q* J% H+ ]' U2 x8 b4 `, B
  33.   mapping(address => uint256) balances;5 W3 O) i0 H7 r/ P0 T5 {' b8 g
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**( X: u" X7 S  K' L* m
  35.   * Gets the balance of the specified address.+ F* B% h/ |1 W- C
  36.   * @param _owner The address to query the the balance of.2 q! t# q" T2 ]% F# }6 _+ D/ u
  37.   * @return An uint256 representing the amount owned by the passed address.
    9 i1 |3 o4 U7 o' r  O
  38.   */
    ( K! _7 c% \+ b8 P- K/ s
  39.   function balanceOf(address _owner) public view returns (uint256) 3 I8 f7 A' ^5 E
  40.      {    return balances[_owner];
    8 Z, i$ A5 R5 ?1 n, M6 g
  41.   }  /**! y& |; f0 L& e  @, }
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.0 Q3 e0 y4 r2 r8 D6 k4 q4 A+ D, ^
  43.    * @param _owner address The address which owns the funds.
    3 e) A( V: K# F5 ?" w
  44.    * @param _spender address The address which will spend the funds.
    % }; E6 m7 g" @1 U" A- c
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.' y# c+ W; w' ^+ V, S! |
  46.    */6 _1 s4 W9 z1 x; w* q
  47.   function allowance(address _owner, address _spender) public view returns/ i9 x2 T. B3 w! a
  48.       (uint256){    return allowed[_owner][_spender];* I. X- N( R2 P) p9 I% K
  49.   }  /**
    8 [" @' y2 L5 l1 k
  50.   * Transfer token for a specified address0 _1 E; t3 S! m1 {9 A' T. J+ q1 h
  51.   * @param _to The address to transfer to.
    ( f% a5 E, o: \$ `
  52.   * @param _value The amount to be transferred.
    ( l3 @  R7 o9 y; W4 K9 O( e, I
  53.   */% }0 R; a- U2 j0 N+ i! e6 u, r
  54.   function transfer(address _to, uint256 _value) public returns
    # }/ Q8 U; z+ }# ^
  55.       (bool) {    require(_value = oldValue) {6 f6 y+ r! C0 `7 I
  56.       allowed[msg.sender][_spender] = 0;; f- _+ U+ p+ V
  57.     } else {& q$ I* H, n) C5 N  G: j( _
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);" W0 Y& H  r2 p6 Y( a7 B# n  m
  59.     }6 e. u) x1 @1 ?2 B  x
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;
    2 ]: h8 Y9 |6 Y0 E" q5 b  E: E7 t
  61.   }  
    7 l- m; Y) L- f
  62.    /**
    5 @, f5 Q3 _$ y7 s6 B7 N
  63.      * Destroy tokens, x0 p4 P8 i5 y/ T" H8 d! y
  64.      *5 ^( `, m- f# F9 k" l9 s  {
  65.      * Remove `_value` tokens from the system irreversibly
    / t* {9 \% L% P& e  ^0 X* z$ [
  66.      *9 K$ C! w) {3 {+ q6 w, D6 e
  67.      * @param _value the amount of money to burn; H  g* ?- V% P
  68.      */
    5 z8 H$ l( W, r& \) @
  69.     function burn(uint256 _value) public returns (bool success)
    $ X! c8 [9 u/ O% W( w
  70.           {        require(balances[msg.sender] >= _value);   
    ' F7 [9 }) @* F9 Y4 u9 }/ a
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          ' Z6 \; H8 V: [5 F0 e
  72.         totalSupply = totalSupply.sub(_value);                     
    & ?5 v+ w. j/ A/ f: _) z, t0 d
  73.         emit Burn(msg.sender, _value);        return true;
    $ q9 A/ X! ]0 K0 F
  74.     }    /**
    , d9 E' e9 L3 Z9 S: n3 L
  75.      * Destroy tokens from other account
    % G* c: r# G. Y5 f" i5 E
  76.      *$ V6 S6 |- k$ b! d  s
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.5 \" Y; H3 W4 U6 e8 u+ Z
  78.      *, d& Y6 P9 H2 `' O9 o+ |5 `: a
  79.      * @param _from the address of the sender
    * Z( t4 j# j7 j* U& g+ g) t, Q1 Q
  80.      * @param _value the amount of money to burn/ M2 f8 L: i7 h: ?) \, B$ ?' l2 p% n
  81.      */' ]4 }) h, r- Z6 i; i
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success)
    3 n4 D! N3 e- }1 X! P
  83.           {        require(balances[_from] >= _value);               
    3 F8 H6 B' [& _( c3 Y% |; _, I
  84.         require(_value
复制代码
( F* @, Q6 v& A/ ^2 i
这些代码是什么意思呢?
5 f  E* s' i& a/ G+ ~一、ERC20(EIP-20)说明
5 s& M# |/ w+ O, v3 eERC20是一个标准的token接口规范:A standard interface for tokens
6 a; Z1 R8 U0 I/ Z8 u" s* I2 V该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
8 \8 t' m" o" ]* D7 Y我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
1 h9 w% U% w. l4 x* K8 H9个方法包括:
# M  g; X( Z& A) M: {返回token的名字
, M, ?- [* x4 _function name() view returns (string name)
+ I& N, `% `+ F" [返回token的代码$ q9 S( B# q, x8 ]
function symbol() view returns (string symbol)9 M1 Z, I8 L) |) S% a5 b" w: B- b
返回token的小数点位数
: d9 J2 w+ T% M2 e/ Q3 Hfunction decimals() view returns (uint8 decimals)% y; l' \6 s6 G* V+ N
返回供应总量: @. S, z- S% B' I# n
unction totalSupply() view returns (uint256 totalSupply)
& ^9 c! {. W4 h$ M查询某个地址的余额$ }9 g; S3 L/ f2 k- s8 V3 @& M" D
function balanceOf(address _owner) view returns (uint256 balance)1 R. W3 Y. o6 R# O" g4 W
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false8 M/ {: J- x+ d: b+ q9 h. S
function transfer(address _to, uint256 _value) returns (bool success)
1 E6 I( T9 v- x从from地址转账到to地址,该方法用于委托给其他合约代理你转账5 Z$ r6 m3 L4 w  o  N" Z
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
0 c2 p, g2 v, g( x( q允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value2 e4 t1 a7 F3 s+ G* F3 c
function approve(address _spender, uint256 _value) returns (bool success)
! q0 J5 s' z& C; S( a- S返回_spender仍允许退出的金额_owner
  x% L  [" A# X" y" e5 K2 Xfunction allowance(address _owner, address _spender) view returns (uint256 remaining)
: Q) m$ s  c& D2个事件包括:
7 \; t6 a/ ~7 E( I5 c0 a/ z转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候# Z) G. }: s  a, H( S$ J! z. F
event Transfer(address indexed _from, address indexed _to, uint256 _value)
% c8 x9 l( i  V' E0 `2 X委托转账必须触发
& |  S$ e( R( p3 @' v5 R' k, v, a, sevent Approval(address indexed _owner, address indexed _spender, uint256 _value)
- E( K6 x* J) g! q" i; u
0 @0 H# z% |8 w5 C# N
" p" b0 U. K2 n二、代码解释' b4 w  N( ^6 ^" G; G
0 I. q6 A' \( n  }$ K1 A
代码包括几部分:1 R& @; S4 T3 W1 a% m, r
7 O7 e( q* i) C- Y% M2 b& A
安全的数学计算库0 i2 ~- k* t* h. r) C
" \/ g0 N- `" {+ @2 o' V; z4 J3 m4 ]
contract类 ERC20,主要针对ERC20规范定义方法和事件, G! N0 G  |$ g1 Y9 E

# _( P7 j& v! y: @+ v) ]contract类StandardToken继承ERC20,定义具体的方法实现
; H: z( Y1 |' A1 I7 i- P
) V% m- F* m( |8 y& s/ s3 w( Acontract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5