Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。
% P4 L' Z+ L, v, w9 t% H: l废话不少,先上完整代码:
( q# l  c, M) [2 |4 }/ d
  1. pragma solidity ^0.4.24;
      j9 A  X: i' Z$ S" J
  2. library SafeMath {  /**0 U$ L" u9 w. t" n
  3.   * @dev Multiplies two numbers, throws on overflow.
    ; r5 q9 R! w# {0 r' m. L
  4.   */
    ' `8 L: K+ h# p0 `( N
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)9 K! n2 @0 s: T) [
  6. {    if (_a == 0) {      return 0;
    ' P8 K( x* m& n5 M
  7.     }* H; Y) o! T/ s; n/ W+ R' k# }
  8.     c = _a * _b;
    8 m: ^; v( c2 s+ a6 P& z
  9.     assert(c / _a == _b);    return c;
    ; F+ w/ M" r+ h9 H
  10.   }  /**: b( F$ p+ A# u
  11.   * Integer division of two numbers, truncating the quotient.
    2 k5 J8 q1 I, X- `$ H7 q
  12.   */
    / r/ n; i# y! _; z+ f" H
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    $ q; X7 v0 t6 e2 l% P, V
  14.   }  /**+ }, i5 T8 P% s4 h1 N/ |
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).3 K7 X- @2 s* n
  16.   */! h, O# c$ l8 @+ z+ L- H
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {1 W1 U# h+ B: J  i! b
  18.     assert(_b = _a);    return c;
    / k$ N- y$ f* K- e2 |/ `; z
  19.   }- ?5 ^/ G! x$ c: P9 r0 z
  20. }( W5 ~& R' J$ j% k: I9 g' U$ h" R
  21. contract ERC20 {
    $ x: P8 e3 H' `4 }
  22.   uint256 public totalSupply;  function balanceOf(address _who)) G1 T6 k4 |6 a
  23.   public view returns (uint256); 1 R! I& c3 E7 }" `
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
    7 m# L. y: z- \" u7 D( ~
  25.     function transfer(address _to, uint256 _value) public returns (bool);  1 h4 T! ~3 v. ]6 ?. v: k
  26.   function approve(address _spender, uint256 _value) public returns (bool);  ( Y2 m, f/ Q, ]$ ~' _5 t1 m
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  
    $ @+ o+ ^8 N1 z8 j
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);
    8 e2 K+ Y& s( x  k( Y! m* z
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  . S- X1 F0 M0 ]' [) Y5 ]
  30.   event Burn(address indexed from, uint256 value);5 d: c: P5 a3 B
  31. }contract StandardToken is ERC20 {
    & ~4 J6 ~2 R% c
  32.   using SafeMath for uint256;
    / f: K9 v# L% k9 e/ r9 B
  33.   mapping(address => uint256) balances;
    & ?" `7 g4 I8 f& \
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**8 I, }- o! A8 A. z
  35.   * Gets the balance of the specified address.
    : `) z% p9 \' \+ p( e
  36.   * @param _owner The address to query the the balance of.9 Z, [) U; E# M, c& R# ]" \. F
  37.   * @return An uint256 representing the amount owned by the passed address.3 A1 Z  @0 C: f8 y/ ^; Q3 S
  38.   */- p, U( }  ^2 R- k& v9 h1 J& r
  39.   function balanceOf(address _owner) public view returns (uint256) - f* R* }: m* D; I$ U: v1 U
  40.      {    return balances[_owner];9 Z2 G  Y6 {, v3 d. o
  41.   }  /**9 ~* o& T% @# j# l9 D/ _
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.% ?; ]; e/ U3 U
  43.    * @param _owner address The address which owns the funds.& G; c# \; _6 k: M' l
  44.    * @param _spender address The address which will spend the funds.8 A2 l6 [0 F' y+ W
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.
    : r3 c+ W( c5 s5 H) B/ ]6 ]
  46.    */
    ; d. q5 j! y& W/ X& k8 @5 W( u
  47.   function allowance(address _owner, address _spender) public view returns% m& n, {  R0 b( f# @! a
  48.       (uint256){    return allowed[_owner][_spender];2 T3 r2 ]/ g  b" @; ?6 c" {! m
  49.   }  /**" l6 c# Y; Q' G( w; C3 [
  50.   * Transfer token for a specified address% P1 ]0 Q$ z2 v% m# h1 U: f
  51.   * @param _to The address to transfer to.
    - m; R: e4 o% G6 L) x. |+ ^
  52.   * @param _value The amount to be transferred.6 h- N" p2 _/ a9 J; E" O) n
  53.   */
    9 O; F: Q% e  I" G* K) [, n
  54.   function transfer(address _to, uint256 _value) public returns 8 s' P+ ^0 ~" B" L+ ~1 X1 \3 g0 e7 |
  55.       (bool) {    require(_value = oldValue) {8 L" D) u- u2 v2 K; T
  56.       allowed[msg.sender][_spender] = 0;$ x. Z7 s8 t$ i% w) y% {
  57.     } else {
    ! \  x0 o5 e8 [7 n) i5 F$ ~4 q
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);4 z" I. w$ X9 u6 {" i, {
  59.     }
    . k4 `1 ]' F& ^1 H5 q. O8 j2 m" I
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;# V, c- _" Q) v
  61.   }  
    / s- k: C1 R, w. |( G
  62.    /**
    ) x; ?( M. |" [" B7 C- z% t8 i
  63.      * Destroy tokens/ ]  v  s; W% u1 E% C
  64.      *
    9 ^" l; f* F! V- ]  Y4 n: h
  65.      * Remove `_value` tokens from the system irreversibly7 u5 r. ]5 K! Z6 Y/ ~: D! z: s
  66.      *
    - q( Q% i. \' u" f1 h
  67.      * @param _value the amount of money to burn
    ( z# [5 T% G; \0 s4 k
  68.      */
    / z6 j& Z. q8 x9 d
  69.     function burn(uint256 _value) public returns (bool success)
    # b' b2 h/ O- l
  70.           {        require(balances[msg.sender] >= _value);   
    4 J, P2 g8 m/ {. N
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          # i4 h, D  P! ^
  72.         totalSupply = totalSupply.sub(_value);                      ) |  a, _9 t/ n0 V2 J7 G
  73.         emit Burn(msg.sender, _value);        return true;
    6 R7 F$ Z; V& ?7 M7 H
  74.     }    /**. a" m* U! g7 G: n; ]8 b7 K3 J1 ^
  75.      * Destroy tokens from other account
    8 v  c: z- e3 u7 M( ]8 P+ w, V
  76.      *( X4 f) l# `& @; S9 P
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.: _3 Z$ M6 [% C- G* p% ]
  78.      *
    - W+ ?5 ?6 r/ W
  79.      * @param _from the address of the sender1 b: S! q) n2 g2 c  o+ u
  80.      * @param _value the amount of money to burn5 Y6 t9 _& C; R& u' O& [( e
  81.      */
      j: g  Y6 p/ t8 p
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success)
    ; ?3 L, K) D. v. `9 d8 L" i
  83.           {        require(balances[_from] >= _value);               
    2 ]& o" m. b) L3 a8 v( W
  84.         require(_value
复制代码

. O( x- {# l* z7 l5 X" t这些代码是什么意思呢?" \' N1 c' O+ d; y, v. I
一、ERC20(EIP-20)说明
$ K4 \/ ?5 u1 g6 I4 r; mERC20是一个标准的token接口规范:A standard interface for tokens2 Y5 [! J1 V! `$ O- e
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
. T, @( ?) r- Q3 G5 Z我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
7 z" U, Y. v  u; {& s& _2 i+ o9个方法包括:4 |3 V1 |! E' ?% b
返回token的名字: u% O6 i$ b8 q' }
function name() view returns (string name), F; ~$ M" c6 I0 e0 l7 S
返回token的代码* k4 \* [* O2 i' T+ \
function symbol() view returns (string symbol)
& p' r2 x/ B* l' a返回token的小数点位数- }' k2 {1 ]0 }8 J% ?
function decimals() view returns (uint8 decimals)4 `" q1 E4 W2 M- {
返回供应总量
+ H: _5 n% a0 S) l& k: R. Tunction totalSupply() view returns (uint256 totalSupply)8 l9 A! x6 Q- X& @6 F# c
查询某个地址的余额: R  g, o# g: E" Q! J: S# M
function balanceOf(address _owner) view returns (uint256 balance)
( R4 {4 d2 T. I+ N给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false# r& I+ h7 S) r5 t. z# x6 `# Q
function transfer(address _to, uint256 _value) returns (bool success)( B6 C6 J+ c& Q) V9 W9 V
从from地址转账到to地址,该方法用于委托给其他合约代理你转账% D/ I- \8 j3 L9 h9 c
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)5 o* O$ g+ [; ]$ o
允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value$ N* c$ S3 p9 A2 Y* x
function approve(address _spender, uint256 _value) returns (bool success)
0 t( g# O) f( X* [% y3 l/ n7 v返回_spender仍允许退出的金额_owner% E: W4 o3 k( ^  t. w
function allowance(address _owner, address _spender) view returns (uint256 remaining), G" m9 ?) F" y+ z5 W
2个事件包括:9 F: o9 {3 y) P* X& m5 v9 O+ V
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候; J1 J0 a! D' `" @7 o; F7 v
event Transfer(address indexed _from, address indexed _to, uint256 _value)( ]4 g5 [0 \( S2 @" ]! \! z7 Y
委托转账必须触发/ t' u5 Z$ e! W9 ^! @- }
event Approval(address indexed _owner, address indexed _spender, uint256 _value)  }/ T3 L* r* Q3 x5 I
# E6 c3 [4 w' e  A* m  h& J9 v! e
3 w+ v* O9 S! p; ^4 V: Q
二、代码解释+ u. v# m2 r1 j" F* O& ^

7 o  P$ Z  U, t* a, d6 N代码包括几部分:
5 v6 V* y( G8 U+ G7 f1 r
- |: W! A, E2 A2 ^7 @7 O安全的数学计算库. B4 M: t9 \# q" a0 {5 F
+ B* a: w! A6 m: F  W, r
contract类 ERC20,主要针对ERC20规范定义方法和事件
( z8 D6 H9 E2 \2 r* m
- S3 e1 K" [* ?' econtract类StandardToken继承ERC20,定义具体的方法实现5 {: v2 v" c5 r7 v0 A. t

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

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5