Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。9 v# i, o, V7 U0 }: x+ a
废话不少,先上完整代码:% K/ r& g6 H. u1 Q0 n
  1. pragma solidity ^0.4.24;# G1 y2 V) Z5 |  t9 q
  2. library SafeMath {  /**
    6 V# F+ P5 ]# _
  3.   * @dev Multiplies two numbers, throws on overflow.
    & W& [: D* q! F) f; \
  4.   */% q# |, z: P/ \. g) d' f
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)
    . C( ~7 a6 l; S- e% A. n9 `8 ?" J
  6. {    if (_a == 0) {      return 0;
    $ H' n& O8 M: m& {! q4 n$ A
  7.     }, Q" L2 q/ G$ Z+ \! t2 B+ ?
  8.     c = _a * _b;" S4 m4 M2 J! z% o: n* I5 B; J3 k
  9.     assert(c / _a == _b);    return c;, ~+ u7 A& p& p- {$ q
  10.   }  /**7 h. ?; M/ Y, W6 W
  11.   * Integer division of two numbers, truncating the quotient.  C! v5 o8 K" @' X
  12.   */4 o- P. q$ P3 @; S7 @3 t
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    ' p8 h$ E/ {# _! l
  14.   }  /**
    ( }" E$ _0 Z9 g$ b
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    + K8 `$ J8 l( n% d
  16.   */. d# Z: N- P9 P
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    8 y" f! r% }) a
  18.     assert(_b = _a);    return c;) d( d2 i1 V9 J$ ~. r
  19.   }
    & B, R3 y( m) C6 n* w
  20. }- E: G# A' Y( ], `0 \
  21. contract ERC20 {
      M0 ?+ q  n1 }1 m+ ]3 I
  22.   uint256 public totalSupply;  function balanceOf(address _who)/ L6 z: _) a/ j! I
  23.   public view returns (uint256); 4 A% R5 g; V+ S' C& E( J- p3 p- Q8 O. j
  24.    function allowance(address _owner, address _spender) public view returns (uint256); 7 l: q5 p7 u7 i, {  g& J
  25.     function transfer(address _to, uint256 _value) public returns (bool);  0 p9 S6 m7 W6 k2 X0 T' o: i+ x( x
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    + J" x$ U6 r8 A3 O: b
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  8 I$ p6 L  K: N3 Q9 y9 w
  28.     event Transfer( address indexed from, address indexed to,  uint256 value); ' f) Z6 G" S! h5 u; r3 K
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    0 ]; T3 d5 F0 e- w% H
  30.   event Burn(address indexed from, uint256 value);1 V. w6 d, z9 A4 U( {7 ~
  31. }contract StandardToken is ERC20 {
    0 ^3 h2 z& z+ s9 H5 u3 u
  32.   using SafeMath for uint256;
    * s' W5 g+ d' J3 k5 H
  33.   mapping(address => uint256) balances;
    1 G; Z  Y% }; S/ q% W
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    . z# Z9 a/ D1 r2 A- q
  35.   * Gets the balance of the specified address.
    + O$ i$ Y' C4 Y2 n6 t' f
  36.   * @param _owner The address to query the the balance of.
    ) {6 y6 _3 m) S2 p2 D9 d0 c( R
  37.   * @return An uint256 representing the amount owned by the passed address.
    ; n; n3 }6 O/ W- i
  38.   */
    ; h7 Q+ @+ J, x/ Z9 S. d; B4 g
  39.   function balanceOf(address _owner) public view returns (uint256)
    1 N: ?1 c5 K' w9 d& _
  40.      {    return balances[_owner];" o* j% }: n& M9 k
  41.   }  /**7 O7 e$ h* ^( V" y) U
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.
    6 D9 O# q4 u$ K
  43.    * @param _owner address The address which owns the funds.
    * a1 _: x- S& {8 U0 m2 O" e* A  a
  44.    * @param _spender address The address which will spend the funds.
    ) ~% c7 m3 w1 H7 }3 g
  45.    * @return A uint256 specifying the amount of tokens still available for the spender." N" S5 P. j) A8 |
  46.    */
    & q$ c4 b( x% _* p% S$ m/ r5 i5 x
  47.   function allowance(address _owner, address _spender) public view returns# N/ z! Z& a6 j; t$ K* B8 X. w. d
  48.       (uint256){    return allowed[_owner][_spender];5 s0 _+ u; Z; M+ b
  49.   }  /**6 ~9 Y( v) G# I, ^
  50.   * Transfer token for a specified address6 Q+ N6 x  J9 m/ t3 }3 \
  51.   * @param _to The address to transfer to.3 I7 o8 n0 F8 h* E: Y
  52.   * @param _value The amount to be transferred./ }( A- ~; @6 R! q1 M6 F' x
  53.   */. b. }& T0 M9 D
  54.   function transfer(address _to, uint256 _value) public returns # Y+ M$ g6 d1 g0 r: i: s
  55.       (bool) {    require(_value = oldValue) {4 y# L: m* ^. B  T1 M6 \. x
  56.       allowed[msg.sender][_spender] = 0;
    . E1 z0 N9 L3 V" k1 A
  57.     } else {
    ; m  k% W- [3 T( A: \* b9 [
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    3 H9 p7 A3 n% d
  59.     }
    * z: `2 u! E9 |2 z/ i: V% y
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;3 Q* b9 G! ~% Y$ Z, @) ?) Y
  61.   }  
    9 _) l) V% Y4 z! Z" O# \2 a% D. D
  62.    /**
    $ P3 f9 w! S& T" ^
  63.      * Destroy tokens3 c1 v- B& }( y5 A
  64.      *2 Y5 w2 p1 B. [7 y( k& h
  65.      * Remove `_value` tokens from the system irreversibly0 p6 Z" N. t1 k$ e) ^) s, I0 u; B
  66.      *2 T8 ~2 T, b7 @7 O# e0 J
  67.      * @param _value the amount of money to burn
    . r' u: c  y6 c# M
  68.      */1 ~# _8 ^* e  q1 S, d
  69.     function burn(uint256 _value) public returns (bool success)* C0 w! U6 F/ L: g( ]5 F6 l5 b
  70.           {        require(balances[msg.sender] >= _value);   - I+ u3 q* d- d
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          6 d1 x0 ~, w) `9 H
  72.         totalSupply = totalSupply.sub(_value);                     
    ! S) J* t* g, w+ x
  73.         emit Burn(msg.sender, _value);        return true;
    & P, }: `6 Q  ^  n8 f4 R, ?
  74.     }    /*** @  p2 z$ f; }# w' A* s0 Z
  75.      * Destroy tokens from other account  O! y2 n' Y4 ~6 e* F* j  h
  76.      *0 H4 Q1 [2 ], J0 T2 k3 {  s, R$ C
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.; }' ~. Y$ L# C2 c3 N" f9 Y
  78.      *
    $ {# Q& Q# I# ~% q4 o/ {7 T1 p
  79.      * @param _from the address of the sender
    ( J2 d& N' u, E- B1 G
  80.      * @param _value the amount of money to burn
    & d  g9 e$ F! p
  81.      */
    8 b6 t% n1 c. H
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) - e8 o5 g- c4 {. y
  83.           {        require(balances[_from] >= _value);                6 \( P/ e$ x1 g: s1 ~
  84.         require(_value
复制代码

: U/ a3 A4 N( h, B' |# N7 A这些代码是什么意思呢?9 q: Y' e, Z5 T
一、ERC20(EIP-20)说明- ~! p" k+ R3 E: ^
ERC20是一个标准的token接口规范:A standard interface for tokens; X; }( v/ k7 z- Q
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
$ u0 J2 F. x3 a) S9 `1 k我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件- Z' A+ a/ i; ]0 B/ Q
9个方法包括:
5 C! q8 z( l# _, K: w0 |$ M7 ^返回token的名字( h8 a4 H2 r6 ~' _1 X" s
function name() view returns (string name)
' k: m8 g8 Y# g3 u返回token的代码
) D( V6 F) @; k& |+ f& H7 gfunction symbol() view returns (string symbol)) ]4 {8 Z3 Z; Z( T5 N5 m
返回token的小数点位数4 W6 a4 ~: P4 J1 Z
function decimals() view returns (uint8 decimals). s8 Z6 G$ m+ x3 }7 `  x0 I
返回供应总量
  _  {+ E+ l- H2 P: [8 I' f, a# r7 gunction totalSupply() view returns (uint256 totalSupply)7 c. M1 `# J6 B9 V/ x
查询某个地址的余额3 z6 m# h% r8 ?* c
function balanceOf(address _owner) view returns (uint256 balance)
. w2 y# W  a; b, F6 R3 r给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false6 B! h  O' ^$ x; T! e+ T1 i
function transfer(address _to, uint256 _value) returns (bool success)
% z: J6 i* H; c+ P' A8 l从from地址转账到to地址,该方法用于委托给其他合约代理你转账, }$ V  R- S( [1 x
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
) @/ i& |2 j: t( Z" K1 i" v5 L+ J允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
$ z! j' _" ^4 t9 Zfunction approve(address _spender, uint256 _value) returns (bool success)
0 d" @1 i4 Y1 V1 e返回_spender仍允许退出的金额_owner; U% i0 t* E7 g
function allowance(address _owner, address _spender) view returns (uint256 remaining)2 n4 e# o& {" p8 B
2个事件包括:
' \, v% b. ~' L# G转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候8 ^  k: X! \- v0 S; C. G
event Transfer(address indexed _from, address indexed _to, uint256 _value)' m# \. @  S8 E9 P: f: ~4 @6 j
委托转账必须触发
1 f" X8 u& J& B- n! ^5 Vevent Approval(address indexed _owner, address indexed _spender, uint256 _value)
; j7 |% p" `) C- E" J
) R/ B4 ?) E- Y: |) A
0 Q# t! N. K4 ]" I( z3 ?二、代码解释
9 j: P6 S" k- ~+ t3 V4 j6 y
# q+ @  @- k; X( G1 O代码包括几部分:9 ~: h* d- y! w( H/ Q+ U% t

& r0 J5 b" I5 G6 K- Y+ H8 y$ K$ @安全的数学计算库
+ Q. w1 ~/ B- ^7 |( F& q2 V' d) l" m4 H  [
contract类 ERC20,主要针对ERC20规范定义方法和事件, x2 J, l- ^. U3 d" W" p# b

1 g" M, D6 r4 }* ^7 _& S2 T8 n4 ocontract类StandardToken继承ERC20,定义具体的方法实现- _* E% T+ E( V6 {9 V# A! q! s5 X5 ?
4 u7 q8 C) `3 v4 T4 m9 j# i
contract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5