前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >以太坊ERC20协议以及发行自己代币

以太坊ERC20协议以及发行自己代币

作者头像
若与
发布2018-11-23 18:03:02
2.1K0
发布2018-11-23 18:03:02
举报

什么是 ERC20

ERC-20 标准是在2015年11月份推出的,使用这种规则的代币,表现出一种通用的和可预测的方式。

简单地说,任何 ERC-20 代币都能立即兼容以太坊钱包(几乎所有支持以太币的钱包,包括Jaxx、MEW、imToken等,也支持 erc-20的代币),由于交易所已经知道这些代币是如何操作的,它们可以很容易地整合这些代币。这就意味着,在很多情况下,这些代币都是可以立即进行交易的。

标准化非常有利,也就意味着这些资产可以用于不同的平台和项目,否则只能用在特定的场合。

代币(Token)是区块链中定义价值的方式,用于标定金融或数字资产。在以太坊上,代币使用相同的标准,这样代币之间的兑换和DAPP支持就会变得容易。

标准规定了哪些内容

ERC20 是各个代币的标准接口。ERC20 代币仅仅是以太坊代币的子集。为了充分兼容 ERC20,开发者需要将一组特定的函数(接口)集成到他们的智能合约中,以便在高层面能够执行以下操作:

  • 获得代币总供应量
  • 获得账户余额
  • 转让代币
  • 批准花费代币

ERC20 让以太坊区块链上的其他智能合约和去中心化应用之间无缝交互。一些具有部分但非所有ERC20标准功能的代币被认为是部分 ERC20兼容,这还要视其具体缺失的功能而定,但总体是它们仍然很容易与外部交互。

ERC20 标准

ERC20 标准定义了一个兼容协议, 需要实现的函数. 具体如下.

代码语言:javascript
复制
  contract ERC20Interface {

    // 代币名称
    string public constant name = "Token Name";
    // 符号
    string public constant symbol = "SYM";
    // 小数点位数
    uint8 public constant decimals = 18;  // 18 is the most common number of decimal places
    // 0.0000000000000000001  个代币

    // 法币总量
    function totalSupply() public constant returns (uint);

    // 查看对应账号的代币余额
    function balanceOf(address tokenOwner) public constant returns (uint balance);

    // 控制代币的交易
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

    // 允许用户可花费的代币数
    function approve(address spender, uint tokens) public returns (bool success);

    // 实现代币交易,转账
    function transfer(address to, uint tokens) public returns (bool success);

    //实现代币之间的交易
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);


    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

同时规定了三个必须定义的变量,分别是

  • 合约名称
  • 合约代号
  • 合约进制
代码语言:javascript
复制
     string public constant name = "Token Name";
     string public constant symbol = "SYM";
     uint8 public constant decimals = 18;  // 18 is the most common number of decimal places

ERC20 并不是完美的

ERC-20标准还有待完善。

  1. 其中一个障碍是,将令牌直接发送给令牌的智能合同将导致资金损失。这是因为一个令牌的合同只会跟踪和分配资金。例如,当您从钱包中向另一个用户发送令牌时,该钱包将调用令牌的合约来更新数据库。所以如果您试图将令牌直接传输到令牌的合约中,那么由于该令牌的合约无法响应,所以金钱就“丢失”了。
  2. ERC20标准无法通过接收方合同处理传入的交易。这是该令牌存在的最大问题,也是开发者一直希望改进的地方。ERC20令牌无法将令牌发送给一个与这些令牌不兼容的契约,也正因为这样,部分资金存在丢失的风险。
  3. Reddit上的一篇文章指出,由于被发送到“错误”的合同上,大约价值40万美元的ERC20令牌被困,这对整个以太坊生态系统而言是一个巨大的威胁。幸运的是,ERC223令牌可以解决这一难题,前提是该令牌能够获得批准并被引入。

抽象

以下标准允许在智能合约中实施标记的标记API。 该标准提供了转移token的基本功能,并允许token被批准,以便他们可以由另一个在线第三方使用。

动机

标准接口可以让Ethereum上的任何令牌被其他应用程序重新使用:从钱包到分散式交换。

规则

Token
方法

注意:调用者必须处理返回false的returns (bool success).调用者绝对不能假设返回false的情况不存在。

name

返回这个令牌的名字,比如"MyToken".

可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。

代码语言:javascript
复制
function name() constant returns (string name)
symbol

返回令牌的符号,比如HIX.

可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。

代码语言:javascript
复制
function symbol() constant returns (string symbol)
decimals

返回token使用的小数点后几位, 比如 8,表示分配token数量为100000000

可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。

代码语言:javascript
复制
function decimals() constant returns (uint8 decimals)
totalSupply

返回token的总供应量。

代码语言:javascript
复制
function totalSupply() constant returns (uint256 totalSupply)
balanceOf

返回地址是_owner的账户的账户余额。

代码语言:javascript
复制
function balanceOf(address _owner) constant returns (uint256 balance)
transfer

转移_value的token数量到的地址_to,并且必须触发Transfer事件。 如果_from帐户余额没有足够的令牌来支出,该函数应该被throw。

创建新令牌的令牌合同应该在创建令牌时将_from地址设置为0x0触发传输事件。

注意 0值的传输必须被视为正常传输并触发传输事件。

代码语言:javascript
复制
function transfer(address _to, uint256 _value) returns (bool success)
transferFrom

从地址_from发送数量为_value的token到地址_to,必须触发Transfer事件。

