Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。! `1 E# ^/ ?! q+ F" k
废话不少,先上完整代码:4 F% K# E0 v2 f5 e/ W" j5 T( h
  1. pragma solidity ^0.4.24;# D& G: ^; \9 f
  2. library SafeMath {  /**9 b/ n3 `3 Q- X" Z/ N; \: u7 [
  3.   * @dev Multiplies two numbers, throws on overflow.
    : O8 s& J( f% z7 t9 o& k* H
  4.   */0 s1 \0 `' U# u2 p2 v; v
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c). F, S2 v! K" ?
  6. {    if (_a == 0) {      return 0;" n+ u. P9 v& a& t
  7.     }
    , W% `1 V' U/ x# a' Q) V: Y5 c
  8.     c = _a * _b;7 J( g7 n- p  Q2 y7 p. f
  9.     assert(c / _a == _b);    return c;
    6 [5 b. l- F5 U/ n6 ]& H: M
  10.   }  /**
    4 n4 T6 [* b# g8 P. l
  11.   * Integer division of two numbers, truncating the quotient.; t9 Z" V2 ^$ ^- N. U$ a9 O5 _. W
  12.   */" V' L! p" G5 _" `" V, S6 N
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    & o8 ?0 T; @3 k/ z  S4 K. M
  14.   }  /**
    * h/ G: i+ Y1 P1 X4 r
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    ( e$ q- `: S- l6 o) ~$ `/ X
  16.   */
    # O- E$ E. o" D2 N# f* g
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    : _( o/ H. U$ w' ~5 c
  18.     assert(_b = _a);    return c;( Z5 E! V2 n7 ^  J  Z) h( s$ C
  19.   }
    + c5 P! v3 w; W" K* l
  20. }
    6 h0 ]6 L' _2 F6 S
  21. contract ERC20 {
    0 j+ u! S! ~4 l- O1 v, H
  22.   uint256 public totalSupply;  function balanceOf(address _who)
    ' X. r. r% q. C$ r
  23.   public view returns (uint256);
    5 W4 u0 B, C  f7 f7 h: V2 @
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
    / E5 E% p; X& d
  25.     function transfer(address _to, uint256 _value) public returns (bool);  
    0 E7 S, a1 F' |+ m# g. F2 r
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    - i0 Z0 w8 H% F+ V  ~7 i
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  
    : x& {0 @* s2 o; p6 M% Z' r
  28.     event Transfer( address indexed from, address indexed to,  uint256 value); ! {- h# o$ ?9 F
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  
    4 F& c9 w8 R* l9 q" e
  30.   event Burn(address indexed from, uint256 value);- A2 B9 E% J6 Z
  31. }contract StandardToken is ERC20 {* t0 o1 \! |1 {4 m/ a7 V
  32.   using SafeMath for uint256;; r+ d3 ^6 s8 D* }! R
  33.   mapping(address => uint256) balances;
    / r. k/ R) x. v; S4 \" T
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    # n! j7 X+ }- t2 s, I- A9 a  l
  35.   * Gets the balance of the specified address.2 T+ J2 S, j" k) s* b+ Z7 [
  36.   * @param _owner The address to query the the balance of.
    4 s. C+ u' V% f; z: ^- N
  37.   * @return An uint256 representing the amount owned by the passed address." j3 X) k9 o) ~" a9 ?, r6 s* z
  38.   */" g, I6 E; E6 \0 U- N  S
  39.   function balanceOf(address _owner) public view returns (uint256)
    - G7 x5 D% Y( y) R( l* |: W
  40.      {    return balances[_owner];
    - {/ X; s9 u0 g9 J6 _( |
  41.   }  /**
    , p; m' g: c) r2 R$ u7 D
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.
    2 Z$ W4 k, |. S' ?" [( x* L
  43.    * @param _owner address The address which owns the funds.
    - _/ o* H) @% G; Z$ v
  44.    * @param _spender address The address which will spend the funds.
    6 |  e0 {: J+ d8 o
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.
    2 w" N7 @. y# R3 @8 ?: _! V+ V
  46.    */
    0 _+ ~( Y( J( Y- l/ r* d$ _
  47.   function allowance(address _owner, address _spender) public view returns
    4 a( L* z$ V' {% ^. r- t
  48.       (uint256){    return allowed[_owner][_spender];
    ; H6 C$ ^. B3 f, E: O9 F% w
  49.   }  /**
    ; n3 Q! x7 I5 D
  50.   * Transfer token for a specified address! v+ G6 B; v0 B4 p% v9 X. S
  51.   * @param _to The address to transfer to.
    7 n) y- X5 `' O) M1 ?+ E
  52.   * @param _value The amount to be transferred.
    8 t( U3 N0 Y1 K8 w+ F
  53.   */
    8 D% k, F( u% U5 H* A$ O( \+ V
  54.   function transfer(address _to, uint256 _value) public returns ( E2 Y7 o- p/ O* T( @9 W
  55.       (bool) {    require(_value = oldValue) {$ E! x9 J: ^0 Y9 t( ]
  56.       allowed[msg.sender][_spender] = 0;1 a- d. r/ l4 H( Q% ]8 Y( z6 k
  57.     } else {: [! Z. k9 l3 d/ K5 o% ?
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);7 q- P: I8 \; r$ T- H! g1 |  T
  59.     }4 K) P: C3 l! j8 ^; `+ V
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;
    ; V7 x7 ]' n8 T* L; Z( ?
  61.   }  
    0 I* y3 f& G- [) ]/ m6 H
  62.    /**8 Q# x5 [8 L: o9 R% f$ g0 c. Z
  63.      * Destroy tokens' R, i8 N/ L; t6 s3 V8 D& E- y
  64.      *
    % c' \, @$ |' X% k
  65.      * Remove `_value` tokens from the system irreversibly$ o4 e3 y7 X0 E, v$ C  c
  66.      *
    9 W$ u* {; F& \5 N6 ^7 e! D- x
  67.      * @param _value the amount of money to burn
    ! v6 z: `4 p: v
  68.      */
    0 S& F1 U' u3 }! N* H
  69.     function burn(uint256 _value) public returns (bool success)" z, {$ M$ E2 D: T( {
  70.           {        require(balances[msg.sender] >= _value);   
    ! }9 z" l/ z, _# T# [' ~4 @
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          8 C( [0 h7 n0 R* H- K" O- F
  72.         totalSupply = totalSupply.sub(_value);                      8 L" r/ \% V; h4 p. X  w/ D
  73.         emit Burn(msg.sender, _value);        return true;
    % a/ @. V4 s  T, J/ d
  74.     }    /**: a& y4 y9 m- w; s2 W
  75.      * Destroy tokens from other account
    5 n! ^& G# i9 Z
  76.      *2 j/ e+ E7 `! [! I2 b) X
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`." }; F4 x( n5 u7 o1 z. r7 u- l
  78.      *5 X5 ?) w( ]: }
  79.      * @param _from the address of the sender) F! \8 u- v1 G0 B& x8 K' }/ O$ Z7 V
  80.      * @param _value the amount of money to burn" S" Z& m) M# ^5 \8 Z+ G4 \
  81.      */  z* N1 C/ ^% h3 w
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success)
    * u& \  d7 e5 ]* }, ]4 [
  83.           {        require(balances[_from] >= _value);               
    / T: M+ z9 S- S, C4 r( T0 ~4 e) i
  84.         require(_value
复制代码

1 p0 t7 }. x8 Z! f. n5 A: C6 T这些代码是什么意思呢?
( ?/ ~" T2 l* X, n9 t# k" {一、ERC20(EIP-20)说明
& H- B+ U  [" S" ?: q) }6 dERC20是一个标准的token接口规范:A standard interface for tokens4 A. j* U0 g2 n2 Y& t
该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md  S5 @' ?: {' o/ p( ]7 v9 i
我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件3 m7 V6 H$ S' H" K9 j
9个方法包括:
3 E+ |- B! o, d: G. c; K& }- a返回token的名字! a1 B: p* s  I6 U3 e
function name() view returns (string name)
7 \! I+ @3 A- I* R* \& A返回token的代码
& k# |5 b$ ?9 d6 f3 Jfunction symbol() view returns (string symbol)
" x2 A, ?; `1 \  c0 h4 \返回token的小数点位数
9 o0 A- u9 H& b+ x  afunction decimals() view returns (uint8 decimals)
+ m$ Z5 `6 e6 ~2 ?返回供应总量  t2 ?0 O% U; E
unction totalSupply() view returns (uint256 totalSupply)" J9 v% U; [: f  E* V2 Y9 z
查询某个地址的余额
( ~% f' }* m) @  i/ m9 h; _function balanceOf(address _owner) view returns (uint256 balance)4 m3 {5 m, p( j  v! ?8 _( e
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false
9 k! O0 ]8 k( mfunction transfer(address _to, uint256 _value) returns (bool success)
1 d  U& B, v0 O9 {4 V, h% H从from地址转账到to地址,该方法用于委托给其他合约代理你转账1 K$ O2 @6 R: o0 h* f$ R% q- S
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
* U9 k- a# A) b$ P) l4 d1 ]允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value; y0 r; b1 a3 M# z% d- ~! G
function approve(address _spender, uint256 _value) returns (bool success)
( b% [" Z# C: P/ Q( ?5 u/ ~返回_spender仍允许退出的金额_owner
6 t% C8 T: a7 S/ F2 p0 _1 D7 zfunction allowance(address _owner, address _spender) view returns (uint256 remaining), U/ e4 B" M( z! Q! o) B# A( |. X
2个事件包括:
- ~: f9 }* c; g3 i转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候  k2 x" B/ I9 H$ y, c$ ^9 R
event Transfer(address indexed _from, address indexed _to, uint256 _value)# r1 e+ A  Z1 F, v  O/ Y
委托转账必须触发! ^, V/ z# P- y, r- d% H
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
8 T" M6 n( h6 B6 v+ l5 V8 V) ~$ a2 @+ b$ p7 u

; y: l; D/ d5 X5 l二、代码解释
( H& A5 _8 ~  h4 X/ u, [1 O0 m& j
6 |+ |! R+ }( r9 L$ r代码包括几部分:" Q9 U0 x- q! Y  |" |' Q* W  r
# ?4 F. D+ S: W/ C) W5 h1 S
安全的数学计算库
  i  j7 s' J; U
* |. J! e, K" Acontract类 ERC20,主要针对ERC20规范定义方法和事件
: k" G, F" D! o" o& [2 E" k
8 T/ j" u" n( o* h  E' O- k  k- P, Ucontract类StandardToken继承ERC20,定义具体的方法实现
( k* K- b) p9 S6 S3 E/ s+ u) G4 t3 z; t
contract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5