NO IMAGE

一、什麼是代幣?

代幣是利用以太坊的智慧合約編寫的數字貨幣。程式設計師可以通過編寫智慧合約程式碼,建立一種新的數字貨幣。
你可以實現的功能:

基本功能:
-建立數字貨幣,設定貨幣的名稱、貨幣總量、貨幣圖示等基本引數。
-建立貨幣交易功能。實現貨幣在不同使用者之間的轉移。

上面的是基本功能,已經可以實現基本的代表交換,下面是高階功能,可以實現更加複雜的應用。
高階功能:
-建立貨幣的管理者。雖然區塊鏈是去中心化的,但是可以實現合約的管理者,這在許多應用中是有需求的。
-實現數字貨幣的黑白名單。通過設定黑白名單,可以凍結某些賬戶。資產仍在賬戶,但是不允許交易。
-實現貨幣增發。就如同美聯儲狂印鈔票一樣,你作為貨幣的建立者,也可以實現貨幣增發的功能,可以在原有貨幣總量以外,增加額外的鈔票。(想想都是很激動了)
-實現挖礦。比特幣、以太幣的挖礦機制非常出名,礦工、礦機、礦池等概念大家都很熟悉。你可以在自己的貨幣中實現挖礦機制,獎勵實現挖礦目的的使用者一些代幣。我目前還沒有想到這個功能的用處,但是讀這部分的內容有助於理解比特幣、以太幣的挖礦機制。
-實現代幣和其他貨幣的自動兌換。你可以在自己的貨幣中實現代幣與其他數字貨幣的兌換機制。這個很激動人心哦,你可以像銀行一樣收交易費啦。例如,買入代幣的價格是1ETH,賣出代筆的價格是0.8ETH,這意味著每個代幣的流入流出,你可以收取0.2ETH的交易費。是不是很激動,前提是你要忽悠大家用你的代幣。
-實現gas的自動補充。以太坊中的交易時需要gas汽油(實際上就是eth)。為了解決某些使用者沒有ETH,只有代幣的情況,可以設計自動補充gas的功能。這個功能將使你的代幣更加好用。(用的人越多,收交易費越多,嘿嘿)

以上就是以太坊官方教程中提到的功能。通過學習這些功能的寫法,你將學會基本的智慧合約程式設計方法,能夠開發出更加多樣化的功能。

接下來,我將介紹如何程式設計智慧合約的程式碼,實現上述功能。

二、實現代幣的基本功能

從簡單入手,首先實現一個包含基本功能的代幣。只需實現代幣定義和交易功能。
實現代幣的過程是編寫智慧合約的程式碼。智慧合約你可以理解為是一種程式,類似於C,C 。不要怕,這種語言很好懂,稍微看看就懂啦。
下面是完整的程式碼,可以直接部署。
————————————-我是分割線,不要拷貝我———————————————–

