この記事は Ethereum Advent Calendar 2017 の2日目の記事です。
今日は、Ethereum 入門者の方向けに「ERC20トークン」の作成方法をご紹介しようと思います。意外と簡単で驚かれるかもしれません。
ERC20 トークンとは
ERC20 は、Ethereum ブロックチェーン上でトークンを発行する際の標準規格です。ERC20 に準拠したトークンであれば、無数に存在する種類のトークンを同じ枠組みで価値移転することができます。
ちなみに ERC とは「Ethereum RFC (Request for Comment)」の意味で、その20番目だったために「ERC20」と呼ばれます。仕様の詳細は以下にまとまっています。
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
具体的には、以下の 6つの function
と 2つの event
を実装すれば、ERC20 トークンとなります。
contract ERC20 {
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);
}
トークン作成の流れ
では実際に ERC20 トークンを作ってみましょう。今回は、ライブラリを活用してサクッと ERC20 トークンのコントラクトを作成し、それをローカルマシン上の仮想的なプライベートチェーンにデプロイするまでを行います。
全体の流れは以下のとおりです。
- Truffle フレームワークのインストール
- OpenZeppelin ライブラリの導入
- Solidity コードの作成
- Solidity コードのコンパイル
- マイグレーションファイルの作成
- コントラクトのデプロイ
- デプロイされたコントラクトの確認
Truffle フレームワークのインストール
Truffle は、Ethereum の開発フレームワークです。コントラクトコードのコンパイルやデプロイ、アドレス管理などの面倒を見てくれます。
以下のコマンドで、Truffle をインストールしてください1。本記事執筆時点での Truffle の最新バージョンは 4.0.1 でした。
$ npm install -g truffle
新しくプロジェクトフォルダを作成して、truffle init
を実行します。
$ mkdir ~/my_erc20_token
$ cd ~/my_erc20_token
$ truffle init
以下のようなフォルダ構成でファイル一式がダウンロードされたかと思います。
OpenZeppelin ライブラリの導入
OpenZeppelin は、Ethereum のスマートコントラクト開発を補助するライブラリです。ERC20 トークンの実装も含まれているので、今回はそれを使用します。
Truffle のプロジェクトフォルダの中で、以下のコマンドを実行してください。
$ npm init -f
$ npm install zeppelin-solidity --save
これで、OpenZeppelin のコードを、自分のコントラクトコードの中から使えるようになりました。
Solidity コードの作成
Solidity は、Ethereum のスマートコントラクトを記述するためのプログラミング言語の1つです。他にも使用できる言語はありますが、現時点では Solidity がデファクトスタンダードになっています。
では、ERC20 トークンの Solidity コードを書きましょう。MyToken.sol
というファイルを contracts
フォルダの中に用意し、以下のコードを記述してください。
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
contract MyToken is StandardToken {
string public name = "MyToken";
string public symbol = "MTKN";
uint public decimals = 18;
function MyToken(uint initialSupply) public {
totalSupply_ = initialSupply;
balances[msg.sender] = initialSupply;
}
}
短いコードなので、順番に解説していきます。
pragma solidity ^0.4.18;
↑ コンパイル時に使用する Solidity コンパイラのバージョンを指定しています。
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
↑ OpenZeppelin ライブラリから、ERC20 の実装クラスである StandardToken.sol
をインポートしています2。
contract MyToken is StandardToken {
...
}
↑ コントラクトの宣言です。is StandardToken
の部分で、MyToken
が StandardToken
を継承していることを表しています。
string public name = "MyToken";
string public symbol = "MTKN";
uint public decimals = 18;
↑ コントラクトの状態変数 name
, symbol
, decimals
に値を代入しています。ここでは、名前が "MyToken"、シンボルが "MTKN"、小数点の桁数が 18 のトークンとしています。
function MyToken(uint initialSupply) public {
...
}
↑ コントラクト作成時に呼ばれるコンストラクタです。contract 名と同じ名称の function がコンストラクタとなります。
totalSupply_ = initialSupply;
↑ トークンの総発行量を表す totalSupply_
という変数に、コンストラクタで受け取った initialSupply
を代入しています。totalSupply_
は、MyToken
コントラクトが継承している OpenZeppelin の StandardToken
が持つ状態変数です。
balances[msg.sender] = initialSupply;
発行したトークンを、全て msg.sender
のアドレス(口座)に入れています。msg.sender
は、コントラクト実行者の Ethereum アドレスを表し、balances
は、アドレスをキーとした key/value 型の変数です。
Solidity コードのコンパイル
では、記述した Solidity コードをコンパイルしましょう。
$ truffle compile
を実行すると、継承先のコントラクトも含めてコンパイルされます。ビルド結果は、build/contracts
に、Truffle の Contract Artifact という形式の JSON ファイルで保存されます。
マイグレーションファイルの作成
次に、MyToken
コントラクトをデプロイするためのマイグレーションファイルを作成します。migrations
フォルダの中に、2_deploy_my_token.js
というファイルを作成し、以下のコードを記述します。
const MyToken = artifacts.require('./MyToken.sol')
module.exports = (deployer) => {
const initialSupply = 50000e18
deployer.deploy(MyToken, initialSupply)
}
ここでは、トークン発行量が 50,000 MTKN になるように、MyToken
のコンストラクタへ initialSupply
の値を渡しています。
ちなみにマイグレーションの仕組みは、デプロイの順番や状態を管理するため、マイグレーションファイル名は [数字]_[名称].js
という形式にする必要があります。
コントラクトのデプロイ
$ truffle develop
というコマンドを実行すると、ローカルマシンの 9545 ポート (localhost:9545
) で Ethereum ブロックチェーンのエミュレータが起動し、利用可能な Ethereum アドレスのリストが表示されます。
Truffle Develop started at http://localhost:9545/
Accounts:
(0) 0x...
(1) 0x...
...
同時に、インタラクティブにやり取りできるコンソールも立ち上がります。そこで migrate
というコマンドを打つと、作成したマイグレーションファイルに従って、コントラクトのデプロイが実行されます。
truffle(develop)> migrate
Using network 'develop'.
Running migration: 1_initial_migration.js
Replacing Migrations...
... 0x54f6d0cef097d4fb43e0eae48f889a59af725f92a701f5f4ba7adac693118159
Migrations: 0x8f0483125fcb9aaaefa9209d8e9d7b9c8b9fb90f
Saving successful migration to network...
... 0x2e369ab2d57c20d6f0be342da05a0e340a8e85de0aef12b3199e44de9005d26c
Saving artifacts...
Running migration: 2_deploy_my_token.js
Replacing MyToken...
... 0x1228137c93414046875fa0ca1e85a6c65db529d13010579ecd1b4ec689688448
MyToken: 0x2c2b9c9a4a25e24b174f26114e8926a9f2128fe4
Saving successful migration to network...
... 0xf222e7a6a6255bd91b1dd223d30f4d2c18056ceb7b496cc47db3a6da4bbb7417
Saving artifacts...
↑のように表示されれば成功です。上の例であれば、0x2c2b9c9a4a25e24b174f26114e8926a9f2128fe4
というアドレスに MyToken
コントラクトがデプロイされました。
デプロイされたコントラクトの確認
続けて、Truffle のコンソール上で MyToken
コントラクトとやり取りしてみましょう。
truffle(develop)> myToken = MyToken.at(MyToken.address)
...
とすると、myToken
という変数に、デプロイされた MyToken
コントラクトオブジェクトが代入されます。
例えば、
truffle(develop)> myToken.name()
'MyToken'
truffle(develop)> myToken.totalSupply()
BigNumber { s: 1, e: 22, c: [ 500000000 ] }
とすると、トークンの名称、総発行量が確認できます3。
トークンの口座残高を見てみましょう。次のコマンドを打つと、Truffle が用意してくれたアドレスのリストが表示されます。
truffle(develop)> web3.eth.accounts
[ '0x0...', ... ]
先程のデプロイは、一番目のアドレス (web3.eth.accounts[0]
) で行ったことになるので、このアドレスに発行した全てのトークンが入っており、他のアドレスの残高はゼロになっています。
truffle(develop)> myToken.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 22, c: [ 500000000 ] }
truffle(develop)> myToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }
最後に、accounts[0]
から accounts[1]
に、1,000 MTKN だけ移してみましょう。
truffle(develop)> myToken.transfer(web3.eth.accounts[1], 1000e18)
...
truffle(develop)> myToken.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 22, c: [ 490000000 ] }
truffle(develop)> myToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 21, c: [ 10000000 ] }
おわりに
今回は、Truffle フレームワークと OpenZepplein ライブラリを活用して ERC20 トークンを作成してみました。ご覧になった通り、ERC20 トークンを作成するだけであれば、10行程のコードを書くだけで実現できます。
独自トークンの発行はスタートに過ぎず、重要なのは、そのトークンを使って何を実現するかです。ぜひ皆さんも、Ethereum ブロックチェーンを活用して素晴らしいアイデアを実現してみてください。