ERC20の簡単なまとめ

#はじめに
ERC20を使って簡単にトークンを作れる、ということをよく聞くので、実際に作ってみようと思いました。
そして結論から言うと、作るだけなら簡単にできました。
[Truffle で始める Ethereum 入門 - ERC20 トークンを作ってみよう](https://qiita.com/amachino/items/8cf609f6345959ffc450#%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E4%BD%9C%E6%88%90%E3%81%AE%E6%B5%81%E3%82%8C)
この記事は開発環境から説明してありわかりやすいと思います。

ただ詳細を理解しようとすると、難しいところがありましたので、自分なりに重要だとまとめてみました。

#コントラクトの全体像
コントラクトの全体像は下記のようなコードになります。

MyToken.sol

```js
pragma solidity >=0.4.21 <0.6.0;

contract MyToken {
  string  public name = "My Token";　//Tokenの名前
  string  public symbol = "MY";　//Tokenの単位
  string  public standard = "Token v1.0";　//Tokenのバージョン
  uint256 public totalSupply; 

  event Transfer(
    address indexed _from, 
    address indexed _to, 
    uint256 _value
  );

  event Approval(
    address indexed _owner, 
    address indexed _spender, 
    uint256 _value
  );

  mapping(address => uint256) public balanceOf;
  mapping(address => mapping(address => uint256)) public allowance;
  
  constructor(uint256 _initialSupply) public {
    balanceOf[msg.sender] = _initialSupply;
    totalSupply = _initialSupply;
  }

  function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balanceOf[msg.sender] >= _value);
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  function approve (address _spender, uint256 _value) public returns (bool success) {
    //allowance
    allowance[msg.sender][_spender] = _value;
    //Approval event
    emit Approval (msg.sender, _spender, _value);

    return true;
  }
  function transferFrom (address _from, address _to, uint256 _value) public returns (bool success) {

    require(_value <= balanceOf[_from]);
    require(_value <= allowance[_from][msg.sender] );

    balanceOf[_from] -= _value;
    balanceOf[_to] += _value;

    allowance[_from][msg.sender] -= _value;

    emit Transfer(_from, _to, _value);
    return true;
  }
}
```

```2_MyToken_migration.js
var MyToken = artifacts.require("./MyToken.sol");

module.exports = function(deployer).then(function() { 
    deployer.deploy(MyToken, 1000000)
  });
};
```

上記のコードで個人的に重要だと思ったところを書いていきます。

# 1. constructor
コンストラクタはコントラクトのデプロイ時に実行される関数で、コントラクトに状態変数を持たせることができます。
ここでは`_initialSupply`が初期値として渡されています。

```js
pragma solidity >=0.4.21 <0.6.0;

contract MyToken {
  uint256 public totalSupply; 
  //constructor
  constructor(uint256 _initialSupply) public {
    //コントラクトの作成者に全てのトークンを持たせる
    balanceOf[msg.sender] = _initialSupply;
    totalSupply = _initialSupply;
  }
...
}
```

##コンストラクタ作成時の注意点
先ほど説明したように、「コントラクトのデプロイ時に実行される関数」ですので、migrationファイルで変数を渡すことを忘れないようにしましょう。
今回は`1000000`を`_initialSupply`として渡しました。

```js
//MyToken.sol
constructor(uint256 _initialSupply) public {
...
}
```
```2_MyToken_migration.js

var MyToken = artifacts.require("./MyToken.sol");
...
deployer.deploy(MyToken, 1000000)
```

###コンストラクタの書き方
Solidityではv0.4.23以降でコンストラクタの書き方が変わってるので参考にしてみてください。
[Ethereum: Solidity v0.4.23〜 の新しいコンストラクタの書き方](https://qiita.com/sot528/items/50548945325a0e63fe22)

balanceOf変数はmapping型（Key-Value配列）になっており、Keyがアカウントのアドレス、Valueが残高を表します。送金機能（transfer）を持っており、送金先のアカウントアドレスと送金額を指定することでトークンを送ることができます。

#2. mapping
```js
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
```
mappingは連想配列やデータ保管のキーバリューストアと言われています。
上記の１つ目ので例えると、`key`が`address`,`uint256`が`value`に当たります。

つまり`balanceOf()`関数を利用する際に、引数にaddress型のデータを与えることで、uint256型のデータを取得できる、と言う意味です。

```js
balanceOf[msg.sender] -= _value;
```
実際の使用例をみると`msg.sender`(メモ参照)はaddress型のデータですが、
このaddress型のデータに紐づくuint256型（数値）が取得されており、
同じuint256型（数値）である`_value`と同時に使えて計算できています。


#3. Transfer関数
Transfer関数は、関数を呼び出した人から、指定した`_to`にトークンを送る関数です。
Trensfer関数は必ずイベントを呼び出す必要があります。

```MyToken.js
  //Transfer event 必須
  event Transfer(
    address indexed _from, 
    address indexed _to, 
    uint256 _value
  );
...

  //Transfer関数
  function transfer(address _to, uint256 _value) public returns (bool success) {
    //Tokenを送る人が十分なTokenを保有してるか確認
    require(balanceOf[msg.sender] >= _value);
    //msg.senderから_toに送金され、各アカウントのトークンバランスを変更する
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
    //Transfer event の呼び出し
    emit Transfer(msg.sender, _to, _value);
    //boolをtrueに
    return true;
  }
```

#4. allowance関数, transferFrom関数, approve関数 
transferFrom, approve, approveは Delegate functionとも呼ばれており、
第三者がTokenの送信、受け取りを可能にする関数です。

## 4-1. approve関数

関数を呼びたした人が、`_spender`に対して、関数を呼びたした人の残高から`_value`分のTokenを引き出すことを許可する関数です。
Tokenの小切手のようにイメージするとわかりやすいと思います。

approve関数を使う際は、Approval eventの呼び出しが必須になります。

```js
function approve (address _spender, uint256 _value) public returns (bool success) {
  //allowance関数（4-2参照）
  allowance[msg.sender][_spender] = _value;
  //Approval eventの呼び出し
  emit Approval (msg.sender, _spender, _value);
  return true;
}
```

## 4-2.allowance関数

approve関数で小切手を受け取った`_spender`が引き出せるTokenの量を返す関数です。

allowanceはmappinngで定義し、approve関数内で使えるようにしています。

```js
mapping(address => mapping(address => uint256)) public allowance;
```

１つ目のaddressが、approve関数を呼び出した人、つまり小切手を渡した人
２つ目のaddressが、approve関数の`_spender`,つまり小切手を受け取った人
`uint256`は`_spender`が使える小切手の量を表します。

そして下記のように使えます。
第一引数に小切手を渡した人のアドレス、第二引数に小切手を受け取った人を与えることで
使える小切手の量を取得できます。

```js
allowance[msg.sender][_spender]
```

## 4-3. transferFrom関数
`transferFrom`関数は`Transfer`関数と似ていますが、
`Transfer`関数は関数の呼び出し者からある特定のアドレスにTokenを送信できるのに対し、
`transferFrom`は第三者があるアカウントからあるアカウントにTokenを送信することを可能にする関数です。

transferFrom関数は単独でも使えると思いますが、Transfer関数との違いを明確にするため
approve関数とallowance関数と一緒に使っています。

今回は、
approve関数で小切手を渡した人が関数を呼び出す人
`_from`がapprove関数で小切手を受け取った人
`_to`が実際にtokenを受け取る人
と仮定します。

```js
function transferFrom (address _from, address _to, uint256 _value) public returns (bool success) {
  
　//小切手を受け取った人の小切手の額が送信額より多いか
  require(allowance[_from][msg.sender] >= _value );
　//_toに送信され、_fromが保有する小切手の額を変更する
  balanceOf[_to] += _value;
  allowance[_from][msg.sender] -= _value;
　//Transfer eventの呼び出し
  emit Transfer(_from, _to, _value);
 
  return true;
```

#5.consoleでの動作確認

```js
truffle(development)> MyToken.deployed().then(function(instance) {tokenInstance = instance ; })
undefined
truffle(development)> tokenInstance
TruffleContract {
  constructor:
   { [Function: TruffleContract]
     _static_methods:
......
```

##Tokenの名前の取得

```js
truffle(development)> tokenInstance.name();
'My Token'
truffle(development)> tokenInstance.symbol();
'MY'
truffle(development)> tokenInstance.standard();
'My Token v1.0'
```

##totalSupplyの取得
`totalSupply`はpublicだけど`totalSupply`はconstructorのargumentでデプロイした際に定義されています。

```js
truffle(development)> tokenInstance.totalSupply().then(function (s) {supply = s});
undefined

truffle(development)> supply
BigNumber { s: 1, e: 6, c: [ 1000000 ] }
```

##Ganacheのaccount addressの取得

```js
truffle(development)> web3.eth.accounts
[ '0x82eb7aa8e65099fdffb14a0cca8f7eab0026dc86',
  '0xeb827c448545e8562d26e1d70741a7d5ced86ac3',
  '0x19235a06bbd84e0f475e17774ad61b9c76b4091d',
  '0x6322ea177d669ff5674412b49fce7eb05e8d167e',
  '0xb3ca53eddcdd60c96880cd84136b338394cc0406',
  '0x6f43c1b676d8b53fb9f28327881fec1134b9128a',
  '0x2642c077d5514c366e9248d7175d802c038b5e06',
  '0xc555ea1163931b5d8dd7e9bc1fc556e6cad2db69',
  '0x900c5e4572854faae159dbbd4314a1a05d2050f4',
  '0xf3dbc7b5c5710049674aaca74d7880ea28283a9f' ]

1番目のアドレスを取得
truffle(development)> web3.eth.accounts[0]
'0x82eb7aa8e65099fdffb14a0cca8f7eab0026dc86'
```

##Transer関数で送金
```jsx
//web3.eth.accounts[0]のバランスの確認
truffle(development)> tokenInstance.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 6, c: [ 1000000 ] }

//web3.eth.accounts[1]に10Tokenの送信
truffle(development)> tokenInstance.transfer(web3.eth.accounts[1], 10, {from: web3.eth.accounts[0]})
{ tx:
   '0x8a2f5c7efd2b7898663f7079723a193173a5f58ebd6170d2d12a0f3718558b66',
  receipt:
   { transactionHash:
      '0x8a2f5c7efd2b7898663f7079723a193173a5f58ebd6170d2d12a0f3718558b66',
     ...
      
```
＊web3.eth.accounts[0]はコントラクトの作成者になるので全てのTokenを保有します。

##残高の確認

```js
truffle(development)> tokenInstance.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 5, c: [ 999990 ] }

truffle(development)> tokenInstance.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 1, c: [ 10 ] }
```

##approve関数、allowance関数, transferFrom関数の確認

```js
truffle(development)> tokenInstance.approve(web3.eth.accounts[1], 100, {from: web3.eth.accounts[0]})
...

truffle(development)> tokenInstance.allowance(web3.eth.accounts[0], web3.eth.accounts[1]);
BigNumber { s: 1, e: 2, c: [ 10 ] }

truffle(development)> tokenInstance.transferFrom(web3.eth.accounts[0], web3.eth.accounts[2], 10, {from: web3.eth.accounts[1]})
...

truffle(development)> tokenInstance.balanceOf(web3.eth.accounts[2])
BigNumber { s: 1, e: 2, c: [ 10 ] }
truffle(development)> tokenInstance.allowance(web3.eth.accounts[0], web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }

```

わかりずらいかもしれませんが上記の流れを図で表すとこのようになります。

![スクリーンショット 2019-05-06 12.44.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342028/f30b9234-f821-3943-db73-8b10145432b1.png)

Aは`web3.eth.accounts[0]`
Bは`web3.eth.accounts[1]`
Cは`web3.eth.accounts[2]`
＊A(`web3.eth.accounts[0]`)はコントラクトをデプロイしたアドレスなので1000000Token持っています。


#メモ

開発を行う際に重要だと思ったことを簡単に整理しておきます。

##`_`をつける理由
関数の中でのみ使える変数は変数の前に`_`をつけて他の変数と区別する

##・msg.sender 
`msg.sender`はSolidityで使えるグローバル変数で、関数を呼び出したaddressを取得します。
[Solidityのグローバル変数リスト](https://solidity.readthedocs.io/en/v0.5.8/units-and-global-variables.html)

##require()
`require`の中身が`true`だった場合のみ、その後のコードを実行するが、
`true`出なかったら関数の処理を`error`にする。
errorになった場合、Gasは`msg.sender`に戻されます。

#参考サイト
[Code Your Own Cryptocurrency on Ethereum ](https://www.youtube.com/watch?v=XdKv5uwEk5A)
7時間ほどのビデオです。
基礎的なことから説明されているためかなりオススメです。

#終わりに
次はReactでフロントを作成してみようと思います。
また、自分の認識に間違いがあった場合はコメントください！！よろしくお願いします。