NFTミントチュートリアル
Web2のバックグラウンドを持つ開発者にとって最大の課題の1つは、スマート・コントラクトをフロントエンドプロジェクトに接続し、それとやり取りする方法を理解することです。
デジタル資産へのリンク、タイトル、説明を入力できるシンプルなUIであるNFTミンターを構築することで、以下の方法を学びます。
- フロントエンドプロジェクトを介してメタマスクに接続する
- フロントエンドからスマート・コントラクトのメソッドを呼び出す
- メタマスクを使用してトランザクションに署名する
このチュートリアルでは、フロントエンドフレームワークとしてReact (opens in a new tab)を使用します。このチュートリアルは主にWeb3開発に焦点を当てているため、Reactの基礎を解説することに多くの時間は費やしません。代わりに、プロジェクトに機能をもたらすことに焦点を当てます。
前提条件として、Reactの初心者レベルの理解(コンポーネント、props、useState/useEffect、および基本的な関数呼び出しの仕組み)が必要です。これらの用語を聞いたことがない場合は、このReact入門チュートリアル (opens in a new tab)を確認することをお勧めします。視覚的に学びたい方には、Net Ninjaによる素晴らしいFull Modern React Tutorial (opens in a new tab)ビデオシリーズを強くお勧めします。
また、まだお持ちでない場合は、このチュートリアルを完了し、ブロックチェーン上で何かを構築するために、Alchemyアカウントが絶対に必要になります。こちら (opens in a new tab)から無料アカウントにサインアップしてください。
それでは、さっそく始めましょう!
NFT作成の基礎
コードを見始める前に、NFTの作成がどのように機能するかを理解することが重要です。これには2つのステップが含まれます。
イーサリアムブロックチェーン上にNFTスマート・コントラクトを公開する
2つのNFTスマート・コントラクト標準の最大の違いは、ERC-1155がマルチトークン標準でありバッチ機能を含んでいるのに対し、ERC-721はシングルトークン標準であるため、一度に1つのトークンの転送しかサポートしていないことです。
ミンティング関数を呼び出す
通常、このミンティング関数では、パラメータとして2つの変数を渡す必要があります。1つ目は新しくミントされたNFTを受け取るアドレスを指定するrecipient、2つ目はNFTのメタデータを記述したJSONドキュメントに解決される文字列であるNFTのtokenURIです。
NFTのメタデータは、名前、説明、画像(または別のデジタル資産)、その他の属性などのプロパティを持たせることで、NFTに命を吹き込むものです。NFTのメタデータを含むtokenURIの例はこちら (opens in a new tab)です。
このチュートリアルでは、パート2である、React UIを使用して既存のNFTのスマート・コントラクトのミンティング関数を呼び出すことに焦点を当てます。
このチュートリアルで呼び出すERC-721 NFTスマート・コントラクトへのリンクはこちら (opens in a new tab)です。その作成方法を学びたい場合は、別のチュートリアルである「NFTの作成方法」 (opens in a new tab)を確認することを強くお勧めします。
素晴らしい!NFTの作成方法を理解したところで、スターターファイルをクローンしましょう!
スターターファイルをクローンする
まず、nft-minter-tutorialのGitHubリポジトリ (opens in a new tab)にアクセスして、このプロジェクトのスターターファイルを取得します。このリポジトリをローカル環境にクローンしてください。
このクローンしたnft-minter-tutorialリポジトリを開くと、minter-starter-filesとnft-minterの2つのフォルダが含まれていることに気づくでしょう。
minter-starter-filesには、このプロジェクトのスターターファイル(基本的にはReact UI)が含まれています。このチュートリアルでは、このUIをイーサリアムウォレットとNFTスマート・コントラクトに接続して機能させる方法を学ぶため、このディレクトリで作業します。nft-minterには、完成したチュートリアル全体が含まれており、行き詰まった場合の参考として用意されています。
次に、コードエディタでminter-starter-filesのコピーを開き、srcフォルダに移動します。
記述するコードはすべてsrcフォルダ内に配置されます。Minter.jsコンポーネントを編集し、プロジェクトにWeb3機能を追加するための追加のJavaScriptファイルを記述します。
ステップ2: スターターファイルを確認する
コーディングを始める前に、スターターファイルで既に提供されているものを確認することが重要です。
Reactプロジェクトを実行する
ブラウザでReactプロジェクトを実行することから始めましょう。Reactの素晴らしい点は、プロジェクトをブラウザで実行すると、保存した変更がブラウザ上でリアルタイムに更新されることです。
プロジェクトを実行するには、minter-starter-filesフォルダのルートディレクトリに移動し、ターミナルでnpm installを実行してプロジェクトの依存関係をインストールします。
cd minter-starter-files
npm install
インストールが完了したら、ターミナルでnpm startを実行します。
npm start
これにより、ブラウザで http://localhost:3000/ (opens in a new tab) が開き、プロジェクトのフロントエンドが表示されるはずです。これは3つのフィールドで構成されています。NFTの資産へのリンクを入力する場所、NFTの名前を入力する場所、そして説明を提供する場所です。
「Connect Wallet」または「Mint NFT」ボタンをクリックしようとすると、機能しないことに気づくでしょう。これは、まだその機能をプログラミングする必要があるためです! :)
Minter.jsコンポーネント
注: nft-minterフォルダではなく、minter-starter-filesフォルダにいることを確認してください!
エディタでsrcフォルダに戻り、Minter.jsファイルを開きましょう。これは私たちが作業する主要なReactコンポーネントであるため、このファイル内のすべてを理解することが非常に重要です。
このファイルの上部には、特定のイベント後に更新する状態(state)変数があります。
//状態変数
const [walletAddress, setWallet] = useState("")
const [status, setStatus] = useState("")
const [name, setName] = useState("")
const [description, setDescription] = useState("")
const [url, setURL] = useState("")
Reactの状態変数やステートフックについて聞いたことがありませんか?こちら (opens in a new tab)のドキュメントを確認してください。
各変数が表すものは次のとおりです。
walletAddress- ユーザーのウォレットアドレスを格納する文字列status- UIの下部に表示するメッセージを含む文字列name- NFTの名前を格納する文字列description- NFTの説明を格納する文字列url- NFTのデジタル資産へのリンクである文字列
状態変数の後には、未実装の3つの関数、useEffect、connectWalletPressed、およびonMintPressedがあります。これらの関数はすべてasyncであることに気づくでしょう。これは、その中で非同期API呼び出しを行うためです!それらの名前は、その機能にちなんで名付けられています。
useEffect(async () => {
//TODO: 実装
}, [])
const connectWalletPressed = async () => {
//TODO: 実装
}
const onMintPressed = async () => {
//TODO: 実装
}
useEffect(opens in a new tab) - これは、コンポーネントがレンダリングされた後に呼び出されるReactフックです。空の配列[]プロパティが渡されているため(3行目を参照)、コンポーネントの_最初_のレンダリング時にのみ呼び出されます。ここでは、ウォレットリスナーと別のウォレット関数を呼び出して、ウォレットが既に接続されているかどうかを反映するようにUIを更新します。connectWalletPressed- この関数は、ユーザーのメタマスクウォレットを分散型アプリケーション (dapp) に接続するために呼び出されます。onMintPressed- この関数は、ユーザーのNFTをミントするために呼び出されます。
このファイルの終わり近くに、コンポーネントのUIがあります。このコードを注意深く見ると、対応するテキストフィールドの入力が変更されたときに、url、name、およびdescriptionの状態変数を更新していることがわかります。
また、IDがmintButtonとwalletButtonのボタンがそれぞれクリックされたときに、connectWalletPressedとonMintPressedが呼び出されることもわかります。
//コンポーネントのUI
return (
<div className="Minter">
<button id="walletButton" onClick={connectWalletPressed}>
{walletAddress.length > 0 ? (
"Connected: " +
String(walletAddress).substring(0, 6) +
"..." +
String(walletAddress).substring(38)
) : (
<span>Connect Wallet</span>
)}
</button>
<br></br>
<h1 id="title">🧙♂️ Alchemy NFT Minter</h1>
<p>
Simply add your asset's link, name, and description, then press "Mint."
</p>
<form>
<h2>🖼 Link to asset: </h2>
<input
type="text"
placeholder="e.g., https://gateway.pinata.cloud/ipfs/<hash>"
onChange={(event) => setURL(event.target.value)}
/>
<h2>🤔 Name: </h2>
<input
type="text"
placeholder="e.g., My first NFT!"
onChange={(event) => setName(event.target.value)}
/>
<h2>✍️ Description: </h2>
<input
type="text"
placeholder="e.g., Even cooler than cryptokitties ;)"
onChange={(event) => setDescription(event.target.value)}
/>
</form>
<button id="mintButton" onClick={onMintPressed}>
Mint NFT
</button>
<p id="status">{status}</p>
</div>
)
最後に、このMinterコンポーネントがどこに追加されるかについて説明します。
他のすべてのコンポーネントのコンテナとして機能するReactのメインコンポーネントであるApp.jsファイルに移動すると、Minterコンポーネントが7行目に挿入されていることがわかります。
このチュートリアルでは、Minter.js fileのみを編集し、srcフォルダにファイルを追加します。
作業内容を理解したところで、イーサリアムウォレットをセットアップしましょう!
イーサリアムウォレットをセットアップする
ユーザーがスマート・コントラクトとやり取りできるようにするには、イーサリアムウォレットをdappに接続する必要があります。
メタマスクをダウンロードする
このチュートリアルでは、イーサリアムアカウントアドレスを管理するために使用されるブラウザ内の仮想ウォレットであるメタマスクを使用します。イーサリアム上のトランザクションの仕組みについて詳しく知りたい場合は、こちらのページを確認してください。
こちら (opens in a new tab)から無料でメタマスクアカウントをダウンロードして作成できます。アカウントを作成する際、または既にアカウントを持っている場合は、右上の「ロプステンテストネットワーク」に切り替えてください(実際の資金を扱わないようにするためです)。
フォーセットからイーサを追加する
NFTをミントする(またはイーサリアムブロックチェーン上でトランザクションに署名する)には、偽のETHが必要です。ETHを取得するには、ロプステンフォーセット (opens in a new tab)にアクセスしてロプステンアカウントアドレスを入力し、「Send Ropsten Eth」をクリックします。すぐにメタマスクアカウントにETHが表示されるはずです!
残高を確認する
残高があることを再確認するために、Alchemyのコンポーザーツール (opens in a new tab)を使用してeth_getBalance (opens in a new tab)リクエストを行いましょう。これにより、ウォレット内のETHの量が返されます。メタマスクアカウントアドレスを入力して「Send Request」をクリックすると、次のような応答が表示されるはずです。
{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}
注: この結果はETHではなくWeiです。Weiはイーサの最小単位として使用されます。WeiからETHへの変換は、1 ETH = 10¹⁸ Weiです。したがって、0xde0b6b3a7640000を10進数に変換すると1*10¹⁸となり、1 ETHに等しくなります。
ふう!偽のお金がすべて揃いました!
メタマスクをUIに接続する
メタマスクウォレットのセットアップが完了したので、dappをそれに接続しましょう!
MVC (opens in a new tab)パラダイムに従うため、dappのロジック、データ、ルールを管理する関数を含む別のファイルを作成し、それらの関数をフロントエンド(Minter.jsコンポーネント)に渡します。
connectWallet関数
これを行うには、srcディレクトリにutilsという新しいフォルダを作成し、その中にinteract.jsというファイルを追加します。このファイルには、ウォレットとスマート・コントラクトのやり取りに関するすべての関数が含まれます。
interact.jsファイルにconnectWallet関数を記述し、それをインポートしてMinter.jsコンポーネントで呼び出します。
interact.jsファイルに以下を追加します。
export const connectWallet = async () => {
if (window.ethereum) {
try {
const addressArray = await window.ethereum.request({
method: "eth_requestAccounts",
})
const obj = {
status: "👆🏽 Write a message in the text-field above.",
address: addressArray[0],
}
return obj
} catch (err) {
return {
address: "",
status: "😥 " + err.message,
}
}
} else {
return {
address: "",
status: (
<span>
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your
browser.
</a>
</p>
</span>
),
}
}
}
このコードが何を行うかを分解してみましょう。
まず、関数はブラウザでwindow.ethereumが有効になっているかどうかを確認します。
window.ethereumは、メタマスクやその他のウォレットプロバイダーによって挿入されるグローバルAPIであり、ウェブサイトがユーザーのイーサリアムアカウントを要求できるようにします。承認されると、ユーザーが接続しているブロックチェーンからデータを読み取り、ユーザーにメッセージやトランザクションへの署名を提案できます。詳細については、メタマスクのドキュメント (opens in a new tab)を確認してください!
window.ethereumが存在_しない_場合、それはメタマスクがインストールされていないことを意味します。これによりJSONオブジェクトが返され、返されるaddressは空の文字列になり、status JSXオブジェクトはユーザーがメタマスクをインストールする必要があることを伝えます。
私たちが記述する関数のほとんどは、状態変数とUIを更新するために使用できるJSONオブジェクトを返します。
さて、window.ethereumが存在_する_場合、ここからが面白くなります。
try/catchループを使用して、window.ethereum.request({ method: "eth_requestAccounts" }); (opens in a new tab)を呼び出すことでメタマスクへの接続を試みます。この関数を呼び出すと、ブラウザでメタマスクが開き、ユーザーはウォレットをdappに接続するように求められます。
- ユーザーが接続を選択した場合、
method: "eth_requestAccounts"はdappに接続されているユーザーのすべてのアカウントアドレスを含む配列を返します。全体として、connectWallet関数は、この配列の_最初_のaddress(9行目を参照)と、ユーザーにスマート・コントラクトへのメッセージの書き込みを促すstatusメッセージを含むJSONオブジェクトを返します。 - ユーザーが接続を拒否した場合、JSONオブジェクトには返される
addressの空の文字列と、ユーザーが接続を拒否したことを反映するstatusメッセージが含まれます。
Minter.js UIコンポーネントにconnectWallet関数を追加する
このconnectWallet関数を記述したので、それをMinter.js.コンポーネントに接続しましょう。
まず、Minter.jsファイルの上部にimport { connectWallet } from "./utils/interact.js";を追加して、関数をMinter.jsファイルにインポートする必要があります。Minter.jsの最初の11行は次のようになります。
import { useEffect, useState } from "react";
import { connectWallet } from "./utils/interact.js";
const Minter = (props) => {
//状態変数
const [walletAddress, setWallet] = useState("");
const [status, setStatus] = useState("");
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [url, setURL] = useState("");
次に、connectWalletPressed関数内で、インポートしたconnectWallet関数を次のように呼び出します。
const connectWalletPressed = async () => {
const walletResponse = await connectWallet()
setStatus(walletResponse.status)
setWallet(walletResponse.address)
}
機能のほとんどがinteract.jsファイルからMinter.jsコンポーネントから抽象化されていることに注目してください。これはM-V-Cパラダイムに準拠するためです!
connectWalletPressedでは、インポートしたconnectWallet関数に対して単にawait呼び出しを行い、その応答を使用して、ステートフックを介してstatusおよびwalletAddress変数を更新します。
それでは、Minter.jsとinteract.jsの両方のファイルを保存し、これまでのUIをテストしてみましょう。
ブラウザで localhost:3000 を開き、ページの右上にある「Connect Wallet」ボタンを押します。
メタマスクがインストールされている場合は、ウォレットをdappに接続するように求められるはずです。接続の招待を承認します。
ウォレットボタンにアドレスが接続されていることが反映されるはずです。
次に、ページを更新してみてください...これは奇妙です。ウォレットボタンは、既に接続されているにもかかわらず、メタマスクを接続するように求めています...
でも心配しないでください!getCurrentWalletConnectedという関数を実装することで、これを簡単に修正できます。この関数は、アドレスが既にdappに接続されているかどうかを確認し、それに応じてUIを更新します!
getCurrentWalletConnected関数
interact.jsファイルに、次のgetCurrentWalletConnected関数を追加します。
export const getCurrentWalletConnected = async () => {
if (window.ethereum) {
try {
const addressArray = await window.ethereum.request({
method: "eth_accounts",
})
if (addressArray.length > 0) {
return {
address: addressArray[0],
status: "👆🏽 Write a message in the text-field above.",
}
} else {
return {
address: "",
status: "🦊 Connect to MetaMask using the top right button.",
}
}
} catch (err) {
return {
address: "",
status: "😥 " + err.message,
}
}
} else {
return {
address: "",
status: (
<span>
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your
browser.
</a>
</p>
</span>
),
}
}
}
このコードは、先ほど記述したconnectWallet関数に_非常に_似ています。
主な違いは、ユーザーがウォレットを接続するためにメタマスクを開くメソッドeth_requestAccountsを呼び出す代わりに、ここでは現在dappに接続されているメタマスクアドレスを含む配列を単に返すメソッドeth_accountsを呼び出すことです。
この関数の動作を確認するために、Minter.jsコンポーネントのuseEffect関数で呼び出してみましょう。
connectWalletで行ったように、この関数をinteract.jsファイルからMinter.jsファイルに次のようにインポートする必要があります。
import { useEffect, useState } from "react"
import {
connectWallet,
getCurrentWalletConnected, //ここにインポート
} from "./utils/interact.js"
これで、useEffect関数で単に呼び出すだけです。
useEffect(async () => {
const { address, status } = await getCurrentWalletConnected()
setWallet(address)
setStatus(status)
}, [])
getCurrentWalletConnectedへの呼び出しの応答を使用して、walletAddressおよびstatus状態変数を更新していることに注目してください。
このコードを追加したら、ブラウザウィンドウを更新してみてください。ボタンには接続されていることが表示され、更新後でも接続されているウォレットのアドレスのプレビューが表示されるはずです!
addWalletListenerを実装する
dappウォレットのセットアップの最後のステップは、ユーザーがアカウントを切断したり切り替えたりしたときなど、ウォレットの状態が変化したときにUIが更新されるようにウォレットリスナーを実装することです。
Minter.jsファイルに、次のような関数addWalletListenerを追加します。
function addWalletListener() {
if (window.ethereum) {
window.ethereum.on("accountsChanged", (accounts) => {
if (accounts.length > 0) {
setWallet(accounts[0])
setStatus("👆🏽 Write a message in the text-field above.")
} else {
setWallet("")
setStatus("🦊 Connect to MetaMask using the top right button.")
}
})
} else {
setStatus(
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your browser.
</a>
</p>
)
}
}
ここで何が起こっているかを簡単に分解してみましょう。
- まず、関数は
window.ethereumが有効になっているか(つまり、メタマスクがインストールされているか)を確認します。- 有効になっていない場合は、
status状態変数を、ユーザーにメタマスクのインストールを促すJSX文字列に設定するだけです。 - 有効になっている場合は、3行目にリスナー
window.ethereum.on("accountsChanged")を設定します。これは、ユーザーが追加のアカウントをdappに接続したとき、アカウントを切り替えたとき、またはアカウントを切断したときなど、メタマスクウォレットの状態の変化をリッスンします。少なくとも1つのアカウントが接続されている場合、walletAddress状態変数は、リスナーによって返されるaccounts配列の最初のアカウントとして更新されます。それ以外の場合、walletAddressは空の文字列として設定されます。
- 有効になっていない場合は、
最後に、これをuseEffect関数で呼び出す必要があります。
useEffect(async () => {
const { address, status } = await getCurrentWalletConnected()
setWallet(address)
setStatus(status)
addWalletListener()
}, [])
これで完成です!ウォレット機能のすべてのプログラミングが完了しました!ウォレットのセットアップが完了したので、NFTをミントする方法を考えましょう!
NFTメタデータの基礎
このチュートリアルのステップ0で話したNFTメタデータを覚えていますか。これはNFTに命を吹き込み、デジタル資産、名前、説明、その他の属性などのプロパティを持たせることを可能にします。
このメタデータをJSONオブジェクトとして構成して保存し、スマート・コントラクトのmintNFT関数を呼び出すときにtokenURIパラメータとして渡せるようにする必要があります。
「Link to Asset」、「Name」、「Description」フィールドのテキストは、NFTのメタデータのさまざまなプロパティを構成します。このメタデータをJSONオブジェクトとしてフォーマットしますが、このJSONオブジェクトを保存する場所にはいくつかのオプションがあります。
- イーサリアムブロックチェーン上に保存することもできますが、そうすると非常に費用がかかります。
- AWSやFirebaseのような中央集権型サーバーに保存することもできます。しかし、それでは分散化の精神に反してしまいます。
- 分散型ファイルシステムでデータを保存および共有するための分散型プロトコルおよびピア・ツー・ピアネットワークであるIPFSを使用できます。このプロトコルは分散型であり無料であるため、これが最良のオプションです!
メタデータをIPFSに保存するには、便利なIPFS APIおよびツールキットであるPinata (opens in a new tab)を使用します。次のステップで、その正確な方法を説明します!
Pinataを使用してメタデータをIPFSにピン留めする
Pinata (opens in a new tab)アカウントをお持ちでない場合は、こちら (opens in a new tab)から無料アカウントにサインアップし、メールアドレスとアカウントを確認する手順を完了してください。
Pinata APIキーを作成する
https://pinata.cloud/keys (opens in a new tab)ページに移動し、上部の「New Key」ボタンを選択して、Adminウィジェットを有効に設定し、キーに名前を付けます。
その後、API情報を含むポップアップが表示されます。これを安全な場所に保管してください。
キーのセットアップが完了したので、プロジェクトに追加して使用できるようにしましょう。
.envファイルを作成する
Pinataキーとシークレットは環境ファイルに安全に保存できます。プロジェクトディレクトリにdotenvパッケージ (opens in a new tab)をインストールしましょう。
ターミナルで新しいタブを開き(ローカルホストを実行しているものとは別に)、minter-starter-filesフォルダにいることを確認してから、ターミナルで次のコマンドを実行します。
npm install dotenv --save
次に、コマンドラインに次のように入力して、minter-starter-filesのルートディレクトリに.envファイルを作成します。
vim.env
これにより、vim(テキストエディタ)で.envファイルが開きます。保存するには、キーボードで「esc」+「:」+「q」の順に押します。
次に、VSCodeで.envファイルに移動し、次のようにPinata APIキーとAPIシークレットを追加します。
REACT_APP_PINATA_KEY = <pinata-api-key>
REACT_APP_PINATA_SECRET = <pinata-api-secret>
ファイルを保存すると、JSONメタデータをIPFSにアップロードする関数の記述を開始する準備が整います!
pinJSONToIPFSを実装する
幸いなことに、PinataにはJSONデータをIPFSにアップロードするための専用API (opens in a new tab)と、わずかな変更で使用できる便利なaxiosを使用したJavaScriptの例があります。
utilsフォルダに、pinata.jsという別のファイルを作成し、次のように.envファイルからPinataシークレットとキーをインポートしましょう。
require("dotenv").config()
const key = process.env.REACT_APP_PINATA_KEY
const secret = process.env.REACT_APP_PINATA_SECRET
次に、以下の追加コードをpinata.jsファイルに貼り付けます。心配しないでください、すべてが何を意味するかを分解して説明します!
require("dotenv").config()
const key = process.env.REACT_APP_PINATA_KEY
const secret = process.env.REACT_APP_PINATA_SECRET
const axios = require("axios")
export const pinJSONToIPFS = async (JSONBody) => {
const url = `https://api.pinata.cloud/pinning/pinJSONToIPFS`
//Pinataへのaxios POSTリクエストを作成 ⬇️
return axios
.post(url, JSONBody, {
headers: {
pinata_api_key: key,
pinata_secret_api_key: secret,
},
})
.then(function (response) {
return {
success: true,
pinataUrl:
"https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash,
}
})
.catch(function (error) {
console.log(error)
return {
success: false,
message: error.message,
}
})
}
では、このコードは正確に何を行うのでしょうか?
まず、ブラウザおよびNode.js用のプロミスベースのHTTPクライアントであるaxios (opens in a new tab)をインポートします。これを使用してPinataにリクエストを行います。
次に、非同期関数pinJSONToIPFSがあります。これは、入力としてJSONBodyを受け取り、ヘッダーにPinata APIキーとシークレットを受け取り、すべてpinJSONToIPFS APIへのPOSTリクエストを行うためのものです。
- このPOSTリクエストが成功した場合、関数は
successブール値をtrueとし、メタデータがピン留めされたpinataUrlを含むJSONオブジェクトを返します。返されたこのpinataUrlを、スマート・コントラクトのミント関数へのtokenURI入力として使用します。 - このPOSTリクエストが失敗した場合、関数は
successブール値をfalseとし、エラーを伝えるmessage文字列を含むJSONオブジェクトを返します。
connectWallet関数の戻り値の型と同様に、JSONオブジェクトを返しているため、そのパラメータを使用して状態変数とUIを更新できます。
スマート・コントラクトをロードする
pinJSONToIPFS関数を介してNFTメタデータをIPFSにアップロードする方法ができたので、スマート・コントラクトのmintNFT関数を呼び出せるように、スマート・コントラクトのインスタンスをロードする方法が必要になります。
前述のように、このチュートリアルではこの既存のNFTスマート・コントラクト (opens in a new tab)を使用します。ただし、その作成方法を学びたい場合、または自分で作成したい場合は、別のチュートリアルである「NFTの作成方法」 (opens in a new tab)を確認することを強くお勧めします。
コントラクトABI
ファイルを注意深く調べた場合、srcディレクトリにcontract-abi.jsonファイルがあることに気づいたでしょう。ABIは、コントラクトがどの関数を呼び出すかを指定し、関数が期待する形式でデータを返すことを保証するために必要です。
また、イーサリアムブロックチェーンに接続してスマート・コントラクトをロードするために、Alchemy APIキーとAlchemy Web3 APIも必要になります。
Alchemy APIキーを作成する
まだAlchemyアカウントをお持ちでない場合は、こちらから無料でサインアップしてください。 (opens in a new tab)
Alchemyアカウントを作成したら、アプリを作成してAPIキーを生成できます。これにより、ロプステンテストネットワークにリクエストを行うことができます。
ナビゲーションバーの「Apps」にカーソルを合わせ、「Create App」をクリックして、Alchemyダッシュボードの「Create App」ページに移動します。
アプリに名前を付け(私たちは「My First NFT!」を選びました)、短い説明を提供し、アプリの簿記に使用する環境として「Staging」を選択し、ネットワークとして「Ropsten」を選択します。
「Create app」をクリックすれば完了です!アプリが下の表に表示されるはずです。
素晴らしい!HTTP Alchemy API URLを作成したので、クリップボードにコピーしてください...
…そして、それを.envファイルに追加しましょう。全体として、.envファイルは次のようになります。
REACT_APP_PINATA_KEY = <pinata-key>
REACT_APP_PINATA_SECRET = <pinata-secret>
REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/<alchemy-key>
コントラクトABIとAlchemy APIキーが揃ったので、Alchemy Web3 (opens in a new tab)を使用してスマート・コントラクトをロードする準備が整いました。
Alchemy Web3エンドポイントとコントラクトをセットアップする
まず、まだインストールしていない場合は、ターミナルでホームディレクトリnft-minter-tutorialに移動して、Alchemy Web3 (opens in a new tab)をインストールする必要があります。
cd ..
npm install @alch/alchemy-web3
次に、interact.jsファイルに戻りましょう。ファイルの上部に次のコードを追加して、.envファイルからAlchemyキーをインポートし、Alchemy Web3エンドポイントをセットアップします。
require("dotenv").config()
const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(alchemyKey)
Alchemy Web3 (opens in a new tab)はWeb3.js (opens in a new tab)のラッパーであり、強化されたAPIメソッドやその他の重要な利点を提供して、Web3開発者としての生活を楽にします。最小限の構成で済むように設計されているため、アプリですぐに使用を開始できます!
次に、コントラクトABIとコントラクトアドレスをファイルに追加しましょう。
require("dotenv").config()
const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(alchemyKey)
const contractABI = require("../contract-abi.json")
const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE"
これら両方が揃ったら、ミント関数のコーディングを開始する準備が整います!
mintNFT関数を実装する
interact.jsファイル内で、その名の通りNFTをミントする関数mintNFTを定義しましょう。
多数の非同期呼び出し(メタデータをIPFSにピン留めするためのPinata、スマート・コントラクトをロードするためのAlchemy Web3、およびトランザクションに署名するためのメタマスク)を行うため、関数も非同期になります。
関数への3つの入力は、デジタル資産のurl、name、およびdescriptionになります。connectWallet関数の下に次の関数シグネチャを追加します。
export const mintNFT = async (url, name, description) => {}
入力エラー処理
当然のことながら、関数の開始時に何らかの入力エラー処理を行うことは理にかなっているため、入力パラメータが正しくない場合はこの関数を終了します。関数内に次のコードを追加しましょう。
export const mintNFT = async (url, name, description) => {
//エラー処理
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
}
基本的に、入力パラメータのいずれかが空の文字列である場合、successブール値がfalseであり、status文字列がUIのすべてのフィールドに入力する必要があることを伝えるJSONオブジェクトを返します。
メタデータをIPFSにアップロードする
メタデータが適切にフォーマットされていることがわかったら、次のステップはそれをJSONオブジェクトにラップし、記述したpinJSONToIPFSを介してIPFSにアップロードすることです!
これを行うには、まずpinJSONToIPFS関数をinteract.jsファイルにインポートする必要があります。interact.jsの一番上に次を追加しましょう。
import { pinJSONToIPFS } from "./pinata.js"
pinJSONToIPFSはJSONボディを受け取ることを思い出してください。したがって、それを呼び出す前に、url、name、およびdescriptionパラメータをJSONオブジェクトにフォーマットする必要があります。
コードを更新してmetadataというJSONオブジェクトを作成し、このmetadataパラメータを使用してpinJSONToIPFSを呼び出しましょう。
export const mintNFT = async (url, name, description) => {
//エラー処理
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
//メタデータを作成
const metadata = new Object()
metadata.name = name
metadata.image = url
metadata.description = description
//Pinataを呼び出す
const pinataResponse = await pinJSONToIPFS(metadata)
if (!pinataResponse.success) {
return {
success: false,
status: "😢 Something went wrong while uploading your tokenURI.",
}
}
const tokenURI = pinataResponse.pinataUrl
}
pinJSONToIPFS(metadata)への呼び出しの応答をpinataResponseオブジェクトに保存していることに注目してください。次に、このオブジェクトを解析してエラーがないか確認します。
エラーがある場合は、successブール値がfalseであり、status文字列が呼び出しに失敗したことを伝えるJSONオブジェクトを返します。それ以外の場合は、pinataResponseからpinataURLを抽出し、それをtokenURI変数として保存します。
これで、ファイルの上部で初期化したAlchemy Web3 APIを使用してスマート・コントラクトをロードする時間です。mintNFT関数の下部に次のコード行を追加して、コントラクトをwindow.contractグローバル変数に設定します。
window.contract = await new web3.eth.Contract(contractABI, contractAddress)
mintNFT関数に追加する最後のものは、イーサリアムトランザクションです。
//イーサリアムのトランザクションを設定する
const transactionParameters = {
to: contractAddress, // コントラクトの公開時を除き必須。
from: window.ethereum.selectedAddress, // ユーザーのアクティブなアドレスと一致する必要があります。
data: window.contract.methods
.mintNFT(window.ethereum.selectedAddress, tokenURI)
.encodeABI(), //NFTスマート・コントラクトを呼び出す
}
//メタマスク経由でトランザクションに署名する
try {
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
})
return {
success: true,
status:
"✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +
txHash,
}
} catch (error) {
return {
success: false,
status: "😥 Something went wrong: " + error.message,
}
}
イーサリアムトランザクションに既に精通している場合は、構造がこれまで見たものと非常に似ていることに気づくでしょう。
- まず、トランザクションパラメータをセットアップします。
toは受信者アドレス(スマート・コントラクト)を指定しますfromはトランザクションの署名者(メタマスクに接続されているユーザーのアドレス:window.ethereum.selectedAddress)を指定しますdataには、スマート・コントラクトのmintNFTメソッドへの呼び出しが含まれており、入力としてtokenURIとユーザーのウォレットアドレスwindow.ethereum.selectedAddressを受け取ります
- 次に、メタマスクにトランザクションへの署名を要求するawait呼び出し
window.ethereum.request,を行います。このリクエストでは、ethメソッド(eth_SentTransaction)を指定し、transactionParametersを渡していることに注目してください。この時点で、ブラウザでメタマスクが開き、ユーザーにトランザクションへの署名または拒否を求めます。- トランザクションが成功した場合、関数はブール値
successがtrueに設定され、status文字列がユーザーにトランザクションの詳細についてEtherscanを確認するように促すJSONオブジェクトを返します。 - トランザクションが失敗した場合、関数は
successブール値がfalseに設定され、status文字列がエラーメッセージを伝えるJSONオブジェクトを返します。
- トランザクションが成功した場合、関数はブール値
全体として、mintNFT関数は次のようになります。
export const mintNFT = async (url, name, description) => {
//エラー処理
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
//メタデータを作成
const metadata = new Object()
metadata.name = name
metadata.image = url
metadata.description = description
//Pinataのpinリクエスト
const pinataResponse = await pinJSONToIPFS(metadata)
if (!pinataResponse.success) {
return {
success: false,
status: "😢 Something went wrong while uploading your tokenURI.",
}
}
const tokenURI = pinataResponse.pinataUrl
//スマート・コントラクトを読み込む
window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract();
//イーサリアムのトランザクションを設定する
const transactionParameters = {
to: contractAddress, // コントラクトの公開時を除き必須。
from: window.ethereum.selectedAddress, // ユーザーのアクティブなアドレスと一致する必要があります。
data: window.contract.methods
.mintNFT(window.ethereum.selectedAddress, tokenURI)
.encodeABI(), //NFTスマート・コントラクトを呼び出す
}
//メタマスク経由でトランザクションに署名する
try {
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
})
return {
success: true,
status:
"✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +
txHash,
}
} catch (error) {
return {
success: false,
status: "😥 Something went wrong: " + error.message,
}
}
}
これは巨大な関数ですね!あとは、mintNFT関数をMinter.jsコンポーネントに接続するだけです...
mintNFTをMinter.jsフロントエンドに接続する
Minter.jsファイルを開き、上部のimport { connectWallet, getCurrentWalletConnected } from "./utils/interact.js";行を次のように更新します。
import {
connectWallet,
getCurrentWalletConnected,
mintNFT,
} from "./utils/interact.js"
最後に、onMintPressed関数を実装して、インポートしたmintNFT関数へのawait呼び出しを行い、トランザクションが成功したか失敗したかを反映するようにstatus状態変数を更新します。
const onMintPressed = async () => {
const { status } = await mintNFT(url, name, description)
setStatus(status)
}
ライブウェブサイトにNFTをデプロイする
ユーザーがやり取りできるようにプロジェクトをライブにする準備はできましたか?ミンターをライブウェブサイトにデプロイするためのこちらのチュートリアル (opens in a new tab)を確認してください。
最後のステップ...
ブロックチェーンの世界に旋風を巻き起こす
冗談です、チュートリアルの最後までたどり着きましたね!
要約すると、NFTミンターを構築することで、以下の方法を無事に学びました。
- フロントエンドプロジェクトを介してメタマスクに接続する
- フロントエンドからスマート・コントラクトのメソッドを呼び出す
- メタマスクを使用してトランザクションに署名する
おそらく、dappを介してミントされたNFTをウォレットで披露したいと思うでしょう。そのため、クイックチュートリアル「ウォレットでNFTを表示する方法」 (opens in a new tab)を必ず確認してください!
そして、いつものように、質問がある場合はAlchemyのディスコード (opens in a new tab)でお手伝いします。このチュートリアルの概念を将来のプロジェクトにどのように適用するかを見るのが待ちきれません!
ページの最終更新: 2026年4月3日