9.8 ERC20可置换代币模块
token称为代币或者通证代表各种类型的数字资产,其本质是基于以太坊的智能合约。在ERC20协议出现之前都已经出现了各种各样的数字资产, 但由于各自都有不同的接口使得彼此之间不能互相交换,在DAPP中也以各自不同的实现方式进行工作和交互。ERC20协议为不同的token制定了统一的规范和接口标准,兼容ERC20协议的代币能在不同的DAPP之间以相同的方式进行工作和交互,大大繁荣了以太的生态甚至可以说以太坊平台第一次为大众所知就得益于ERC20标准的制定和推广,并诞生了各种类型的交易所以及他们之间的爱恨情杀故事。
ERC20是一个关于协议规范和接口标准合约,其提供了一系列公共函数和事件定义,只要遵循ERC20协议的代币都会以自己的方式实现规范所要求的接口和函数。由于ERC20协议如此通用zeppelin对ERC20协议提供了直接的模块支持,基于zeppelin库开发ERC20协议兼容的代币就变得相对比较轻松和愉快了。
zeppelin在ERC20协议的标准上扩充了很多有用的基础功能,通过继承这些基础的功能合约会大大提高编程效率和速度,不过也使得其内部依赖和继承关系比较复杂,整个ERC20代币模块依赖图如下:
image.png
由继承依赖图可知整个ERC20代币模块其核心是ERC20Basic合约和ERC20接口合约。其他合约都以这两个合约为基础进行功能扩展,内部的算术运算大量依赖于SafeMath库合约。现在以太坊平台上运行的应用基本一大半都直接或间接与ERC20协议相关,因此该模块也是zeppelin库的特色和核心并在实际编程中有很大的用处。
9.8.1 ERC20Basic、BasicToken
ERC20Basic接口合约是ERC20协议的一个简化版本接口定义,其只包含基础的余额查询、转账以及代币总量查询,接口定义如下:
contract ERC20Basic {
function totalSupply() public view returns (uint256);
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);
}
需要注意的是转账接口定义中的布尔返回值。该返回值对外部账户通过合约接口调用进行转账时没实际意义,但在合约之间交互时该返回值是比较重要的判断依据用于确定是否转账成功。
BasicToken代币合约是ERC20Basic接口合约的一个具体实现,其提供了基本的余额查询、代币转账与总额查询。内部账户及余额的记录是通过映射结构实现的,实现如下:
mapping(address => uint256) balances;
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
核心功能转账其实是不同账户之余额的变动,具体实现思路为对映射结构不同的账户余额进行加减,在进行内部的算术运算时其主要依赖SafeMath函数库合约,核心实现如下:
function transfer(address _to, uint256 _value)
public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
需要注意的是该基础代币合约并不是直接对外提供给用户使用的,而是作为一个基础功能合约为上层合约提供底层通用代币功能支持。直接使用该合约你会发现任何人都不能转账,因为没有接口可以设置初始发行人及其代币总量,而且所有人的余额都是零。
9.8.2 ERC20****与****DetailedERC20
网友评论