美文网首页程序员区块链研习社
ERC20代币智能合约解析

ERC20代币智能合约解析

作者: Andytl的世界 | 来源:发表于2018-04-27 06:33 被阅读0次

上一篇文章讲了如何发行自己的代币,重点讲发币的流程,对代币的智能合约代码没有讲解,直接借用现成的代码复制粘贴。为弥补上一篇的遗憾,本文对一个ERC20代币智能合约代码深入解析一下。

OTB代币智能合约

OTCBTC是一个数字货币场外交易平台。平台发行的代币叫OTB。OTCBTC的白皮书中描述了OTB,大致内容是

1.发行2亿枚
2.开发者持有40%
3.用户可用于手续费抵扣
4.每季度利润20%用来回购OTB并销毁

下面贴出OTB代币合约代码,我在代码注释中详细解释OTB的智能合约(solidity语法参考)。

pragma solidity ^0.4.19;//告诉编译器solidity版本号
//SafeMath库,用来防止加减乘除运算中出现数据溢出
library SafeMath {
    //乘法
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
       //任何数乘0,结果都是0,
       //很像一句废话,但可以防止下面除0运算出现。
        if (a == 0) {
          return 0;
        }
        uint256 c = a * b;
        assert(c / a == b);//逆向检查,如果c溢
//出将终止执行,也就是括号里为假,程序终止。
        return c;
    }
    //除法
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a / b;//由于整数除以整数不会溢出,不需要做逆向检查。
        return c;
    }
    //减法
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);//如果b>a,b-a是负数,溢出
        return a - b;
    }
    //加法
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);//如果a加上b结果更小了,说明溢出了  
        //有人可能会问,为啥不检查c=>b呢?
       //因为如果c<a,则说明a+b结果溢出,也就是b+a会溢出,也就是b越加a越小,即c<b。
        return c;   
    }
}
//所有权合约,用来判断操作币的人是否合法,以及转移所有权
contract Owned {
    address public owner;//全局变量
    address public newOwner;//全局变量
    modifier onlyOwner { require(msg.sender == owner); _; }//修饰函数用的,在函数运行前检查调用者是否为所有者
    event OwnerUpdate(address _prevOwner, address _newOwner);//事件,更新所有者

    function Owned() public {//构造函数,与合约同名,第一次构造合约的时候调用一次,就只有这一次哦
        owner = msg.sender;//初始化所有者
    }

    function transferOwnership(address _newOwner) public onlyOwner {//更新所有者函数,onlyOwner使得只有原所有者可以调用该函数
        require(_newOwner != owner);
        newOwner = _newOwner;
    }

    function acceptOwnership() public {//确认所有权,在原所有者出让所有权后,新所有者发起事件,将新所有权写入区块链
        require(msg.sender == newOwner);
        OwnerUpdate(owner, newOwner);
        owner = newOwner;
        newOwner = 0x0;
    }
}

// ERC20 Interface,定义ERC20代币规范的函数和事件接口
contract ERC20 {
   //总发行量查询函数
    function totalSupply() public view returns (uint _totalSupply);
   //账户余额查询函数
    function balanceOf(address _owner) public view returns (uint balance);
   //代币转移函数1,发送者调用发币
    function transfer(address _to, uint _value) public returns (bool success);
    //代币转移函数2,接收者调用收币,或者转移给第三方,类似于比特币中消费UTXO
    function transferFrom(address _from, address _to, uint _value) public returns (bool success);
    //批准代币转移函数,配合transferFrom使用,类似于比特币中构造UTXO
    function approve(address _spender, uint _value) public returns (bool success);
    //可消费余额查询函数
    function allowance(address _owner, address _spender) public view returns (uint remaining);
  //代币转移事件
    event Transfer(address indexed _from, address indexed _to, uint _value);
    //代币转移批准事件
    event Approval(address indexed _owner, address indexed _spender, uint _value);
}

// ERC20Token,定义ERC20代币的函数内容
contract ERC20Token is ERC20 {
    using SafeMath for uint256;//使用SafeMath库
    mapping(address => uint256) balances;//记录账户余额的表,地址为索引,余额为值
    mapping (address => mapping (address => uint256)) allowed;//记录转移可用余额的表,索引是转移的输入地址和输出地址,余额为值,类似于比特币里的未消费输出UTXO。
    uint256 public totalToken; //代币总量
//代币转移函数,_to目标地址,_value代币数量,公有函数哦,谁调用就转谁的币,函数将返回转移是否成功
    function transfer(address _to, uint256 _value) public returns (bool success) {
        if (balances[msg.sender] >= _value && _value > 0) {//转移者必须有足够的币吧,而且格外检查数量不是负数,防止有人没钱装大佬,设计合约真的是要格外小心啊
            balances[msg.sender] = balances[msg.sender].sub(_value);
            balances[_to] = balances[_to].add(_value);
            Transfer(msg.sender, _to, _value);
            return true;
        } else {
            return false;
        }
    }
//调用函数者将其控制的币(别人调用approve函数得来)转移(可以给自己,也可以给第三个人)
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
            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;
        } else {
            return false;
        }
    }
    //总发行量查询
    function totalSupply() public view returns (uint256) {
        return totalToken;
    }
    //账户余额查询
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return balances[_owner];
    }
