使用mpl-token-metadata创建Metaplex元数据账户报索引越界错误
问题描述
使用@metaplex-foundation/mpl-token-metadata库的createCreateMetadataAccountV2Instruction方法创建元数据账户时,交易发送失败,模拟阶段抛出如下错误:
SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Program failed to complete at Connection.sendEncodedTransaction (C:\xampp\htdocs\sol-tools\node_modules\@solana\web3.js\src\connection.ts:4464:13) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async Connection.sendRawTransaction (C:\xampp\htdocs\sol-tools\node_modules\@solana\web3.js\src\connection.ts:4423:20) at async Connection.sendTransaction (C:\xampp\htdocs\sol-tools\node_modules\@solana\web3.js\src\connection.ts:4411:12) at async sendAndConfirmTransaction (C:\xampp\htdocs\sol-tools\node_modules\@solana\web3.js\src\util\send-and-confirm-transaction.ts:31:21) at async addMetadataToToken (C:\xampp\htdocs\sol-tools\src\lib\metadata.ts:86:16) at async Command.<anonymous> (C:\xampp\htdocs\sol-tools\src\cli.ts:48:7) { logs: [ 'Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [1]', 'Program log: Instruction: Create Metadata Accounts v2', "Program log: panicked at 'range end index 36 out of range for slice of length 0', program/src/utils.rs:231:27", 'Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 6223 of 1400000 compute units', 'Program failed to complete: BPF program panicked', 'Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s failed: Program failed to complete' ] }
对应实现代码:
import { createCreateMetadataAccountV2Instruction, PROGRAM_ID, } from '@metaplex-foundation/mpl-token-metadata' import { Connection, Keypair, PublicKey, sendAndConfirmTransaction, Transaction, } from '@solana/web3.js' export const addMetadataToToken = async ( connection: Connection, tokenMint: PublicKey, tokenOwner: Keypair, name: string, symbol: string, arweaveLink: string ) => { const seed1 = Buffer.from('metadata', 'utf8') const seed2 = PROGRAM_ID.toBuffer() const seed3 = tokenMint.toBuffer() const [metadataPDA, _bump] = PublicKey.findProgramAddressSync( [seed1, seed2, seed3], PROGRAM_ID ) const accounts = { metadata: metadataPDA, mint: tokenMint, mintAuthority: tokenOwner.publicKey, payer: tokenOwner.publicKey, updateAuthority: tokenOwner.publicKey, } const dataV2 = { name, symbol, uri: arweaveLink, sellerFeeBasisPoints: 0, creators: null, collection: null, uses: null, } const args = { createMetadataAccountArgsV2: { data: dataV2, isMutable: true, }, } const ix = createCreateMetadataAccountV2Instruction(accounts, args) const tx = new Transaction() tx.add(ix) const txid = await sendAndConfirmTransaction(connection, tx, [tokenOwner]) console.log(txid) }
报错原因
核心错误来自元数据合约执行时的越界访问:合约执行Create Metadata Accounts v2指令时,会先读取传入mint账户的前36字节数据(4字节mint权限标记+32字节mint权限公钥)做权限校验,但实际读取到的mint账户数据长度为0,直接触发合约panic。
触发该问题的常见场景有3种:
- 传入的
tokenMint对应的SPL代币铸造账户未完成链上初始化,比如创建mint的交易还没得到链上确认,就提前发起了元数据创建交易 - 传入的
tokenMint公钥有误,对应链上账户不是已初始化的标准SPL Token Mint账户,账户数据为空或格式不符合SPL Mint规范 - 创建mint时使用了SPL Token 2022程序,而当前使用的旧版mpl-token-metadata库的V2指令不支持Token 2022格式的mint账户,无法正确解析mint数据
修复方案
- 先确认mint创建状态:调用元数据创建接口前,必须等待mint创建交易完成链上确认,可通过
connection.getAccountInfo(tokenMint)确认mint账户存在且数据长度符合SPL Mint规范(标准SPL Mint账户数据长度为82字节) - 校验mint公钥正确性:在链上浏览器查询传入的
tokenMint地址,确认其归属为标准SPL Token程序(程序ID为TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA),且mint权限与传入的tokenOwner公钥一致 - 若使用SPL Token 2022创建mint,需升级
@metaplex-foundation/mpl-token-metadata到支持Token 2022的版本,替换为对应支持Token 2022的元数据创建指令 - 现有代码中PDA推导逻辑、元数据参数传值没有语法问题,不需要调整这部分实现
内容的提问来源于stack exchange,提问作者user2270536
相关产品推荐
相关产品推荐

