目次

ether.jsを使用したDApps開発

ether.js と React を使用して DApps を開発します。

完成したスースコードは shinoburc/SimpleReactEthereumClient で管理しています。

下記手順を実行するか、上記リポジトリを利用してください。

前提

Truffleを使ったスマートコントラクト開発 で作成した Counter スマートコントラクトを使用しますので、先に実施しておいてください。

MetaMask を使用しますので、MetaMaskの使用 を実施しておいてください。

Reactプロジェクトの生成

> npx create-react-app react-etherjs
Need to install the following packages:
  create-react-app
Ok to proceed? (y) y
npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.
 
Creating a new React app in C:\Users\miyazato\work\ethereum\react-etherjs.
 
Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...
 
 
added 1377 packages in 2m
 
179 packages are looking for funding
  run `npm fund` for details
 
Initialized a git repository.
 
Installing template dependencies using npm...
npm WARN deprecated source-map-resolve@0.6.0: See https://github.com/lydell/source-map-resolve#deprecated
 
added 39 packages in 17s
 
179 packages are looking for funding
  run `npm fund` for details
Removing template package using npm...
 
 
removed 1 package, and audited 1416 packages in 6s
 
179 packages are looking for funding
  run `npm fund` for details
 
6 moderate severity vulnerabilities
 
To address all issues (including breaking changes), run:
  npm audit fix --force
 
Run `npm audit` for details.
 
Created git commit.
 
Success! Created react-etherjs at C:\Users\miyazato\work\ethereum\react-etherjs
Inside that directory, you can run several commands:
 
  npm start
    Starts the development server.
 
  npm run build
    Bundles the app into static files for production.
 
  npm test
    Starts the test runner.
 
  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!
 
We suggest that you begin by typing:
 
  cd react-etherjs
  npm start
 
Happy hacking!
> cd react-etherjs

ether.js のインストール

ether.js の npm パッケージ名は ethers なので、それをインストールします。

react-etherjs> npm install --save ethers

フロントエンドの実装

react-etherjs> code .\src\App.js
import './App.css';
 
import React, {  useState } from "react";
import { ethers } from "ethers";
 
function App() {
  const [provider, setProvider] = useState(null);
  const [counter, setCounter] = useState(null);
  const [account, setAccount] = useState(null);
  const [count, setCount] = useState(null);
  const [transactionHash, setTransactionHash] = useState(null);
  const [transactionInfo, setTransactionInfo] = useState(null);
 
  // counterAddress と counterAbi は環境によって書き換える必要があります。
  // Counater.json を読み込んで利用するとよりスマート。
  const counterAddress = "0x5E5A16AaFb816F04E09a05d1C03d98D7b1ee56C2";
  const counterAbi = [
        {
        "constant": true,
        "inputs": [],
        "name": "count",
        "outputs": [
            {
            "internalType": "uint256",
            "name": "",
            "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
        },
        {
        "constant": true,
        "inputs": [],
        "name": "get",
        "outputs": [
            {
            "internalType": "uint256",
            "name": "",
            "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
        },
        {
        "constant": false,
        "inputs": [],
        "name": "inc",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
        },
        {
        "constant": false,
        "inputs": [],
        "name": "dec",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
        }
    ];
 
    //メタマスクの接続
    const connectMetaMask= () => {
        if (window.ethereum && window.ethereum.isMetaMask) {
            window.ethereum
                .request({ method: "eth_requestAccounts" })
                .then((accounts) => {
                    setAccount(accounts[0]);
                    let provider = new ethers.providers.Web3Provider(window.ethereum);
                    setProvider(provider);
                    let signer = provider.getSigner(0);
                    setCounter(new ethers.Contract(counterAddress, counterAbi, signer));
                })
                .catch((error) => {
                    console.log("MetaMask error" + error)
                });
        } else {
            console.log("Need to install MetaMask");
        }
    };
 
  // Counter.get でカウントの値を取得する関数
  const  getCount =  async () => {
    let count = await counter.get();
    setCount(count.toNumber());
  };
 
  // Counter.inc を呼び出す関数
  const  incCount =  async () => {
    let transaction = await counter.inc();
    // トランザクションが処理されるのを待つ
    await transaction.wait();
    setTransactionHash(transaction.hash);
    getCount();
  };
 
  // Counterdec を呼び出す関数
  const  decCount =  async () => {
    let transaction = await counter.dec();
    // トランザクションが処理されるのを待つ
    await transaction.wait();
    setTransactionHash(transaction.hash);
    getCount();
  };
 
  // transactionHash からトランザクション情報を取得する関数
  const getTransactionInfo =  async () => {
    let transactionInfo = await provider.getTransaction(transactionHash);
    setTransactionInfo(JSON.stringify(transactionInfo, null, 2));
  };
 
  return (
    <div className="App">
      <header className="App-header">
      <div>
        Account: { account }
        <div>
            Count: { count }
        </div>
        <div>
            TransactionHash: { transactionHash }
        </div>
        <input type="button" value="connect" onClick={ connectMetaMask }/>
        <input type="button" value="get" onClick={ getCount }/>
        <input type="button" value="inc" onClick={ incCount }/>
        <input type="button" value="dec" onClick={ decCount }/>
        <input type="button" value="getTransactionInfo" onClick={ getTransactionInfo } />
      </div>
      <div>
        <pre>
          { transactionInfo }
        </pre>
      </div>
      </header>
    </div>
  );
}
 
export default App;

実行

react-etherjs> npm start

「connect」をクリックすると MetaMask が立ち上がりますので、使用するアカウントを選択します。

アカウントが選択できたら他のボタンをクリックすることで Counter スマートコントラクトの各メソッドが実行できます。