Metaplex Create an Asset into a Collection を試していたときに発生したエラー。
Agenda
現象
サンプル通りに作成して実行すると以下のエラーが発生。
ts-node src/creatingAssetIntoCollection.ts
/Users/metaplex/core/node_modules/@solana/web3.js/src/connection.ts:5923
throw new SendTransactionError(
^
SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Program failed to complete
at Connection.sendEncodedTransaction (/Users/metaplex/core/node_modules/@solana/web3.js/src/connection.ts:5923:13)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Connection.sendRawTransaction (/Users/metaplex/core/node_modules/@solana/web3.js/src/connection.ts:5880:20)
at async Object.sendTransaction (/Users/metaplex/core/node_modules/@metaplex-foundation/umi-rpc-web3js/src/createWeb3JsRpc.ts:327:25)
at async TransactionBuilder.sendAndConfirm (/Users/metaplex/core/node_modules/@metaplex-foundation/umi/src/TransactionBuilder.ts:359:23) {
logs: [
'Program CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d invoke [1]',
'Program log: Instruction: Create',
"Program log: panicked at 'index out of bounds: the len is 0 but the index is 0', programs/mpl-core/src/utils.rs:28:22",
'Program CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d consumed 5985 of 200000 compute units',
'Program CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d failed: SBF program panicked'
]
}
ソース
// Docs: https://developers.metaplex.com/core/create-asset
// Lib
import * as dotenv from 'dotenv';
import * as bs58 from 'bs58';
import { sleep } from './lib/sleep';
// Metaplex
import { keypairIdentity, generateSigner } from '@metaplex-foundation/umi';
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import {
mplCore,
createV1,
createCollectionV1,
} from '@metaplex-foundation/mpl-core';
// Solana
import { Connection } from '@solana/web3.js';
const creatingAssetIntoCollection = async () => {
// -------------------------------------
// Setup
// -------------------------------------
dotenv.config();
// Set Endpoint
const endpoint = process.env.ENDPOINT;
if (!endpoint) throw new Error('endpoint not found.');
const umi = createUmi(endpoint);
// Set Payer
const payerSecretKey = process.env.PAYER_SECRET_KEY;
if (!payerSecretKey) throw new Error('payerSecretKey not found.');
const secretKeyUInt8Array = new Uint8Array(JSON.parse(payerSecretKey));
const payerKeypair =
umi.eddsa.createKeypairFromSecretKey(secretKeyUInt8Array);
umi.use(keypairIdentity(payerKeypair));
// Register Library
umi.use(mplCore());
// -------------------------------------
// Create a Collection
// -------------------------------------
const collection = generateSigner(umi);
const creatingCollectionResult = await createCollectionV1(umi, {
collection: collection,
name: 'Core Collection',
uri: 'https://example.com/my-nft.json',
}).sendAndConfirm(umi);
// -------------------------------------
// Create an Asset Into a Collection
// -------------------------------------
const asset = generateSigner(umi);
const creatingAssetResult = await createV1(umi, {
asset,
name: 'My Core NFT',
uri: 'https://arweave.net/IjF_Sd0zcvGwTbkfFjPFoiHlmVPn7duJ1diU92OZHKo',
collection: collection.publicKey,
}).sendAndConfirm(umi);
console.log('payer =>', payerKeypair.publicKey.toString());
console.log('collection =>', collection.publicKey.toString());
console.log('asset =>', asset.publicKey.toString());
console.log(
'creatingCollectionResult signature =>',
bs58.encode(creatingCollectionResult.signature)
);
console.log(
'creatingAssetResult signature =>',
bs58.encode(creatingAssetResult.signature)
);
};
creatingAssetIntoCollection();
何回か実行すると、たまに成功する。
原因
以下2STEPで処理を進めているが、Collectionが作成されていないのに紐付けてCore NFTを作成してしまっていることが原因。
- Core NFT Collectionを作成 ← これがまだ作成完了していない
- 上記Collectionに紐付けてCore NFTを作成
対応
Collectionの作成有無をチェックしてから次の処理に進める。
ソース
// -------------------------------------
// Create a Collection
// -------------------------------------
const collection = generateSigner(umi);
const creatingCollectionResult = await createCollectionV1(umi, {
collection: collection,
name: 'Core Collection',
uri: 'https://example.com/my-nft.json',
}).sendAndConfirm(umi);
// ーーー以下を追加ーーーーーーーーーーーーーーーー
// -------------------------------------
// Check a Created Collection
// -------------------------------------
const sleep = (ms: number): Promise<void> => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
const connection = new Connection(endpoint, 'confirmed');
let status = await connection.getSignatureStatus(
bs58.encode(creatingCollectionResult.signature),
{
searchTransactionHistory: true,
}
);
while (
status.value?.err === null &&
status.value?.confirmationStatus === 'confirmed'
) {
console.log('Collection not found. Sleep then check again...');
await sleep(3000); // 1000 = 3sec
status = await connection.getSignatureStatus(
bs58.encode(creatingCollectionResult.signature),
{
searchTransactionHistory: true,
}
);
}
// ーーー追加ここまでーーーーーーーーーーーーーーーー
// -------------------------------------
// Create an Asset Into a Collection
// -------------------------------------
備考
本件は、NFT作成でよく発生する現象で、NFTを作る場合は、その前段階でいくつか処理が入っていて、順番に1つずつ処理が終わってから次に進める必要がある。間に完了チェックを入れずに、一気に処理を進めてしまうと、ブロックチェーン上の処理が終わっていないのにも関わらず、処理を進めてしまい失敗する、といった現象になる。
基礎的なハマりポイントなのに忘れがちなため、要注意。