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

これからもエンジニアとして生きていくためには、ブロックチェーン・仮想通貨などを少しでも勉強しておかないと、やばい。
やばいぞ！

と感じ、最近やっと重い腰を上げて軽くさわり始めてみているおっさんが、時代に取り残されないよう足掻くために、アドベントカレンダーに参加してみました！
よろしくお願いいたします。

# 社内通貨(風)のものを作ってみたい

今勤務している会社では、その昔、社内通貨風なものがあり、イベントでその通貨が付与されたり配られたり、はたまたその通貨を使ってお菓子やジュースが買えたりなどなどしていました。
紆余曲折あり、近年は無くなってしまったのですが、せっかく仮想通貨の時代なので復活させたい！と思い、とりあえずテスト的にプロトタイプを作ってみることとします。
コンプライアンスやなんやかんやで、実運用にのせるまではまだまだ時間がかかる予感がするとしても！

# 下準備

## Hi-Ether に入れていただく

まず、初心者がアレコレするには、書籍やWebを検索して勉強するのはもちろんのことですが、それで動くものが出来たとしても、書き方が変じゃないのか？ふつーそうじゃないだろ的な感じで作ってないのか？とかを知るすべがありません。
逆に、コミュニティに入れていただいて相談できる環境があればとてもよいのではないでしょうか？

ということで、このアドベントカレンダーの初日に書いていただいている「Hi-Ether」に入れていただきました！

https://qiita.com/amachino/items/605ff76209d7193dc92c

まだ、質問などできるレベルに達していないとしても！

## 社内通貨(風)の仕様を考える

今勤務している会社では、理念経営ということもあり、社内の文化醸成の施策に力を入れています。
たとえば、

- ありがとうを伝えるカードを送りあう
- 力の入った社内新聞が毎月発行される
- 文化専任の社員がいる
- イベントの本気度がやばい
- イベントの頻度がすごく多い

などなど。

そこで、ありがとうを伝えるカードの代わりにスマートコントラクトを利用し、メッセージを送ると社内通貨(風)が同時に自動的に送られるようにしてみます。
また、送られたメッセージを見られるようにします。

そして、社内通貨(風)なので、社内の担当が通貨の発行総数を増やせるようにしたいと思います。

まとめると、

- ありがとうメッセージを送れる
- ありがとうメッセージを送ると自動的に社内通貨(風)も送られる
- 担当が発行総数を増やせる

という感じで行ってみたいと思います。

## 開発環境構築

まず、開発する環境を整備します。
このアドベントカレンダーの２日目、
「Truffle で始める Ethereum 入門 - ERC20 トークンを作ってみよう」
https://qiita.com/amachino/items/8cf609f6345959ffc450
こちらのやり方で作ってみたいと思います。

上記の
「OpenZeppelin ライブラリの導入」
までをやっておきます。

## テストネットワーク準備

今回は、Ropstenのテストネットを使って試してみようと思います。
gethとかでアレコレするのもよいのですが、お手軽にInfuraというサービスを使って簡単に準備します。

「Ropstenのテストネット上でERC20トークンを作成・送付してみる」
https://tech.pepabo.com/2017/12/06/erc20-token-on-ropsten/
こちらを参考にさせていただき、
「ネットワークの準備」
までやっておきます。

# 作ってみる

## InnoCoinのコードを書く

上記仕様をもとに、こんなコードを書いてみました。

```javascript:InnoCoin.sol
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/StandardToken.sol";

contract InnoCoin is StandardToken {

    string public name = "InnoCoin";
    string public symbol = "INNO";
    uint public decimals = 18;

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

    function InnoCoin(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;
    }

    // ありがとうメッセージを送ると、100INNOも一緒に送られる
    function thanks(address _to, string _message) public {
        transfer(_to, 100e18);
        thanksMessage[_to] = _message;
    }

    // 最新ありがとうメッセージを見る
    function thanksMessage(address _address) public constant returns (string) {
        return thanksMessage[_address];
    }

}
```

これを、contractsディレクトリに保存します

## コンパイルする

```shell
$ truffle compile
Compiling ./contracts/InnoCoin.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts
```

こんな感じでエラーがでなければOK！

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

