Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。6 f8 r( p- g1 |
废话不少,先上完整代码:
3 F0 O/ [8 d, t4 X8 b. [
  1. pragma solidity ^0.4.24;
    + p2 ?% `& h; U( H* _7 q( w/ x
  2. library SafeMath {  /**( A1 r) Y3 `7 w$ ?
  3.   * @dev Multiplies two numbers, throws on overflow.3 H* U0 s4 g' T2 D/ \) e
  4.   */' o* p+ |& N7 r$ U! k$ |
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)
    " T2 O# T5 A6 Y1 u+ b
  6. {    if (_a == 0) {      return 0;
    & I8 K, B6 L" A) c( y
  7.     }- H; q, l6 B* t# w7 Z
  8.     c = _a * _b;
    & H/ b2 e, D: f1 i# L8 @: K* x
  9.     assert(c / _a == _b);    return c;  i# F- H/ ~& g, f
  10.   }  /**
    ! g' N% Z7 |8 G7 U
  11.   * Integer division of two numbers, truncating the quotient.4 e0 p7 H1 _, U6 f: \
  12.   */; R( A  J& g6 J  O# D% G
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    & o+ \7 w! j8 V, f; X+ H
  14.   }  /**2 i4 k- `; T5 j7 {) E# L6 w
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).- b. B  x* E8 y+ H
  16.   */
    7 h! x# x& \5 S2 H
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    . n' a' Y' |( c* y
  18.     assert(_b = _a);    return c;
    3 W1 `5 O% \" G3 F' N
  19.   }
    . y; @2 Z7 k. P& e! D! K
  20. }
    ( j% ?- }, T+ t) g- @7 x1 A; v
  21. contract ERC20 {
    3 I6 H) S! \# p$ |$ m& h
  22.   uint256 public totalSupply;  function balanceOf(address _who)
    9 Y% c4 j8 m$ ^( u3 O  b6 H
  23.   public view returns (uint256); + h# t8 m4 E& v# w
  24.    function allowance(address _owner, address _spender) public view returns (uint256); : O% z* g+ v+ E3 I1 s  O4 ^, W4 z2 G
  25.     function transfer(address _to, uint256 _value) public returns (bool);  
    + P6 _3 P! r/ k
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    & h& R4 ~1 S  g! }7 y
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  
    8 q+ g. ^. Z7 v/ i0 }
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);   I5 r7 ]2 |. J7 t5 P( U
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  ) n0 ~8 J6 R% G2 n; l+ S+ Y2 I  ?
  30.   event Burn(address indexed from, uint256 value);7 D; Q  @9 `3 N9 `4 g3 m, ^
  31. }contract StandardToken is ERC20 {+ c4 `& a/ ]7 q/ D) N# ^
  32.   using SafeMath for uint256;$ |" {0 a0 [" J2 m, j* `  X% [
  33.   mapping(address => uint256) balances;8 T; K( Y+ R. m
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    % K) g0 w, v& Q) c
  35.   * Gets the balance of the specified address.
    * z( S; u) j- u. s
  36.   * @param _owner The address to query the the balance of.
    1 L4 U) H. H- M+ p& q& o- M% W
  37.   * @return An uint256 representing the amount owned by the passed address.
    ( F8 _1 l# d* H6 S! P
  38.   */
    : w) p( W7 h0 v: W
  39.   function balanceOf(address _owner) public view returns (uint256) 1 t: N: I+ C* d
  40.      {    return balances[_owner];2 e1 d8 U& Y- \
  41.   }  /**
    9 P& i3 T0 f; h$ p/ {5 @4 G& t7 U
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.8 \9 g, F5 v, v1 a
  43.    * @param _owner address The address which owns the funds.  s8 A6 H5 U1 q: R; }. _
  44.    * @param _spender address The address which will spend the funds.4 y1 S* d0 V/ @
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.% m1 L! ^2 M: j
  46.    */! X* X/ ^4 d8 e1 X: F1 ^
  47.   function allowance(address _owner, address _spender) public view returns( u6 Z, I* y# I" \
  48.       (uint256){    return allowed[_owner][_spender];) M' o& t; _5 [* i6 A" ?5 m1 h
  49.   }  /**9 \0 E' s7 v( r5 [! g
  50.   * Transfer token for a specified address( L0 W$ B$ [" y! M' E7 Q! f+ b
  51.   * @param _to The address to transfer to.8 P% ^1 X! u; h* }. N; \! U' A
  52.   * @param _value The amount to be transferred.
    - Q8 q) b$ t( O/ r( E2 H% f6 O
  53.   */
    8 L& }: T* g3 f7 e6 ?, p! o; A
  54.   function transfer(address _to, uint256 _value) public returns
    $ g) a, W, ?! w; f. l
  55.       (bool) {    require(_value = oldValue) {
    7 }- X! j" S; x- E
  56.       allowed[msg.sender][_spender] = 0;" I2 K$ u/ E  ]0 m5 S9 u! Q
  57.     } else {
    1 ~8 V' f- O! x0 F! X
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);4 w* h0 @6 ~) V) W8 L) U
  59.     }1 o0 m8 r- O9 P, Z9 s3 {3 H
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;7 l9 w: z+ A* m) |) O
  61.   }  
    + M. P$ k3 {8 y; P8 q% [
  62.    /**
    3 {) ]% ?8 i$ N; k0 G5 P
  63.      * Destroy tokens. }6 V% Q: n+ Y- R* b  _. M
  64.      *
    $ Z  n( |( e/ g3 l  y2 W
  65.      * Remove `_value` tokens from the system irreversibly
    " d. Z# \* e, A6 a# A8 R$ {
  66.      *, Y6 p9 X1 t4 Z% N3 f# O0 g
  67.      * @param _value the amount of money to burn
    / M' R0 x7 r% C5 j
  68.      */
    ( C' [* p: C$ g6 T7 ~6 ^  d- Z
  69.     function burn(uint256 _value) public returns (bool success)
    2 }5 Z6 B' m& V1 ^) z
  70.           {        require(balances[msg.sender] >= _value);   7 T- @; w% B2 S" Y
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);         
    5 d8 R- @" {4 F2 L8 r* v
  72.         totalSupply = totalSupply.sub(_value);                     
    ) g4 W: ^: {5 z3 ?" @- G
  73.         emit Burn(msg.sender, _value);        return true;
    ; \+ f3 K- e/ e$ n* ]' D
  74.     }    /**
    $ J' w% z, R9 w# I: D2 G0 ?
  75.      * Destroy tokens from other account
    " A* }8 h0 U/ S* M) p. P
  76.      *
    . x' o: T3 f/ g4 J1 m1 b
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
    / c5 J& }6 g% k, I- u* K& x- F5 B
  78.      *. U5 g4 g" h0 {; i; s, b' t9 h* d
  79.      * @param _from the address of the sender% Y# H! S. T- }: I" x( s( q: f6 l
  80.      * @param _value the amount of money to burn
    $ w) V0 o# M. i' Q
  81.      */2 l% t& P; a' V/ l8 E% ^
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) % b2 [$ d' \$ }
  83.           {        require(balances[_from] >= _value);                6 U% a* B: d- W! Y
  84.         require(_value
复制代码

+ D# P6 u/ \+ z% s" J$ p0 n这些代码是什么意思呢?# Y4 g) m8 ?" X
一、ERC20(EIP-20)说明
. t, `; o* o5 m: ^" K2 ~ERC20是一个标准的token接口规范:A standard interface for tokens
& o2 g7 F5 B0 R( h该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md2 L7 J, F& E2 W: X. q+ E
我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
  Y) E" f/ `; E2 R8 E% N5 v9个方法包括:
