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

この記事は [Ethereum Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ethereum) の2日目の記事です。

今日は、Ethereum 入門者の方向けに「ERC20トークン」の作成方法をご紹介しようと思います。意外と簡単で驚かれるかもしれません。

# ERC20 トークンとは

ERC20 は、Ethereum ブロックチェーン上でトークンを発行する際の標準規格です。ERC20 に準拠したトークンであれば、無数に存在する種類のトークンを同じ枠組みで価値移転することができます。

ちなみに ERC とは「Ethereum RFC (Request for Comment)」の意味で、[その20番目だった](https://github.com/ethereum/EIPs/issues/20)ために「ERC20」と呼ばれます。仕様の詳細は以下にまとまっています。
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md

具体的には、以下の 6つの `function` と 2つの `event` を実装すれば、ERC20 トークンとなります。

```js
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 フレームワークのインストール](https://qiita.com/amachino/items/8cf609f6345959ffc450#truffle-%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
2. [OpenZeppelin ライブラリの導入](https://qiita.com/amachino/items/8cf609f6345959ffc450#openzeppelin-%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E5%B0%8E%E5%85%A5)
3. [Solidity コードの作成](https://qiita.com/amachino/items/8cf609f6345959ffc450#solidity-%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E4%BD%9C%E6%88%90)
4. [Solidity コードのコンパイル](https://qiita.com/amachino/items/8cf609f6345959ffc450#solidity-%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB)
5. [マイグレーションファイルの作成](https://qiita.com/amachino/items/8cf609f6345959ffc450#%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)
6. [コントラクトのデプロイ](https://qiita.com/amachino/items/8cf609f6345959ffc450#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%A9%E3%82%AF%E3%83%88%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)
7. [デプロイされたコントラクトの確認](https://qiita.com/amachino/items/8cf609f6345959ffc450#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%95%E3%82%8C%E3%81%9F%E3%82%B3%E3%83%B3%E3%83%88%E3%83%A9%E3%82%AF%E3%83%88%E3%81%AE%E7%A2%BA%E8%AA%8D)

# Truffle フレームワークのインストール

[Truffle](http://truffleframework.com/) は、Ethereum の開発フレームワークです。コントラクトコードのコンパイルやデプロイ、アドレス管理などの面倒を見てくれます。

以下のコマンドで、Truffle をインストールしてください[^1]。本記事執筆時点での Truffle の最新バージョンは 4.0.1 でした。

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

```
$ npm install -g truffle
```

新しくプロジェクトフォルダを作成して、`truffle init` を実行します。

```
$ mkdir ~/my_erc20_token
$ cd ~/my_erc20_token
$ truffle init
```

以下のようなフォルダ構成でファイル一式がダウンロードされたかと思います。

<img width="298" src="https://qiita-image-store.s3.amazonaws.com/0/10941/e0db15df-d201-5160-6df9-9e805ae9b7db.png">

# OpenZeppelin ライブラリの導入

[OpenZeppelin](https://openzeppelin.org/) は、Ethereum のスマートコントラクト開発を補助するライブラリです。ERC20 トークンの実装も含まれているので、今回はそれを使用します。

Truffle のプロジェクトフォルダの中で、以下のコマンドを実行してください。

```
$ npm init -f
$ npm install zeppelin-solidity --save
```

これで、OpenZeppelin のコードを、自分のコントラクトコードの中から使えるようになりました。 

# Solidity コードの作成

[Solidity](https://solidity.readthedocs.io/en/develop/) は、Ethereum のスマートコントラクトを記述するためのプログラミング言語の１つです。他にも使用できる言語はありますが、現時点では Solidity がデファクトスタンダードになっています。

では、ERC20 トークンの Solidity コードを書きましょう。`MyToken.sol` というファイルを `contracts` フォルダの中に用意し、以下のコードを記述してください。

```js

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;
  }
}

