ERC20详解

1、ERC20Basic

   安全考虑定义抽象函数和发送事件,个人认为隔离设计更安全

        function totalSupply()

        function balanceOf()

        function transfer() 

        event Transfer();

2、ERC20

    安全考虑定义抽象函数和发送事件,这里ERC20符合ERC20的标准

        function allowance ()

        function transferFrom ()

        function approve() 

        event Transfer();

3、ERC20Basic的实现----------------BasicToken

        function totalSupply()

        function balanceOf()

        function transfer() 

4、ERC20 的实现----------------StandardToken

   实现了ERC20标准的所有函数,另外增加了对允许转账金额的增加和修改

        function allowance ()

        function transferFrom ()

        function approve() 

        function increaseApproval()

        function decreaseApproval()

具体代码:

pragma solidity ^0.4.18;

/**

* @title ERC20Basic

* @dev Simpler version of ERC20 interface

* @dev see https://github.com/ethereum/EIPs/issues/179

*/

contract ERC20Basic {

  function totalSupply() public view returns (uint256);  // totalSupply - 总发行量

  function balanceOf(address who) public view returns (uint256);  // 余额

  function transfer(address to, uint256 value) public returns (bool);  // 交易

  event Transfer(address indexed from, address indexed to, uint256 value);  // 交易事件

}

/**

* @title SafeMath

* @dev Math operations with safety checks that throw on error

*/

library SafeMath {

  /**

  * @dev Multiplies two numbers, throws on overflow.

  */

  function mul(uint256 a, uint256 b) internal pure returns (uint256) {

    if (a == 0) {

      return 0;

    }

    uint256 c = a * b;

    assert(c / a == b);

    return c;

  }

  /**

  * @dev Integer division of two numbers, truncating the quotient.

  */

  function div(uint256 a, uint256 b) internal pure returns (uint256) {

    // assert(b > 0); // Solidity automatically throws when dividing by 0

    uint256 c = a / b;

    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;

  }

  /**

  * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).

  */

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {

    assert(b <= a);

    return a - b;

  }

  /**

  * @dev Adds two numbers, throws on overflow.

  */

  function add(uint256 a, uint256 b) internal pure returns (uint256) {

    uint256 c = a + b;

    assert(c >= a);

    return c;

  }

}

/**

* @title ERC20 interface

* @dev see https://github.com/ethereum/EIPs/issues/20

*/

contract ERC20 is ERC20Basic {

  function allowance(address owner, address spender) public view returns (uint256);  // 获取被授权令牌余额,获取 _owner 地址授权给 _spender 地址可以转移的令牌的余额

  function transferFrom(address from, address to, uint256 value) public returns (bool);  // A账户-》B账户的转账

  function approve(address spender, uint256 value) public returns (bool);  // 授权,允许 _spender 地址从你的账户中转移 _value 个令牌到任何地方

  event Approval(address indexed owner, address indexed spender, uint256 value);  // 授权事件

}

/**

* @title Basic token

* @dev Basic version of StandardToken, with no allowances.

*/

contract BasicToken is ERC20Basic {

  using SafeMath for uint256;

  mapping(address => uint256) balances; // 余额

  uint256 totalSupply_;  // 发行总量

  /**

  * @dev total number of tokens in existence

  */

  function totalSupply() public view returns (uint256) {

    return totalSupply_;

  }

  /**

  * @dev transfer token for a specified address

  * @param _to The address to transfer to.

  * @param _value The amount to be transferred.

  */

  function transfer(address _to, uint256 _value) public returns (bool) {

    require(_to != address(0));  // 无效地址

    require(_value <= balances[msg.sender]);  // 转账账户余额大于转账数目

    // SafeMath.sub will throw if there is not enough balance.

    balances[msg.sender] = balances[msg.sender].sub(_value);  // 转账账户余额=账户余额-转账金额

    balances[_to] = balances[_to].add(_value); // 接收账户的余额=原先账户余额+账金额

    Transfer(msg.sender, _to, _value);  // 转账

    return true;

  }

  /**

  * @dev Gets the balance of the specified address.

  * @param _owner The address to query the the balance of.

  * @return An uint256 representing the amount owned by the passed address.

  */

  function balanceOf(address _owner) public view returns (uint256 balance) {

    return balances[_owner];  // 查询合约调用者的余额

  }

}

