Ethereum
solidity
truffle
OpenZeppelin
ERC20

Truffle で始める Ethereum 入門 - ERC20 トークンを作ってみよう

この記事は 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 トークンのコントラクトを作成し、それをローカルマシン上の仮想的なプライベートチェーンにデプロイするまでを行います。

全体の流れは以下のとおりです。

  1. Truffle フレームワークのインストール
  2. OpenZeppelin ライブラリの導入
  3. Solidity コードの作成
  4. Solidity コードのコンパイル
  5. マイグレーションファイルの作成
  6. コントラクトのデプロイ
  7. デプロイされたコントラクトの確認

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 の部分で、MyTokenStandardToken を継承していることを表しています。

  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 ブロックチェーンを活用して素晴らしいアイデアを実現してみてください。

See Also


  1. Node.js 環境がない方はインストールしておいてください  

  2. 使用する OpenZeppelin のバージョンによって、パスや変数名が異なることがあります 

  3. 数値は BigNumber オブジェクトをで返されます