Metaplexを使ってSolana上にNFTをミントするAPIを作ろう!
はじめに
皆さん、こんにちは!
9月中旬〜10月初旬まで開催されていた Solana の大型ハッカソン Radar Hackathon に参加しました。
その時にNFT特化のライブラリなどを提供している Metaplex を使ってみたところ使い勝手が良かったので記事にしてみました!
僕は、 Yukiさんにお声がけいただいて AW系のゲームである Q-drop Adventure というプロダクトの開発をご一緒させていただきました!!
Live demoは以下で公開されています!!
ぜひ触ってみてください!!
Metaplexとは
Metaplex はSolana上でNFT開発ツールやライブラリを提供しています!
今年の3月に 新しいNFT標準となる「Core」というものを発表しています。
以下のブログではその Core NFTを発行する手順が丁寧に解説されているのですが今回はこの内容を参考にNext.jsに組み込んでみました!!
自分でも試してみたリポジトリは以下の通りです。
こっちはミニマムのコードで Metaplex Core NFTの実装を試せるのでおすすめです!!
今回の実装
今回実装したソースコードは以下のGitHubリポジトリに含まれています。
ゲームをクリアした人には NFTを2種類ミントすることを考えているのですがそのための方法として Metaplex を使いました!!
例えば、 WinnerNFTを発行する時のコードは以下のように実装しています!
import { create, mplCore } from "@metaplex-foundation/mpl-core";
import {
createGenericFile,
generateSigner,
keypairIdentity
} from "@metaplex-foundation/umi";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { irysUploader } from "@metaplex-foundation/umi-uploader-irys";
import { base58 } from "@metaplex-foundation/umi/serializers";
import fs from "fs";
import { NextResponse } from "next/server";
import path from "path";
/**
* NFT作成用のAPI
* @returns
*/
export async function POST() {
try {
// UMI インスタンスを作成する。
const umi = createUmi("https://api.devnet.solana.com")
.use(mplCore())
.use(
irysUploader({
address: "https://devnet.irys.xyz",
})
);
// バックエンド用の鍵ペアを読み込む
const keyData = fs.readFileSync(path.join(process.cwd(), "src", "data", "id.json"));
const walletFile = JSON.parse(keyData.toString());
// キーペアを作成
let keypair = umi.eddsa.createKeypairFromSecretKey(
new Uint8Array(walletFile)
);
// バックエンド用の鍵ペアとUMIを紐付ける。
umi.use(keypairIdentity(keypair));
// Upload image data
const imageFile = fs.readFileSync(path.join(process.cwd(), 'public/images/nft/winnerNft.png'));
const umiImageFile = createGenericFile(imageFile, "image.png", {
tags: [{ name: "Content-Type", value: "image/png" }],
});
console.log("Uploading Image...");
// upload
const imageUri = await umi.uploader.upload([umiImageFile]).catch((err) => {
throw new Error(err);
});
const irysImageUri = imageUri[0].replace("arweave.net", "gateway.irys.xyz");
console.log("imageUri: " + irysImageUri);
const metadata = {
name: "Q Drop Adventure Winner NFT",
description: "This is a Q Drop Adventure Winner NFT",
image: irysImageUri,
external_url: "https://x.com/a_kingdom_radar",
attributes: [
{
trait_type: "rarity",
value: "max",
},
],
properties: {
files: [
{
uri: imageUri[0],
type: "image/jpeg",
},
],
category: "image",
},
};
// Call upon umi's `uploadJson` function to upload our metadata to Arweave via Irys.
console.log("Uploading Metadata...");
const metadataUri = await umi.uploader.uploadJson(metadata).catch((err) => {
throw new Error(err);
});
const irysMetadataUri = metadataUri.replace(
"arweave.net",
"gateway.irys.xyz"
);
console.log("metadataUri: " + irysMetadataUri);
const asset = generateSigner(umi);
console.log("Creating NFT...");
// NFTを作成するトランザクションを署名して送信
const tx = await create(umi, {
asset,
name: "My Super NFT",
uri: irysMetadataUri,
}).sendAndConfirm(umi);
// Finally we can deserialize the signature that we can check on chain.
const signature = base58.deserialize(tx.signature)[0];
// Log out the signature and the links to the transaction and the NFT.
console.log("\nNFT Created");
console.log("View Transaction on Solana Explorer");
console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`);
console.log("\n");
console.log("View NFT on Metaplex Explorer");
console.log(
`https://core.metaplex.com/explorer/${asset.publicKey}?env=devnet`
);
return NextResponse.json({
txHash: `https://explorer.solana.com/tx/${signature}?cluster=devnet`,
metaplexUrl: `https://core.metaplex.com/explorer/${asset.publicKey}?env=devnet`,
})
} catch (error) {
console.error("error:", error);
throw error;
}
}
発行の際ウォレットが必要になるのですが、今回はウォレットを持っていない人でも発行できるようにバックエンドウォレットを用意してそこから発行するようにしています!
上から順に
- UMIインスタンスの設定
- 画像データのホスティング
- NFTメタデータの設定
- メタデータのホスティング
- NFTの発行
という実装になっています!!
Areweave 上に画像データをホスティングしているらしいのですが、その時に必要な資産も SOL でOKです!!
ここがMetaplexの使いやすい点だなと思いました!!
動かしてみた!
ではこのコードを動かしてみます!!
まずフロントエンドを起動します!!
yarn dev
その後、以下のコマンドを打って APIを呼び出してみます!!
curl -XPOST "http://localhost:3000/api/nft/mint/winnerNft"
しばらく待つと・・・
ターミナル上にはログが出力されます!!
bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)
Uploading Image...
imageUri: https://gateway.irys.xyz/5TLfaC5dSK6JYHtEcrPXVXVjqYq91YvE68UqzqVWYQ1C
Uploading Metadata...
metadataUri: https://gateway.irys.xyz/CidsQDowbZKjUarbqyXi8PV1GNMaRWAesVy9bPM5Kdmn
Creating NFT...
NFT Created
View Transaction on Solana Explorer
https://explorer.solana.com/tx/4PLrhxdVdaD1xkUzcUbUGgW4vvE3FAjFZ1MdjRDFGkXS2DLZ5K7vFm1Cqk1Vcua4fvdM12C7u324yWofDcd7D87o?cluster=devnet
View NFT on Metaplex Explorer
https://core.metaplex.com/explorer/Bor7wL2cKrJzQkPXSMzpZ1pTVfrew2LH2XF9bEb8YPdX?env=devnet
POST /api/nft/mint/winnerNft 200 in 45673ms
結果としてブロックエクスプローラーとNFTまでのURLが出力されます!!
{
"txHash":"https://explorer.solana.com/tx/4PLrhxdVdaD1xkUzcUbUGgW4vvE3FAjFZ1MdjRDFGkXS2DLZ5K7vFm1Cqk1Vcua4fvdM12C7u324yWofDcd7D87o?cluster=devnet",
"metaplexUrl":"https://core.metaplex.com/explorer/Bor7wL2cKrJzQkPXSMzpZ1pTVfrew2LH2XF9bEb8YPdX?env=devnet"
}
無事にNFTが発行されたようです!!
念の為両方にアクセスして確認してみます!!
ちゃんと発行できていました!!
まとめ
いかがでしたでしょうか??
普段は Solana 系のプロトコルやSDKには触れないのですが、今回はハッカソンということでちょっと触れてみました!
画像のホスティングからNFT発行まで一気通貫でできるので Metaplex は非常に使い勝手が良いと思いました!!!
皆さんも触ってみてください!!
また、最後になりますが僕たちのチームのプロダクトである Q Drop Adventure を応援していただけると大変嬉しいです!!
プロダクトページは以下です!
プロダクトのピッチ資料やビデオは以下で確認ができます!!
良かったら見てみてください!!
今回は以上となります!!
ここまで読んでいただきありがとうございました!!
Discussion