ERC-20

ERC20是以太坊上的一种代币,它定义了一组接口(方法和事件),使得代币可以在不同的应用程序,钱包和交易所之间进行互操作。

原生币和代币

原生币(ETH)是以太坊区块链的原生加密货币。它直接由区块链协议生成和管理。主要用于支付网络上的交易费用(Gas)以及奖励矿工(现在是验证者)。原生币的交易是直接在区块链上进行的,不需要任何智能合约。以太币的交易地址是由以太坊协议生成的。

代币(例如ERC20)是通过智能合约创建和管理的加密货币。它们不是区块链的原生币,而是构建在区块链之上的。可以代表各种资产或功能,如稳定币、权益证明、治理代币等。ERC20 代币遵循以太坊改进提案 20(EIP-20)的标准,实现了一组基本的接口和功能,使其能够在去中心化应用(DApps)之间互操作。ERC20 代币的合约地址是由智能合约生成的。

ERC-20标准

标准规定:6个函数,2个事件,3个变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
contract ERC20Interface {
function totalSupply() public view returns (uint256);
function balanceOf(address _owner) public view returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) public view returns (uint256 remaining);


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

string public constant name = "";
string public constant symbol = "";
uint8 public constant decimals = ;
}

解释

1
totalSupply()

返回代币的总量

1
balanceOf()

查询某个账户的代币余额

1
transfer()

从当前的自己账户,实现代币的交易

1
transferFrom()

实现用户之间的代币交易(非自己账户)

1
approve()

设置允许某个账户spender从此地址可使用的代币数

1
allowance()

查询某个账户可转账金额,用于控制代币的交易

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

当代币被交易时会触发此函数

1
event Approval(address indexed tokenOwner, address indexed spender, uint tokens)

当成功调用approve函数时会触发此函数

name

代币名称

symbol

代币简称

decimals

返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示。一般为18位。

变量及函数定义

定义变量

一般会定义几个映射变量

mapping (address => uint256) public balances

保存着每个地址对应的余额。

mapping (address => mapping (address => uint256)) public allowed

两层映射。保存着某个地址A允许另一个地址B可操作的金额。最外层映射为某个地址A,内层映射为另一个地址B,值为可操作(发起交易)金额总量。

函数实现

1
2
3
function balanceOf(address tokenOwner) public constant returns (uint balance) {
return balances[tokenOwner];
}

从映射变量balances中取出某个地址的余额。

1
2
3
4
5
6
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = balances[msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
Transfer(msg.sender, to, tokens);
return true;
}

当前账户转账操作

1
2
3
4
5
6
7
function transferFrom(address from, address to, uint tokens) public returns (bool success){
balances[from] = balances[from].sub(tokens);
allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
Transfer(from, to, tokens);
return true;
}

用户之间转账操作,由from地址发起转账交易。

1
2
3
4
5
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
Approval(msg.sender, spender, tokens);
return true;
}

设置某账户spender可操控msg.sender的代币数

ERC20高级功能

高级功能:代币管理,代币增发,空投代币,代币冻结,销毁代币,代币兑换

代币管理

有时代币需要有一个管理者功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
contract Owned {
address public owner;

constructor() public {
owner = msg.sender;
}

modifier onlyOwner {
require(msg.sender == owner);
_;
}

function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}

如果是 owner 调用这个函数,则函数会被执行,否则会抛出异常。

代币增发

代币增发可使代币总供应量增加,可以指定某个账户的代币增加,同时总供应量也随之增加。

1
2
3
4
5
6
function mintToken(address target, uint256 mintedAmount) onlyOwner public {
balances[target] += mintedAmount;
_totalSupply += mintedAmount;
emit Transfer(address(0), address(this), mintedAmount);
emit Transfer(address(this), target, mintedAmount);
}

代币销毁

管理者代币销毁

1
2
3
4
5
6
7
function burn(uint256 _value) onlyOwner public returns (bool success) {
require(balances[owner] >= _value);
balances[owner] -= _value;
_totalSupply -= _value;
emit Burn(owner, _value);
return true;
}

用户代币销毁

1
2
3
4
5
6
7
8
9
function burnFrom(address _from, uint256 _value) onlyOwner public returns (bool success) {
require(balances[_from] >= _value);
require(_value <= allowed[_from][owner]);
balances[_from] -= _value;
allowed[_from][owner] -= _value;
_totalSupply -= _value;
emit Burn(_from, _value);
return true;
}