Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。
! e& p$ i2 D; S. E3 g废话不少,先上完整代码:2 L; h1 ~5 o) U4 ]. ~6 A
  1. pragma solidity ^0.4.24;: j, a; R: [: s$ ~3 j2 A/ ]; Y- k
  2. library SafeMath {  /**$ q. `( A8 u9 o! ~$ ?( D' [
  3.   * @dev Multiplies two numbers, throws on overflow.' L- J( l  G) Z$ W, U
  4.   */
    ! e' N: X  u& a: |9 j9 z
  5.   function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)" A. R5 s& [7 B: t- A
  6. {    if (_a == 0) {      return 0;
    % B0 N: @1 V& O
  7.     }, p. I7 L. R% i% q7 d( P
  8.     c = _a * _b;, }& B# ~3 B4 W+ e
  9.     assert(c / _a == _b);    return c;
    5 W' m4 `* ^; k) S$ ^
  10.   }  /**6 D" ]7 L7 O5 e/ |* i& P) K. y0 k
  11.   * Integer division of two numbers, truncating the quotient.
    ; w  ]* E+ X% o0 ~( b
  12.   */
    " K0 F# \* J% O# ]5 [+ O
  13.   function div(uint256 _a, uint256 _b) internal pure returns (uint256) {    return _a / _b;
    , x8 B5 |  y/ E3 ?5 H
  14.   }  /**
    2 C5 I4 f% a4 I# a3 F" z5 p1 ?0 [' G
  15.   * Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    0 m3 |0 S) p8 w- q" t. B: y3 b
  16.   */- U7 X; k+ G! ~3 X0 U9 e  \% p
  17.   function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    8 U* \' w* l# Y
  18.     assert(_b = _a);    return c;
    & M9 z* s, v5 h- I
  19.   }
    # }3 s1 G" X$ n& {6 h" j
  20. }4 I9 N2 p) {9 \/ j4 o( {* \: M
  21. contract ERC20 {
    6 @9 L2 X: y. {# L: y; J
  22.   uint256 public totalSupply;  function balanceOf(address _who)
    ( ~) X! Q7 `4 |& ?; t
  23.   public view returns (uint256); # k) _: [2 k! x, r' T* j
  24.    function allowance(address _owner, address _spender) public view returns (uint256);
    2 D/ m0 k1 l  t9 ~# [9 i0 [1 P+ Q- t
  25.     function transfer(address _to, uint256 _value) public returns (bool);  
    ! q# D1 F! R5 s3 k* \$ I
  26.   function approve(address _spender, uint256 _value) public returns (bool);  
    : C5 D9 ]" Q. s) r  d
  27.     function transferFrom(address _from, address _to, uint256 _value) public returns (bool);  # V0 X' x  G% l" `' j( j
  28.     event Transfer( address indexed from, address indexed to,  uint256 value);
    . k, L7 w9 t( Y
  29.      event Approval(address indexed owner, address indexed spender, uint256 value);  5 N' V2 [# F. H
  30.   event Burn(address indexed from, uint256 value);- F4 s9 l7 h7 [& q# R
  31. }contract StandardToken is ERC20 {# C3 {( q" j  f$ q* Y+ V
  32.   using SafeMath for uint256;; v6 ~" Y. D0 p$ g' v
  33.   mapping(address => uint256) balances;
    / `. Z: e! j+ f8 i6 t
  34.   mapping (address => mapping (address => uint256)) internal allowed;  /**
    / s: D+ @! r8 `0 h7 }$ o
  35.   * Gets the balance of the specified address.- {+ s) C" T# V
  36.   * @param _owner The address to query the the balance of.# P# A' p- [1 |/ i. z% K- o; p- V
  37.   * @return An uint256 representing the amount owned by the passed address.3 ]/ h( b* s0 {, k. ~) F
  38.   */
    7 V! D5 z9 B7 r$ [
  39.   function balanceOf(address _owner) public view returns (uint256)
    ) c) K# f& C$ k$ B% _- e* _: w
  40.      {    return balances[_owner];. D. ^7 q3 Y( A& h( G+ W$ z) m
  41.   }  /**
    : U  H9 @# Z/ V/ N+ \$ C. S
  42.    *  Function to check the amount of tokens that an owner allowed to a spender.+ U7 S& X: }7 C
  43.    * @param _owner address The address which owns the funds.3 r3 ^+ d5 C& A, O
  44.    * @param _spender address The address which will spend the funds.
    9 [9 l8 t' }9 ^( Y! Z5 z' a
  45.    * @return A uint256 specifying the amount of tokens still available for the spender.2 I% X$ d$ Q: B0 Q. c
  46.    */
    , p3 ]6 T: k9 n- E0 l8 N
  47.   function allowance(address _owner, address _spender) public view returns
    4 @1 y+ B0 Q) A  N( {& |8 V; q
  48.       (uint256){    return allowed[_owner][_spender];
    / Z# E. M7 K! Z- O3 _: r
  49.   }  /**
    + b, z: G7 G- C4 L" u( K
  50.   * Transfer token for a specified address% W% s% X0 @; D6 }: M9 Q& L6 b- B; E
  51.   * @param _to The address to transfer to.% \. M2 G( c! p( z4 i/ P
  52.   * @param _value The amount to be transferred.
      b3 a7 S9 m  k# p2 b  y! R. p
  53.   */: o6 `( `4 N. P0 O7 @/ I8 Z
  54.   function transfer(address _to, uint256 _value) public returns / f5 G: @( j0 {( O+ C  E% H  {
  55.       (bool) {    require(_value = oldValue) {. O- S, Z' }) o+ ?
  56.       allowed[msg.sender][_spender] = 0;
    5 v2 `( a; a6 d0 R2 T5 ?% v
  57.     } else {
    - a$ `! Q. s& W9 {/ v( G
  58.       allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    ! R+ d4 z7 C. x5 n
  59.     }
    4 l) T) e' s, _. a7 O2 \+ }
  60.     emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);    return true;
    ; z* S8 T- X% E: i& U
  61.   }  9 C9 r% Y2 J9 A+ J* m
  62.    /**
    4 d% D  d) G: S+ P# W
  63.      * Destroy tokens+ A# w+ i6 w4 f
  64.      *
    " R7 X- c# F/ K, N/ i/ K
  65.      * Remove `_value` tokens from the system irreversibly  }7 A* h1 r/ x- n
  66.      *# i5 h  c4 V; ]9 i+ K$ S4 }
  67.      * @param _value the amount of money to burn9 Y( S, A1 L: d6 R8 ~2 O0 O
  68.      */! @' z, V& w. M8 b3 Y
  69.     function burn(uint256 _value) public returns (bool success)6 W# E  Y8 C( y
  70.           {        require(balances[msg.sender] >= _value);   
    & D3 H6 \7 Z: K% }! v, d
  71.         balances[msg.sender] = balances[msg.sender].sub(_value);          3 y  Z$ T8 \' F/ X1 ]0 G: x
  72.         totalSupply = totalSupply.sub(_value);                      2 B0 R0 A" p8 j2 t$ B" l$ `
  73.         emit Burn(msg.sender, _value);        return true;
    : {/ ^0 c; ]/ c# V! X
  74.     }    /**
    ! B) U& Y8 _/ m) w! T: {6 l0 M
  75.      * Destroy tokens from other account
    8 Y' e( S2 n) X0 U8 J8 B  Z0 I
  76.      *
    6 y; i. i  b# V0 v# T! g
  77.      * Remove `_value` tokens from the system irreversibly on behalf of `_from`.3 T! {0 R& ?% l1 K
  78.      *5 v2 `* g" N4 b. B: z
  79.      * @param _from the address of the sender% m& s8 \" n4 q/ r2 }- ?
  80.      * @param _value the amount of money to burn3 ]3 r+ o& t& _, C+ b
  81.      */
    . L, H0 n1 \6 L) b
  82.     function burnFrom(address _from, uint256 _value) public returns (bool success) ; a1 P' w1 M4 Y5 F0 ]; [
  83.           {        require(balances[_from] >= _value);                # \% N5 i0 M* s; l
  84.         require(_value
复制代码
4 W1 S. \# s$ V7 N+ n9 M0 a
这些代码是什么意思呢?8 C$ o7 e* p: M5 x$ P) @
一、ERC20(EIP-20)说明
% h1 A# u) c  ?1 r6 W3 \7 Z9 P" ]7 NERC20是一个标准的token接口规范:A standard interface for tokens
' Z1 P& f, P2 f% r7 I: n6 k5 e4 `该接口的官网说明在下面的链接:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md2 ~7 ]2 G. e! K3 f$ k, w
我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件2 P# Q4 ^. t+ ~3 `$ H2 I5 c
9个方法包括:
& C# e# J0 ^) n' O3 d( k" S返回token的名字
1 B2 o. z4 E6 k+ s4 w9 Efunction name() view returns (string name)1 c7 d' I% e9 `0 B" o# A
返回token的代码
/ z7 k2 ^' p* G! @9 g* a3 ufunction symbol() view returns (string symbol)- P7 b# [5 Q' ]) R0 T" t
返回token的小数点位数
9 c- g0 U  R. }/ c( ~function decimals() view returns (uint8 decimals)
/ s' O$ E7 z3 g, ]返回供应总量( i; L  t! c! y; G3 c! _  [: L
unction totalSupply() view returns (uint256 totalSupply)1 m3 r. O* ]! t& K  K+ g
查询某个地址的余额0 f2 b! J/ d" Z4 d2 @5 H/ }/ `. q
function balanceOf(address _owner) view returns (uint256 balance)0 R3 i) a, G( ^
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false) C* D' G6 o9 N! j
function transfer(address _to, uint256 _value) returns (bool success)
& ^! a7 [8 M  z( U# _6 Y9 x) ^0 }从from地址转账到to地址,该方法用于委托给其他合约代理你转账  O2 v2 U: @. z! ]' e
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)3 a: A! l' c" X9 D; k
允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value# K, r- [; z, m, L
function approve(address _spender, uint256 _value) returns (bool success)
# w  ?9 G+ x$ ^返回_spender仍允许退出的金额_owner" K! \$ l$ p% c3 v5 \" t6 Z! h
function allowance(address _owner, address _spender) view returns (uint256 remaining)
7 p3 K) x1 b7 N- B2个事件包括:5 {* N, a& t- z5 ]$ P1 F5 Y  I
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候
" r- d) v4 K$ l; T! r+ k( P" j9 xevent Transfer(address indexed _from, address indexed _to, uint256 _value)
; F8 @" L! [0 `9 U0 C, j委托转账必须触发3 X$ }; |8 w8 t/ k
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
& n. R; n; S; V: F7 t
* z) K$ ^' l( }4 G- B
9 {4 V; a' |) @5 g$ u+ U2 [" s3 u* A二、代码解释6 t2 t. t* s! V8 f' o# ^# G8 }

1 k" {9 ~, S+ |$ J3 T0 x* x6 U代码包括几部分:4 I( b) L% w' ~# a' B9 Z$ D
: v: M: O6 \6 c3 Y2 F: _
安全的数学计算库
8 |4 M: n/ Y7 K5 ^2 P! d. I! b9 Y. A
contract类 ERC20,主要针对ERC20规范定义方法和事件3 u' _9 `! {2 Y' w3 E
8 ]2 N6 Z* H* v4 z# w8 B4 u8 r5 ~
contract类StandardToken继承ERC20,定义具体的方法实现
3 X0 `6 Q0 r3 t* r
0 K; j; j( R6 F9 Fcontract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一杯浓咖啡 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    5