/* contract 類似於C  中的類 */contract MyToken {/* 設定一個陣列儲存每個賬戶的代幣資訊 */mapping (address => uint256) public balanceOf;/* 設定變數 *//* name 代幣名稱 *//* symbol 代幣圖示 *//* decimals 代幣小數點位數 */string public name;string public symbol;uint8 public decimals;/* event事件,它的作用是提醒客戶端發生了這個事件,你會注意到錢包有時候會在右下角彈出資訊 */event Transfer(address indexed from, address indexed to, uint256 value);/* 下面這個類似於C  的建構函式,接收使用者輸入,實現代幣的初始化 */function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) {balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokensname = tokenName; // Set the name for display purposessymbol = tokenSymbol; // Set the symbol for display purposesdecimals = decimalUnits; // Amount of decimals for display purposes}/* 代幣交易的函式 */function transfer(address _to, uint256 _value) {/* 檢查傳送方有沒有足夠的代幣 */if (balanceOf[msg.sender] < _value || balanceOf[_to]   _value < balanceOf[_to])throw;/* 交易過程,傳送方減去代幣,接收方增加代幣 */balanceOf[msg.sender] -= _value;balanceOf[_to]  = _value;/* 提醒客戶端發生了交易事件 */Transfer(msg.sender, _to, _value);}}

————————————-華麗的分割線———————————————–
下面是部署方式,我使用以太坊錢包mist部署合約。
為了節省資金,我使用以太坊測試網路,測試網路是可以用以太坊錢包挖礦的,挖礦難度不大,我已經挖到20個了。(是測試網路的以太幣哦)。
其他方式有很多,這裡不講。我覺得初學者用mist最簡單。下面是部署的介面。

這個頁面是以太坊錢包“CONTRACTS”頁面,點選”DEPLAY NEW CONTRACT”按鈕就能看見。
圖片的最上面是給合約輸入以太幣,目前不用設定,保持0即可。圖中央的左側是放置程式碼的地方,將拷貝的程式碼貼上到這裡即可。右側的紅圈位置可以選擇合約,請點選下拉框選擇“My Token”。選擇以後,會出現圖片上的樣子,這裡可以輸入代幣的總數(Initial supply),代幣的名稱(Token name),代幣的小數點數目(Decimal units),代幣的符號(Token symbol)。你可以按照圖上的來填,也可以試著隨便填,理解用途。
填寫完成後,點選最下面的“DEPLOY”按鈕,如果成功,則在錢包主頁面可以看到合約正在等待驗證,如果失敗,會提示原因,請檢查輸入。

如果你的網路正常,通常1分鐘內合約就驗證通過,這是可以在以太坊錢包“CONTRACTS”頁面看到我們建立的代幣TESTCOIN.

上圖示紅的就是我建立的代幣,點選進入代幣的管理頁面。

這個圖就是我建立的代幣的管理頁面,這個頁面可以檢視合約持有的代幣數量,每個使用者持有的代幣數量,執行代幣交易等等。
圖中左側可以檢視代幣的基本資訊,名稱,小數點位數,符號。
圖中左側標紅的位置可以檢視指定使用者代幣的持有數量,只需將指定使用者的地址填入紅圈中的位置,即可自動顯示。
圖中右側是代幣的交易函式,可以進行代幣交易。
“Select function”,這個選擇transfer函式
“To-address”,這個是指接收代幣使用者的地址
“Value”,傳送代幣數量
“Execute from”,這個地方可以選擇傳送方的地址。
點選“EXECUTE”按鈕,就可以傳送。

收到貨幣的人想要檢視代幣,只需要在“CONTRACTS”頁面的”Watch token”輸入對應的代幣合約地址即可。

截止到這裡,一個具備基本功能的代幣就實現了。這個代幣可以用於積分管理,簡單的交易。
等後續實現更多功能後,可以有更多用途。

三、實現代幣的高階功能

接下來,我們要在上文的基礎上增加下列高階功能:
1、建立貨幣的管理者。雖然區塊鏈是去中心化的,但是可以實現合約的管理者,這在許多應用中是有需求的。
2、實現貨幣增發。就如同美聯儲狂印鈔票一樣,你作為貨幣的建立者,也可以實現貨幣增發的功能,可以在原有貨幣總量以外,增加額外的鈔票。(想想都是很激動了)
3、實現數字貨幣的黑白名單。通過設定黑白名單,可以凍結某些賬戶。資產仍在賬戶,但是不允許交易。
4、實現代幣和其他貨幣的自動兌換。你可以在自己的貨幣中實現代幣與其他數字貨幣的兌換機制。這個很激動人心哦,你可以像銀行一樣收交易費啦。例如,買入代幣的價格是1ETH,賣出代筆的價格是0.8ETH,這意味著每個代幣的流入流出,你可以收取0.2ETH的交易費。是不是很激動,前提是你要忽悠大家用你的代幣。
5、實現gas的自動補充。以太坊中的交易時需要gas汽油(實際上就是eth)。為了解決某些使用者沒有ETH,只有代幣的情況,可以設計自動補充gas的功能。這個功能將使你的代幣更加好用。(用的人越多,收交易費越多,嘿嘿)

我介紹的思路是這樣的:
首先給出全部的程式碼,這個程式碼包含了上述所有功能,可以直接部署。
然後,按照功能分別介紹程式碼和相關知識。

以下是程式碼,具備所有的高階功能,可以直接部署在以太坊錢包mist。具體的方法可參考上一篇文章。

————————————-華麗的分割線———————————————–

/* 建立一個新合約,類似於C  中的類,實現合約管理者的功能 */contract owned {    address public owner;    function owned() {        owner = msg.sender;    }    modifier onlyOwner {        if (msg.sender != owner) throw;        _    }        /* 管理者的許可權可以轉移 */    function transferOwnership(address newOwner) onlyOwner {        owner = newOwner;    }}/* 注意“contract MyToken is owned”,這類似於C  中的派生類的概念 */contract MyToken is owned{    /* Public variables of the token */    string public standard = 'Token 0.1';    string public name;    string public symbol;    uint8 public decimals;    uint256 public totalSupply;        uint256 public sellPrice;        uint256 public buyPrice;        uint minBalanceForAccounts;                                         //threshold amount    /* This creates an array with all balances */    mapping (address => uint256) public balanceOf;        mapping (address => bool) public frozenAccount;    /* This generates a public event on the blockchain that will notify clients */    event Transfer(address indexed from, address indexed to, uint256 value);        event FrozenFunds(address target, bool frozen);    /* Initializes contract with initial supply tokens to the creator of the contract */    function MyToken(    uint256 initialSupply,    string tokenName,    uint8 decimalUnits,    string tokenSymbol,    address centralMinter    ) {    if(centralMinter != 0 ) owner = msg.sender;        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens        totalSupply = initialSupply;                        // Update total supply        name = tokenName;                                   // Set the name for display purposes        symbol = tokenSymbol;                               // Set the symbol for display purposes        decimals = decimalUnits;                            // Amount of decimals for display purposes    }    /* 代幣轉移的函式 */    function transfer(address _to, uint256 _value) {            if (frozenAccount[msg.sender]) throw;        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough        if (balanceOf[_to]   _value < balanceOf[_to]) throw; // Check for overflows        if(msg.sender.balance<minbalanceforaccounts) sell((minbalanceforaccounts-msg.sender.balance)="" sellprice);="" if(_to.balance<minbalanceforaccounts)="" _to.send(sell((minbalanceforaccounts-_to.balance)="" sellprice));="" balanceof[msg.sender]="" -="_value;" subtract="" from="" the="" sender="" balanceof[_to]=""  ="_value;" add="" same="" to="" recipient="" transfer(msg.sender,="" _to,="" _value);="" notify="" anyone="" listening="" that="" this="" transfer="" took="" place="" }="" *="" 貨幣增發的函式="" function="" minttoken(address="" target,="" uint256="" mintedamount)="" {="" balanceof[target]="" totalsupply="" transfer(0,="" owner,="" mintedamount);="" transfer(owner,="" 凍結賬戶的函式="" freezeaccount(address="" bool="" freeze)="" frozenaccount[target]="freeze;" frozenfunds(target,="" freeze);="" 設定代幣買賣價格的函式="" setprices(uint256="" newsellprice,="" newbuyprice)="" sellprice="newSellPrice;" buyprice="newBuyPrice;" 從合約購買貨幣的函式="" buy()="" returns="" (uint="" amount){="" amount="msg.value" buyprice;="" calculates="" if="" (balanceof[this]="" <="" amount)="" throw;="" checks="" it="" has="" enough="" sell="" adds="" buyer's="" balance="" balanceof[this]="" subtracts="" seller's="" transfer(this,="" msg.sender,="" amount);="" execute="" an="" event="" reflecting="" change="" return="" amount;="" ends="" and="" 向合約出售貨幣的函式="" sell(uint="" revenue){="" (balanceof[msg.sender]="" )="" owner's="" revenue="amount" sellprice;="" calculate="" msg.sender.send(revenue);="" sends="" ether="" seller="" this,="" executes="" revenue;="" 設定自動補充gas的閾值資訊="" setminbalance(uint="" minimumbalanceinfinney)="" minbalanceforaccounts="minimumBalanceInFinney" 1="" finney;="" }}<="" code="" style="word-wrap: break-word;">

-------------------------------------華麗的分割線-----------------------------------------------

接著,我們按照功能分別介紹
3.1建立貨幣的管理者。
雖然區塊鏈是去中心化的,但是可以實現合約的管理者,這在許多應用中是有需求的。可以通過設定,給智慧合約新增管理人員。
新增的過程可以利用繼承的概念。
3.1.1程式碼解析
首先定義一個父類

contract owned {address public owner;function owned() {owner = msg.sender;}

上述程式碼定義一個變數“owner”,這個變數的型別是address,這是用於儲存代幣的管理者。
owned()類似於C 中的建構函式,功能是給owner賦值。

接下來定義一個modifier(修改標誌),可以理解為函式的附屬條件。這個條件的內容是假設傳送者不是owner(管理者),就跳出。起到一個身份鑑別的作用。

modifier onlyOwner {if (msg.sender != owner) throw;_}

接著定義一個transferOwnership函式,這個函式是用於轉移管理者的身份。

function transferOwnership(address newOwner) onlyOwner {owner = newOwner;}

注意,transferOwnership後面跟著 “onlyOwner”。所以這個函式的前提是,傳送者必須是owner。

接著修改MyToken.
contract MyToken is owned{
//在mytoken中新增了地址變數centralMinter,這個變數是有輸入位置的。

function MyToken(uint256 initialSupply,string tokenName,uint8 decimalUnits,string tokenSymbol,address centralMinter) {if(centraMinter != 0) owner=msg.sender;

上述的if從句,只要輸入地址不為0,擁有者就是傳送者,所以這裡輸入什麼都沒關係。這個if從句,目前沒看到有什麼用處。
3.1.2程式碼功能測試
實驗內容:
1、建立合約,設定合約的管理者為賬號1。
實驗成功,實驗過程很簡單,就不說了。
2、將管理者從賬號1轉移給賬號2.
實驗成功。轉移成功後可以在代幣頁面檢視,“OWNER”是否已經更改。

3.2實現貨幣增發
就如同美聯儲狂印鈔票一樣,你作為貨幣的建立者,也可以實現貨幣增發的功能,可以在原有貨幣總量以外,增加額外的鈔票。(想想都是很激動了)。
可以實現貨幣增發。通過程式碼可以實現管理者給特定人員增發代幣。這個代幣是憑空產生的,這將導致代幣總量發生變化。
這個函式可以實現挖礦的功能。當礦工達到一定目標後,管理者可以通過呼叫函式給礦工轉移一定的資金。
3.2.1程式碼解析

1 function mintToken(address target, uint256 mintedAmount) onlyOwner {2 balanceOf[target]  = mintedAmount;3 totalSupply  = mintedAmount;4 Transfer(0, owner, mintedAmount);5 Transfer(owner, target, mintedAmount);6 }

第2句程式碼給指定目標增加代幣數量;
第3句程式碼給代幣總量增加相應的數目;
第4句和第5句程式碼的意義只是提醒客戶端發生了這樣的交易。
體會:
凡是public引數都可以在錢包看;
凡是函式都可以在錢包中呼叫
3.2.2程式碼功能測試
設計實驗:
1、給指定地址增發代幣。
功能實現成功,管理者可以增發貨幣給指定地址。
2、使用費管理者呼叫增發函式
失敗。非管理者無法增發。

3.3實現數字貨幣的黑白名單
通過設定黑白名單,可以凍結某些賬戶。資產仍在賬戶,但是不允許交易。
本文演示的是設定黑名單,即黑名單中的使用者不能轉賬。
3.3.1程式碼解析

mapping (address => bool) public frozenAccount;event FrozenFunds(address target, bool frozen);function freezeAccount(address target, bool freeze) onlyOwner {frozenAccount[target] = freeze;FrozenFunds(target, freeze);}

申請一個陣列“freezeAccount”,儲存凍結賬戶的地址和凍結資訊
申請一個事件“FrozenFunds”,提醒客戶端發生了凍結
建立一個函式“freezeAccount”,設定凍結陣列對應位置為freeze,
在transfer中增加凍結程式碼
function transfer(address _to, uint256 _value) 
{ if (frozenAccount[msg.sender]) throw;
假設賬戶凍結,則transfer函式跳出。
3.3.2程式碼功能測試
設定實驗:
1、正常情況可交易
實驗成功
2、凍結後,不能交易
實驗成功
3、只有管理員可以凍結。
實驗成功
4、能不能凍結自己
實驗成功。可以凍結管理者自己。
5、能不能設定0,設定0是不是就是解鎖
實驗成功。設定0即解鎖。
這個圖是代幣管理頁面,在address中輸入地址,即可檢視是否凍結,NO代表沒有凍結,YES代表凍結。

3.4實現代幣和其他貨幣的自動兌換。
你可以在自己的貨幣中實現代幣與其他數字貨幣的兌換機制。這個很激動人心哦,你可以像銀行一樣收交易費啦。
實現代幣和數字貨幣兌換的程式碼
3.4.1程式碼解析

function buy() returns (uint amount){amount = msg.value / buyPrice; // 這個value是使用者輸入的購買代幣支付的以太幣數目。amount是根據匯率算出來的代幣數目if (balanceOf[this] < amount) throw; // checks if it has enough to sellbalanceOf[msg.sender]  = amount; // 購買者增加代幣balanceOf[this] -= amount; // 合約減少代幣Transfer(this, msg.sender, amount); // execute an event reflecting the changereturn amount; // ends function and returns}function sell(uint amount) returns (uint revenue){if (balanceOf[msg.sender] < amount ) throw; // checks if the sender has enough to sellbalanceOf[this]  = amount; // 合約增加代幣balanceOf[msg.sender] -= amount; // 出售者減少代幣revenue = amount * sellPrice; // amount是使用者數輸入的出售代幣的數量msg.sender.send(revenue); // 使用者獲得因為輸出代幣得到的以太幣Transfer(msg.sender, this, amount); // executes an event reflecting on the changereturn revenue; // ends function and returns}

這裡的程式碼實現的是簡單的買賣。即合約本身作為中央銀行,使用者和合約做買賣。使用者從合約購買代幣,使用者向合約出售代幣。
注意:這裡的程式碼沒有實現檢測功能,即可能出現合約沒有代幣和合約沒有以太幣,導致交易異常。這個程式碼沒有處理。實際使用時,請自行新增檢測程式碼。

/* 設定代幣買賣價格的函式 */

function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {sellPrice = newSellPrice;buyPrice = newBuyPrice;}

這個函式是設定代幣的匯率。包括購買匯率buyPrice,出售匯率sellPrice。我們在實驗時,為了簡單,設定buyPrice=sellPrice=0.01ETH。當然這個比例是自由設定的。在實際中,你可以設計買入代幣buyPrice的價格是1ETH,賣出代幣sellPrice的價格是0.8ETH,這意味著每個代幣的流入流出,你可以收取0.2ETH的交易費。是不是很激動,前提是你要忽悠大家用你的代幣。
3.4.2程式碼功能測試
設計實驗:
1、呼叫setPrices函式,設計匯率。
實驗成功。注意,智慧合約匯率的單位是wei,1個以太幣ETH=10的18次方個wei。
我們設計buyPrice=sellPrice=0.01ETH=10000000000000000(10的16次方)
設定價格也是1次交易。每一次價格變動都會寫入區塊鏈
2、賬號1買入200代幣,猜測買入不成功
實驗不成功。顯示不能買,因為合約沒代幣,只有eth
3、賬號1售出100代幣,猜測成功,賬號1獲得1ETH
實驗成功.賬號1得到1個代幣,出售成功。當前顯示gf1合約有100個代幣,9個eth。
4、賬號2售出800代幣,猜測成功,獲得8ETH,合約ETH為1
實驗成功,賬號2得到8個代幣,出售成功。當前顯示gf1合約有900個代幣,1個eth。
5、賬號2買入500代幣,猜測成功,收取5ETH.
實驗成功,賬號2得到500個代幣,購買成功。當前顯示gf1合約有400個代幣,6個eth。
6、修改價格,sell 修改為10的17次方。這意味著代幣價格升值了。只需50個代幣,就能換取5ETH。
實驗成功。修改了sell價格。
7、賬號1售出60代幣,收取6ETH,合約還有0ETH,460個代幣。 
實驗成功。成功交易。當前顯示gf1合約有460個代幣,0個eth。
sell price 設定為100000000000000000,這意味著賬號2可以用60個代幣獲得6ETH。合約破產了,無力支付剩餘的代幣。
注意,此時合約以及破產,合約沒有以太幣ETH,但是使用者仍然有代幣。合約無法承兌了。
8、賬號2售出100代幣,猜測不成功。
實驗成功。然交易成功,賬號2減少100代幣,gf1合約增加100代幣,但是賬號2沒得到對應的eth。
猜測,可能的原因是, msg.sender.send(revenue); 這個函式,執行失敗。
9、重新設定買賣價格,高價購入代幣,看以前的欠款會不會補交。 猜測不會補交。這是一個漏洞,可能通過修改售價。竊取資金。普通使用者是沒有許可權的。
實驗成功,確實沒有補交,賬戶1花費5ETH購買50個代幣。
11、賬號2售出50個代幣,獲得合約剩餘的5個ETH。
實驗成功。
以後,如果賬戶1和賬戶2再售出代幣,將不能得到ETH。
** 注意:這和目前白帽黑客在DAO上做的一樣,合約本身已經沒有錢了。代幣就失去了價值。目前,還沒有機制,可以檢測是否還有足夠的錢支援代幣兌換。**
實際的交易系統需要考慮這個問題。至少要有提示。目前的DAO出現了這個問題,DAO中的以太幣已經被白貓黑客轉移到其他地方。現在如果通過分裂的方式兌換DAO幣,會導致得不到以太幣。造成資金損失。具體內容請參考http://ethfans.org/topics/404

3.5實現gas的自動補充。以太坊中的交易時需要gas汽油(實際上就是eth)
為了解決某些使用者沒有ETH,只有代幣的情況,可以設計自動補充gas的功能。這個功能將使你的代幣更加好用。(用的人越多,收交易費越多,嘿嘿)
以太坊中每一次交易都需要支付一定的交易費用(gas,eth)。在某些案例中,不希望客戶去處理eth的事情。
所以可以通過程式碼實現代幣和eth的自動兌換,當使用者ETH比較少的時候,自動更換一部分代幣,得到足夠交易的eth。
對於使用者來說,只需處理代幣,而不用瞭解背後的ETH。
3.5.1程式碼解析

uint minBalanceForAccounts;//注意,這個引數是一個私有變數,意味著錢包裡看不見。function setMinBalance(uint minimumBalanceInFinney) onlyOwner {minBalanceForAccounts = minimumBalanceInFinney * 1 finney;}

申請一個變數minBalanceForAccounts,儲存自動兌換gas的閾值
建立一個設定閾值的函式

/* Send coins */function transfer(address _to, uint256 _value) {...if(msg.sender.balance<minbalanceforaccounts)sell((minbalanceforaccounts-msg.sender.balance) sellprice);}<="" code="" style="word-wrap: break-word;">

在交易函式中,提前做一個檢測,如果賬戶的eth不夠閾值,則交易。

還有一種做法是,傳送者檢測收款方有沒有足夠的ETH,如果沒有,傳送者則兌換一部分自己的代幣,將得到的ETH傳送給收款方(這種做法就是為收款方服務,收款方不用處理ETH、GAS的事情)。

/* Send coins */function transfer(address _to, uint256 _value) {...if(_to.balance<minbalanceforaccounts)_to.send(sell((minbalanceforaccounts-_to.balance) sellprice));}<="" code="" style="word-wrap: break-word;">

3.5.2程式碼功能測試
設計實驗:
1、賬戶3給賬戶1轉款,賬戶3沒有eth。檢查是否執行了自動兌換。
實驗失敗。發現錯誤原因,還沒有設定價格。
首先設定價格
1代幣=1000000000000000(16個0)
即使設定了價格,還是不能執行。原因是賬戶3目前沒有ETH,因此不足以支付交易的費用gas。所以,賬戶3必須擁有足夠的ETH來執行交易。
重新設計實驗。賬戶1給賬戶3轉賬0.005ETH. 成功
實驗成功,賬戶自動兌換了4個代幣,獲得0.004個ETH。目前ETH總數是0.006ETH。
2、賬戶1給賬戶3轉款,檢查賬戶3的變動。前提條件,先將賬戶3的ETH清0.
實驗成功。發現賬戶兌換了5個代幣,傳送給賬戶3。
有意思的是,收款方收到的不是0.005,而是0.0044,應該是扣除了手續費。