$ O& D8 D# z9 J( P% K3 c2 ?9 L/ o返回token的名字; Y, I" @0 P- c6 _9 G
function name() view returns (string name)5 P9 m( ~( i% F$ u; [$ \
返回token的代码
* E2 G6 R8 V7 O) \  R2 j6 rfunction symbol() view returns (string symbol)6 l4 X1 J2 {- p+ j
返回token的小数点位数5 U. P$ S2 L9 m, h  \  g
function decimals() view returns (uint8 decimals)$ }; k- A2 i/ P* B  `
返回供应总量
6 ~( g3 B/ t5 B: G+ Z7 Dunction totalSupply() view returns (uint256 totalSupply)
( W# t8 [. B& I( d5 Z- O1 q8 P, W查询某个地址的余额4 q7 ]6 {. U+ b
function balanceOf(address _owner) view returns (uint256 balance)3 p9 {4 [9 M2 s1 ~" U: O
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false
) ]0 c! g0 T  |- S2 e9 G+ W4 f2 \function transfer(address _to, uint256 _value) returns (bool success)
$ _1 ^- i9 d7 K) G% A% @从from地址转账到to地址,该方法用于委托给其他合约代理你转账
  T/ \* d; Y$ B+ T% a- Nfunction transferFrom(address _from, address _to, uint256 _value) returns (bool success)
5 ^4 z8 W0 k5 M& G& i; i允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
( V4 p. X7 n3 Xfunction approve(address _spender, uint256 _value) returns (bool success)* t- t' k0 X( d1 b2 t
返回_spender仍允许退出的金额_owner
# r7 z! [. z0 _& O9 Hfunction allowance(address _owner, address _spender) view returns (uint256 remaining)6 I3 q" u2 {1 N+ Y5 B
2个事件包括:
& L; `" t+ [/ Y7 D3 u转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候
: E; s$ a$ T4 Zevent Transfer(address indexed _from, address indexed _to, uint256 _value)
! R8 ]9 `2 R/ t6 P- W委托转账必须触发
+ e! U  H0 r$ X9 [9 O6 b# pevent Approval(address indexed _owner, address indexed _spender, uint256 _value), N; B2 \2 ^) f9 x0 q
: h* O6 u# ~5 y" C- k3 s
7 T- D9 f" {- W/ m3 `7 ]
二、代码解释
( D  u' A$ u8 f! m
; O0 X4 J/ _+ h4 z代码包括几部分:7 N0 p& F* r% }, O" @7 e+ b
3 L+ B7 v  S# g& A, r+ }* e
安全的数学计算库' l5 Z! b  M6 b8 n. X

6 D$ Q( U0 s6 A9 H/ {+ I, g8 vcontract类 ERC20,主要针对ERC20规范定义方法和事件/ c+ |  L( _! x) J2 I+ a
; N6 x6 M5 R6 \( r& w, d$ n/ @
contract类StandardToken继承ERC20,定义具体的方法实现, ]; T# n( d" n

5 |& G! l$ w( W1 m4 ^  v+ b+ Xcontract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5