简单来说,可以把ERC-20理解成在以太坊上发布Token合约的规范,规范的好处就是可以带来更好的兼容性,遵守规范的代币可以认为是标准化的代币。
ERC-20标准接口代码
pragma solidity ^0.5.10;
contract ERC20Interface{
string public name; // 代币的名字
string public symbol; // 代笔的符号,例如BTC、ETH、EOS
uint8 public decimals; // 支持小数点后几位
uint256 public totalSupply; // 总发行量
// 调用transfer函数将自己的token转账给_to地址,_value是转账数
function transfer(address _to, uint256 _value) public returns (bool success);
// 与approve搭配使用,approve批准后,调用teansferFrom函数来转移Token
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
// 批准_spender账户从自己的账户转移_value个token,可分多次转移
function approve(address _spender, uint256 _value) public returns (bool success);
// 返回_spender还能提取的token数
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
// 账户A有1000个ETH,想允许B账户随意调用100个ETH。A账户按照以下形式调用approve函数approve(B,100)。
// 当B账户想用这100个ETH中的10个ETH给C账户时,则调用transferFrom(A, C, 10)。
// 这时调用allowance(A, B)可以查看B账户还能够调用A账户多少个token。
// 成功转移token时,一定要触发Transfer事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// 当调用approval函数成功时,一定要触发Approval事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
传送门:
深入理解Token和ERC-20
ERC-20标准
接下来我们就根据ERC-20标准编写一个Token合约吧!
编写符合ERC-20标准的Token合约
pragma solidity ^0.5.10;
import './ERC20Interface.sol'; // 引用接口文件
contract ERC20 is ERC20Interface{
mapping (address => uint256) public balanceOf; // 定义每一个地址对应的余额
mapping (address => mapping (address => uint256)) internal allowed; // 代理授权 owner => 授权人 => 额度
// 状态变量初始化
constructor() public{
totalSupply = 1000; // 总发行量
name = 'JueJin Token'; //代币名称
symbol = 'JJT'; // 代币简称,如BTC、ETH、EOS
decimals = 0; // 最小交易数额,返回token使用的小数点后几位。 如设置为3,就是支持0.001表示
balanceOf[msg.sender] = totalSupply; // 初始发行量属于合约拥有者
}
// 返回账号的余额
function balance(address _owner) public view returns(uint256){
return balanceOf[_owner];
}
function transfer(address _to, uint _value) public returns(bool success){
require(_to != address(0));
require(balanceOf[msg.sender] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]); // 判断目标账户金额是否大于存储上线,避免溢出
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint _value) public returns(bool success){
require(_to != address(0));
require(balanceOf[_from] >= _value);
require(allowed[_from][msg.sender] >= _value); // 判断是否具有足够授权的额度
require(balanceOf[_to] + _value >= balanceOf[_to]); // 判断目标账户金额是否大于存储上线,避免溢出
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
// _sepnder: 授权人 _value: 授权额度
function approve(address _spender, uint256 _value) public returns(bool success){
allowed[msg.sender][_spender] += _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns(uint256){
return allowed[_owner][_spender];
}
}