transferFrom方法用于提取工作流,允许合同代您转移token。这可以用于例如允许合约代您转让代币和/或以子货币收取费用。除了_from帐户已经通过某种机制故意地授权消息的发送者之外,该函数应该throw。

注意 0值的传输必须被视为正常传输并触发传输事件。

代码语言:javascript
复制
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
approve

允许_spender多次取回您的帐户,最高达_value金额。 如果再次调用此函数,它将以_value覆盖当前的余量。

注意:为了阻止向量攻击,客户端需要确认以这样的方式创建用户接口,即将它们设置为0,然后将其设置为同一个花费者的另一个值。虽然合同本身不应该强制执行,允许向后兼容以前部署的合同兼容性

代码语言:javascript
复制
function approve(address _spender, uint256 _value) returns (bool success)
allowance

返回_spender仍然被允许从_owner提取的金额

代码语言:javascript
复制
function allowance(address _owner, address _spender) constant returns (uint256 remaining)
Events

Transfer 当token被转移(包括0值),必须被触发。

代码语言:javascript
复制
event Transfer(address indexed _from, address indexed _to, uint256 _value)
Approval

当任何成功调用approve(address _spender, uint256 _value)后,必须被触发。

代码语言:javascript
复制
event Approval(address indexed _owner, address indexed _spender, uint256 _value)

发行代币demo

代码

代码语言:javascript
复制
pragma solidity ^0.4.20;

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }

contract TokenERC20 {
    string public name;
    string public symbol;
    uint8 public decimals = 18;  // decimals 可以有的小数点个数,最小的代币单位。18 是建议的默认值
    uint256 public totalSupply;

    // 用mapping保存每个地址对应的余额
    mapping (address => uint256) public balanceOf;
    // 存储对账号的控制
    mapping (address => mapping (address => uint256)) public allowance;

    // 事件,用来通知客户端交易发生
    event Transfer(address indexed from, address indexed to, uint256 value);

    // 事件,用来通知客户端代币被消费
    event Burn(address indexed from, uint256 value);

    /**
     * 初始化构造
     */
    constructor(uint256 initialSupply, string tokenName, string tokenSymbol) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // 供应的份额,份额跟最小的代币单位有关,份额 = 币数 * 10 ** decimals。
        balanceOf[msg.sender] = totalSupply;                // 创建者拥有所有的代币
        name = tokenName;                                   // 代币名称
        symbol = tokenSymbol;                               // 代币符号
    }

    /**
     * 代币交易转移的内部实现
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // 确保目标地址不为0x0,因为0x0地址代表销毁
        require(_to != 0x0);
        // 检查发送者余额
        require(balanceOf[_from] >= _value);
        // 确保转移为正数个
        require(balanceOf[_to] + _value > balanceOf[_to]);

        // 以下用来检查交易,
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);

        // 用assert来检查代码逻辑。
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     *  代币交易转移
     * 从创建交易者账号发送`_value`个代币到 `_to`账号
     *
     * @param _to 接收者地址
     * @param _value 转移数额
     */
    function transfer(address _to, uint256 _value) public {
        _transfer(msg.sender, _to, _value);
    }

    /**
     * 账号之间代币交易转移
     * @param _from 发送者地址
     * @param _to 接收者地址
     * @param _value 转移数额
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * 设置某个地址(合约)可以交易者名义花费的代币数。
     *
     * 允许发送者`_spender` 花费不多于 `_value` 个代币
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
    returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    /**
     * 设置允许一个地址(合约)以交易者名义可最多花费的代币数。
     *
     * @param _spender 被授权的地址(合约)
     * @param _value 最大可花费代币数
     * @param _extraData 发送给合约的附加数据
     */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
    public
    returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }

    /**
     * 销毁创建者账户中指定个代币
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }

    /**
     * 销毁用户账户中指定个代币
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        emit Burn(_from, _value);
        return true;
    }
}

在remix中编译运行上面的上面的智能合约,键入参数,配合metamask插件,

在METAMASK中查看自己的代币:

ERC223要解决的首要问题是什么?

自从引入ERC20令牌标准以来,几乎所有的基于以太坊的令牌都成功的接受了这个新标准。然而其自身的缺点需要及时解决,这便是ERC223令牌诞生的原因。

防止丢失

ERC223令牌标准将向现有的ERC20标准引入一个新功能,以防止意外转移的发生。ERC223令牌标准可以防止令牌在以太坊网络上丢失。

困难的转换

假设 ERC223 令牌标准能够取代ERC20成为新的标准,现有令牌的发行方需要做一些艰难的决定。因为,从现实情况来看,不管用何种方式,从ERC20转换到ERC223是不可能的,同样的,所有ERC20令牌都需要在ERC223标准下重新部署。这也意味着任何交易平台的上市都需要更新他们的信息和地址。这是一个艰苦的过程,这也就意味着,在未来很少有现有的令牌被有效地转换为ERC223。

正如Alex van de Sande在Reddit上指出的那样,“更方便”的过程可能是创建新的令牌,它们是通过持有旧令牌的合同支持的。这可能是大多数项目最合理的选择,但只有时间才能确定哪些选项将被实施。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.10.23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是 ERC20
  • 标准规定了哪些内容
  • ERC20 标准
  • ERC20 并不是完美的
    • 抽象
      • 动机
        • 规则
          • Token
          • 方法
        • name
          • symbol
          • decimals
          • totalSupply
          • balanceOf
          • transfer
          • transferFrom
          • approve
          • allowance
          • Events
          • Approval
        • 发行代币demo
          • ERC223要解决的首要问题是什么?
            • 防止丢失
              • 困难的转换
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档