0%

eth | ERC 20

这里讲一下什么是 ERC20。并且在 Ropsten 发布自己的币。


参考资料



ERC20 Token


ERC20 是一个协议,遵循这种协议的代币,我们称之为 ERC20

其接口如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

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 transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, 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);
}

简单说明一下:

  • name : 代币名称
  • symbol: 代币符号
  • decimals: 代币小数点位数,代币的最小单位, 18表示我们可以拥有 .0000000000000000001单位个代币。
  • totalSupply() : 发行代币总量。
  • balanceOf(): 查看对应账号的代币余额。
  • transfer(): 实现代币转账交易,用于给用户发送代币(从我们的账户里)。
  • transferFrom(): 给被授权的用户使用,他可以从我们(参数 from)的账户里发送代币给其他用户(参数 to)。
  • allowance(): 返回授权花费的代币数。
  • approve(): 授权用户可代表我们花费的代币数。

另外,openzeppelin 可以参考openzeppelin

然后我们写一份合约。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
pragma solidity ^0.4.16;

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

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);

/**
* 初始化构造
*/
function TokenERC20(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;
Transfer(_from, _to, _value);

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

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

/**
* 账号之间代币交易转移
* @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
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
Burn(_from, _value);
return true;
}
}

使用 remix 部署 Ropsten 合约

我们首先新建一个 test.sol 文件,然后把上面的合约内容复制进去。

然后进行编译该合约。

如果编译通过,会在左侧的图标上有绿色的对号。

在部署之前,首先用 metamask 连接这个网站,然后按照下图进行部署

这样我们就能创建一个 erc20 的代币了。

请我喝杯咖啡吧~