OpenZeppelinのv2.0.0を使ってERC20トークンを発行してみよう

2018年9月にsolidityのライブラリであるOpenZeppelinのv2.0.0がリリースされました。それに伴い、OpenZeppelinを使ったERC20トークンの発行方法も変わっているので、ご紹介したいと思います。

# ERC20トークンとは
ERC20トークンとは、Ethereum上で発行されるトークンの規格の一種で、最も有名なものです。この規格はオープンに議論されており、下記リンクから参照可能です。
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md

この規格に対応したトークンを発行することで、対応している多くのウォレットで扱うことができるようになります。

# OpenZeppelinとは
OpenZeppelinnとはスマートコントラクト用のライブラリで、コントラクト実装には欠かせない存在です。
> OpenZeppelin is a battle-tested framework of reusable smart contracts for Ethereum and other EVM and eWASM blockchains.

`battle-tested` と書かれている通り、しっかりとテストされたコントラクトなので、安心して利用できます。（コントラクトは基本的に一度デプロイすると変更できないので、しっかりテストされたライブラリを活用して実装することがおすすめです）

**オフィシャルサイト**
https://openzeppelin.org/

**コード**
https://github.com/OpenZeppelin/openzeppelin-solidity

# ERC20トークンのコード
それでは、ERC20トークンを発行していきます。
solidityというEthereumのスマートコントラクト言語を用いて記述していきます。
以下が最終のERC20のコードです。

```javascript:MyToken.sol
pragma solidity >=0.5.0 <0.7.0;

import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";

contract MyToken is ERC20, ERC20Detailed {
    
    string private _name = "TAKASE";
    string private _symbol = "TKS";
    uint8 private _decimals = 18;
    
    address account = msg.sender;
    uint value = 100000000000000000000;
    
    constructor() ERC20Detailed( _name, _symbol, _decimals) public {
        _mint(account, value);
    }
}
```

ここから各行について解説していきます。

```javascript
pragma solidity >=0.5.0 <0.7.0;
```
ここで、solidityのコンパイラのバージョンを指定します。

```javascript
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
```
次に、OpenZeppelinから`ERC20.sol`と`ERC20Detailed.sol`をインポートしてきます。`ERC20.sol`では基本的なERC20の機能が実装されております。また、`ERC20Detailed.sol`には「名前」「シンボル」「小数点の桁数」の設定が可能になっています。

```javascript
contract MyToken is ERC20, ERC20Detailed {
    ...
}
```
`MyToken`という名前のコントラクトを定義し、`ERC20`, `ERC20Detailed`のコントラクトを継承します。

```javascript
string private _name = "TAKASE";
string private _symbol = "TKS";
uint8 private _decimals = 18;
```
発行するトークンの「名前」、「シンボル」、「小数点の桁数」の値を代入します。

```javascript
address account = msg.sender;
uint value = 100000000000000000000;
```
発行時のトークンをどのウォレットに付与するかを決定する必要があり、ここでは`msg.sender`（このコントラクトをデプロイした時のウォレット）のアドレスを代入しています。
また、`value`でトークンの初期発行数を設定しています。

```javascript
constructor() ERC20Detailed( _name, _symbol, _decimals) public {
    _mint(account, value);
}
```
constructor()とは、コントラクトをデプロイする時に１度だけ呼ばれるももので、初期値の設定などに活用されます。

今回のMyTokenコントラクトでは、`ERC20Detailed`のコントラクトを継承しているで、`ERC20Detailed`のコンストラクタもよんでおきます。引数には先ほど設定した、「名前」「シンボル」「小数点の桁数」を渡してあります。

また、` _mint()`は`ERC20.sol`で定義されている`internal`な関数で、継承している`MyToken`から呼び出しています。引数には先ほど定義したウォレットのアドレスと初期発行数を渡しています。

# 発行方法（コントラクトのデプロイ）
solidityのIDE（統合開発環境）を使って、実装したコントラクトをデプロイしていきます。

**Remix**
https://remix.ethereum.org/

具体的な方法については過去noteを参照いただけると幸いです。（記事中盤のRemix活用の部分）
https://note.mu/toshitoissho/n/n93eadf07fd47


# 機能の拡張
上記は、非常にシンプルなERC20を実装しました。
ですが、OpenZeppelinでは他にも機能拡張させたコントラクトを用意してくれています。
そこで、以下のように２種の概念を追加したERC20のコントラクトを実装してみます。

```javascript
pragma solidity >=0.5.0 <0.7.0;

import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";

contract MyToken is ERC20Mintable, ERC20Burnable, ERC20Detailed {
    
    string private _name = "TAKASE";
    string private _symbol = "TKS";
    uint8 private _decimals = 18;
    
    uint value = 100000000000000000000;
    
    constructor()
        ERC20Detailed(_name, _symbol, _decimals)
        ERC20Burnable()
        ERC20Mintable()
        public
    {
        _mint(msg.sender, value);
    }
}
```
追加したのは、
1. ERC20Mintable.sol
2. ERC20Burnable.sol

の２種です。

```javascript
constructor()
    ERC20Detailed(_name, _symbol, _decimals)
    ERC20Burnable()
    ERC20Mintable()
    public
{
    _mint(msg.sender, value);
}
```
実装は極めてシンプルで、importして継承したコントラクトをconstructorで呼び出すだけです。

では、具体的に何ができるようになったのか、以下で見ていきます。

### ERC20Mintable.sol
初期のシンプルなERC20では、初期に発行したトークンの数量を増やすことはできませんでした。

一方`ERC20Mintable`では、`mint`関数を使って、随時トークンの発行を可能にします。そのため、権限者の意図によって総発行数量を増やすことができます。

また、`addMinter`関数でトークンを発行する権利をもつウォレットを追加可能にしています。

### ERC20Burnable.sol
初期コントラクトでは、発行したトークンを増やすことができないのと同様に、減らすこともできませんでした。

一方、`ERC20Burnable.sol`は、発行したトークンをバーン（消去）することができます。そのため、総発行数量を減らすことができます。

# まとめ
OpenZeppelinの2.0.0では、目的別の実装がシンプルでわかりやすく実装できるようになった印象があります。ですが、結局のところERC20トークンはドシドシ発行したところで無価値すぎるので、どんな用途に使うのか考え抜いて発行しないといけないなと思います。
とりあえず、OpenZepplinを使ってみたい方や、v2.0.0になって戸惑っている方にお役立ちできる内容になっていれば幸いです。


以上