Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。
, C# U# p/ V* \: y5 k, L+ y# c废话不少,先上完整代码:8 D. Q# U. f$ p; K1 X& V! C
  1. pragma solidity ^0.4.24;
    0 y( c6 E/ z$ E$ K1 e% ~
  2. library SafeMath {  /**7 S4 p/ P+ G5 l2 Q5 t" F8 F
  3.   * @dev Multiplies two numbers, throws on overflow.& e$ p9 K& a" w1 V
  4.   */, I% X2 G! _' {; r8 z/ |- x6 W" l' P
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)4 I# p% j5 A7 j
  6. {    if (_a == 0) {      return 0;: g* b! t* ^- m1 ?$ t; m
  7.     }! L' h; d5 {! w# L$ F. o+ Z
  8.     c = _a * _b;
    8 o' n" `9 v. N4 `
  9.     assert(c / _a == _b);    return c;
    6 d( S( C0 c! {; c- c7 o7 h
  10.   }  /**- P7 }9 q$ B4 y: q7 a
  11.   * Integer division of two numbers, truncating the quotient.4 v7 O% @0 M% S! S  G5 E- a
  12.   */3 W0 s$ |' d) V; w' }
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;" T: c2 V( J9 j4 G' x
  14.   }  /**
    1 i9 e! ~$ [1 Q6 n. o, B4 t
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend)./ {& S: _' P, b
  16.   */
    # M+ u9 z8 r5 U) Z6 e/ g! m
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {. C7 p) b  j( v7 g
  18.     assert(_b = _a);    return c;) W3 g# C4 Y0 _# r( x
  19.   }/ [8 o: [- ~! {' S' q
  20. }8 a! q: \+ j9 v* K) G# c" k
  21. contract ERC20 {8 S  X1 m, L; A. W9 _
  22.   uint256 public totalSupply;  function balanceOf(address _who); D4 ~* Q* ^5 m5 X7 `6 U
  23.   public view returns (uint256);
    , T& ~- C* N4 Y
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
    1 i9 M* n  O1 r* M" _: C
  25.     function transfer(address _to, uint256 _value) public returns (bool);  
    % p1 A1 _, v5 x1 `* j
  26.   function approve(address _spender, uint256 _value) public returns (bool);  & g. l' h; u: d1 i2 k1 Y
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  5 m. A" A& `! R; e3 Q
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);
    0 y" ~) K7 {6 \; I: y! q: z
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    0 [$ L9 i( b( A  ]
  30.   event Burn(address indexed from, uint256 value);
    $ Y9 ?) J. l) p) J8 b
  31. }contract StandardToken is ERC20 {8 x" ?: ^5 `8 V' K8 I) s
  32.   using SafeMath for uint256;5 G9 q8 z+ u- B: Y. e- C
  33.   mapping(address => uint256) balances;- v% V3 W5 y" L: S& `0 o/ `
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    0 O, v1 L. r2 c4 Y' z% v% b
  35.   * Gets the balance of the specified address.* h" j- i: V$ Y8 M) t: ?
  36.   * @param _owner The address to query the the balance of.* b( F3 u+ d. F2 ^
  37.   * @return An uint256 representing the amount owned by the passed address.
      h, `- T( m. q, y
  38.   */
    2 E6 u3 }  b/ M# `. ~
  39.   function balanceOf(address _owner) public view returns (uint256) " Z$ t) g$ c  \& n
  40.      {    return balances[_owner];
    9 |& S4 L# z5 z9 u5 d
  41.   }  /**
    9 ]5 f( u$ p( Q) B6 t1 i. c
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.; K( n+ ?5 g  y3 q& w: p9 e) a
  43.    * @param _owner address The address which owns the funds.4 R0 i2 e+ f( z) \
  44.    * @param _spender address The address which will spend the funds.! C( Q' j0 L7 Z* ]' h' H
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.
    , z" X9 e% f3 z
  46.    */
    + {) }7 I& r# \# A
  47.   function allowance(address _owner, address _spender) public view returns
    3 Z% Y$ E! m; O- L" j
  48.       (uint256){    return allowed[_owner][_spender];$ i* G3 M  \, z7 |2 @/ g
  49.   }  /**" z1 r7 M5 ~3 Q8 w4 L
  50.   * Transfer token for a specified address1 c$ Z  \4 j( s2 [) h
  51.   * @param _to The address to transfer to.
    & {/ t; c/ \* |
  52.   * @param _value The amount to be transferred.
    : q" H, o& C: k7 I
  53.   */
    % h: U  N9 s2 k. [8 D
  54.   function transfer(address _to, uint256 _value) public returns & H  Z. \$ z; H) q1 y0 U+ u* u" f
  55.       (bool) {    require(_value = oldValue) {- r. ~& \! z3 D* I! p
  56.       allowed[msg.sender][_spender] = 0;; U5 m6 F7 H+ P6 ]0 V
  57.     } else {1 y8 V8 u( w0 H9 ?2 k  P: r2 [5 N9 c
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);9 z6 D! D- o2 F  N8 |/ ^) Z! x
  59.     }
    # K& I& P# S* Z
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;, D1 V, @7 b8 U6 H4 [% o' O9 [* Q+ I
  61.   }  6 z. D5 M3 L% u7 u$ U1 K6 U
  62.    /**8 }) ~# d, C$ Y+ n: h6 s
  63.      * Destroy tokens; v  O- E+ K( t- i# @. j
  64.      *4 `6 G6 i' E( s$ }: F# d
  65.      * Remove `_value` tokens from the system irreversibly
    9 L  I. @; v( Y4 m/ \3 S" v% X) B6 m
  66.      *. p) y2 o2 T# V* a9 z" Q& W/ h! p
  67.      * @param _value the amount of money to burn/ Z" Z$ y2 \! u0 f& c/ n6 |
  68.      */
    - e% B5 m; V7 D7 b9 {7 G5 y
  69.     function burn(uint256 _value) public returns (bool success)
    - R# B+ z5 {4 X/ D+ c4 }
  70.           {        require(balances[msg.sender] >= _value);   
      }9 |" \/ \$ [3 p
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);         
    % g) ^; w# z; I
  72.         totalSupply = totalSupply.sub(_value);                      * V$ q7 s- }- D' g) _
  73.         emit Burn(msg.sender, _value);        return true;
    9 Q6 R9 ~% j5 l8 \( C7 a4 ^
  74.     }    /**
    0 @! D+ }' Y2 T* Y' `$ q2 p
  75.      * Destroy tokens from other account6 J* R7 |, W* {* ^3 P; }
  76.      *
    + J( M( T1 }% B2 D) [
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
    + z" U+ a3 j- z$ Z
  78.      *
    & {: G8 E; H3 Y! X4 M. o0 J
  79.      * @param _from the address of the sender: u/ n, Z6 \6 E. s
  80.      * @param _value the amount of money to burn. Z3 w9 _& f/ l
  81.      */
    8 G3 l1 V6 Z0 J
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success)
    . t, E$ H, e5 ]0 D# d3 W
  83.           {        require(balances[_from] >= _value);                9 o4 {, _3 D- t/ [: ~: E
  84.         require(_value
复制代码
/ [2 p6 y; o5 b  {9 u1 ^
这些代码是什么意思呢?4 t) d& Z8 B7 A4 d* ~3 ^7 B' K2 ^
一、ERC20(EIP-20)说明
; C) z  N3 T( EERC20是一个标准的token接口规范:A standard interface for tokens* k9 V6 u$ Q: ]3 z1 s" i7 x+ N" {
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
- G+ i5 ]! o  \5 V2 M' _8 h; X我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件* T, N; T7 K. {4 G; F
9个方法包括:  M# s# t: u# }& Q
返回token的名字6 {" V' H# V5 l) I5 |
function name() view returns (string name)
; p- q. l3 V7 D: ]5 ^2 w5 N9 B2 g返回token的代码7 o, X! V) h, Q, Q' o
function symbol() view returns (string symbol)
. h- R6 K4 P: L$ _0 Y3 f- Q7 H2 S返回token的小数点位数
0 v2 \! D8 h: }( p+ pfunction decimals() view returns (uint8 decimals)- D. l7 c6 e, U, `, ?) _+ y3 j9 u
返回供应总量
) N, G1 L) O3 Munction totalSupply() view returns (uint256 totalSupply)
6 |3 Q8 M" y& }: J查询某个地址的余额5 C+ F+ F% g9 w8 c/ V7 O
function balanceOf(address _owner) view returns (uint256 balance)$ K4 [5 @2 G) O. z* Y) ~$ U! j
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false- b, V- f' o8 O9 e  t0 q4 q5 Q
function transfer(address _to, uint256 _value) returns (bool success)
: V6 B8 A3 x) _5 D: b" @; Z: ^! V7 b从from地址转账到to地址,该方法用于委托给其他合约代理你转账
7 O: l4 \- n( W1 pfunction transferFrom(address _from, address _to, uint256 _value) returns (bool success)$ U; S1 \# i1 H9 K7 u# S
允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value9 z# G1 w- S: O* v
function approve(address _spender, uint256 _value) returns (bool success). {" H8 w" O, D$ Y& A0 ]6 o
返回_spender仍允许退出的金额_owner( ]0 i4 ]6 `9 p! M# @* ~9 h" @( L% D
function allowance(address _owner, address _spender) view returns (uint256 remaining)" ]8 K  Q0 Y  H* ~3 Z4 |+ ^" H
2个事件包括:1 t# C  Y1 W* k& t$ x9 |
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候
" r" W3 v( Z& x( e, e: b9 nevent Transfer(address indexed _from, address indexed _to, uint256 _value)+ V) e0 I4 C2 Y* u/ q
委托转账必须触发% z; a) V6 G2 y$ `9 m: }8 \
event Approval(address indexed _owner, address indexed _spender, uint256 _value)" H, U3 k, q; A/ ^1 e+ `+ ^6 q

  ?2 A' S  U8 k( y3 v# N' V5 Y) O
* n4 J: b2 j' @: A- R  _3 j# D# r二、代码解释2 J; }7 m# X0 w& {+ T6 ?) X
" Y* k6 n2 V0 S- n6 u! b! [
代码包括几部分:0 y% k$ w2 k+ \2 w
/ s. j) K" ~( |8 s1 |3 |1 }
安全的数学计算库
3 s0 F5 b. c! ~
2 g/ ?; C; O1 |" Econtract类 ERC20,主要针对ERC20规范定义方法和事件2 {. y9 f- g2 T

7 l- K9 \8 w( S) `; P; Scontract类StandardToken继承ERC20,定义具体的方法实现3 g# t0 z1 n% m9 ?9 @! R

) `) [( a* e4 t# N. ccontract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5