WEBアプリからコントラクトを呼び出そう
☘️ Web アプリケーションから NFT を Mint する
前回のレッスンでは、Webアプリケーションを立ち上げました。
これから、Web アプリケ ーションからMyEpicNFT.sol
コントラクトにアクセスして、NFT を発行するmakeAnEpicNFT
関数を呼び出していきましょう。
- 以前のレッスンで
makeAnEpicNFT
関数はMyEpicNFT.sol
に実装しました。
まず、App.js
の1行目に、下記のコードを追加してください。
// App.js
import { ethers } from "ethers";
ここでは、フロントエンドとコントラクトを連携させるライブラリethers
をインポートしています。
次に、下記のコードをApp.js
のconnectWallet
関数の下にaskContractToMintNft
関数を追加してください。
- フロントエンドに実装する
askContractToMintNft
関数が、コントラクトとWebサイトを 連動させ、makeAnEpicNFT
関数を呼び出します。
// App.js
const askContractToMintNft = async () => {
const CONTRACT_ADDRESS =
"ここに Sepolia Test Network にデプロイしたコントラクトのアドレスを貼り付けてください";
try {
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const connectedContract = new ethers.Contract(
CONTRACT_ADDRESS,
myEpicNft.abi,
signer
);
console.log("Going to pop wallet now to pay gas...");
let nftTxn = await connectedContract.makeAnEpicNFT();
console.log("Mining...please wait.");
await nftTxn.wait();
console.log(
`Mined, see transaction: https://sepolia.etherscan.io/tx/${nftTxn.hash}`
);
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
console.log(error);
}
};
1行ずつ、コードを見ていきましょう。
// App.js
const CONTRACT_ADDRESS =
"ここに Sepolia Test Network にデプロイしたコントラクトのアドレスを貼り付けてください";
ここでは、コントラクトのアドレスをCONTRACT_ADDRESS
に格納しています。
ETH-NFT-Collection
ディレクトリ直下で、もう一度下記を実行し、コントラクトのアドレスを取得してください。
yarn contract deploy:sepolia
貼り付けるアドレスの例は、以下のようになります。
Contract deployed to: 0x88a0e9c2F3939598c402eccb7Ae1612e45448C04
上記のアドレスを"ここに ... 貼り付けてください"
の中身と入れ替えてください。
次に、追加されたコードを見ながら、新しい概念について学びましょう。
I. provider
// App.js
const provider = new ethers.providers.Web3Provider(ethereum);
provider
を介して、ユーザーはブロックチェーン上に存在するイーサリアムノードに接続することができます。 MetaMask が提供するイーサリアムノードを使用して、デプロイされたコントラクトからデータを送受信するために上記の実装を行いました。
ethers
のライブラリによりprovider
のインスタンスを新規作成しています。
II. signer
// App.js
const signer = provider.getSigner();
signer
は、ユーザーのウォレットアドレスを抽象化したものです。
provider
を作成し、provider.getSigner()
を呼び出すだけで、ユーザーはウォレットアドレスを使用してトランザクションに署名し、そのデータをイーサリアムネットワークに送信することができます。
provider.getSigner()
は新しいsigner
インスタンスを返すので、それを使って署名付きトランザクションを送信することができます。
III. コントラクトインスタンス
// App.js
const connectedContract = new ethers.Contract(
CONTRACT_ADDRESS,
myEpicNft.abi,
signer
);ここでは、コントラクトへの接続を行っています。
新しいコントラクトインスタンス(=
connectedContract
)を作成するには、以下 3 つの変数をethers.Contract
関数に渡す必要があります。
CONTRACT_ADDRESS
: コントラクトのデプロイ先のアドレス(ローカル、テストネット、またはイーサリアムメインネット)
myEpicNft.abi
: コントラクトの ABI
signer
もしくはprovider
コントラクトインスタンスでは、コントラクトに格納されているすべての関数を呼び出すことができます。
もしこのコントラクトインスタンスに
provider
を渡すと、そのインスタンスは読み取り専用の機能しか実行できなくなります。一方、
signer
を渡すと、そのインスタンスは読み取りと書き込みの両方の機能を実行できるようになります。※ ABI についてはこのレッスンの終盤にて詳しく説明します。
次に、下記のコードを見ていきましょう。
// App.js
console.log("Going to pop wallet now to pay gas...");
ここでは、ethers.Contract
でコントラクトとの接続を行った後、承認が開始されることを通知しています。
次に、下記のコードを見ていきましょう。
// App.js
let nftTxn = await connectedContract.makeAnEpicNFT();
console.log("Mining...please wait.");
ここでは、makeAnEpicNFT
関数をコントラクトから呼び出し、await
を使用して、NFTの発行が承認(=マイニング)されるまで、処理をやめています。
console.log
では、NFTを発行するためのトランザクションが「承認中」であることを通知しています。
次に、下記のコードを見ていきましょう。
// App.js
await nftTxn.wait();
console.log(
`Mined, see transaction: https://sepolia.etherscan.io/tx/${nftTxn.hash}`
);
承認が終わったら、await nftTxn.wait()
が実行され、トランザクションの結果を取得します。コードが冗長に感じるかもしれませんが、大事な処理です。
console.log
では、取得したトランザクションの結果を、Etherscan URLとして出力してい ます。
ユーザーがMint NFT
ボタンをクリックしたときに、askContractToMintNft
関数を呼び出すコードを見ていきましょう。
// App.js
return (
{currentAccount === ""
? renderNotConnectedContainer()
: (
/* ユーザーが Mint NFT ボタンを押した時に、askContractToMintNft 関数を呼び出します */
<button onClick={askContractToMintNft} className="cta-button connect-wallet-button">
Mint NFT
</button>
)
}
);
条件付きレンダリングについて復習していきましょう。
currentAccount === ""
は、currentAccount
にユーザーのウォレットアドレスが紐づいているかどうか判定しています。
条件付きレンダリングは、下記のように実行されます。
{ currentAccount === "" ? ( currentAccount にアドレスが紐づいてなければ、A を実行 ) : ( currentAccount にアドレスが紐づいれば B を実行 )}
App.js
の場合、A
並ばは、renderNotConnectedContainer()
を実行し、B
ならば、Mint NFT
ボタンをフロントエンドに反映させています。
最後に、onClick={null}
をonClick={askContractToMintNft}
に変更することをお忘れなく!
すべての変更をApp.js
に反映させた後、ターミナルで下記を実行してみてください。
yarn client start
ローカルサーバーで、Webサイトが立ち上がり、下記のようなエラーがターミナルに出力されていれば、ここまでの実装は成功です。
Failed to compile.
src/App.js
Line 78:73: 'myEpicNft' is not defined no-undef
Search for the keywords to learn more about each error.
これから、ABIファイルを取得して、myEpicNft
変数を定義していきます。
📂 ABI ファイルを取得する
ABI(Application Binary Interface)はコントラクトの取り扱い説明書のようなものです。
Webアプリケーションがコントラクトと通信するために必要な情報が、ABIファイルに含まれています。
コントラクト1つ1つにユニークなABIファイルが紐づいており、その中には下記の情報が含まれています。
-
そのコントラクトに使用されている関数の名前
-
それぞれの関数にアクセスするために必要なパラメータとその型
-
関数の実行結果に対して返るデータ型の種類
ABIファイルは、コントラクトがコンパイルされた時に生成され、packages/contract/artifacts
ディレクトリに自動的に格納されます。
ターミナルでpackages/contract
ディレクトリに移動し、ls
を実行しましょう。
artifacts
ディレクトリの存在を確認してください。
ABIファイルの中身は、MyEpicNFT.json
というファイルに格納されいます。
下記を実行して、ABIファイルをコピーしましょう。
1. ターミナル上でpackages/contract
ディレクトリにいることを確認する(もしくは移動する)。
2. ターミナル上で下記を実行する。
code artifacts/contracts/MyEpicNFT.sol/MyEpicNFT.json
3. VS CodeでMyEpicNFT.json
ファイルが開かれるので、中身をすべてコピーしましょう。※ VS Codeのファインダーを使って、直接MyEpicNFT.json
を開くことも可能です。
次に、下記を実行して、ABIファイルをWebアプリケーションから呼び出せるようにしましょう。
1. ターミナル上でpackages/client
ディレクトリにいることを確認する(もしくは移動する)。
2. 下記を実行して、packages/client/src/
の中にutils
ディレクトリを作成する。
mkdir src/utils
3. 下記を実行して、utils