@metaplex-foundation/js - uploadMetadata を実装していたときのメモ。
現象
チュートリアルを参考に以下を実装。
uploadMetadata.ts
// Ref: https://github.com/metaplex-foundation/js#uploadmetadata
import { Metaplex, keypairIdentity, bundlrStorage } from "@metaplex-foundation/js";
import { Connection, clusterApiUrl, Keypair, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
const main = async() => {
const connection = new Connection(clusterApiUrl("devnet"));
const wallet = Keypair.generate();
// airdrop
let airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL,
);
const latestBlockHash = await connection.getLatestBlockhash();
await connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
});
const walletBalance = await connection.getBalance(wallet.publicKey);
console.log('walletBalance =>', walletBalance);
// End airdrop
const metaplex = Metaplex.make(connection)
.use(keypairIdentity(wallet))
.use(bundlrStorage());
const { uri } = await metaplex.nfts().uploadMetadata({
name: "My NFT",
description: "My description",
image: "https://arweave.net/ovSe7hNSNMYGQU55V8pOfIsIlZ4KIQNip6g25AnMu9s",
});
console.log(uri);
};
main();
実行するとbundler(Bundlr Network)のtxが400とのこと。
% ts-node uploadMetadata.ts
Error: HTTP Error: Posting transaction 3EgQcVLCfeBrm2qoA7DfA14iEy8PmqP8T8YReTxWPnjofJsbxgXm8YNGrHT3fU2UiqPVUL1CDiTeypdLJvXVEzSB information to the bundler: 400 Invalid tx
at Function.checkAndThrow (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@bundlr-network/client/src/common/utils.ts:27:19)
at Fund.fund (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@bundlr-network/client/src/common/fund.ts:48:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async BundlrStorageDriver.fund (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@metaplex-foundation/js/src/plugins/bundlrStorage/BundlrStorageDriver.ts:152:5)
at async BundlrStorageDriver.uploadAll (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@metaplex-foundation/js/src/plugins/bundlrStorage/BundlrStorageDriver.ts:110:5)
at async Object.handle (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@metaplex-foundation/js/src/plugins/nftModule/uploadMetadata.ts:33:25)
at async /Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@metaplex-foundation/js/src/utils/Task.ts:82:23
at async Disposable.run (/Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/scripts/metaplex/latest/node_modules/@metaplex-foundation/js/src/utils/Disposable.ts:34:14)
原因
@metaplex-foundation/js - bundlrStorage に記載されているが、デフォルトはBundlr NetworkのMainnetが設定されている。
Devnetの設定のまま、Bundler NetworkはMainnet指定だったため、整合性があわなくなっていた。
By default, it will use the same RPC endpoint used by the Metaplex instance as a providerUrl and the mainnet address "https://node1.bundlr.network" as the Bundlr address.
Devnetで実装する場合は以下の設定が必要。
import { bundlrStorage } from "@metaplex-foundation/js";
metaplex.use(bundlrStorage({
address: 'https://devnet.bundlr.network',
providerUrl: 'https://api.devnet.solana.com',
timeout: 60000,
}));
対応
上記の設定を組み込むと、最終版は以下のようになった。
// Ref: https://github.com/metaplex-foundation/js#uploadmetadata
import { Metaplex, keypairIdentity, bundlrStorage } from "@metaplex-foundation/js";
import { Connection, clusterApiUrl, Keypair, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
const main = async() => {
const connection = new Connection(clusterApiUrl("devnet"));
const wallet = Keypair.generate();
// airdrop
let airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL,
);
const latestBlockHash = await connection.getLatestBlockhash();
await connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
});
const walletBalance = await connection.getBalance(wallet.publicKey);
console.log('walletBalance =>', walletBalance);
// End airdrop
const metaplex = Metaplex.make(connection)
.use(keypairIdentity(wallet))
.use(bundlrStorage({
address: 'https://devnet.bundlr.network',
providerUrl: 'https://api.devnet.solana.com',
timeout: 60000,
}));
const { uri } = await metaplex.nfts().uploadMetadata({
name: "My NFT",
description: "My description",
image: "https://arweave.net/ovSe7hNSNMYGQU55V8pOfIsIlZ4KIQNip6g25AnMu9s",
});
console.log(uri);
};
main();