WEBアプリからコントラクトを呼び出そう
📒 Web アプリケーションからスマートコントラクトを呼び出す
このレッスンでは、MetaMaskの認証機能を使用して、Webアプリケーションから実際にあなたのコントラクトを呼び 出す機能を実装します。
WavePortal.sol
に実装したgetTotalWaves
関数を覚えていますか?
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
App.js
を以下のように更新して、フロントエンドからgetTotalWaves
関数へアクセスできるようにします。
/* ethers 変数を使えるようにする*/
import { ethers } from "ethers";
import React, { useEffect, useState } from "react";
import "./App.css";
const App = () => {
// ユーザーのパブリックウォレットを保存するために使用する状態変数を定義します。
const [currentAccount, setCurrentAccount] = useState("");
console.log("currentAccount: ", currentAccount);
// window.ethereumにアクセスできることを確認します。
const checkIfWalletIsConnected = async () => {
try {
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have MetaMask!");
return;
} else {
console.log("We have the ethereum object", ethereum);
}
// ユーザーのウォレットへのアクセスが許可されているかどうかを確認します。
const accounts = await ethereum.request({ method: "eth_accounts" });
if (accounts.length !== 0) {
const account = accounts[0];
console.log("Found an authorized account:", account);
setCurrentAccount(account);
} else {
console.log("No authorized account found");
}
} catch (error) {
console.log(error);
}
};
// connectWalletメソッドを実装
const connectWallet = async () => {
try {
const { ethereum } = window;
if (!ethereum) {
alert("Get MetaMask!");
return;
}
const accounts = await ethereum.request({
method: "eth_requestAccounts",
});
console.log("Connected: ", accounts[0]);
setCurrentAccount(accounts[0]);
} catch (error) {
console.log(error);
}
};
// waveの回数をカウントする関数を実装
const wave = async () => {
try {
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(
contractAddress,
contractABI,
signer
);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
console.log("Signer:", signer);
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
console.log(error);
}
};
// WEBページがロードされたときに下記の関数を実行します。
useEffect(() => {
checkIfWalletIsConnected();
}, []);
return (
<div className="mainContainer">
<div className="dataContainer">
<div className="header">
<span role="img" aria-label="hand-wave">
👋
</span>{" "}
WELCOME!
</div>
<div className="bio">
イーサリアムウォレットを接続して、「
<span role="img" aria-label="hand-wave">
👋
</span>
(wave)」を送ってください
<span role="img" aria-label="shine">
✨
</span>
</div>
{/* waveボタンにwave関数を連動させる。*/}
<button className="waveButton" onClick={wave}>
Wave at Me
</button>
{/* ウォレットコネクトのボタンを実装 */}
{!currentAccount && (
<button className="waveButton" onClick={connectWallet}>
Connect Wallet
</button>
)}
{currentAccount && (
<button className="waveButton" onClick={connectWallet}>
Wallet Connected
</button>
)}
</div>
</div>
);
};
export default App;
ここで実装した新しい機能は下記の3つです。
1 . ethers 変数を使えるようにする
import { ethers } from "ethers";
ethers
のさまざまなクラスや関数は、ethersproject が提供するサブパッケージからインポートできます。これは、Webアプリケーションからコントラクトを呼び出す際に必須となるので、覚えておきましょう。
2 . wave の回数をカウントする関数を実装する
const wave = async () => {
try {
// ユーザーがMetaMaskを持っているか確認
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(
contractAddress,
contractABI,
signer
);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
console.log("Signer:", signer);
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
console.log(error);
}
};
追加されたコードを見ながら、新しい概念について学びましょう。
I. provider
const provider = new ethers.providers.Web3Provider(ethereum);
ここでは、
provider
(= MetaMask) を設定しています。provider
を介して、ユーザーはブロックチェーン上に存在するイーサリアムノードに接続することができます。 MetaMask が提供するイーサリアムノードを使用して、デプロイされたコントラクトからデータを送受信するために上記の実装を行いました。
ethers
のライブラリによりprovider
のインスタンスを新規作成しています。
II. signer
const signer = provider.getSigner();
signer
は、ユーザーのウォレットアドレスを抽象化したものです。
provider
を作成し、provider.getSigner()
を呼び出すだけで、ユーザーはウォレットアドレスを使用してトランザクションに署名し、そのデータをイーサリアムネットワークに送信することができます。
provider.getSigner()
は新しいsigner
インスタンスを返すので、それを使って署名付きトランザクションを送信することができます。
III. コントラクトインスタンス
const wavePortalContract = new ethers.Contract(
contractAddress,
contractABI,
signer
);ここで、コントラクトへの接続を行っています。
コントラクトの新しいインスタンスを作成するには、以下 3 つの変数を
ethers.Contract
関数に渡す必要があります。
- コントラクトのデプロイ先のアドレス(ローカル、テストネット、またはイーサリアムメインネット)
- コントラクトの ABI
provider
、もしくはsigner
コントラクトインスタンスでは、コントラクトに格納されているすべての関数を呼び出すことができます。
もしこのコントラクトインスタンスに
provider
を渡すと、そのインスタンスは読み取り専用の機能しか実行できなくなります。一方、
signer
を渡すと、そのインスタンスは読み取りと書き込みの両方の機能を実行できるようになります。※ ABI についてはこのレッスンの終盤にて詳しく説明します。
3 . wave ボタンに wave 関数を連動させる
<button className="waveButton" onClick="{wave}">Wave at Me</button>
onClick