以太坊发token教程
2017年出现了非常多的数字货币。但是这种货币是如何产生的,作为一个程序员。怀着对发币的好奇,自己动手把发币的流程给走了一遍。再此记录下。这里发币特指ERC20 token。
在发Token前,你先的确定一下几点:
- Token的名称
- Token的标识
- Token的小数位
- Token发型量
我的选择是:
- 名称:MyFreeCoin
- 标识:MFC
- 小数位: 18
- 发行量: 10000
小数位是18位,表示MFC这个Token最小可以到 .0000000000000000001。
编写 MFC的智能合约:
Token的合约代码我们参考Token-Factory的代码。
pragma solidity ^0.4.4;
contract Token {
/// @return 返回token的发行量
function totalSupply() constant returns (uint256 supply) {}
/// @param _owner 查询以太坊地址token余额
/// @return The balance 返回余额
function balanceOf(address _owner) constant returns (uint256 balance) {}
/// @notice msg.sender(交易发送者)发送 _value(一定数量)的 token 到 _to(接受者)
/// @param _to 接收者的地址
/// @param _value 发送token的数量
/// @return 是否成功
function transfer(address _to, uint256 _value) returns (bool success) {}
/// @notice 发送者 发送 _value(一定数量)的 token 到 _to(接受者)
/// @param _from 发送者的地址
/// @param _to 接收者的地址
/// @param _value 发送的数量
/// @return 是否成功
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
/// @notice 发行方 批准 一个地址发送一定数量的token
/// @param _spender 需要发送token的地址
/// @param _value 发送token的数量
/// @return 是否成功
function approve(address _spender, uint256 _value) returns (bool success) {}
/// @param _owner 拥有token的地址
/// @param _spender 可以发送token的地址
/// @return 还允许发送的token的数量
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
/// 发送Token事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/// 批准事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
/*
This implements ONLY the standard functions and NOTHING else.
For a token like you would want to deploy in something like Mist, see HumanStandardToken.sol.
If you deploy this, you won't have anything useful.
Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20
实现ERC20标准
.*/
pragma solidity ^0.4.4;
import "./Token.sol";
contract StandardToken is Token {
function transfer(address _to, uint256 _value) returns (bool success) {
//默认token发行量不能超过(2^256 - 1)
//如果你不设置发行量,并且随着时间的发型更多的token,需要确保没有超过最大值,使用下面的 if 语句
//if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
} else { return false; }
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
//向上面的方法一样,如果你想确保发行量不超过最大值
//if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
return true;
} else { return false; }
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 public totalSupply;
}
/*
This Token Contract implements the standard token functionality (https://github.com/ethereum/EIPs/issues/20) as well as the following OPTIONAL extras intended for use by humans.
In other words. This is intended for deployment in something like a Token Factory or Mist wallet, and then used by humans.
Imagine coins, currencies, shares, voting weight, etc.
Machine-based, rapid creation of many tokens would not necessarily need these extra features or will be minted in other manners.
1) Initial Finite Supply (upon creation one specifies how much is minted).
2) In the absence of a token registry: Optional Decimal, Symbol & Name.
3) Optional approveAndCall() functionality to notify a contract if an approval() has occurred.
.*/
pragma solidity ^0.4.4;
import "./StandardToken.sol";
contract MyFreeCoin is StandardToken {
function () {
//if ether is sent to this address, send it back.
throw;
}
/* Public variables of the token */
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; //token名称: MyFreeCoin
uint8 public decimals; //小数位
string public symbol; //标识
string public version = 'H0.1'; //版本号
function MyFreeCoin(
uint256 _initialAmount,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol
) {
balances[msg.sender] = _initialAmount; // 合约发布者的余额是发行数量
totalSupply = _initialAmount; // 发行量
name = _tokenName; // token名称
decimals = _decimalUnits; // token小数位
symbol = _tokenSymbol; // token标识
}
/* 批准然后调用接收合约 */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
//调用你想要通知合约的 receiveApprovalcall 方法 ,这个方法是可以不需要包含在这个合约里的。
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//假设这么做是可以成功,不然应该调用vanilla approve。
if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
return true;
}
}
如果想要发行自己的token,只需要把 MyFreeCoin
出现的地方替换为你的token名称。
需要注意的一点是,你发行的数量需要相对token小数点来设置。例如如果token的小数点是0,而你要发行1000个token,那么发行数量的值1000。但是如果token的小数点是18位,你要发行1000个token,那么发行数量的值是1000000000000000000000(1000后面加上18个0)。
balances[msg.sender] = _initialAmount;
这行代码,我们把合约的发布者的余额设置为发行量的数量。
在测试网络上发行我们的token:
- 安装MetaMask钱包。
-
安装MetaMask之后,登陆Metamask, 左上角选择Ropsten。如下图:
1.jpg
这个账号将会是我们的智能合约的所有者,也就是说token发行数量都是存入到这个账号。
-
打开Solidity Remix Compiler ,remix 是一个在线编译器可以帮我们把智能合约直接发布到以太坊上。
-
把上面三个文件代码复制到remix编辑器中。可以先删除remix中默认ballot.sol 文件,在新建 Token.sol , StandardToken.sol, MyFreeCoin.sol 三个文件, 相应的把代码复制到文件中,如下图:
2.jpg -
点击
start to compile
编译代码文件。 -
给我们的测试账号申请点 eth来测试,如下图点击 buy按钮,再点击
3.jpgropsten test faucet
。
4.jpg -
会打开 faucet metamask 网站,点击
5.jpg
request 1 eth from faucet
。成功后会生成 交易记录。
6.jpg -
可以查看到我们的测试账户上已经有了eth可以用了。
7.jpg -
选中remix中的run 菜单,下拉框中选择MyFreeCoin, 在create按钮的左边输入框中输入
8.jpg"10000000000000000000000","MyFreeCoin",18,"MFC"
, 如下图
-
点击create 按钮,需要注意的是发行量需要包含在 "" 中。 metamask会弹出确认框。如下图:
9.jpg -
确定后,会进入挂起状态,等待旷工打包。
-
等一段时间后,交易完成,会显示MyFreeCoin 合约。
10.jpg -
点击MyFreeCoin 的复制按钮,复制合约地址在 ropsten etherscan中查询,可以查询到我们的合约情况,如下图:
11.jpg
-
验证我们发布的token。在metamask的token中点击 add token 按钮。如下图:
12.jpg -
在add token 的地址填入我们刚才复制的合约地址,如下图:
13.jpg -
可以在token中看到我们新创建的token。如下图:
14.jpg -
认证我们的合约代码。 在刚才ropsten ethscan 的合约地址页面中,点击Contract code, 如下图:
15.jpg -
点击Verify and Publish, 会进入如下页面:
16.jpg
- 在
Contract name:
的输入框输入token 名称MyFreeCoin, Compiler 选择在remix的sttings 中Solidity version 显示的版本号。Optimization 选择 No。 然后在Enter the Solidity Contract Code below 下面的输入框中填入代码,我们的代码有三个文件,需要把它们合并成一个文件,合并的格式是这样:
pragma solidity ^0.4.4;
contract Token {
}
contract StandardToken is Token {
}
contract MyFreeCoin is StandardToken {
}
去掉原来代码文件中的 import语句。最后提交。成功后,会显示下面的页面表示验证成功:
17.jpg
最后让我们在不同地址之间流通这个token。我们第一个账户已经有1000的MFC了。
先让我们在创建一个新的账户,如下图:
18.jpg
可以看到我们新创建的账户 MFC的值是0.
19.jpg
在切回我们的第一个账户,在transfer 中填入第二账户的地址和转入的数量("0xe4da4CBC744708A6656BeD252f49DF5exxxxxxC97","1000000000000000000")。如下图:
20.jpg
点击transfer 会弹出弹框让你确定,点击sumbit,等待区块打包。切换到第二个账户,查看MFC余额。可以看到已经到转过来的1MFC了。
21.jpg
最终我们的发token的流程已经结束了。但是这还只是第一步,后面我们还需要程序化的执行token的充币,提币操作。也是一个应用若想引入token进来必须要有的功能。后面我会继续研究下去,实现用程序来操作token的转让。