鏈聞 ChainNews:

本文不僅使我們瞭解以太坊、代幣、ERC20、智能合約等以太坊代幣開發中的基本概念,更是從代碼設計實現的角度根據以太坊 ERC20 標準實現了代幣的開發,讓我們輕鬆明白代幣的開發過程,輕鬆發行自己的以太坊代幣。

來源:ragames 的博客
作者:ragames

以太坊 ERC20 代幣開發首先需要對以太坊 , 代幣 ,ERC20, 智能合約等以太坊代幣開發中的基本概念有了解。根據我們的示例代碼就可以發行自己的以太坊代幣。

什麼是 ERC20

可以把 ERC20 簡單理解成以太坊上的一個代幣協議,所有基於以太坊開發的代幣合約都遵守這個協議。遵守這些協議的代幣我們可以認爲是標準化的代幣,而標準化帶來的好處是兼容性好。這些標準化的代幣可以被各種以太坊錢包支持,用於不同的平臺和項目。說白了,你要是想在以太坊上發行代幣融資,必須要遵守 ERC20 標準。
ERC20 的標準接口是這樣的 :
contract ERC20 {
function name() constant returns (string name)
function symbol() constant returns (string symbol)
function decimals() constant returns (uint8 decimals)
function totalSupply() constant returns (uint totalSupply);
function balanceOf(address_owner) constant returns (uint balance);
function transfer(address_to\\, uint_value) returns (bool success);
function transferFrom(address_from\\, address_to\\, uint_value) returns (bool success);
function approve(address_spender\\, uint_value) returns (bool success);
function allowance(address_owner\\, address_spender) constant returns (uint remaining);
event Transfer(address indexed_from\\, address indexed_to\\, uint_value);
event Approval(address indexed_owner\\, address indexed_spender\\, uint_value);
}
name
返回 ERC20 代幣的名字,例如「My test token」。

symbol
返回代幣的簡稱,例如:MTT,這個也是我們一般在代幣交易所看到的名字。

decimals
返回 token 使用的小數點後幾位。比如如果設置爲 3,就是支持 0.001 表示。

totalSupply
返回 token 的總供應量。

balanceOf
返回某個地址 (賬戶) 的賬戶餘額。

transfer
從代幣合約的調用者地址上轉移 _value 的數量 token 到的地址 _to,並且必須觸發
Transfer 事件。

transferFrom
從地址 _from 發送數量爲 _value 的 token 到地址 _to, 必須觸發 Transfer 事件。

transferFrom 方法用於允許合同代理某人轉移 token。

條件是 from 賬戶必須經過了 approve。

這個後面會舉例說明。

approve
允許 _spender 多次取回您的帳戶,最高達 _value 金額。 如果再次調用此函數,它將以 _value 覆蓋當前的餘量。

allowance
返回 _spender 仍然被允許從 _owner 提取的金額。
後面三個方法不好理解,這裏還需要補充說明一下,
approve 是授權第三方(比如某個服務合約)從發送者賬戶轉移代幣,然後通過 transferFrom() 函數來執行具體的轉移操作。

賬戶 A 有 1000 個 ETH,想允許 B 賬戶隨意調用他的 100 個 ETH,過程如下:

  1. A 賬戶按照以下形式調用 approve 函數 approve(B,100)
  2. B 賬戶想用這 100 個 ETH 中的 10 個 ETH 給 C 賬戶,調用 transferFrom(A, C, 10)
  3. 調用 allowance(A, B) 可以查看 B 賬戶還能夠調用 A 賬戶多少個 token

後面兩個是事件,事件是爲了獲取日誌方便提供的。前者是在代幣被轉移時觸發,後者是在調用 approve 方法時觸發。

基於 ERC20 編寫的一個代幣合約

pragma solidity ^0.4.16;
contract Token{
uint256 public totalSupply;
function balanceOf(address _owner) public constant 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 constant returns
(uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256
_value);
}
contract TokenDemo is Token {
string public name; // 名稱,例如 \”My test token\”
uint8 public decimals; // 返回 token 使用的小數點後幾位。比如如果設置爲 3,就是支持 0.001 表示 .
string public symbol; //token 簡稱 ,like MTT
function TokenDemo(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) public {
totalSupply = initialAmount * 10 ** uint256(decimalUnits); // 設置初始總量
balances[msg.sender] = totalSupply; // 初始 token 數量給予消息發送者,因爲是構造函數,所以這裏也是合約的創建者
name = _tokenName;
decimals = _decimalUnits;
symbol = _tokenSymbol;
}
function transfer(address _to, uint256 _value) public returns (bool success) {
// 默認 totalSupply 不會超過最大值 (2^256 – 1).
// 如果隨着時間的推移將會有新的 token 生成,則可以用下面這句避免溢出的異常
require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
require(_to != 0x0);
balances[msg.sender] -= value;// 從消息發送者賬戶中減去 token 數量 value
balances[_to] += _value;// 往接收賬戶增加 token 數量 value_
Transfer(msg.sender, _to, _value);// 觸發轉幣交易事件
return true;
}

function transferFrom(address _from, address _to, uint256 _value) public returns
(bool success) {
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
balances[_to] += _value;// 接收賬戶增加 token 數量 value_
balances[_from] -= _value; // 支出賬戶 _from 減去 token 數量 _value
allowed[_from][msg.sender] -= _value;// 消息發送者可以從賬戶 _from 中轉出的數量減少 _value
Transfer(_from, _to, value);// 觸發轉幣交易事件 _
return true;
}
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balances[_owner];
}

