Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。/ D' U, f8 m; i& Q0 t% I' {
废话不少,先上完整代码:% Q, c& z; C% {. M' n
  1. pragma solidity ^0.4.24;
    / y, m, d5 t0 f0 y2 O4 r0 W
  2. library SafeMath {  /**% }9 q- r, o" S2 v+ J8 j
  3.   * @dev Multiplies two numbers, throws on overflow.
    ; ]( Q8 A' e2 H. H- g2 H; a
  4.   */, i% z% ~. H  L: V$ Q  b
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)+ Q1 X; X; O" `
  6. {    if (_a == 0) {      return 0;
    7 t- N& l4 M* b. G3 ?& a: U
  7.     }
    % e% p, [* ]7 A' p$ x. Q) ^" y
  8.     c = _a * _b;
    ! ]' x7 K3 j2 ]# V3 k( E
  9.     assert(c / _a == _b);    return c;
    0 e" G6 g0 b: b/ \4 v
  10.   }  /**9 B4 D- }. n. W. B  u7 c0 }
  11.   * Integer division of two numbers, truncating the quotient.
    7 }# u9 k. e4 V2 E+ Y. x9 F
  12.   */' V2 Z% W1 X+ O1 E7 H  \, g/ U1 l7 p
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    5 f% t$ ]0 S+ I& `9 T
  14.   }  /**
    , x, b" h- q' c9 d
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).4 O" y+ O* J# f  L6 l1 m6 e
  16.   */( F9 Q! p: B) e4 C
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {, p- o& b2 _1 a& X$ L& N& b! L
  18.     assert(_b = _a);    return c;
    - r- K) ?$ x  R' q/ p
  19.   }
    & \1 ^- L$ O- [( i
  20. }
    - s9 e6 @# [  X0 I8 K, s
  21. contract ERC20 {, i' A$ M  _  N* O7 z
  22.   uint256 public totalSupply;  function balanceOf(address _who)
    8 ^# V3 A/ j' Q' f  `
  23.   public view returns (uint256);
    % B; V8 b! ~' v2 c! ]+ ~6 w9 B% A8 E
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
      V. j. x5 Q- U4 g
  25.     function transfer(address _to, uint256 _value) public returns (bool);  " q5 ]" }( V) V6 Y6 h
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    3 b; ~( ]2 F. L- O- Q: M
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  4 v0 i0 y2 s1 n) {
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);   {1 q  w+ O% I3 u/ O% k8 L& A
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  7 g' n$ T& C0 {& l
  30.   event Burn(address indexed from, uint256 value);6 M% Z% q8 ?. h7 B" A# p
  31. }contract StandardToken is ERC20 {
    1 ^. z1 ^! a# o, ^' `" ^
  32.   using SafeMath for uint256;
    1 j3 f, x: ^4 v& ~# r4 u$ l" u
  33.   mapping(address => uint256) balances;6 a" T% l! u1 R0 T# \
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    , ^( w7 k* y# S5 a7 E6 P2 @$ c
  35.   * Gets the balance of the specified address.' J  j0 D% w9 x6 s+ _9 `9 N
  36.   * @param _owner The address to query the the balance of.
    5 r$ X) @: I$ V7 ~( t
  37.   * @return An uint256 representing the amount owned by the passed address.3 r% T8 ]/ [8 n
  38.   */$ X1 d( s/ |0 [, e9 g$ c3 Q
  39.   function balanceOf(address _owner) public view returns (uint256)
    8 \& [1 S7 G; f3 A+ \& f; a' Z
  40.      {    return balances[_owner];  b: v. v% g1 N
  41.   }  /**
    % y3 }/ X2 L; M9 t4 Z% k
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.
    ) |1 {3 h4 f3 O5 y# ^
  43.    * @param _owner address The address which owns the funds." ]6 q! Y5 l5 {$ f7 `  [6 O
  44.    * @param _spender address The address which will spend the funds.
    8 @" T7 ~, ]# J8 k, B. P
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.
    " g; b7 s! a$ M! G6 v1 S3 L
  46.    */- O  f4 w! Y* H
  47.   function allowance(address _owner, address _spender) public view returns
    - G" \$ x$ _/ Q' r8 c
  48.       (uint256){    return allowed[_owner][_spender];
    ) h- H5 [1 Y) ?8 v' r
  49.   }  /**
    : W7 {4 ^$ K  A2 e! _
  50.   * Transfer token for a specified address
    $ f$ o0 u$ b5 C' E# T8 }8 I
  51.   * @param _to The address to transfer to.
    ( R& Z  N" O: [/ ]
  52.   * @param _value The amount to be transferred.
    ) r7 Z8 o  ^0 |
  53.   */& W/ G! E: K6 S  L
  54.   function transfer(address _to, uint256 _value) public returns 9 O" A' `' `- m. }3 q+ T, H8 m* |
  55.       (bool) {    require(_value = oldValue) {
    , c& R# W. a8 n6 n) W# q
  56.       allowed[msg.sender][_spender] = 0;
      R4 e+ x# a( k" F: k" y
  57.     } else {8 Q1 J. }8 R8 z# K9 w4 N  P! t
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    + M+ O" k8 w" V2 d* ?5 Y+ N: A: S
  59.     }- l& \1 y: M# Y6 B8 ~- [
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;9 g* m2 X. G( D0 @% [% M. H$ w
  61.   }  4 b2 d5 I7 `4 N- t# K+ U/ ~
  62.    /**
    4 I  K: P. j9 c9 u6 u5 s3 h5 t8 |
  63.      * Destroy tokens
    6 R) T5 e1 P& x0 N' f
  64.      *
    0 C& ^5 l4 `2 I4 G! L' K- |
  65.      * Remove `_value` tokens from the system irreversibly
    6 w1 S( w3 X8 T/ G1 C
  66.      *
    2 e* c6 r, X) T# j0 u5 }/ n2 ]8 M; [
  67.      * @param _value the amount of money to burn
    7 T4 ?  C/ @- H" I
  68.      */
    : ~  K$ L" d& m4 h! N4 }6 a/ S! f
  69.     function burn(uint256 _value) public returns (bool success)
    / _: J% t; o7 @, I; B
  70.           {        require(balances[msg.sender] >= _value);   # Z$ k# Z( f% W; l
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          - n0 O. g4 }- n( P+ y* ]
  72.         totalSupply = totalSupply.sub(_value);                     
    * g( l) n9 Z- ?, j8 _
  73.         emit Burn(msg.sender, _value);        return true;
    : ^# A# j+ u# ?3 G. t
  74.     }    /**9 v, L1 v* E1 z( ^0 E7 U
  75.      * Destroy tokens from other account
    ; k1 y& r6 b% x$ B9 l
  76.      *
    5 v+ ]- e- b1 C$ s+ E: C
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
    1 }% y+ h8 `) ^* ]7 }
  78.      *
    ( M2 E( ?% t6 v' {
  79.      * @param _from the address of the sender  O( y8 W' P) ^# Q% M% L  N
  80.      * @param _value the amount of money to burn: }, _! L4 D; b9 G5 ^7 q$ K% Q
  81.      */
    2 B0 P2 f! C/ x. ^. Z' U# F
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) ) O" ^/ N& k- ~' a( L; t  u
  83.           {        require(balances[_from] >= _value);                * y5 w" C/ g) P0 J! W' T
  84.         require(_value
复制代码
' T' C/ b+ U5 Q6 B1 W' Z! v
这些代码是什么意思呢?
' i6 A# a+ R& b; Y. y/ J3 L一、ERC20(EIP-20)说明
* a2 }- d8 k5 dERC20是一个标准的token接口规范:A standard interface for tokens
2 C3 C( m( l4 s* T该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
( b  |4 t8 B6 l+ p6 n我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
2 L9 ~  i0 g: p# C( q, P9个方法包括:9 i$ |+ I/ `9 o+ B7 C. t
返回token的名字; k& O3 X1 k% v0 D) G
function name() view returns (string name)
8 J. f' i& W+ T% N) K9 {1 m  m% Q2 U  H返回token的代码
) a& Z, S" G( R5 ?: r0 J% }function symbol() view returns (string symbol)& o. q8 U# t0 m( \
返回token的小数点位数, @1 _7 S( R0 Q! V/ _
function decimals() view returns (uint8 decimals)# z* |; H$ u% d
返回供应总量
# v4 V+ Y, c1 ]; O- U, xunction totalSupply() view returns (uint256 totalSupply)
% M3 t! r5 J( `& g0 I查询某个地址的余额
- k9 q* r& N! `0 t% x& l5 Hfunction balanceOf(address _owner) view returns (uint256 balance)
1 F% ?; A7 X3 a: D给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false
$ ?. A; y, s7 {' @# Q6 j5 |* wfunction transfer(address _to, uint256 _value) returns (bool success)" j# L7 ^* i' F
从from地址转账到to地址,该方法用于委托给其他合约代理你转账5 u  w: o% x2 }5 L
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
' i, P, E, R' Y; h/ x/ V# l允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
* x  Q4 ]( m' `) n" R' Qfunction approve(address _spender, uint256 _value) returns (bool success)- C6 ^& U3 g* ?% s9 j; D
返回_spender仍允许退出的金额_owner2 j/ _  M7 X8 E/ c. s
function allowance(address _owner, address _spender) view returns (uint256 remaining)% o1 l+ r8 X* q% S6 ^9 s  ]: {
2个事件包括:
9 L9 c4 |* J) y! V0 x1 E" K# n转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候
1 q( Z- ~* F# |0 ^5 \. |5 wevent Transfer(address indexed _from, address indexed _to, uint256 _value)
! A) c. Z0 V' V) V: `委托转账必须触发2 r7 q' c% p6 Z, D) ^1 D1 m$ h
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
0 E- D( r; D$ W. Z9 |5 l! b6 E
! {, y3 f* s5 m- `# b1 }# t* r! r4 V' u3 g5 H& M  X
二、代码解释, g+ N# a. {" D  p# j# d5 V

& M) h0 Q2 G0 h3 I% c. S; R代码包括几部分:
1 C/ |( ?( I" O0 S* M' @( C/ e1 B5 C. t5 Z% U
安全的数学计算库6 ^8 L& X: Q- h& m! a8 `
* i1 Z# I: D: S
contract类 ERC20,主要针对ERC20规范定义方法和事件
! P, F' V; Q; {! O8 f4 T) U) k7 U
contract类StandardToken继承ERC20,定义具体的方法实现
; Z% C" ?8 K8 r+ _2 t  J$ Q9 j! f8 V. [3 z9 Q
contract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5