【初めてのDApps開発①】ReactでシンプルなDAppsを作ってみよう！~コントラクト編~

#はじめに
私はつい最近までブロックチェーンって何？なんか面白そう！ってゆー感じだったDApps開発初心者です。
この記事は、**Ethereumで簡単なDappsを作ってDapps開発の流れを掴んでいくのが目的**です。
自分が初めてDAppsを作る際にあったらよかったなあ〜と感じたロードマップを書きました。

この開発では以下の３つの項目を行っていきます。
3項目の内この記事では、1と2を行なっていきます。3については、[【初めてのDApps開発②】](https://qiita.com/sho11hei12-1998/items/1f8e2ad18ee9fb23eb01)の記事を参照して下さい。

>**1. Remixを用いたスマートコントラクト開発**
**2. Truffleを用いたスマートコントラクトのデプロイ**
3. Reactを用いたフロントエンド開発

#作っていくアプリケーション

今回作成するアプリケーションはブロックチェーン上に自分の氏名、年齢、趣味をブロックチェーン上に記録するだけのシンプルなものです。
URL: [https://diarydapp-2a69c.web.app](https://diarydapp-2a69c.web.app)

完成するアプリケーションは、以下のものなります。
1. 左側のフォームでユーザーの氏名、年齢、趣味を入力。入力された情報は、ブロックチェーン上に記録。
2. 右側のフォームでユーザー情報の検索を行う。検索したいユーザーのアドレスを入力。
3. 入力されたアドレスを持つユーザーの情報を表示。

![スクリーンショット 2020-11-29 11.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/3db09300-1644-3001-6c06-960314363ad2.png)

本記事では、スマートコントラクトの開発からデプロイまでを行っていきます！
では、一緒に開発を進めていきましょう！！



#Remixでスマートコントラクト開発

[Remix](https://remix.ethereum.org/#optimize=false&version=soljson-v0.5.0+commit.1d4f565a.js&evmVersion=null)はブラウザ上でスマートコントラクトを作成し、テストができるツールです。
リンクからRemixを開き、
左上の+マークをクリックしてファイルを作成し、コントラクトを書いていきます。

>今回扱う言語Solidityについては、こちらを参考にしてください。
[【Solidity入門】まず最初にSolidityで覚えるべき基本構文まとめ](https://qiita.com/sho11hei12-1998/items/31ed7c5d4c2f34409223)
[Solidity公式ドキュメント](https://solidity-jp.readthedocs.io/ja/latest/)

###コントラクト作成
今回使用するコントラクトは以下のものを使います。

```Resister.sol
// コンパイラのバージョン指定（0.5.0以上）
pragma solidity ^0.5.0;

contract Resister {
    
    // アカウント情報
    struct Data {
        string name; // 名前
        uint256 age; // 年齢
        string hobby; // 趣味
    }
   
    address[] public users; // 全ユーザーのアドレスを格納

    mapping(address => Data) accounts;
    
    // アカウントを登録する関数
    function registerAccount(string memory _name, uint256 _age, string memory _hobby)
        public
        returns (bool)
    {
        //アカウントが登録されていなければ新規会員登録をする
        if (!isUserExist(msg.sender)) {
            users.push(msg.sender);
        }
        accounts[msg.sender].name = _name;
        accounts[msg.sender].age = _age;
        accounts[msg.sender].hobby = _hobby;
        return true;
    }

    // アカウントが登録されているかどうかを確認
    function isUserExist(address user) public view returns (bool) {
        for (uint256 i = 0; i < users.length; i++) {
            if (users[i] == user) {
                return true;
            }
        }
        return false;
    }

    // アカウント情報を読み込む
    function viewAccount(address user) public view returns (string memory, uint256, string memory) {
        string memory _name = accounts[user].name;
        uint256 _age = accounts[user].age;
        string memory _hobby = accounts[user].hobby;

        return (_name, _age, _hobby);
    }   
}
```

一つずつ見ていきましょう。


```
struct Data {
        string name; 
        uint256 age; 
        string hobby; 
    }
```
これはデータの構造体です。氏名、年齢、趣味を記録します。stringは文字列を指定します。uint256 はデータの型で256bitまでの符号なし整数(自然数)を指定します。

```
address[] public users; 

mapping(address => Data) accounts;
```

上は配列です。氏名、年齢、趣味を記録したユーザーのETHアドレスを保存します。 solidityにはaddress型というデータ型が存在します。

配列の下はデータとデータを紐付けるためのものです。例えば, `accounts[ETHアドレス] `とすると上で定義した任意のData構造体にアクセスできます。

```
function registerAccount(string memory _name, uint256 _age, string memory _hobby)
        public
        returns (bool)
    {
        if (!isUserExist(msg.sender)) {
            users.push(msg.sender);
        }
        accounts[msg.sender].name = _name;
        accounts[msg.sender].age = _age;
        accounts[msg.sender].hobby = _hobby;
        return true;
    }
```

これは、アカウント情報（氏名、年齢、趣味）の登録を行う関数です。
`msg.sender `はトランザクションの送信者のアドレスです。ユーザーがすでに配列に含まれているかを確認して, `users[]`に追加します。
`accounts[msg.sender].name = _name`のようにしてアドレスに紐づく構造体にデータを追加します。

```
function isUserExist(address user) public view returns (bool) {
        for (uint256 i = 0; i < users.length; i++) {
            if (users[i] == user) {
                return true;
            }
        }
        return false;
    }
```

これは、ユーザーが配列（`users[]`）に含まれているかどうかを調べる関数です。

```
function viewAccount(address user) public view returns (string memory, uint256, string memory) {
        string memory _name = accounts[user].name;
        uint256 _age = accounts[user].age;
        string memory _hobby = accounts[user].hobby;

        return (_name, _age, _hobby);
    }   
```

アドレスに紐づくデータをみるための関数です。
`string memory _name = accounts[user].name` のようにして, 構造体に記録されているデータを取得します。最後に氏名、年齢、趣味を返り値として返します。

###コントラクトのテスト
次は、コントラクトのテストを行っていきます。
まず最初に、画面左の**SOLIDITY COMPILER**タブに移動。COMPILERを以下の画像で選択されている`0.5.0+commit. 1d4f565a`に選択。それ以上のバージョンなら問題ないと思います。

選択したら、画面中部の**青いボタン**`Compile Resister.sol`を押せばコンパイルしてくれます（⌘＋Sでも可能）。
コンパイルが完了すると、画像のようにチェックマークが付きます。

![スクリーンショット 2020-11-18 20.15.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/5185399d-fea6-67ff-da00-7b5a3b9b4deb.png)



コンパイルが完了したら、次に**DEPLOY & RUN TRANSACTIONS**タブに移動します。
ENVIRONMENT を `JavaScriptVM`に設定, CONTRACTはResisterを選択し, Deploy をクリックします。

![スクリーンショット 2020-11-18 20.35.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/a55ebb9d-f36b-54fc-7c7d-589f795535d6.png)

次に関数をテストしていきます。
`Deployed Contracts`欄から
まず, `resisterAccount` に 適当に氏名、年齢、趣味を入力し, `transact`ボタンをクリックします。

![スクリーンショット 2020-11-18 20.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/6398b67c-31ec-df2f-1ec8-3e070ed54167.png)

以下のように表示されれば関数呼び出し成功です。
![スクリーンショット 2020-11-18 21.03.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/e36586b7-f429-91c6-b514-06d7b653cb54.png)

次に `users` に `0` を入力し, `call`ボタン をクリックします。これは usersの配列の0番目の要素を取得しています。すると先ほど resisterAccountを実行したアドレスが表示されます。
そのアドレスをコピーして `viewAccount` に入力します。そして `call` ボタンをクリックすると登録したデータが呼び出されます。

![スクリーンショット 2020-11-18 21.18.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/e263a71a-1d28-d79f-0ab2-fc138fac9290.png)


以上のことが問題なく動作できればテストは完了です。


#Truffleでスマートコントラクトをデプロイ
Truffleはスマートコントラクトをテストしたり, デプロイしたりできるツールです。 今回はRinkebyテストネットにコントラクトをデプロイするためだけに使います。

今後nodeとnpmがインストールされていることを前提に話を進めます。
インストールされていない方はこちらの記事などを参考にしてください。
Mac用：[買いたてのＭacにNode.jsとnpmをインストール](https://qiita.com/taketakekaho/items/dd08cf01b4fe86b2e218)
Windows用：[Node.js / npmをインストールする（for Windows）](https://qiita.com/taiponrock/items/9001ae194571feb63a5e)

↓私のバージョンです。
>node：v14.2.0
npm：v6.14.8

まずTruffleのコマンドラインツールをインストールします。

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

ディレクトリを作って移動し,`truffle init` します. このコマンドで色々ファイルが生成されます。その後 `truffle-hdwallet-provider` をインストールしてください。


```
$ mkdir dapps-deploy
$ cd dapps-deploy
$ truffle init
$ npm i --save truffle-hdwallet-provider
```

###infuraエンドポイント& ニーモニック取得
次にinfuraでプロジェクトを作ります。infuraはEthereumノードを提供してくれるツールです。infuraを利用することでEthereumブロックチェーンに接続できるようになります。


![スクリーンショット 2020-11-21 15.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/61dc6f21-ce66-1e5d-a5cd-a5dc755ceb76.png)




ユーザー登録を済ませたらプロジェクトを作成。作成したプロジェクトに移動しSETTING画面へ。  `KEYS` の `ENDPOINT` で `RINKEBY` を選択します。このエンドポイントはあとで使用します。

次に、Metamask のニーモニック（12個の英単語）を取得します。
![45a7e0137f6e059636572f2b98db9db7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/dfca30ca-f532-fa25-b100-17307b68b66e.png)

まず、[Metamask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=ja)をインストールしましょう。
インストール後、Metamaskを起動して右上のアカウントマークをクリック→、設定→, Security & Privacyを選択。パスフレーズを表示をクリックし, ニーモニックを取得します。

>※[注意]ニーモニックの流出は秘密鍵の流出を意味するので, 絶対にGithubなどにそのまま公開しないように！


###ファイルの作成&編集
`dapps-deploy` ディレクトリ下の `truffle-config.js` を編集します。
以下をコピペして先ほど取得したメタマスク のニーモニックとinfuraのエンドポイントを指定の場所に貼ります。


```
var HDWalletProvider = require("truffle-hdwallet-provider");
var mnemonic = 'メタマスクのニーモニック';
var accessToken = 'infuraのエンドポイント';
const gas = 4000000;
const gasPrice = 1000000000 * 60;
module.exports = {
  networks: {
    rinkeby: {
      provider: function () {
        return new HDWalletProvider(
          mnemonic,
          accessToken
        );
        },
        network_id: 4,
        gas: gas,
        gasPrice: gasPrice,
        skipDryRun: true
      }
    },
    compilers: {
      solc: {
        version: "0.5.2",
      }
    }
};
```

次に `dapps-sample` 下の `migrations` ディレクトリに `2_deploy_contract.js` というファイルを作成してください。以下のように編集してください。
.require('ここで.solの**コントラクト名**を指定')

```
var contract = artifacts.require('Resister');
module.exports = function(deployer) {
  deployer.deploy(contract)
};
```


最後に`dapps-deploy` 下の `contract` ディレクトリに `Resister.sol` というファイルを作成し, Remixで作成したコントラクトを貼ります。

```Resister.sol
pragma solidity ^0.5.0;

contract Resister {
    
    struct Data {
        string name; 
        uint256 age; 
        string hobby; 
    }
   
    address[] public users; 

    mapping(address => Data) accounts;
    
    function registerAccount(string memory _name, uint256 _age, string memory _hobby)
        public
        returns (bool)
    {
        if (!isUserExist(msg.sender)) {
            users.push(msg.sender);
        }
        accounts[msg.sender].name = _name;
        accounts[msg.sender].age = _age;
        accounts[msg.sender].hobby = _hobby;
        return true;
    }

    function isUserExist(address user) public view returns (bool) {
        for (uint256 i = 0; i < users.length; i++) {
            if (users[i] == user) {
                return true;
            }
        }
        return false;
    }

    function viewAccount(address user) public view returns (string memory, uint256, string memory) {
        string memory _name = accounts[user].name;
        uint256 _age = accounts[user].age;
        string memory _hobby = accounts[user].hobby;

        return (_name, _age, _hobby);
    }
    
}
```

最終的なファイル構成はこのようになっています。
![スクリーンショット 2020-12-02 19.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/88e536d8-8434-78ac-1aaf-87c0e6051f4c.png)


###Rinkebyネットワークへのデプロイ
いよいよコントラクトをデプロイします！
rinkebyのETHを持っていないとデプロイ時にGAS代が足りずにはじかれるので、ある程度ETHを持っている必要があります。
僕は以下の記事を参考にして補充しました。

[EtherumのRinkebyテストネットでethを取得する](https://tech.nerune.co/blockchain/faucet-eth/)

完了したら以下のコマンドを実行してください。

```
$ truffle compile
$ truffle migrate --network rinkeby --reset
```

このように返ってきたらデプロイ成功です！お疲れ様です！
あなたが作成したスマートコントラクトがブロックチェーンにデプロイされました！

![スクリーンショット 2020-11-22 20.30.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526953/82f2c4e6-2db5-e172-d59e-40a278a50b88.png)


#最後に
ここまでで、コントラクトのデプロイまでを行うことができるはずです!!
次は、アプリケーションの見た目の部分であるフロントエンドの開発に取り掛かります。
続編となっている[【初めてのDApps開発②】](https://qiita.com/sho11hei12-1998/items/1f8e2ad18ee9fb23eb01)の記事も見てもらえると嬉しいです！