```javascript:2_deploy_innocoin_erc20.js
const InnoCoin = artifacts.require('./InnoCoin.sol')

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

こんな感じの初期値でコントラクトを作成してみたいと思います。
このファイルをmigrationsディレクトリに作成します。

## テストネットにデプロイしてみる

「Ropstenのテストネット上でERC20トークンを作成・送付してみる」
https://tech.pepabo.com/2017/12/06/erc20-token-on-ropsten/
こちらを参考に、Infuraを使ってRopstenのテストネットデブロイして試してみます。

まず、下準備として、

```shell
$ npm install truffle-hdwallet-provider --save
```

で必要なモジュールを入れておきます。

さらに、デプロイに必要な処理として、

```javascript:truffle.js
var HDWalletProvider = require("truffle-hdwallet-provider");
var mnemonic = process.env.ROPSTEN_MNEMONIC;
var accessToken = process.env.INFURA_ACCESS_TOKEN;

module.exports = {
  networks: {
    ropsten: {
      provider: function() {
        return new HDWalletProvider(
          mnemonic,
          "https://ropsten.infura.io/" + accessToken
        );
      },
      network_id: 3,
      gas: 500000
    }   
  }
};
```

を更新しておきます。

そしていよいよ、

```shell
$ truffle migrate --network ropsten
```

でデプロイします。
正常にデプロイが完了すると、

```shell
$ truffle migrate --network ropsten
Using network 'ropsten'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0xbe4eafd7ffc78f34612c8007b7ef7600f22b41e84135314f6a66101a02f7ddfd
  Migrations: 0x6370928e9c6be135c464103996663bbc6f9855bb
Saving successful migration to network...
  ... 0xa3300a758b715799c0fdf93e781479ee07cfce31667b5e91e4ff181b9470530d
Saving artifacts...
Running migration: 2_deploy_innocoin_erc20.js
  Replacing InnoCoin...
  ... 0xe29f3ef3b2e88c38a8f7bf2bfa1515373c90cf6bd87059bc8410063d8741d25a
  InnoCoin: 0xe1c4675620ffb115e19a2b4623622a8c2a8d8c9a
Saving successful migration to network...
  ... 0xbef5b4877d32ab10bfa84b42aabcf7075d297462849b19aec17da10ea2cbad6c
Saving artifacts...
```

こんな感じになります。
ここで「0xe1c4675620ffb115e19a2b4623622a8c2a8d8c9a」がInnoCoinのコントラクトのアドレスに成ります。

## InnoCoinを使ってみる

### コントラクトの確認

まず、コントラクトがちゃんと出来ているか、Etherscanで見てみましょう。
https://ropsten.etherscan.io/token/[アドレス]
なので、
https://ropsten.etherscan.io/token/0xe1c4675620ffb115e19a2b4623622a8c2a8d8c9a
で見てみましょう。

<img width="512" alt="i1.png" src="https://qiita-image-store.s3.amazonaws.com/0/49971/5ed8e216-99e2-3a14-5305-da9e3e5bd755.png">

ちゃんと、InnoCoinがERC20トークンとして認識されているようです。

### ありがとうを送る

では、truffleのコンソールからありがとうを送ってみます。
わたしのテストネットのアドレスは、

```
0x86D3bC6531B5c55b29803580a7eA5d353826d67b
```

なので、ここへ送ってみます。

```
$ truffle console --network ropsten
truffle(ropsten)> contract = InnoCoin.at("0xe1c4675620ffb115e19a2b4623622a8c2a8d8c9a")
　省略・・・
truffle(ropsten)> contract.thanks("0x86D3bC6531B5c55b29803580a7eA5d353826d67b", "Thanks for create InnoCoin!")
　省略・・・
truffle(ropsten)> contract.thanksMessage("0x86D3bC6531B5c55b29803580a7eA5d353826d67b")
'Thanks for create InnoCoin!'
```

ちゃんとメッセージが送られました。
Etherscanで、InnoCoinも送られているか見てみましょう。

<img width="1154" alt="i2.png" src="https://qiita-image-store.s3.amazonaws.com/0/49971/8c38e8ce-6e05-ea84-7508-5de97eba0504.png">

あれ？
100INNOおくったつもりが、0.0000000000000001INNOになっちゃってます・・・

ここは伸びしろっていうことで、調べておきます！笑

2017/12/23追記
> transfer(_to, 100) じゃなくて transfer(_to, 100e18) ですね！

amachinoさんにコメントでご教示いただきまして、修正しておきました！
これで100INNO送られます！

ちなみに、スマートコントラクトを再デプロイするときは、

```
truffle migrate --network ropsten --reset
```

でできました。

# まとめ

もはや、いろいろツールや情報がそろっているので、ここくらいまでは驚くほど簡単にできました！
実際に社内で運用できるように、フロントを作るなどブラッシュアップしていきたいと思います。
これを機に、実際に仮想通貨やトークンに触れる機会を、社内をはじめ、まわりの人にどんどん提供していきたいと思います！

以上でした。