NFTをミントする方法(NFTチュートリアルシリーズ パート2/3)
「非代替性トークン (NFT) のミンティング」とは、ブロックチェーン上でERC-721トークンのユニークなインスタンスを公開する行為です。このNFTチュートリアルシリーズのパート1で作成したスマート・コントラクトを使用して、Web3のスキルを活かし、NFTをミントしてみましょう。このチュートリアルの最後には、心(とウォレット)が望む限り、いくらでもNFTをミントできるようになります!
さあ、始めましょう!
ステップ1:セットアップの確認
NFTスマート・コントラクトの作成に関する最初のチュートリアルに従った場合、必要なものはすべて揃っています。Ethersプラグイン (新しいタブで開きます)とEthers.js (新しいタブで開きます)(イーサリアムのブロックチェーンへのリクエスト作成を容易にするライブラリ)を含むHardhat 3プロジェクトです。ミンティングのコードはHardhatスクリプトとして記述するため、パート1のSepoliaネットワーク設定とAPI_URLおよびPRIVATE_KEYの値を再利用します。新しくインストールするものはありません。
ステップ2:mint-nft.jsファイルの作成
scriptsディレクトリ内にmint-nft.jsファイルを作成し、以下のコードを追加します。
import { network } from "hardhat"
const { ethers } = await network.create()
デプロイ・スクリプトと同様に、network.create()はスクリプトの実行時に--networkで選択したネットワークに接続し、そのネットワーク用のethersオブジェクトを提供します。
ステップ3:コントラクトABIの取得
コントラクトのアプリケーション・バイナリ・インターフェース (ABI) は、スマート・コントラクトと対話するためのインターフェースです。について詳しく学ぶことができます。Hardhatは、コントラクトをコンパイルする際に自動的にABIを生成し、artifacts/contracts/MyNFT.sol/MyNFT.jsonファイルに保存します。ステップ5でコントラクトのインスタンスを作成する際、Hardhat EthersプラグインがそこからABIを読み込んでくれるため、自分で読み込む必要はありません。
ABIを確認したい場合は、コンソールに出力することができます。プロジェクトのルートディレクトリから、以下を実行します。
node -p "JSON.stringify(require('./artifacts/contracts/MyNFT.sol/MyNFT.json').abi)"
ステップ4:IPFSを使用してNFTのメタデータを設定する
パート1のチュートリアルを思い出していただくと、mintNFTスマート・コントラクト関数は、NFTのメタデータを記述したJSONドキュメントに解決されるべきtokenURIパラメータを受け取ります。このメタデータこそがNFTに命を吹き込むものであり、名前、説明、画像、その他の属性など、設定可能なプロパティを持たせることができます。
Interplanetary File System (IPFS) は、分散型ファイルシステムでデータを保存および共有するための分散型プロトコルおよびピア・ツー・ピアのネットワークです。
NFTのアセットとメタデータを保存し、NFTが真に分散型であることを保証するために、便利なIPFSのアプリケーション・プログラミング・インターフェース(API)およびツールキットであるPinataを使用します。Pinataアカウントをお持ちでない場合は、こちら (新しいタブで開きます)から無料アカウントにサインアップし、メールアドレスの確認手順を完了してください。
アカウントを作成したら、以下の手順に従います。
-
Filesページ (新しいタブで開きます)に移動し、ページ右上にある「Add」ボタンをクリックします。
-
Pinataに画像をアップロードします。これがNFTの画像アセットになります。アセットの名前は自由につけて構いません。必ずパブリックIPFSにアップロードしてください。プライベートIPFS (新しいタブで開きます)上のファイルは、NFTを表示するウォレットやマーケットプレイスから取得できません。
-
アップロード後、FilesページにファイルがCID(コンテンツ識別子)とともにリストされているのがわかります。CIDをコピーします。アップロードしたファイルは、
https://gateway.pinata.cloud/ipfs/<CID>、またはPinataのサイドバーの「Gateways」の下にリストされている専用ゲートウェイから確認できます。例えば、私たちがIPFSで使用した画像はこちら (新しいタブで開きます)で確認できます。
さて、Pinataにもう1つドキュメントをアップロードする必要があります。しかしその前に、それを作成しなければなりません!
ルートディレクトリにnft-metadata.jsonという新しいファイルを作成し、以下のJSONコードを追加します。
{
"attributes": [
{
"trait_type": "Breed",
"value": "Maltipoo"
},
{
"trait_type": "Eye color",
"value": "Mocha"
}
],
"description": "The world's most adorable and sensitive pup.",
"image": "ipfs://QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb",
"name": "Ramses"
}
JSONのデータは自由に変更してください。attributesセクションを削除したり追加したりできます。最も重要なのは、imageフィールドがipfs://<image-CID>の形式でIPFS画像の場所を指していることを確認することです。そうしないと、あなたのNFTには(とても可愛い!)犬の写真が含まれることになります。
JSONファイルの編集が完了したら保存し、画像をアップロードしたのと同じ手順でPinataにアップロードします。nft-metadata.jsonのCIDもコピーしておいてください。ステップ9で必要になります。
ステップ5:コントラクトのインスタンスを作成する
さて、コントラクトと対話するために、コード内でそのインスタンスを作成する必要があります。そのためには、パート1でデプロイ・スクリプトが出力したコントラクトのアドレスが必要です。コントラクトをデプロイする際に使用したアドレスを検索することで、Etherscan (新しいタブで開きます)やBlockscout (新しいタブで開きます)で見つけることもできます。
上記の例では、コントラクトのアドレスは0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778です。
次に、Hardhat EthersプラグインのgetContractAtメソッドを使用して、名前(どのABIを使用するかを指示します)とアドレスを使用してコントラクトを作成します。mint-nft.jsファイルに以下を追加し、アドレスを自分のものに置き換えてください。
const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"
const nftContract = await ethers.getContractAt("MyNFT", contractAddress)
ステップ6:.envファイルの確認
送信するすべてのトランザクションは、アカウントの秘密鍵で署名される必要があります。チュートリアルのパート1を完了している場合、.envファイルはすでに以下のようになっているはずです。
API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"
パブリック・アドレスを追加する必要はありません。ethersが秘密鍵からそれを算出します。
ステップ7:トランザクションの作成
まず、mintNFT(tokenURI)という名前の関数を定義し、以下の手順でトランザクションを作成しましょう。
-
トランザクションを送信するアカウントを取得します。
ethers.getSigners()はネットワークに設定されたアカウントを返します。Sepoliaの場合、これは.envに秘密鍵があるアカウントです。mintNFTはonlyOwnerであるため、これはコントラクトをデプロイしたのと同じアカウントである必要があります。 -
コントラクトのインスタンスで
mintNFT関数を呼び出し、自分自身のアドレスを受信者として、メタデータのURIを指定します。これがこのトランザクションで実行したい計算であり、この場合はNFTのミンティングです。
ナンス(リプレイ攻撃を防ぐための、あなたのアドレスから送信されたトランザクションの数)、ガス・リミット、または手数料を自分で計算する必要はありません。ethersがトランザクションを送信する前にそれらを取得または見積もります。
現在のmint-nft.jsファイルは以下のようになっているはずです。
import { network } from "hardhat"
const { ethers } = await network.create()
const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"
const nftContract = await ethers.getContractAt("MyNFT", contractAddress)
async function mintNFT(tokenURI) {
const [signer] = await ethers.getSigners()
// トランザクションを送信します。ethersがノンス、ガスリミット、手数料を自動的に入力します。
const tx = await nftContract.mintNFT(signer.address, tokenURI)
}
ステップ8:トランザクションへの署名
ネットワークは私たちの秘密鍵で設定されているため、ethersはトランザクションを送信する前に自動的にそれで署名します。
mintNFTを呼び出すと、トランザクションが送信された後に戻り値としてトランザクション・ハッシュが得られます。これを使用して、トランザクションがマイニングされ、ネットワークによって破棄されなかったことを確認できます。その後、tx.wait()はトランザクションがブロックに含まれるまで待機します。また、トランザクションが正常に処理されたかどうかを知るために、いくつかのエラーチェックも追加しました。
import { network } from "hardhat"
const { ethers } = await network.create()
const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"
const nftContract = await ethers.getContractAt("MyNFT", contractAddress)
async function mintNFT(tokenURI) {
const [signer] = await ethers.getSigners()
try {
// トランザクションを送信します。ethersがノンス、ガスリミット、手数料を自動的に入力します。
const tx = await nftContract.mintNFT(signer.address, tokenURI)
console.log("The hash of your transaction is:", tx.hash)
// トランザクションがブロックに含まれるのを待ちます。
const receipt = await tx.wait()
console.log("Your NFT was minted in block", receipt.blockNumber)
} catch (err) {
console.log("Something went wrong when submitting your transaction:", err)
}
}
ステップ9:mintNFTの呼び出しとmint-nft.jsの実行
Pinataにアップロードしたnft-metadata.jsonを覚えていますか?PinataからそのCIDを取得し、ipfs://<metadata-CID>を関数mintNFTのパラメータとして渡します。ウォレットやマーケットプレイスは、任意のIPFSゲートウェイを通じてipfs:// URIを解決するため、あなたのNFTが単一のゲートウェイに依存することはありません。
別のウィンドウで
https://gateway.pinata.cloud/ipfs/<metadata-CID>を読み込み、コピーしたCIDがnft-metadata.jsonにリンクしていることを再確認してください。ページは以下のスクリーンショットのようになるはずです。
全体として、コードは以下のようになるはずです。
import { network } from "hardhat"
const { ethers } = await network.create()
const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"
const nftContract = await ethers.getContractAt("MyNFT", contractAddress)
async function mintNFT(tokenURI) {
const [signer] = await ethers.getSigners()
try {
// トランザクションを送信します。ethersがノンス、ガスリミット、手数料を自動的に入力します。
const tx = await nftContract.mintNFT(signer.address, tokenURI)
console.log("The hash of your transaction is:", tx.hash)
// トランザクションがブロックに含まれるのを待ちます。
const receipt = await tx.wait()
console.log("Your NFT was minted in block", receipt.blockNumber)
} catch (err) {
console.log("Something went wrong when submitting your transaction:", err)
}
}
await mintNFT("ipfs://QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP")
それでは、Sepoliaに対してスクリプトを実行し、NFTをミントします。
npx hardhat run scripts/mint-nft.js --network sepolia
数秒後、ターミナルに以下のような応答が表示されるはずです。
The hash of your transaction is: 0x301791fdf492001fcd9d5e5b12f3aa1bbbea9a88ed24993a8ab2cdae2d06e1e8
Your NFT was minted in block <block number>
トランザクションの詳細を確認するには、Etherscan (新しいタブで開きます)またはBlockscout (新しいタブで開きます)でそのハッシュを検索してください。
EtherscanでNFTのトランザクション・ハッシュを表示する
これで完了です!イーサリアムのブロックチェーン上でNFTをデプロイし、ミントすることができました
mint-nft.jsを使用すれば、心(とウォレット)が望む限り、いくらでもNFTをミントできます!ただし、NFTのメタデータを記述した新しいtokenURIを渡すことを忘れないでください(そうしないと、IDが異なるだけの同一のNFTを大量に作成することになります)。
おそらく、ウォレットで自分のNFTを自慢したいと思うでしょう。ぜひパート3:ウォレットでNFTを表示する方法をチェックしてください!

