如何撰寫智能合約(Smart Contract)?(II)建立加密代幣
Update: 12/28/2017 更新教程,使用 require 取代 throw。
上一篇中我們已寫好並部署完成了第一個智能合約,也驗證了合約確實可以運作。在閱讀完本篇後,你將學會建立一個簡易的加密代幣🔒💵。本篇目的並非為了寫出一個安全可用的加密代幣,而是以介紹代幣合約的相關概念為主, 是以對合約做了適當地簡化,好更易於理解。
開發前的準備
延續上一篇的內容,在開發的過程中,我們將繼續使用testrpc[^1] 工具在電腦上模擬智能合約所需的乙太坊區塊鏈測試環境。
首先確保已啟動 testrpc,若尚未啟動,可以使用以下命令啟動
$ testrpc
...
這樣我們就可以開始建立加密代幣智能合約專案了。
代幣合約的基礎概念
代幣合約扮演像是銀行🏦的角色。使用者在代幣合約中,用自己的乙太幣帳戶地址當作銀行帳戶,可以透過代幣合約執行轉帳 (transfer,將代幣由一個帳戶傳送到另一個帳戶),查詢餘額 (balanceOf,查詢指定帳戶中擁有的代幣) 等原本由銀行負責的工作。因為合約部署在公開區塊鏈上,所有的交易都是公開透明,可供檢驗的。
建立一個代幣合約
在contracts/目錄下建立一個SimpleToken.sol檔案。也可以使用以下命令來產生檔案:
$ truffle create contract SimpleToken
SimpleToken.sol檔案內容如下:
pragma solidity ^0.4.11;
contract SimpleToken {
uint256 INITIAL_SUPPLY = 10000;
mapping(address => uint256) balances;
function SimpleToken() public {
balances[msg.sender] = INITIAL_SUPPLY;
}
// transfer token for a specified address
function transfer(address _to, uint256 _amount) public {
require(balances[msg.sender] > _amount);
balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
// Gets the balance of the specified address
function balanceOf(address _owner) public constant returns (uint256) {
return balances[_owner];
}
}
講解
pragma solidity ^0.4.11;
第一行指名目前使用的 solidity 版本,不同版本的 solidity 可能會編譯出不同的 bytecode。
uint256 INITIAL_SUPPLY = 10000;
mapping(address => unit256) balances;
我們定義了初始代幣數目INITIAL_SUPPLY。這邊隨意選擇了一個數字10000。
我們用mapping來定義一個可以儲存鍵值對 (key-value pair) 的資料結構 (類似 Javascript 中的{"0xaabbccddeeff": 888}),同時也需要分別指定address作為鍵的型別,指定uint256作為值的型別。和 Javascript 不同,型別定義好後不能隨時更改要儲存的型別。
contract SimpleToken {
function SimpleToken() public {
balances[msg.sender] = INITIAL_SUPPLY;
}
}
和合約同名的SimpleToken函式,就是SimpleToken這個合約的建構函式 (constructor)。函式中我們拿msg.sender當作 key,INITIAL_SUPPLY當作值,將所有的初始代幣INITIAL_SUPPLY都指定給msg.sender帳號。
msg是一個全域 (Global) 物件 [^2],msg.sender表示用作呼叫當前函式的帳號。由於建構函式只有在合約部署時會被執行,因此這邊用到的msg.sender,也就代表著用來部署這個合約的帳號。
function transfer(address _to, uint256 _amount) public {
require(balances[msg.sender] > _amount);
balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
transfer函式定義了如何轉帳,只要指定要傳送的帳號與數目,就會從呼叫者手上把對應數目的代幣移轉到指定的帳號上。
require(balances[msg.sender] > _amount);語句判斷帳戶中是否還有足夠轉出的餘額,若存款小於想轉出的數目,就丟出錯誤。
這個函式這麼寫當然還是過度簡化了,若要能實際使用,需要檢查更多可能的狀況。但就先這樣吧。
function balanceOf(address _owner) public constant returns (uint256) {
return balances[_owner];
}
balanceOf函式的作用,是讓使用者可以查詢任一帳號的餘額。透過傳入_owner帳號,可以查詢_owner帳號儲存在balances對照表中的值。
如此一來,我們就寫好一個新加密代幣🔒💵合約囉!接下來將要編譯合約並部署到區塊鏈上。
編譯與部署
在migrations/目錄下建立一個3_deploy_token.js檔案,內容如下:
var SimpleToken = artifacts.require("SimpleToken");
module.exports = function(deployer) {
deployer.deploy(SimpleToken);
};
現在可執行 compile 與 migrate 命令
$ truffle compile
...
$ truffle migrate
Using network 'development'.
Running migration: 3_deploy_token.js
Deploying HelloToken...
... 0x2c4659528c68b4e43d1edff6c989fba05e8e7e56cc4085d408426d339b4e9ba4
SimpleToken: 0x352fa9aa18106f269d944935503afe57a00a9a0d
Saving successful migration to network...
... 0x1434c1b61e9719f410fc6090ce37c0ec141a1738aba278dd320738e4a5d229fa
Saving artifacts...
如此一來我們已將SimpleToken代幣合約部署到 testrpc 上。