MyToken発行してみた(開発環境編)

> **Note：**記事は執筆時点（2018年6月）の内容です。技術の進歩が早く、今後陳腐化する可能性もあるのでご留意ください。

# はじめに
* ERC20のオリジナルトークンを作ってみよう
* Solidityでコントラクトを作成して、ローカル環境にデプロイしよう


# 事前準備
* 必要なもの
    * Ubuntu
    * Node.js
    * Truffle
    * 開発用エディタ（Visual Studio Code など）

* 環境構築がまだの方はこちらから↓

> **Ethereum開発環境構築：Windows編**

> * https://qiita.com/ttoori-ttoori/items/ffb20fe07d3913a1891f

# 参考資料
* 以下の先生の記事を参考しながら、進めます。先生に感謝。

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

> * https://qiita.com/amachino/items/8cf609f6345959ffc450

> **EthereumのERC20 トークンとして社内通貨(風)のものを作ってみます**

> * https://qiita.com/Yaggytter/items/9df7e35e8725c3baad82


# 作業の流れ
1. プロジェクトフォルダの作成
2. OpenZeppelinのインストール
3. Solidityコードの作成
4. Solidity コードのコンパイル
5. マイグレーションファイルの作成
6. コントラクトのデプロイ
7. デプロイされたコントラクトの確認


# 【手順1】プロジェクトフォルダの作成
* シェルで以下コマンドを実行

### プロジェクトフォルダの作成
```bash
# 作業フォルダ（mntした共有フォルダ）に移動後、以下のコマンドを実行
$ mkdir mycoin
$ cd mycoin

# truffleのinitコマンドでコントラクトの雛形を作成
$ truffle init

# 作成されたフォルダを確認
$ tree -L 2

## 実行結果（例）
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
├── truffle-config.js
└── truffle.js

3 directories, 4 files

# デフォルト設定でpackage.jsonを作成
$ npm init -f
```

> **Note：**`mycoin`の部分を各自変更してください。
> 例）tooricoin


# 【手順2】OpenZeppelinのインストール
* シェルで以下コマンドを実行
 
### OpenZeppelinのインストール
```bash
# OpenZeppelinのインストール
$ npm install zeppelin-solidity --save
```

> **Note：**OpenZeppelinは、ERC20のコントラクトが実装済みです。
> コントラクトの中でimportすることで、簡単にERC20のコントラクトを作成できます。

# 【手順3】Solidityコードの作成
* `contracts`フォルダに移動
* VS Codeで`MyCoin.sol`ファイルを作成

> **Note：**`MyCoin`の部分を各自変更してください。
> 例）TooriCoin.sol

* ファイル作成し、エディタで以下コードを貼り付け

### Solidityコードの作成（サンプル）
```js:MyCoin.sol
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";

contract MyCoin is StandardToken {

    string public name = "MyCoin";
    string public symbol = "MYCO";
    uint public decimals = 18;

    address public owner;
    mapping (address => string) public thanksMessage;
    uint public maxSupply;
    uint public totalSupply;

    constructor(uint _initialSupply, uint _maxSupply) public {
        owner = msg.sender;
        totalSupply = _initialSupply;
        maxSupply = _maxSupply;
        balances[msg.sender] = _initialSupply;
    }

    function addTotalSupply(uint256 _value) public {
        require(owner == msg.sender);
        require(maxSupply >= (totalSupply + _value));

        totalSupply += _value;
        balances[msg.sender] += _value;
    }

    function thanks(address _to, string _message) public {
        transfer(_to, 100e18);
        thanksMessage[_to] = _message;
    }

    function thanksMessage(address _address) public view returns (string) {
        return thanksMessage[_address];
    }

}
```
> **Note**：コントラクトコードの説明

> * 変数定義の他に`constructor`と3つの`function`を定義しています

> * `constructor`：コントラクト作成時に呼ばれるコンストラクタ

> * `function addTotalSupply(uint256 _value)`：Coinの発行総数を増やす関数。増加数を引数に与えます。

> * `function thanks(address _to, string _message)`：ありがとうメッセージと一緒にCoinを送信する関数。送信先アドレスとメッセージを引数に与えます。POSTメソットのイメージです。

> * `function thanksMessage(address _address)`：送信されたthanksMessageを参照する関数。送信先アドレスを引数に与えます。GETメソットのイメージです。




* 今回は自分のTokenを作成したいので、以下のようにカスタマイズ。

