Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。7 N0 D4 l3 y4 b/ E
废话不少,先上完整代码:% d' |- x: c) ^, S
  1. pragma solidity ^0.4.24;* B8 b1 ~; V+ X
  2. library SafeMath {  /**( Y/ u1 A7 @7 o" [# f& W" V
  3.   * @dev Multiplies two numbers, throws on overflow.
    - T# q6 O4 [5 s2 _
  4.   */
    " q& Q8 l) r( ^5 n, p0 L
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)- y& N; D5 a. }
  6. {    if (_a == 0) {      return 0;' e3 |6 _/ U# Y! [. u1 R
  7.     }
    8 {8 [( X( h$ z' N
  8.     c = _a * _b;
    # q5 p! R2 U) I
  9.     assert(c / _a == _b);    return c;: Q/ G9 T5 X6 k; D: v+ u
  10.   }  /**, ?8 W* k, |0 D* ]
  11.   * Integer division of two numbers, truncating the quotient.
    ! H4 `' N3 l( m
  12.   */
    , M! {# [5 R7 O
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;& C. w, z1 U, _4 Y. J" {
  14.   }  /**
    & ]. ^; c$ C1 T7 N! @  D1 p  ]
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    * C2 h  c: }( d" e8 U
  16.   */
    ) x9 D  {" S) Z* P
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {2 |* d, [& P8 p( O% N% E8 c
  18.     assert(_b = _a);    return c;* n: Y7 p0 o/ M' }
  19.   }% Q7 Z. C; U* V$ E/ D" h
  20. }
    * u5 A" f8 ?* }# l  `- Y* i
  21. contract ERC20 {1 f" T3 B7 j' d8 n9 D0 g* f  b% u
  22.   uint256 public totalSupply;  function balanceOf(address _who)  `! y0 Y4 v+ Y3 ?, q, M
  23.   public view returns (uint256); & F; o# x) v( a
  24.    function allowance(address _owner, address _spender) public view returns (uint256); 6 ]! H+ ?( e3 Y: K# @  N4 G
  25.     function transfer(address _to, uint256 _value) public returns (bool);    e) s7 \; V7 w8 _1 h- D, a
  26.   function approve(address _spender, uint256 _value) public returns (bool);  ' ?9 b8 H( p# D* [
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  
    3 P$ n3 J1 [+ }, h. H% W
  28.     event Transfer( address indexed from, address indexed to,  uint256 value); 0 H6 B5 N3 S; [5 I
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    2 `9 q/ l; @4 M- g2 a
  30.   event Burn(address indexed from, uint256 value);
    . C7 |, j% f) ~: ~
  31. }contract StandardToken is ERC20 {
    . Q- K( }: M3 b
  32.   using SafeMath for uint256;
    ' ^3 u) _: {- L8 N( L- R: e" X! {  g4 U
  33.   mapping(address => uint256) balances;7 S. }* {' I8 G. H) K, }. s8 U+ ^
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**# ]& \- w- l3 \" F+ {
  35.   * Gets the balance of the specified address./ z" |6 Q1 D! p1 q
  36.   * @param _owner The address to query the the balance of.6 ?% v, h3 O: u" W2 T
  37.   * @return An uint256 representing the amount owned by the passed address.
    & B8 p0 i( I; a6 n3 ]
  38.   */7 M. p# g/ ~7 `7 z+ o
  39.   function balanceOf(address _owner) public view returns (uint256) 1 a; {& h' ]# `4 _
  40.      {    return balances[_owner];
    # B$ b( `4 }9 t
  41.   }  /**
    ! f1 }. A4 B; s4 B/ v* |4 T
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.
    , I1 z8 A- i! s- F
  43.    * @param _owner address The address which owns the funds.
    + j* s- O. h, |4 f( h( ~4 l
  44.    * @param _spender address The address which will spend the funds.$ Y6 u$ K  G/ Z' w, [
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.: \! a3 V" g  S8 A: T2 j  ~  j. I
  46.    */: V3 ^& I3 _6 D& ?( u) x+ i9 C
  47.   function allowance(address _owner, address _spender) public view returns  \. B5 S; L6 V$ I5 C
  48.       (uint256){    return allowed[_owner][_spender];  ?2 u& P; Y. K4 g5 m
  49.   }  /**
    9 J" e7 q, W0 e& y
  50.   * Transfer token for a specified address3 r5 m4 A9 O  s: G+ r# e
  51.   * @param _to The address to transfer to.8 M3 b: n6 A6 j6 H& Z! N1 j
  52.   * @param _value The amount to be transferred.
    9 I: P$ R4 ~- h
  53.   */4 p* P( e# x$ I3 d
  54.   function transfer(address _to, uint256 _value) public returns
    # {: o5 ]* C+ p) ?- [# \
  55.       (bool) {    require(_value = oldValue) {
    6 ~( [$ }2 X0 b0 v
  56.       allowed[msg.sender][_spender] = 0;
    # {( {* _9 ]# `6 [0 Z7 w9 L
  57.     } else {
    $ `# a5 O# ~8 W) i% E
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    , `. x4 b% n; d; x9 c3 D2 C
  59.     }) J0 l* k( \. j7 I
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;
    + [* H+ |& T( P: z0 c# y
  61.   }  & y. I9 O( Y" ^! B; U: E( X) V
  62.    /**
    & R: Z4 R( ~1 v8 Q' @  ?
  63.      * Destroy tokens; g5 M, o" I. H* B2 j. o. F
  64.      *
    ! D7 e8 v- {& D
  65.      * Remove `_value` tokens from the system irreversibly
    ; d9 t8 k6 P, z0 b! J( _' i% V
  66.      *6 t# g% z* v! }0 i1 M5 t+ ~  {
  67.      * @param _value the amount of money to burn
    + D" X- L) h2 L2 E- j
  68.      */
    # c3 S8 H3 m3 U1 ]8 A
  69.     function burn(uint256 _value) public returns (bool success)! ^# M- d+ r/ Z
  70.           {        require(balances[msg.sender] >= _value);   
    . q! h; E% L* Y0 t3 R% G
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);         
    ; o: E6 O+ N# V0 U
  72.         totalSupply = totalSupply.sub(_value);                     
    4 A! v/ _; G. u8 E' q
  73.         emit Burn(msg.sender, _value);        return true;
    # F& `% s& y; b, y$ z
  74.     }    /**
    , D/ |# l0 l& \, q$ \
  75.      * Destroy tokens from other account
    & j9 w0 k  [  m4 k6 w
  76.      *4 u- Z) k* R& K
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
    8 Y6 Y) ~; x; m. ^, F2 }
  78.      *
    3 k) W, {! }! H, I2 n' k" G
  79.      * @param _from the address of the sender) M2 P  N+ M7 b" z
  80.      * @param _value the amount of money to burn+ m- Z" M% W* X7 a+ ?! I
  81.      */4 I9 `2 N  B2 p! E+ p+ I
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) 7 k) u8 j% c" X1 H- D4 Z/ ^
  83.           {        require(balances[_from] >= _value);               
    + f$ N, q4 T( ~) t' `- q, r# J
  84.         require(_value
复制代码
/ ^7 R. o1 h  x3 ]
这些代码是什么意思呢?9 M2 @8 Q# J( V( S8 K7 U5 G; ]
一、ERC20(EIP-20)说明$ H! F) ]2 z% d5 |; N
ERC20是一个标准的token接口规范:A standard interface for tokens) P# e6 x+ h1 G  i% V/ A" ?3 {
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
# G6 Y" `/ X9 V$ I1 t: G我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
7 N6 W% o0 @6 E8 }" m% O! x. S9个方法包括:; W/ P$ b/ B5 W* f3 h
返回token的名字
0 n' e/ N0 z* q; o# n2 }function name() view returns (string name)
0 C: _9 B) _' V2 l返回token的代码
5 h  U1 F/ Z0 v: G7 Kfunction symbol() view returns (string symbol)
. |4 T9 q9 Y+ O返回token的小数点位数# C' w9 y! |( p8 A* x1 V  C
function decimals() view returns (uint8 decimals)/ U; L  Q4 e0 `" I3 j5 Q5 y- a+ o
返回供应总量7 q' H. z6 p+ f3 b0 l* \# s
unction totalSupply() view returns (uint256 totalSupply)# O# \6 y0 W' s  B5 r- h# k+ w
查询某个地址的余额
3 \9 a) {4 i1 D% v! s& Y+ D- ofunction balanceOf(address _owner) view returns (uint256 balance)
, Q- M3 d6 p  ?! e  [( I& g* f给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false
5 Z+ ^. Y" U' {8 E6 g# efunction transfer(address _to, uint256 _value) returns (bool success)
% S" j6 h: x* D- h. ~7 }从from地址转账到to地址,该方法用于委托给其他合约代理你转账
3 @) U1 q% u/ ^4 x, ^function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
  j0 W- x0 E( Q8 R' D6 r& |允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
& i" m: i+ _* V' r- v6 wfunction approve(address _spender, uint256 _value) returns (bool success)
" o0 w# S* |* K- p( j' c% k7 E2 a返回_spender仍允许退出的金额_owner; u; N) n; n+ C/ H5 i
function allowance(address _owner, address _spender) view returns (uint256 remaining)9 w: |  L- q  e& c! }1 N
2个事件包括:0 N; |, k7 l4 d
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候* g' p" E% _( d, H
event Transfer(address indexed _from, address indexed _to, uint256 _value)& }! _& I: F0 i6 s5 @
委托转账必须触发  ]3 J/ t0 d* r. P# S9 ~. j& ?( `0 S. q
event Approval(address indexed _owner, address indexed _spender, uint256 _value)# ]! T- P( g' d5 y
0 i% D  g- i; \% n
$ k! f! \. L' m. b- z" D/ Y6 e6 a+ W) v8 @
二、代码解释, e' [$ `! W# N' `: B

8 [# C$ Z6 |, T7 c" D/ a/ `; c代码包括几部分:5 B4 G! ?1 b6 W7 d8 M- I3 v
) X3 l$ F/ N: Q0 D
安全的数学计算库3 }  B" ?# C) D9 L; C. h4 E, t5 p
0 C: ~1 V( X: B
contract类 ERC20,主要针对ERC20规范定义方法和事件
+ n% H6 d  e5 }6 i+ x  w2 C+ c) T0 n  K
contract类StandardToken继承ERC20,定义具体的方法实现. T. l1 V( Q3 L

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

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5