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

lesson-2_webアプリケーションからNFTをmintしよう

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

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

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

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

まず、NftUploader.jsximport { Button } from '@mui/material';の下に、下記のコードを追加してください。

// NftUploader.jsx
import { ethers } from "ethers";

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

まだethersのライブラリをインストールしてなかったので、プロジェクトのルートで以下のコマンドを実行してください。

yarn workspace client add ethers@5.7.2

ethersをもっと詳しく知りたい方は、こちらをどうぞ。

次に、下記のコードをNftUploader.jsxconnectWallet関数の下にaskContractToMintNft関数を追加してください。

  • フロントエンドに実装するaskContractToMintNft関数が、コントラクトとWebサイトを連動させ、mintIpfsNFT関数を呼び出します。
// NftUploader.jsx
const askContractToMintNft = async (ipfs) => {
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,
Web3Mint.abi,
signer
);
console.log("Going to pop wallet now to pay gas...");
let nftTxn = await connectedContract.mintIpfsNFT("sample", ipfs);
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行ずつ、コードを見ていきましょう。

// NftUploader.jsx
const CONTRACT_ADDRESS =
"ここに Sepolia Test Network にデプロイしたコントラクトのアドレスを貼り付けてください";

ここでは、コントラクトのアドレスをCONTRACT_ADDRESSに格納しています。

ルーディレクトリでもう一度下記を実行し、コントラクトのアドレスを取得してください。

yarn contract deploy

貼り付けるアドレスの例は、以下のようになります。

Contract deployed to: 0x88a0e9c2F3939598c402eccb7Ae1612e45448C04

上記のアドレスを'ここに ... 貼り付けてください'の中身と入れ替えてください。

providersignerの概念がわからない方は、Project2-section3-lesson3を見て復習してみてください。

では、コントラクトインスタンスの説明から始めます。

// NftUploader.jsx
const connectedContract = new ethers.Contract(
CONTRACT_ADDRESS,
Web3Mint.abi,
signer
);

ここでは、コントラクトへの接続を行っています。

新しいコントラクトインスタンス(= connectedContract )を作成するには、以下 3 つの変数をethers.Contract関数に渡す必要があります。

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

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

  3. signerもしくはprovider

コントラクトインスタンスでは、コントラクトに格納されているすべての関数を呼び出すことができます。

もしこのコントラクトインスタンスにproviderを渡すと、そのインスタンスは読み取り専用の機能しか実行できなくなります

一方、signerを渡すと、そのインスタンスは読み取りと書き込みの両方の機能を実行できるようになります

※ ABI についてはこのレッスンの終盤にて詳しく説明します。

次に、下記のコードを見ていきましょう。

// NftUploader.jsx
let nftTxn = await connectedContract.mintIpfsNFT("sample", ipfs);
console.log("Mining...please wait.");

ここでは、mintIpfsNFT関数をコントラクトから呼び出し、awaitを使用して、NFTの発行が承認(=マイニング)されるまで、処理をやめています。

console.logでは、NFTを発行するためのトランザクションが「承認中」であることを通知しています。

次に、下記のコードを見ていきましょう。

// NftUploader.jsx
await nftTxn.wait();
console.log(
`Mined, see transaction: https://sepolia.etherscan.io/tx/${nftTxn.hash}`
);

承認が終わったら、await nftTxn.wait()が実行され、トランザクションの結果を取得します。コードが冗長に感じるかもしれませんが、大事な処理です。

console.logでは、取得したトランザクションの結果を、Etherscan URLとして出力しています。

askContractToMintNft関数を呼び出すコードはこの後実装していくので、今は気にしないでください。

すべての変更をNftUploader.jsxに反映させた後、ターミナルで下記を実行しみてください。

yarn client start

ローカルサーバーで、Webサイトが立ち上がり、下記のようなエラーがターミナルに出力されていれば、ここまでの実装は成功です。

Failed to compile.
src/App.js
Line 78:73: 'Web3Mint' is not defined no-undef
Search for the keywords to learn more about each error.

これから、ABIファイルを取得して、Web3Mint変数を定義していきます。

📂 ABI ファイルを取得する

ABI(Application Binary Interface)はコントラクトの取り扱い説明書のようなものです。

Webアプリケーションがコントラクトと通信するために必要な情報が、ABIファイルに含まれています。

コントラクト1つ1つにユニークなABIファイルが紐づいており、その中には下記の情報が含まれています。

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

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

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

ABIファイルは、コントラクトがコンパイルされた時に生成され、packages/contract/artifactsディレクトリに自動的に格納されます。

ターミナルでpackages/contractディレクトリに移動し、lsを実行しましょう。

artifactsディレクトリの存在を確認してください。

ABIファイルの中身は、Web3Mint.jsonというファイルに格納されいます。

下記を実行して、ABIファイルをコピーしましょう。

1. ターミナル上でpackges/contractにいることを確認する(もしくは移動する)。

2. ターミナル上で下記を実行する。

code artifacts/contracts/Web3Mint.sol/Web3Mint.json

3. VS Code でWeb3Mint.jsonファイルが開かれるので、中身をすべてコピーしましょう。※ VS Code のファインダーを使って、直接Web3Mint.jsonを開くことも可能です。

次に、下記を実行して、ABIファイルをWebアプリケーションから呼び出せるようにしましょう。

1. ターミナル上でclientにいることを確認する(もしくは移動する)。

2. 下記を実行して、client/src/の中にutilsディレクトリを作成する。

