ERC20是以太坊網(wǎng)絡(luò)上發(fā)行代幣(Token)的一個標準協(xié)議接口亲茅,協(xié)議的github具體描述位于https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md锐朴。一個標準的協(xié)議促使了代幣可以在不同的應(yīng)用中得到使用晓猛,如錢包和去中心化交易所骂际。目前有很多實現(xiàn)該標準協(xié)議的Token Examples,我們將使用https://github.com/ConsenSys/Tokens提供的例子進行演示操作掂咒。我們先來看下這個實現(xiàn)庫中的主要合約文件:
ERC20 Token協(xié)議實現(xiàn)
- Token.sol ERC 20協(xié)議的抽象定義
//Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20
pragma solidity ^0.4.8;
contract Token {
/// token總量洪鸭,默認會為public變量生成一個getter函數(shù)接口奇颠,名稱為totalSupply().
uint256 public totalSupply;
/// 獲取賬戶_owner擁有token的數(shù)量
function balanceOf(address _owner) constant returns (uint256 balance);
//從消息發(fā)送者賬戶中往_to賬戶轉(zhuǎn)數(shù)量為_value的token
function transfer(address _to, uint256 _value) returns (bool success);
//從賬戶_from中往賬戶_to轉(zhuǎn)數(shù)量為_value的token民珍,與approve方法配合使用
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
//消息發(fā)送賬戶設(shè)置賬戶_spender能從發(fā)送賬戶中轉(zhuǎn)出數(shù)量為_value的token
function approve(address _spender, uint256 _value) returns (bool success);
//獲取賬戶_spender可以從賬戶_owner中轉(zhuǎn)出token的數(shù)量
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
//發(fā)生轉(zhuǎn)賬時必須要觸發(fā)的事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
//當函數(shù)approve(address _spender, uint256 _value)成功執(zhí)行時必須觸發(fā)的事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
- StandardToken.sol ERC20協(xié)議的標準實現(xiàn)
/*You should inherit from StandardToken or, for a token like you would want to
deploy in something like Mist, see DAToken.sol.
(This implements ONLY the standard functions and NOTHING else.
If you deploy this, you won't have anything useful.)
Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20.*/
pragma solidity ^0.4.8;
import "./Token.sol";
contract StandardToken is Token {
function transfer(address _to, uint256 _value) returns (bool success) {
//默認totalSupply 不會超過最大值 (2^256 - 1).
//如果隨著時間的推移將會有新的token生成零蓉,則可以用下面這句避免溢出的異常
//require(balances[msg.sender] >= _value && balances[_to] + _value >balances[_to]);
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;//從消息發(fā)送者賬戶中減去token數(shù)量_value
balances[_to] += _value;//往接收賬戶增加token數(shù)量_value
Transfer(msg.sender, _to, _value);//觸發(fā)轉(zhuǎn)幣交易事件
return true;
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
//require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]);
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
balances[_to] += _value;//接收賬戶增加token數(shù)量_value
balances[_from] -= _value; ;//支出賬戶_from減去token數(shù)量_value
allowed[_from][msg.sender] -= _value;//消息發(fā)送者可以從賬戶_from中轉(zhuǎn)出的數(shù)量減少_value
Transfer(_from, _to, _value);//觸發(fā)轉(zhuǎn)幣交易事件
return true;
}
//查詢余額
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
//授權(quán)賬戶_spender可以從消息發(fā)送者賬戶轉(zhuǎn)出數(shù)量為_value的token
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];//允許_spender從_owner中轉(zhuǎn)出的token數(shù)
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
}
- DAToken.sol 具體的token實現(xiàn)
import "./StandardToken.sol";
pragma solidity ^0.4.8;
contract DAToken is StandardToken {
/* Public variables of the token */
string public name; //名稱: eg Davie
uint8 public decimals; //最多的小數(shù)位數(shù)How many decimals to show. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
string public symbol; //token簡稱: eg DAC
string public version = 'H0.1'; //版本
function DAToken(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) {
balances[msg.sender] = _initialAmount; // 初始token數(shù)量給予消息發(fā)送者
totalSupply = _initialAmount; // 設(shè)置初始總量
name = _tokenName; // token名稱
decimals = _decimalUnits; // 小數(shù)位數(shù)
symbol = _tokenSymbol; // token簡稱
}
/* 同意轉(zhuǎn)出并調(diào)用接收合約(根據(jù)自己需求實現(xiàn)) */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
require(_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
return true;
}
}
Token合約發(fā)布
我們將使用MetaMask和Remix(https://ethereum.github.io/browser-solidity)并選擇在Ropsten測試網(wǎng)絡(luò)進行Token合約發(fā)布。
- 切換MetaMask至Ropsten網(wǎng)絡(luò)
2.將所有相關(guān)代碼copy至Remix
或者從這里拷貝https://ropsten.etherscan.io/address/0xaa86b7bc852907e5649c958411465e878c954b67#code
在右側(cè)上方紅框標記處Environment選擇Injected Web3, 下方的Account列表將會列出MetaMask中的賬戶信息穷缤。然后在右側(cè)下方紅框中依次填入初始化DAToken需要的參數(shù),初始token數(shù)量(100000000)箩兽、token的名稱描述(My Test Token)津肛、decimal數(shù)(8)、token簡稱(MTT)汗贫。
- Token合約發(fā)布
“Create”中填入創(chuàng)建的Token參數(shù)身坐,
第一個參數(shù)是Token的數(shù)量;
第二個參數(shù)是Token的全稱落包;
第三個參數(shù)是Token的精度部蛇,即Token最小為小數(shù)點后幾位;
第四個參數(shù)是Token的符號咐蝇;
例如:100000000,"zhongxh's test token",8,"ZTT"
上述例子代表創(chuàng)建的Token的全稱是"zhongxh's test token"涯鲁,符號是“ZTT”, ZTT的最大精度為小數(shù)點后8位有序,即最小是0.000000001ZTT抹腿,總共有1億份,那么總共有100000000 * 10^(-8)ZTT旭寿,即1ZTT
點擊合約DAToken處的create按鈕警绩,將彈出如下畫面:
點擊SUBMIT將該交易請求發(fā)布至Rosten網(wǎng)絡(luò)中,交易變成功打包后盅称〖缦椋可以查詢到本次操作的交易id為0x1aabf45bed257dd7521215f21744d0ad64b4275436bc2c8148fb44c2489efb84后室, 合約地址為0xaa86b7bc852907e5649c958411465e878c954b67,交易截圖如下:
4.合約源代碼上傳
接下來我們看下如何在https://ropsten.etherscan.io上傳合約的源代碼混狠,首先打開合約0xaa86b7bc852907e5649c958411465e878c954b67的詳情頁岸霹,并切換至Contrant Code標簽中,如下圖檀蹋。
在Contract code 標簽頁中點擊“Verify And Publish”鏈接松申,然后填入下圖紅框各項內(nèi)容。
- Contract address為上面創(chuàng)建的合約地址俯逾;
- Contract name為在Remix中選擇創(chuàng)建的合約名稱DAToken贸桶;
- Compiler版本需選擇在Remix進行合約創(chuàng)建時選擇的編譯器版本一致;
- 是否優(yōu)化Optimization也需要與Remix發(fā)布合約時保持一致桌肴;
- 在“Enter the Solidity Contract Code below”中填入之前在Remix中的solidity合約代碼皇筛;
- 在“Constructor Arguments ABI-encoded”中填入構(gòu)造函數(shù)參數(shù)(100000000,“My Test Token”,8,“MTT”)的ABI編碼,這個會自動填好坠七。
填好上述數(shù)據(jù)后水醋,點擊Verify and Publish,如果驗證通過了就會出現(xiàn)如下頁面:
最后我們切換到合約的詳情頁彪置,點擊Contract Source標簽拄踪,就能看到上傳的合約源代碼了,如下圖:
如果遇到錯誤"Unable to Verify Contract at this point time"拳魁,請確認在提交合約源代碼時惶桐,選擇的編譯器版本與是否優(yōu)化選項,與你在Remix中的選擇是否一致潘懊。
- 添加發(fā)布的Token到錢包
我們可以在MetaMask中添加上面生成的Token至MetaMask錢包中姚糊,如下圖。
填入Token地址
點擊Add后可以在Tokens標簽頁中看到上面發(fā)布的Token MTT. (因為我們在創(chuàng)建DAToken時授舟,輸入的初始量為1000000救恨,而decimal值為8,這個初始量值的單位是token的最低單位释树,故總量為0.01MTT肠槽,大家可以根據(jù)自己的情況作出相應(yīng)調(diào)整。)
接下來就可以在Ropsten測試網(wǎng)絡(luò)上進行Token的轉(zhuǎn)賬以及相關(guān)的測試操作了奢啥,如果測試沒問題就按照同樣的流程把合約部署至以太坊主網(wǎng)絡(luò)中發(fā)行真實的token了署浩。
因為Metamask不支持toekn的發(fā)送,我們切換到MyEtherWallet錢包扫尺。
需要注意的是筋栋,MyEtherWallet也需要切換到Rostpen網(wǎng)絡(luò)
接下來切換到“發(fā)送以太幣/發(fā)送代幣”
在這里我選擇用私鑰的方式解鎖錢包,私鑰可以從Metamask獲得
點擊Metamask右上角的“...”正驻,然后點擊"Export Private Key "弊攘,輸入密碼抢腐,即可獲得私鑰
將私鑰拷到MyEtherWallet,就可以解鎖你的錢包了襟交。
點擊右下角的“Load Token Balance”
右下角顯示的正是剛剛創(chuàng)建的Token迈倍,也就是ZTT,余額為1捣域,這表明我的ERC20 Token發(fā)布成功了啼染!
給另一個賬戶轉(zhuǎn)token
獲取第二個賬戶地址
切換到account2
復(fù)制賬戶地址
填入轉(zhuǎn)賬地址和金額,token
注意這里選擇我們剛才發(fā)布的LOVE token
點擊生成交易焕梅,然后發(fā)送交易迹鹅。
稍后回到Metamask查看
可以看到賬戶 account2收到了 100個LOVE