更新metadata
创建update metadata指令
在instructions
中添加update_metadata.rs
,并粘贴以下代码:
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::prelude::*;
use mpl_token_metadata::types::DataV2;
use anchor_spl::{metadata::Metadata as Metaplex, token::{spl_token, Mint, Token}};
use mpl_token_metadata::instructions::{self as mpl_instruction, UpdateMetadataAccountV2InstructionArgs};
use crate::{constants::MINT_SEEDS, errors::ErrorCode, states::TokenMetadata};
#[derive(Accounts)]
#[instruction(metadata_params: TokenMetadata)]
pub struct UpdateTokenMetadata<'info> {
#[account(
seeds = [MINT_SEEDS.as_bytes(), metadata_params.name.as_bytes(), metadata_params.symbol.as_bytes()],
bump,
)]
pub mint: Box<Account<'info, Mint>>,
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: Metadata account
#[account(mut)]
pub metadata: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
pub token_metadata_program: Program<'info, Metaplex>,
}
impl<'info> UpdateTokenMetadata<'info> {
pub fn update_token_metadata(ctx: Context<UpdateTokenMetadata>, metadata: Box<TokenMetadata>) -> Result<()> {
require!(spl_token::ID == ctx.accounts.token_program.key(), ErrorCode::WrongTokenProgram);
let token_data: DataV2 = DataV2 {
name: metadata.name.clone(),
symbol: metadata.symbol.clone(),
uri: metadata.uri.clone(),
seller_fee_basis_points: 0,
creators: None,
collection: None,
uses: None,
};
let seeds = &[MINT_SEEDS.as_bytes(), metadata.name.as_bytes(), metadata.symbol.as_bytes(), &[ctx.bumps.mint]];
let signer = [&seeds[..]];
let update_ix = mpl_instruction::UpdateMetadataAccountV2 {
metadata: ctx.accounts.metadata.key(),
update_authority: ctx.accounts.mint.key(),
}.instruction(
UpdateMetadataAccountV2InstructionArgs {
data: Some(token_data),
new_update_authority: Some(ctx.accounts.mint.key()),
primary_sale_happened: None,
is_mutable: Some(true),
},
);
invoke_signed(
&update_ix,
&[
ctx.accounts.metadata.to_account_info(),
ctx.accounts.mint.to_account_info(),
],
&signer
)?;
Ok(())
}
}
在lib.rs中调用上面的指令
pub fn update_token_metadata(ctx: Context<UpdateTokenMetadata>, metadata: Box<TokenMetadata>) -> Result<()> {
UpdateTokenMetadata::update_token_metadata(ctx, metadata)
}
编译部署
anchor build && anchor deploy
编写测试代码
it("update token metadata", async () => {
// Prepare new metadata
const newMetadata = {
name: metadataParams.name,
symbol: metadataParams.symbol,
uri: "https://node1.irys.xyz/updated_token_metadata",
decimals: 9,
};
// Prepare context for updating metadata
const context = {
mint: mintAccount,
payer: deployerAccount.publicKey,
metadata: metadataAccountPda,
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
};
// Call update_token_metadata instruction
const tx = await program.methods
.updateTokenMetadata(newMetadata)
.accounts(context)
.signers([deployerAccount])
.rpc();
console.log("Update token metadata transaction signature:", tx);
// Optional: Verify metadata update (this might require additional metadata program calls)
console.log("Updated metadata:", newMetadata);
})
运行测试代码后,会发现出错:
Logs:
[
"Program 93aQhvzjs5xmTkB3tfjtNUQHzJnwewcxGcTDfyvZUiWq invoke [1]",
"Program log: Instruction: UpdateTokenMetadata",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [2]",
"Program log: IX: Update Metadata Accounts v2",
"Program log: Data is immutable",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 12339 of 189406 compute units",
"Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s failed: custom program error: 0x3b",
"Program 93aQhvzjs5xmTkB3tfjtNUQHzJnwewcxGcTDfyvZUiWq consumed 22933 of 200000 compute units",
"Program 93aQhvzjs5xmTkB3tfjtNUQHzJnwewcxGcTDfyvZUiWq failed: custom program error: 0x3b"
].
这是因为在创建Token时,使用了:
create_metadata_accounts_v3(metadata_ctx, token_data, false, true, None)?;
也就是is_mutable
为true,不可篡改。
因此,需要把创建Token的代码的代码改为:
create_metadata_accounts_v3(metadata_ctx, token_data, true, true, None)?;
再次运行测试代码,成功。