mkdir src/utils

3. 下記を実行して、utilsディレクトリにWeb3Mint.jsonファイルを作成する。

touch src/utils/Web3Mint.json

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

code client/src/utils/Web3Mint.json

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

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

下記をNftUploader.jsximport ImageLogo from './image.svg';の上に追加しましょう。

// NftUploader.jsx
import Web3Mint from "../../utils/Web3Mint.json";

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

🛠 Web3.storageを使用する

これで、NFTをMintする準備はほとんど終わりましたが、まだ足りないものがありますね。 そうです!受け取った画像をIPFSにアップロードしてCIDを返してもらう機能が足りませんね。

まずは、Web3.storageのライブラリをインストールしましょう!このライブラリを使うことで先ほど手作業で行ったIPFSに画像をアップロードする作業をプログラムで実装できるようになります。

プロジェクトのルートで下記を実行してください。

yarn workspace client add web3.storage@^4.5.4

そしてNftUploader.jsxの中import { useEffect, useState } from 'react';の下に一行を加えましょう。

// NftUploader.jsx
import { Web3Storage } from "web3.storage";

では、このWeb3Storageを使った関数を実装していきましょう。

NftUploader.jsximageToNFT関数を実装しましょう。

// NftUploader.jsx
const imageToNFT = async (e) => {
const client = new Web3Storage({ token: API_KEY });
const image = e.target;
console.log(image);

const rootCid = await client.put(image.files, {
name: "experiment",
maxRetries: 3,
});
const res = await client.get(rootCid); // Web3Response
const files = await res.files(); // Web3File[]
for (const file of files) {
console.log("file.cid:", file.cid);
askContractToMintNft(file.cid);
}
};

この関数は画像を受け取るinputタグのonClickプロパティに実装します。これでinputが画像を受け取るたびにNFTが発行されることになります。変更する箇所が二箇所あるので、注意してください。

// NftUploader.jsx
<input className="nftUploadInput" multiple name="imageURL" type="file" accept=".jpg , .jpeg , .png" onChange={imageToNFT}/>
</div>
<p>または</p>
<Button variant="contained">
ファイルを選択
<input className="nftUploadInput" type="file" accept=".jpg , .jpeg , .png" onChange={imageToNFT} />
</Button>

imageToNFT関数について解説していきます!

// NftUploader.jsx
const imageToNFT = async (e) => {
const client = new Web3Storage({ token: API_KEY })
const image = e.target
console.log(image)

ここでは、inputから受け取った画像をeで受け取って、画像のオブジェクトをe.targetimageに代入しています。

eという合成イベントについては、公式の説明こちらが役に立つと思います。

そしてWeb3Storageにアップロードするために、APIを取得する必要があります。

web3.storageのアカウント画面に行き、create a tokenのボタンを押してください。

すると、Name your tokenという記入画面があると思うので、そこに好きな名前をいれてapi_keyを作りましょう。

名前を入れてenterを押すと、しばらくまって下の画面にkeyがでてくるはずなので、それをコピーしましょう

NftUploader.jsxに戻って、API_KEYを定義しましょう。

// NftUploader.jsx
const API_KEY = "あなたのKEYをいれてください";

次は、下記のコードを解説します。

// NftUploader.jsx
const rootCid = await client.put(image.files, {
name: "experiment",
maxRetries: 3,
});

ここで、画像をIPFSで保存しています。画像のデータと、名前などを設定しています。さらに返り値のCIDrootCidに代入されています。

詳しく知りたい方は、公式 docを参考にしてみてください。

次は、下記のコードを解説します。

// NftUploader.jsx
const res = await client.get(rootCid); // Web3Response
const files = await res.files(); // Web3File[]
for (const file of files) {
console.log("file.cid:", file.cid);
askContractToMintNft(file.cid);
}

先程の返り値をつかって、今度は保存したファイルのデータを取りに行っています。

このfile.cidが送った画像のIPFSになります。気になる方は、console.logで出たものをブラウザに表示させてみてください。 そのfile.cidを引数にして、askContractToMintNft関数を使いましょう。 これで、mintするための準備はすべて整ったはずです。

🥳 NFT を Mint する

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

yarn client start

Webアプリケーションで画像を選択して、下記のようなポップアップが立ち上がったら、Confirmを押してください。

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

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

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

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

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

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

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

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

file.cid: bafkreifhw5rc2vbtpupbdughvz35niquk6bjx6uh6gilyflkh7ao76rwlm
Going to pop wallet now to pay gas...
Mining...please wait.
Mined, see transaction: https://sepolia.etherscan.io/tx/0x5fbe47b7c0fd658f5866d10c70bfa4616d7f26f438dcade022cbff930400f175

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

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

次に、gemcase(NFT で閲覧できるサービス) にアクセスして、MintしたNFTがあなたのSepolia Test Networkのアドレスに紐づいているか確認してみましょう。

Consoleに出力されたcurrentAccount:に続く、0x..のアドレスをgemcaseのWebサイトに貼り付けて、結果が表示されたら、画面右上のProfileメニューを選択してください。それから、ご自身のアカウントを開いて、NFTを確認してみましょう。

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

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

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

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

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

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

  • packages/contract/artifacts/contracts/Web3Mint.sol/Web3Mint.jsonの中身を、packages/client/src/utils/Web3Mint.solの中に貼り付ける必要があります。

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

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

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

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

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

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

🙋‍♂️ 質問する

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

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

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

おめでとうございます!

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

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

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

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