/**

* @title Standard ERC20 token

*

* @dev Implementation of the basic standard token.

* @dev https://github.com/ethereum/EIPs/issues/20

* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol

*/

contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;

  /**

  * @dev Transfer tokens from one address to another

  * @param _from address The address which you want to send tokens from

  * @param _to address The address which you want to transfer to

  * @param _value uint256 the amount of tokens to be transferred

  */

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {

    require(_to != address(0)); // 到达B账户的地址不能为无效地址

    require(_value <= balances[_from]);  // 转账账户余额大于转账金额

    require(_value <= allowed[_from][msg.sender]);  // 允许_from地址转账给 _to地址

    balances[_from] = balances[_from].sub(_value); 

    balances[_to] = balances[_to].add(_value);

    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);  // 允许转账的余额

    Transfer(_from, _to, _value);

    return true;

  }

  /**

    * 设置帐户允许支付的最大金额

    *

    * 一般在智能合约的时候,避免支付过多,造成风险

    *

    * @param _spender 帐户地址

    * @param _value 金额

    */

  function approve(address _spender, uint256 _value) public returns (bool) {

    allowed[msg.sender][_spender] = _value;

    Approval(msg.sender, _spender, _value);

    return true;

  }

  /**

  * @dev Function to check the amount of tokens that an owner allowed to a spender.

  * @param _owner address The address which owns the funds.

  * @param _spender address The address which will spend the funds.

  * @return A uint256 specifying the amount of tokens still available for the spender.

  获取 _owner 地址授权给 _spender 地址可以转移的令牌的余额

  */

  function allowance(address _owner, address _spender) public view returns (uint256) {

    return allowed[_owner][_spender];

  }

  /**

  * @dev Increase the amount of tokens that an owner allowed to a spender.

  *

  * approve should be called when allowed[_spender] == 0. To increment

  * allowed value is better to use this function to avoid 2 calls (and wait until

  * the first transaction is mined)

  * From MonolithDAO Token.sol

  * @param _spender The address which will spend the funds.

  * @param _addedValue The amount of tokens to increase the allowance by.

    增加允许支付的最大额度

  */

  function increaseApproval(address _spender, uint _addedValue) public returns (bool) {

    allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);

    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);

    return true;

  }

  /**

  * @dev Decrease the amount of tokens that an owner allowed to a spender.

  *

  * approve should be called when allowed[_spender] == 0. To decrement

  * allowed value is better to use this function to avoid 2 calls (and wait until

  * the first transaction is mined)

  * From MonolithDAO Token.sol

  * @param _spender The address which will spend the funds.

  * @param _subtractedValue The amount of tokens to decrease the allowance by.

      减少允许支付的最大额度

  */

  function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {

    uint oldValue = allowed[msg.sender][_spender];

    if (_subtractedValue > oldValue) {

      allowed[msg.sender][_spender] = 0;

    } else {

      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);

    }

    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);

    return true;

  }

}

可以参考: 

https://www.jianshu.com/writer#/notebooks/24554485/notes/28544778

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 1、流程图 2、ERC20代码详解 1)、基本合约提供总发行量,余额,交易转账函数以及转账事件 2)、Safe...
    08f1b6c52d2a阅读 6,554评论 0 6
  • (注:本文是在原文的基础上,根据个人的理解,修改部分内容并添加了一些注释) 买卖部分代码未调试通过 基础版的代币合...
    中v中阅读 2,890评论 0 2
  • 看过美剧《权利的游戏》之后,再看别的剧,都一个感觉---太low了。 于是,我在感谢这部剧作,给我带来美好观剧体验...
    木语叨叨阅读 982评论 0 2
  • 你是否还记得那首浅唱的歌谣 你是否记得夜晚罗裙漫过石桥 远处的街灯依然闪烁流淌 街上的叫卖声还能传到耳旁 细听那穿...
    c361279aca9d阅读 113评论 0 3
  • 这两天女儿刚升入初中,日子有些忙乱。有希望,有焦虑,有担心。 这几天军训,女儿有些难受,现在的孩子缺乏锻炼。本想她...
    雨晴天空阅读 251评论 2 8