### Solidityコードの作成（実装例）
```js:TooriCoin.sol
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";

contract TooriCoin is StandardToken {

    string public name = "TooriCoin";
    string public symbol = "TORI";
    uint public decimals = 18;

    address public owner;
    mapping (address => string) public thanksMessage;
    uint public maxSupply;
    uint public totalSupply;

    constructor(uint _initialSupply, uint _maxSupply) public {
        owner = msg.sender;
        totalSupply = _initialSupply;
        maxSupply = _maxSupply;
        balances[msg.sender] = _initialSupply;
    }

    function addTotalSupply(uint256 _value) public {
        require(owner == msg.sender);
        require(maxSupply >= (totalSupply + _value));

        totalSupply += _value;
        balances[msg.sender] += _value;
    }

    function thanks(address _to, string _message) public {
        transfer(_to, 100e18);
        thanksMessage[_to] = _message;
    }

    function thanksMessage(address _address) public view returns (string) {
        return thanksMessage[_address];
    }

}
```

> **Note：**変更箇所は以下の通り

> * contract名を`MyCoin`から`TooriCoin`に変更

> * nameを`MyCoin`から`TooriCoin`に変更

> * symbolを`MYCO`から`TORI`に変更


# 【手順4】Solidity コードのコンパイル
* シェルで以下コマンドを実行

### Solidity コードのコンパイル
```bash
# Solidity コードのコンパイル
$ truffle compile
```

* 正常にコンパイルされると`build`フォルダの中にjsonファイルが作成される

### コンパイル結果の確認
```bash
# コンパイル結果の確認
$ cd build
$ tree -L 2

## 実行結果（例）
.
└── contracts
    ├── BasicToken.json
    ├── ERC20.json
    ├── ERC20Basic.json
    ├── Migrations.json
    ├── MyToken.json
    ├── SafeMath.json
    ├── StandardToken.json
    └── TooriCoin.json

1 directory, 8 files
```

# 【手順5】マイグレーションファイルの作成
* `migrations`フォルダに移動
* VS Codeで`2_deploy_MyCoin.js`ファイルを作成

> **Note：**`MyCoin`の部分を各自変更してください。
> 例）2_deploy_TooriCoin.js

> **Note：**Ethereumでは、デプロイのことをマイグレーションと呼びます。
> migrationsフォルダでは、デプロイ内容をjsファイルに定義します。

> migrationファイルは`[数字]_[名称].js`という形式にする必要があります。
> [数字]の順にmigrationが実行されます


* ファイル作成し、エディタで以下コードを貼り付け

### Migrationファイルの作成（サンプル）
```js:2_deploy_MyCoin.js
const MyCoin = artifacts.require('./MyCoin.sol')

module.exports = (deployer) => {
    let initialSupply = 1000000e18
    let maxSupply = 100000000e18
    deployer.deploy(MyCoin, initialSupply, maxSupply, {
        gas: 2000000
    })
}
```


* 今回は自分のTokenを作成したいので、以下のようにカスタマイズ。

### Migrationファイルの作成（実装例）
```js:2_deploy_TooriCoin.js
const TooriCoin = artifacts.require('./TooriCoin.sol')

module.exports = (deployer) => {
    let initialSupply = 1000000e18
    let maxSupply = 100000000e18
    deployer.deploy(TooriCoin, initialSupply, maxSupply, {
        gas: 2000000
    })
}
```

> **Note：**変更箇所は以下の通り

> * `MyCoin`から`TooriCoin`に変更

# 【手順6】コントラクトのデプロイ
* シェルで以下コマンドを実行

### エミュレータの起動
```bash
# ローカルでのエミュレータの起動
$ truffle develop

// 実行結果（例）
Truffle Develop started at http://127.0.0.1:9545/

Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de

Private Keys:
(0) c87...
(1) ae6...
(2) 0db...
(3) c88...
(4) 388...
(5) 659...
(6) 82d...
(7) aa3...
(8) 0f6...
(9) 8d5...

Mnemonic: candy ...
```

* エミュレータ起動後に、truffleのコンソールモードになるので、以下コマンドを実行してデプロイ

### コントラクトのデプロイ
```js
// コントラクトのデプロイ
$ truffle(develop)> migrate

// 実行結果（例）
Using network 'develop'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x63fb52c38e0c0a6ffb49344b27f96222178399bae48b7bffe5cb1c4b9d808bd9
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_tooricoin.js
  Deploying TooriCoin...
  ... 0x7b30330b3c0f4f3c9ed0b90761be5ae7da706ea7ddb054bcf27eb854adf31d57
  TooriCoin: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
```