//调用函数者将其_value币给_spender控制,_spender通过调用transferFrom可将币转给自己,也可以转给别人
    function approve(address _spender, uint256 _value) public returns (bool success) {
        require((_value == 0) || (allowed[msg.sender][_spender] == 0));
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }
//查询_owner给_spender的可用余额
    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }

}

//OTCBTC合约,定义OTB的基本信息和燃烧OTB的方法
contract OTCBTC is ERC20Token, Owned {

    string  public constant name = "OTCBTC Token";
    string  public constant symbol = "OTB";
    uint256 public constant decimals = 18;
    uint256 public tokenDestroyed;
    event Burn(address indexed _from, uint256 _tokenDestroyed, uint256 _timestamp);

//在构造函数中定义代币初始发行量
    function OTCBTC() public {
        totalToken = 200000000000000000000000000;
        balances[msg.sender] = totalToken;
    }
//转移代币
    function transferAnyERC20Token(address _tokenAddress, address _recipient, uint256 _amount) public onlyOwner returns (bool success) {
        return ERC20(_tokenAddress).transfer(_recipient, _amount);
    }
//燃烧代币
    function burn (uint256 _burntAmount) public returns (bool success) {
        require(balances[msg.sender] >= _burntAmount && _burntAmount > 0);
        balances[msg.sender] = balances[msg.sender].sub(_burntAmount);
        totalToken = totalToken.sub(_burntAmount);
        tokenDestroyed = tokenDestroyed.add(_burntAmount);
        require (tokenDestroyed <= 100000000000000000000000000);
  //燃烧就是转移到0地址      Transfer(address(this), 0x0, _burntAmount);
        Burn(msg.sender, _burntAmount, block.timestamp);
        return true;
    }

}

分析

OTB代币智能合约代码里只能保证代币总量,可以完成代币转移,可燃烧到0地址。其他白皮书的内容只能靠项目方自觉了。

智能合约刚起步,需要更多和产业结合,需要物联网基础设施,需要虚拟货币在人群普遍接受。就像一个刚出生的婴儿,充满希望,但柔弱不堪。智能合约代码的漏洞就像人的基因缺陷,不知道什么时间一触发,就让人病入膏肓,一行代码蒸发了¥6,447,277,680 人民币

我们像上帝一样,创造出一个新的世界,虽然里面的物种不完美,但是一旦产生就回不到以前的世界了。Hello,new world!

相关文章

  • 以太坊-ERC20标准

    目前以太坊上有24351个代币的智能合约,这2万多个代币都会遵寻ERC20标准, ERC20标准涵盖了哪些内容? ...

  • 以太坊根据ERC20标准开发代币

    以太坊ERC20代币开发首先需要对以太坊,代币,ERC20,智能合约等以太坊代币开发中的基本概念有了解。根据我们的...

  • 5.2 智能合约实战 - FurnaceCoin

    智能合约实战 - FurnaceCoin 本示例用于展示如何基于ERC20标准代币,实现一套自己的代币。 1. 创...

  • web3j生成Java版本的智能合约 以太坊 ERC20

    重点:Windows下 使用web3j工具生成Java版本的智能合约。 需要拿到要操作的ERC20代币的合约地...

  • 以太坊ERC20代币合约案例

    一.ERC20代币合约与web3调用 ERC20代币合约在小白看来觉得很高大上,但其实就是一个代币的定义标准,方便...

  • 以太坊开发问题及解决办法案例

    在合约中向其它账户转入其他erc20代币 在需要使用其他erc20代币转账合约中定义token接口,并在接口中定义...

  • ERC20代币智能合约解析

    上一篇文章讲了如何发行自己的代币,重点讲发币的流程,对代币的智能合约代码没有讲解,直接借用现成的代码复制粘贴。为弥...

  • 区块链100讲:ERC20 中文版

    1 摘要 ERC20 中文版简单总结即:代币的标准接口。 下面的标准允许在智能合约中代币的标准API的实现。 该标...

  • 9 zeppelin源码情景分析2

    9.8 ERC20可置换代币模块 token称为代币或者通证代表各种类型的数字资产,其本质是基于以太坊的智能合约。...

  • 教你如何一步步创建ERC20代币

    看这篇文章需要对以太坊,智能合约,代币等概念有基本的了解。 什么是ERC20 可以把ERC20简单理解成以太坊上的...

网友评论

    本文标题:ERC20代币智能合约解析

    本文链接:https://www.haomeiwen.com/subject/sznjlftx.html