众所周知,以太坊在现阶段最大的应用就是令牌发行,而在以太坊中有不少类型的令牌,最著名的当属ERC20了,可是对于其余几种令牌类型,可能还有一些朋友不知道,因此最近规划了一个系列,就是以太坊标准令牌系列。javascript
目前市面上,凡是基于以太坊的令牌,在交易所上线交易的均是ERC20令牌,那么今天咱们就来聊聊ERC20令牌的标准方案吧。java
在基于以太坊发行令牌时,若是各个令牌发行方都使用自有标准去发行令牌,那对于钱包开发者以及交易所对接成本是极其高昂了,由于他们须要为每一种令牌去独立进行对接,为了下降钱包开发者以及交易所的对接成本,以太坊社区制定了一个关于令牌的发行标准。编程
该标准中主要包含了,令牌的转移,地址余额的获取等方法。app
一个令牌的合约,通常须要令牌的发行量,每一个地址的余额,令牌的转移等方法, 而ERC20标准就是将这些最经常使用又是必不可少的方法,对此进行标准化,方便开发者进行令牌合约的开发,也方便钱包开发者以及交易所对接成本降到最低。函数
其中,定义了三类,方法、属性、事件。post
下面介绍这些标准方法:ui
function totalSupply() constant returns (uint256 totalSupply)
方法
该方法用于获取令牌总发行量spa
function balanceOf(address _owner) constant returns (uint256 balance)
方法
该方法用于获取地址 _owner
的令牌余额日志
function transfer(address _to, uint256 _value) returns (bool success)
方法
该方法用于将调用令牌合约的地址中的_value
个令牌转给_to
地址code
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
方法
该方法用于从_from
地址中发送_value
个令牌给_to
地址。
当你但愿可以使用其余智能合约控制你的令牌转移,则可使用transferFrom
方法,而使用transferFrom
方法有一个前提条件,那就是须要调用者须要获得 _from
地址的受权,才能够进行令牌转移的操做。而如何进行受权,咱们接下来会介绍。
function approve(address _spender, uint256 _value) returns (bool success)
方法
容许 _spender
地址从你的帐户中转移 _value
个令牌到任何地方。
当你设置了一个 _value
以后,_spender
地址能够分任何屡次将令牌进行转移,直至_value
为0.
function allowance(address _owner, address _spender) constant returns (uint256 remaining)
方法
获取 _owner
地址受权给 _spender
地址能够转移的令牌的余额。
事件是EVM内置的日志功能,并且在DAPP中,咱们能够经过JS来监听事件的回调。在ERC-20令牌中,定义了如下事件:
event Transfer(address indexed _from, address indexed _to, uint256 _value)
当进行令牌转移时,须要触发调用该事件。其中记录了令牌发送者_from
,令牌接受者_to
,令牌发送量_value
.
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
当进行受权时,须要触发调用该事件,其中记录了受权者_owner
,被受权者_spender
,受权令牌量_value
经过以上的标准,咱们能够了解到一个遵照ERC20令牌标准的令牌合约须要实现的方法,如下是经过规范实现的一个ERC20令牌的接口。
contract EIP20Interface { ///////////////////////////// 方法 /////////////////////////////////// // 获取令牌发行量 // 注意:constant的修饰符是提示该方法中不能进行变量的修改。 // 但编译器不会强制校验。 // @return uint256 totalSupply 总发行量 function totalSupply() constant returns (uint256 totalSupply) // 获取指定地址 // @param address _owner 想要获取的地址 // @return uint256 balance 令牌余额 function balanceOf(address _owner) public view returns (uint256 balance); // 从`msg.sender`中发送`_value`个令牌给`_to` // @param address _to 接收令牌的地址 // @param uint256 _value 发送的令牌数量 // @return bool success 发送令牌成功状态 function transfer(address _to, uint256 _value) public returns (bool success); // 从`_from`地址发送`_value`令牌到`_to`地址 // 须要知足条件,须要被`_from`地址受权给`msg.sender` // @param address _from 发送者地址 // @param address _to 接收者地址 // @param uint256 _value 发送的令牌数量 // @return bool success 发送令牌成功状态 function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); // `msg.sender`受权`_spender`地址能够任意转移`_value`数量的令牌 // @param address _spender 被受权发送令牌的地址 // @param uint256 _value 受权发送令牌的数量 // @return bool success 受权成功状态 function approve(address _spender, uint256 _value) public returns (bool success); /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent // 获取被受权限额 // @param address _owner 令牌全部者的帐户 // @param address _spender 令牌被受权者帐户 // @return uint256 remaining 剩余可发送的令牌数量 function allowance(address _owner, address _spender) public view returns (uint256 remaining); ///////////////////////////// 事件 /////////////////////////////////// // 令牌转移事件 当发生令牌的转移时,须要调用该事件 event Transfer(address indexed _from, address indexed _to, uint256 _value); // 受权转移事件 当进行受权时,须要触发该事件 event Approval(address indexed _owner, address indexed _spender, uint256 _value); }
在标准的基础上,有不少代码的实现方法,好比有的在代码中实现空投,有的在实现锁定,有的实现挖矿等等,可是最常规的实现已经有了官方的实现代码,也有不少组织实现了一些范例,若是没有定制化的地方,彻底能够直接采用这些代码去建立ERC20令牌。
示例代码:
pragma solidity ^0.4.18; contract ERC20 { // 定义一个mapping 存储各个地址的令牌 mapping (address => uint256) public balances; // 定义一个mapping 存储受权详情 mapping (address => mapping (address => uint256)) public allowed; // 如下参数非必须,可是尽可能添加,大多数钱包会经过此获取相关信息 // 令牌发行总量 uint256 public totalSupply; // 令牌名称,如 OmiseGO string public name; // 支持的小数位数 // 由于在EVM中对浮点数的支持不好,在令牌的建立中直接采用整数 // 而后经过该字段进行小数的处理 uint8 public decimals; // 令牌简称,如 OMG string public symbol; // 令牌合约的构造函数 // 在solidity中,和合约名称一致的方法为构造函数,在第一次建立合约时,仅执行一次。 function ERC20( uint256 _totalSupply, // 令牌建立总量 string _name, // 令牌名称 uint8 _decimals, // 支持小数位数 string _symbol // 令牌简称 ) public { // 给建立者帐户初始化令牌 balances[msg.sender] = _totalSupply; // 设置令牌发行量 totalSupply = _totalSupply; // 设置令牌名称 name = _name; // 设置令牌支持小数位数 decimals = _decimals; // 设置令牌简称 symbol = _symbol; } /** * 获取令牌总发行量 * @return uint256 totalSupply 发行总量 */ function totalSupply() constant returns (uint256 totalSupply) { return totalSupply; } /** * 转移令牌 * @param address _to 令牌接收者地址 * @param uint256 _value 发送令牌数量 * @return bool success 发送成功状态 */ function transfer(address _to, uint256 _value) public returns (bool success) { // 判断发送者余额是否充足 require(balances[msg.sender] >= _value); // 从发送者余额中减去`_value`数量的令牌 balances[msg.sender] -= _value; // 给接收者帐户中添加`_value`数量的令牌 balances[_to] += _value; // 记录令牌转移的事件 Transfer(msg.sender, _to, _value); return true; } /** * 转移令牌(受权) * @param address _from 令牌发送者地址 * @param address _to 令牌接收者地址 * @param uint256 _value 令牌发送数量 * @return bool success 方法执行状态 */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { // 其中`msg.sender`是合约方法调用者的地址 // 获取`_from`地址受权给`msg.sender`地址的可转移令牌余额 uint256 allowance = allowed[_from][msg.sender]; // 判断`_from`地址余额是否充足以及受权转移令牌是否充足 require(balances[_from] >= _value && allowance >= _value); // 从`_from`地址减去`_value`数量的令牌 balances[_from] -= _value; // 从受权余额中减去`_value`数量的令牌 allowed[_from][msg.sender] -= _value; // 给`_to`地址添加`_value`数量的令牌 balances[_to] += _value; // 记录转移令牌的事件 Transfer(_from, _to, _value); return true; } /** * 获取`_owner`地址的令牌余额 * @param address _owner 要获取余额的地址 * @return uint256 balance 返回`_owner`地址的余额 */ function balanceOf(address _owner) public view returns (uint256 balance) { return balances[_owner]; } /** * 受权令牌转移方法 * @param address _spender 被受权地址 * @param uint256 _value 受权可转移的数量 * @return bool success 方法执行状态 */ function approve(address _spender, uint256 _value) public returns (bool success) { // `msg.sender`受权`_spender`地址转移`_value`数量的令牌 allowed[msg.sender][_spender] = _value; // 记录受权事件 Approval(msg.sender, _spender, _value); return true; } /** * 获取被受权的令牌余额 * @param address _owner 受权地址 * @param address _spender 被受权地址 * @return uint256 remaining 可转移的令牌余额 */ function allowance(address _owner, address _spender) public view returns (uint256 remaining) { return allowed[_owner][_spender]; } }
大多数在交易所交易的令牌的合约代码就这么简单,其实每个方法拆分开来都是最简单的编程代码,而核心的处理都被EVM进行了封装,以太坊在令牌发行方面确实极大的解放了人类,简单几十行代码就能够发行一个令牌。ERC20令牌又被成为同质化令牌,就是每一个令牌都是一致的,没法区分,而市场上如今冒出了不少以太猫,以太狗的游戏,而这里面也是使用以太坊的令牌来实现的,可是他们选择的不是ERC20令牌,而是被成为非同质化的令牌,被称为ERC721令牌。
下期,咱们一块儿来聊非同质化令牌ERC721。
喜欢,不要说话,扫我~