function approve(address _spender, uint256 _value) public returns (bool success)
{
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
return allowed[_owner][_spender];// 允許 _spender 從 _owner 中轉出的 token 數
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
}

代碼不必過多的解釋,註釋都寫得很清楚了。
這裏可能有人會有疑問,name,totalSupply 這些按照標準不應該都是方法嗎,怎麼這裏定義的是屬性變量? 這是因爲 solidity 會自動給 public 變量生成同名的 getter 接口。

部署測試

我會提供兩個環境的部署測試流程,都是親測過的,大家可以根據自己的喜好選擇。我個人平時用得比較多的是後者。

Remix+MetaMask 環境部署測試

這部分要求你的瀏覽器已經安裝了 MetaMask 插件,至於什麼是 MetaMask 以及如何安裝和使用請自行搜索查詢。MetaMask 我們用的是測試環境的網絡,在測試網絡中可以申請一些以太幣進行測試。
我們把代碼複製到 remix 編譯,沒問題的話如下圖所示點擊 create 創建合約,參數可以按照下圖的方式設置。注意環境選擇 injected web3,這樣會打開瀏覽器插件 MetaMask 進行測試部署。
11831773-76ca0470349abd97

以太坊開發代幣
點擊 create 後會彈出合約確認界面,直接點擊 submit,等待合約確認。

11831773-9f0963b48973360a
以太坊開發代幣
我們可以在 MetaMask 裏點擊該筆合約提交的明細,就會跳轉到以太坊的瀏覽器中,可以在這裏看到合約的各種信息:
11831773-551682f17e2cc078

以太坊開發代幣
如上圖所示,1 表示該筆交易 (合約也是一種交易) 的 hash 值,2 是當前合約所處的區塊位置 (當然是測試環境) 和已經被確認的區塊鏈數量,3 是合約的創建地址,4 是合約本省所在的地址。
3 和 4 的概念容易混淆,注意理解。
進入 MetaMask 的 token 界面中,點擊 add token,然後我們把合約的地址複製到過去提交就可以看到我們的代幣了。還可以點擊代幣的圖標打開瀏覽器查看代幣的詳細信息。

11831773-e315016c12adfc5d

以太坊開發代幣
到這裏你已經完成了代幣的開發部署。接下來我們還要看看如何進行代幣的轉賬,這個也是代幣比較常用的操作。轉賬我們需要結合以太坊錢包 MyEtherWallet,這是個以太坊的網頁版輕量級錢包,利用它可以很方便的對我們的以太幣和其它代幣進行管理。
轉賬前我們首先要把代幣加入到錢包中

11831773-473f0d2b67a78c29
以太坊開發代幣
11831773-69c224dee233e09c

以太坊開發代幣
注意在上圖中,我們選擇的環境同樣是測試環境並且和 MetaMask 中的環境一致。點擊 add custome token,輸入代幣地址等信息就可以看到代幣了,然後進行轉賬操作。

11831773-d685754e716f4713

以太坊開發代幣
我們隨便轉入一個地址,轉賬完成後,發現代幣餘額確實減少了。

11831773-fc716210c0e20a40

以太坊開發代幣

以太坊錢包 mist+geth 私有環境部署測試

我個人開發用這個環境比較多,不過這個環境安裝起來比較麻煩,具體流程可以看下我以前的文章。
打開 mist 錢包,進入合約界面,然後點擊 deploy new contact,然後把代碼複製進去編譯。
11831773-aa0ce9f5b8246c10
以太坊開發代幣
然後點擊 deploy
11831773-1bcb0bca5813e985

以太坊開發代幣
輸入賬戶密碼開始部署。
隨着挖礦的進行,合約就被部署到我的 geth 私有環境中了,

11831773-90bfc192168d35dc

以太坊開發代幣
回到錢包的合約界面已經可以看到合約了,

11831773-736d54a419a325c1

以太坊開發代幣
點擊 transfer ether&tokens,進入轉賬界面,進行轉賬。

11831773-914b405f54e7b5d1

11831773-410ab6d48a5c7a81
以太坊開發代幣
成功後可以看到餘額已經減少,並且轉入賬戶的餘額增加。
11831773-3fe57b09895b28c1
以太坊開發代幣
11831773-96784bef44ef8892
以太坊開發代幣