> **Note：**migrateコマンドを実行したときに表示されるコントラクトのアドレス（0xで始まるコード）をこのあと使用するので控えておきましょう
> 例）TooriCoin: **0x345ca3e014aaf5dca488057592ee47305d9b3e10**



# 【手順7】デプロイされたコントラクトの確認
* truffleコンソールで以下コマンドを実行

### コントラクトのインスタンス化
```js
// コントラクトをインスタンス化します
truffle(develop)> contract = TooriCoin.at("<コントラクトのアドレス>")

// 実行結果（例）
[{...}] （contractが表示される。長いので省略）

```

* コントラクトの基礎情報を確認してみます

### コントラクトの基礎情報確認
```js
// コントラクトの名称を表示
truffle(develop)> contract.name()

// 実行結果（例）
'TooriCoin'

// Tokenの総額を表示
truffle(develop)> contract.totalSupply()

// 実行結果（例）
BigNumber { s: 1, e: 24, c: [ 10000000000 ] }
```

* ローカル環境上のアカウントの一覧を表示してみます

### アカウント一覧の表示
```js
// アカウント一覧の表示
truffle(develop)> web3.eth.accounts

// 実行結果（例）
[ '0x627306090abab3a6e1400e9345bc60c78a8bef57',
  '0xf17f52151ebef6c7334fad080c5704d77216b732',
  '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef',
  '0x821aea9a577a9b44299b9c15c88cf3087f3b5544',
  '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2',
  '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e',
  '0x2191ef87e392377ec08e7c08eb105ef5448eced5',
  '0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5',
  '0x6330a553fc93768f612722bb8c2ec78ac90b3bbc',
  '0x5aeda56215b167893e80b4fe645ba6d5bab767de' ]
```

> **Note：**ローカル環境上のアカウントはtruffle developコマンド実行時にtruffleが自動的に作成してくれます


* 各アカウント毎の残高を表示してみます

### アカウント毎の残高確認（実行前）
```js
// 0番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[0])

// 実行結果（例）
BigNumber { s: 1, e: 24, c: [ 10000000000 ] }

// 1番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])

// 実行結果（例）
BigNumber { s: 1, e: 0, c: [ 0 ] }
```

* 0番目のアカウントから1番目のアカウント(**0xf17f52151ebef6c7334fad080c5704d77216b732**)に対して、メッセージとTokenを送信してみます

### メッセージとTokenの送信
```js
// メッセージとTokenを送信
truffle(develop)> contract.thanks("0xf17f52151ebef6c7334fad080c5704d77216b732", "Thanks!")

// 実行結果（例）
{ tx:
   '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
  receipt:
   { transactionHash:
      '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
     transactionIndex: 0,
     blockHash:
      '0xd699f8e854ab2c79e935229093d9f932d8ebe8ee9b949a77297e781b292a8674',
     blockNumber: 5,
     gasUsed: 73071,
     cumulativeGasUsed: 73071,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash:
        '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
       blockHash:
        '0xd699f8e854ab2c79e935229093d9f932d8ebe8ee9b949a77297e781b292a8674',
       blockNumber: 5,
       address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }
```

> **Note：**ローカル環境でテストする場合は、thanks関数の第一引数の`0xf17f52151ebef6c7334fad080c5704d77216b732`を`web3.eth.accounts[1]`と入力してもOKです。

* メッセージ送信後の各アカウント毎の残高を表示してみます

### アカウント毎の残高確認（実行後）
```js
// 0番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[0])

// 実行結果（例）
BigNumber { s: 1, e: 23, c: [ 9999000000 ] }

// 1番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])

// 実行結果（例）
BigNumber { s: 1, e: 20, c: [ 1000000 ] }
```

* メッセージ内容を表示してみます

### メッセージ内容の表示
```js
// メッセージ内容の表示
truffle(develop)> contract.thanksMessage(web3.eth.accounts[1])

// 実行結果（例）
'Thanks!'
```

> **Note：**Tokenだけでなく、メッセージもEthereum上に記録されていることが確認できます


# まとめ
* ローカル環境上でERC20のオリジナルトークンを作ることができました！
* 次のステップとして、作成したコントラクトをEthereumのテスト環境にデプロイしてみましょう

> **MyToken発行してみた(テスト環境編)**

> * https://qiita.com/ttoori-ttoori/items/865c6f9e45ad8b74c47d