```

短いコードなので、順番に解説していきます。

```javascript
pragma solidity ^0.4.18;
```
↑ コンパイル時に使用する Solidity コンパイラのバージョンを指定しています。

```javascript
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
```
↑ OpenZeppelin ライブラリから、ERC20 の実装クラスである `StandardToken.sol` をインポートしています[^2]。

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

```javascript
contract MyToken is StandardToken {
  ...
}
```
↑ コントラクトの宣言です。`is StandardToken` の部分で、`MyToken` が `StandardToken` を継承していることを表しています。

```javascript
  string public name = "MyToken"; 
  string public symbol = "MTKN";
  uint public decimals = 18;
```
↑ コントラクトの状態変数 `name`, `symbol`, `decimals` に値を代入しています。ここでは、名前が "MyToken"、シンボルが "MTKN"、小数点の桁数が 18 のトークンとしています。

```javascript
  function MyToken(uint initialSupply) public {
    ...
  }
```

↑ コントラクト作成時に呼ばれるコンストラクタです。contract 名と同じ名称の function がコンストラクタとなります。



```javascript
    totalSupply_ = initialSupply;
```
↑ トークンの総発行量を表す `totalSupply_` という変数に、コンストラクタで受け取った `initialSupply` を代入しています。`totalSupply_` は、`MyToken` コントラクトが継承している OpenZeppelin の `StandardToken` が持つ状態変数です。


```javascript
    balances[msg.sender] = initialSupply;
```

発行したトークンを、全て `msg.sender` のアドレス（口座）に入れています。`msg.sender` は、コントラクト実行者の Ethereum アドレスを表し、`balances` は、アドレスをキーとした key/value 型の変数です。

# Solidity コードのコンパイル

では、記述した Solidity コードをコンパイルしましょう。

```
$ truffle compile
```

を実行すると、継承先のコントラクトも含めてコンパイルされます。ビルド結果は、`build/contracts` に、Truffle の Contract Artifact という形式の JSON ファイルで保存されます。

<img width="583" src="https://qiita-image-store.s3.amazonaws.com/0/10941/1ae7ca96-d42c-b263-56b2-a0c783953d75.png">

# マイグレーションファイルの作成

次に、`MyToken` コントラクトをデプロイするためのマイグレーションファイルを作成します。`migrations` フォルダの中に、`2_deploy_my_token.js` というファイルを作成し、以下のコードを記述します。

```javascript
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` コントラクトとやり取りしてみましょう。

```js
truffle(develop)> myToken = MyToken.at(MyToken.address)
...
```

とすると、`myToken` という変数に、デプロイされた `MyToken` コントラクトオブジェクトが代入されます。

例えば、

```js
truffle(develop)> myToken.name()
'MyToken'

truffle(develop)> myToken.totalSupply()
BigNumber { s: 1, e: 22, c: [ 500000000 ] }
```

とすると、トークンの名称、総発行量が確認できます[^3]。

[^3]: 数値は [BigNumber](https://github.com/MikeMcl/bignumber.js/) オブジェクトをで返されます

トークンの口座残高を見てみましょう。次のコマンドを打つと、Truffle が用意してくれたアドレスのリストが表示されます。

```js
truffle(develop)> web3.eth.accounts
[ '0x0...', ... ]
```

先程のデプロイは、一番目のアドレス (`web3.eth.accounts[0]`) で行ったことになるので、このアドレスに発行した全てのトークンが入っており、他のアドレスの残高はゼロになっています。

```js
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 だけ移してみましょう。

```js
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

- [Ethereum 開発者向けコミュニティを作ったよ](https://qiita.com/amachino/items/605ff76209d7193dc92c)
- [Ethereum スマートコントラクト入門：geth のインストールから Hello World まで](https://qiita.com/amachino/items/b59ec8e46863ce2ebd4a)

<a href="https://www.hi-ether.org/"><img src="https://slack.hi-ether.org/badge.svg">