メインコンテンツまでスキップ

lesson-3_WEBアプリからコントラクトを呼び出そう

☘️ Web アプリケーションから NFT を Mint する

前回のレッスンでは、Webアプリケーションを立ち上げました。

これから、Web アプリケーションからMyEpicNFT.solコントラクトにアクセスして、NFT を発行するmakeAnEpicNFT関数を呼び出していきましょう。

  • 以前のレッスンでmakeAnEpicNFT関数はMyEpicNFT.solに実装しました。

まず、App.jsの1行目に、下記のコードを追加してください。

// App.js
import { ethers } from "ethers";

ここでは、フロントエンドとコントラクトを連携させるライブラリethersをインポートしています。

次に、下記のコードをApp.jsconnectWallet関数の下に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関数に渡す必要があります。

  1. CONTRACT_ADDRESS: コントラクトのデプロイ先のアドレス(ローカル、テストネット、またはイーサリアムメインネット)

  2. myEpicNft.abi: コントラクトの ABI

  3. 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ファイルが紐づいており、その中には下記の情報が含まれています。

  1. そのコントラクトに使用されている関数の名前

  2. それぞれの関数にアクセスするために必要なパラメータとその型

  3. 関数の実行結果に対して返るデータ型の種類

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ディレクトリにMyEpicNFT.jsonファイルを作成する。

touch src/utils/MyEpicNFT.json

4. 下記を実行して、MyEpicNFT.jsonファイルをVS Codeで開く。

code src/utils/MyEpicNFT.json

5. 先ほどコピーしたcontract/artifacts/contracts/MyEpicNFT.sol/MyEpicNFT.jsonの中身を新しく作成したclient/src/utils/MyEpicNFT.jsonの中に貼り付けてください。

ABIファイルの準備ができたので、App.jsにインポートしましょう。

下記をApp.jsの1行目に追加しましょう。

// App.js
import myEpicNft from "./utils/MyEpicNFT.json";

ここでは、先ほど取得した、ABIファイルを含むMyEpicNFT.jsonファイルをインポートしています。

🥳 NFT を Mint する

それでは、ターミナル上でETH-NFT-Collectionディレクトリ直下に移動して下記を実行し、ローカル環境でWebアプリケーションをホストしてみましょう。

yarn client start

WebアプリケーションのMint NFTボタンを押して、下記のようなポップアップが立ち上がったら、Confirmを押してください。

ここで請求される少量のETHは、通称ガス代と呼ばれます。

  • ブロックチェーンは、AWSのようなクラウド上にデータを保存できるサーバーのようなものです。

  • しかし、誰もそのデータを所有していません。

  • 世界中に、ブロックチェーン上にデータを保存する作業する「マイナー」と呼ばれる人々が存在します。この作業に対して、私たちは代金を支払います。

  • その代金が、ガス代です。

  • イーサリアムのブロックチェーン上にデータを書き込む際、私たちは代金として$ETHを「マイナー」に支払う必要があります。

Webアプリケーション上でInspectを選択して、Consoleを確認してみましょう。

下記のような結果が出力されていれば、あなたのNFTは正常にMintされています。

Found an authorized account: 0x3a0a49fb3cf930e599f0fa7abe554dc18bd1f135
currentAccount: 0x3a0a49fb3cf930e599f0fa7abe554dc18bd1f135
Going to pop wallet now to pay gas...
Mining...please wait.
Mined, see transaction: https://sepolia.etherscan.io/tx/0x5a08f3e66852b5c1833f3a20fc292816bc2ec5a25eee1e8c83c3755000aa773a

Consoleに出力されたhttps://sepolia.etherscan.io/...のアドレスをクリックしてみましょう。

  • あなたのSepolia Test Network上のトランザクションの履歴が参照できます。

次に、MintしたNFTがあなたのSepolia Test Networkのアドレスに紐づいているか確認してみましょう。上記画像の赤枠で囲まれている部分が、トークンの転送情報です。転送先のアドレス(To xxx...)があなたのウォレットアドレスになっていたら大丈夫です。

それでは、gemcaseにアクセスをして確認をしてみましょう。これまではAddressにデプロイをしたコントラクトのアドレスを入力していましたが、今度はあなたのウォレットアドレスを入力してViewをクリックしてみましょう。

これまでにあなたのアドレスへミントされたNFTの一覧が取得できます。

ステップ通りに進んできた場合は、一番左上のNFTがアプリケーション上のMint NFTをクリックしてミントされたNFTとなります。NFTをクリックして詳細を確認すると、NFTをミントしたアドレスがApp.jsファイルの const CONTRACT_ADDRESSに設定したコントラクトのアドレスとなっているはずです!

🚨 コントラクトを再びデプロイする際の注意点

コントラクトの中身を更新する場合、必ず下記3つのステップを実行することを忘れないようにしましょう。

1 . 再度、コントラクトをデプロイする。

  • yarn contract deploy:sepoliaを実行する必要があります。

2 . フロントエンド(App.js)のCONTRACT_ADDRESSを更新する。

3 . ABIファイルを更新する。

  • packages/contract/artifacts/contracts/MyEpicNFT.sol/MyEpicNFT.jsonの中身を新しく作成するpackages/client/src/utils/MyEpicNFT.jsonの中に貼り付ける必要があります。

コントラクトを更新する際、必ずこの 3 つのステップを実行してください。

  • 一度デプロイされたスマートコントラクトを変更することはできません。

  • コントラクトを変更するには、完全に再デプロイする必要があります。

  • 新しくデプロイされたスマートコントラクトは、ブロックチェーン上で新しいコントラクトとして扱われるため、すべての変数はリセットされます。

  • つまり、コントラクトのコードを更新したい場合、すべての NFT データが失われます。

上記の点に注意しながら、コントラクトの更新を行ってください。

🙋‍♂️ 質問する

ここまでの作業で何かわからないことがある場合は、Discordの#ethereumで質問をしてください。

ヘルプをするときのフローが円滑になるので、エラーレポートには下記の3点を記載してください ✨

1. 質問が関連しているセクション番号とレッスン番号
2. 何をしようとしていたか
3. エラー文をコピー&ペースト
4. エラー画面のスクリーンショット

おめでとうございます!

NFTをMintできるWebアプリケーションはほぼ完成です!

gemcaseのリンクを#ethereumに貼り付けて、あなたのNFTをシェアしてください 😊

あなたの作ったNFTがどんなものなのか気になります ✨

次のレッスンに進みましょう 🎉