2017年出現(xiàn)了非常多的數(shù)字貨幣匆篓。但是這種貨幣是如何產(chǎn)生的,作為一個(gè)程序員胖秒。懷著對(duì)發(fā)幣的好奇缎患,自己動(dòng)手把發(fā)幣的流程給走了一遍。再此記錄下阎肝。這里發(fā)幣特指ERC20 token挤渔。
在發(fā)Token前,你先的確定一下幾點(diǎn):
- Token的名稱
- Token的標(biāo)識(shí)
- Token的小數(shù)位
- Token發(fā)型量
我的選擇是:
- 名稱:MyFreeCoin
- 標(biāo)識(shí):MFC
- 小數(shù)位: 18
- 發(fā)行量: 10000
小數(shù)位是18位盗痒,表示MFC這個(gè)Token最小可以到 .0000000000000000001。
編寫 MFC的智能合約:
Token的合約代碼我們參考Token-Factory的代碼。
pragma solidity ^0.4.4;
contract Token {
/// @return 返回token的發(fā)行量
function totalSupply() constant returns (uint256 supply) {}
/// @param _owner 查詢以太坊地址token余額
/// @return The balance 返回余額
function balanceOf(address _owner) constant returns (uint256 balance) {}
/// @notice msg.sender(交易發(fā)送者)發(fā)送 _value(一定數(shù)量)的 token 到 _to(接受者)
/// @param _to 接收者的地址
/// @param _value 發(fā)送token的數(shù)量
/// @return 是否成功
function transfer(address _to, uint256 _value) returns (bool success) {}
/// @notice 發(fā)送者 發(fā)送 _value(一定數(shù)量)的 token 到 _to(接受者)
/// @param _from 發(fā)送者的地址
/// @param _to 接收者的地址
/// @param _value 發(fā)送的數(shù)量
/// @return 是否成功
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
/// @notice 發(fā)行方 批準(zhǔn) 一個(gè)地址發(fā)送一定數(shù)量的token
/// @param _spender 需要發(fā)送token的地址
/// @param _value 發(fā)送token的數(shù)量
/// @return 是否成功
function approve(address _spender, uint256 _value) returns (bool success) {}
/// @param _owner 擁有token的地址
/// @param _spender 可以發(fā)送token的地址
/// @return 還允許發(fā)送的token的數(shù)量
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
/// 發(fā)送Token事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
/// 批準(zhǔn)事件
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
實(shí)現(xiàn)ERC20標(biāo)準(zhǔn)
.*/
pragma solidity ^0.4.4;
import "./Token.sol";
contract StandardToken is Token {
function transfer(address _to, uint256 _value) returns (bool success) {
//默認(rèn)token發(fā)行量不能超過(2^256 - 1)
//如果你不設(shè)置發(fā)行量俯邓,并且隨著時(shí)間的發(fā)型更多的token骡楼,需要確保沒有超過最大值,使用下面的 if 語(yǔ)句
//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) {
//向上面的方法一樣稽鞭,如果你想確保發(fā)行量不超過最大值
//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; //小數(shù)位
string public symbol; //標(biāo)識(shí)
string public version = 'H0.1'; //版本號(hào)
function MyFreeCoin(
uint256 _initialAmount,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol
) {
balances[msg.sender] = _initialAmount; // 合約發(fā)布者的余額是發(fā)行數(shù)量
totalSupply = _initialAmount; // 發(fā)行量
name = _tokenName; // token名稱
decimals = _decimalUnits; // token小數(shù)位
symbol = _tokenSymbol; // token標(biāo)識(shí)
}
/* 批準(zhǔn)然后調(diào)用接收合約 */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
//調(diào)用你想要通知合約的 receiveApprovalcall 方法 鸟整,這個(gè)方法是可以不需要包含在這個(gè)合約里的。
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//假設(shè)這么做是可以成功朦蕴,不然應(yīng)該調(diào)用vanilla approve篮条。
if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
return true;
}
}
如果想要發(fā)行自己的token,只需要把 MyFreeCoin
出現(xiàn)的地方替換為你的token名稱吩抓。
需要注意的一點(diǎn)是涉茧,你發(fā)行的數(shù)量需要相對(duì)token小數(shù)點(diǎn)來(lái)設(shè)置。例如如果token的小數(shù)點(diǎn)是0疹娶,而你要發(fā)行1000個(gè)token伴栓,那么發(fā)行數(shù)量的值1000。但是如果token的小數(shù)點(diǎn)是18位雨饺,你要發(fā)行1000個(gè)token钳垮,那么發(fā)行數(shù)量的值是1000000000000000000000(1000后面加上18個(gè)0)。
balances[msg.sender] = _initialAmount;
這行代碼额港,我們把合約的發(fā)布者的余額設(shè)置為發(fā)行量的數(shù)量饺窿。
在測(cè)試網(wǎng)絡(luò)上發(fā)行我們的token:
- 安裝MetaMask錢包。
-
安裝MetaMask之后移斩,登陸Metamask肚医, 左上角選擇Ropsten。如下圖:
這個(gè)賬號(hào)將會(huì)是我們的智能合約的所有者叹哭,也就是說token發(fā)行數(shù)量都是存入到這個(gè)賬號(hào)忍宋。
打開Solidity Remix Compiler ,remix 是一個(gè)在線編譯器可以幫我們把智能合約直接發(fā)布到以太坊上。
-
把上面三個(gè)文件代碼復(fù)制到remix編輯器中风罩】放牛可以先刪除remix中默認(rèn)ballot.sol 文件,在新建 Token.sol , StandardToken.sol, MyFreeCoin.sol 三個(gè)文件超升, 相應(yīng)的把代碼復(fù)制到文件中入宦,如下圖:
點(diǎn)擊
start to compile
編譯代碼文件。-
給我們的測(cè)試賬號(hào)申請(qǐng)點(diǎn) eth來(lái)測(cè)試室琢,如下圖點(diǎn)擊 buy按鈕痒给,再點(diǎn)擊
ropsten test faucet
。
-
會(huì)打開 faucet metamask 網(wǎng)站戚篙,點(diǎn)擊
request 1 eth from faucet
撒汉。成功后會(huì)生成 交易記錄轿钠。
-
可以查看到我們的測(cè)試賬戶上已經(jīng)有了eth可以用了。
-
選中remix中的run 菜單病苗,下拉框中選擇MyFreeCoin, 在create按鈕的左邊輸入框中輸入
"10000000000000000000000","MyFreeCoin",18,"MFC"
, 如下圖
-
點(diǎn)擊create 按鈕疗垛,需要注意的是發(fā)行量需要包含在 "" 中。 metamask會(huì)彈出確認(rèn)框硫朦。如下圖:
確定后贷腕,會(huì)進(jìn)入掛起狀態(tài),等待曠工打包咬展。
-
等一段時(shí)間后泽裳,交易完成,會(huì)顯示MyFreeCoin 合約破婆。
-
點(diǎn)擊MyFreeCoin 的復(fù)制按鈕涮总,復(fù)制合約地址在 ropsten etherscan中查詢,可以查詢到我們的合約情況荠割,如下圖:
-
驗(yàn)證我們發(fā)布的token妹卿。在metamask的token中點(diǎn)擊 add token 按鈕。如下圖:
-
在add token 的地址填入我們剛才復(fù)制的合約地址蔑鹦,如下圖:
-
可以在token中看到我們新創(chuàng)建的token夺克。如下圖:
-
認(rèn)證我們的合約代碼。 在剛才ropsten ethscan 的合約地址頁(yè)面中嚎朽,點(diǎn)擊Contract code铺纽, 如下圖:
-
點(diǎn)擊Verify and Publish, 會(huì)進(jìn)入如下頁(yè)面:
- 在
Contract name:
的輸入框輸入token 名稱MyFreeCoin, Compiler 選擇在remix的sttings 中Solidity version 顯示的版本號(hào)哟忍。Optimization 選擇 No狡门。 然后在Enter the Solidity Contract Code below 下面的輸入框中填入代碼,我們的代碼有三個(gè)文件锅很,需要把它們合并成一個(gè)文件其馏,合并的格式是這樣:
pragma solidity ^0.4.4;
contract Token {
}
contract StandardToken is Token {
}
contract MyFreeCoin is StandardToken {
}
去掉原來(lái)代碼文件中的 import語(yǔ)句。最后提交爆安。成功后叛复,會(huì)顯示下面的頁(yè)面表示驗(yàn)證成功:
最后讓我們?cè)诓煌刂分g流通這個(gè)token。我們第一個(gè)賬戶已經(jīng)有1000的MFC了扔仓。
先讓我們?cè)趧?chuàng)建一個(gè)新的賬戶褐奥,如下圖:
可以看到我們新創(chuàng)建的賬戶 MFC的值是0.
在切回我們的第一個(gè)賬戶,在transfer 中填入第二賬戶的地址和轉(zhuǎn)入的數(shù)量("0xe4da4CBC744708A6656BeD252f49DF5exxxxxxC97","1000000000000000000")翘簇。如下圖:
點(diǎn)擊transfer 會(huì)彈出彈框讓你確定撬码,點(diǎn)擊sumbit,等待區(qū)塊打包版保。切換到第二個(gè)賬戶呜笑,查看MFC余額夫否。可以看到已經(jīng)到轉(zhuǎn)過來(lái)的1MFC了叫胁。
最終我們的發(fā)token的流程已經(jīng)結(jié)束了慷吊。但是這還只是第一步,后面我們還需要程序化的執(zhí)行token的充幣曹抬,提幣操作。也是一個(gè)應(yīng)用若想引入token進(jìn)來(lái)必須要有的功能急鳄。后面我會(huì)繼續(xù)研究下去谤民,實(shí)現(xiàn)用程序來(lái)操作token的轉(zhuǎn)讓。