Jacky Gu

Solana开发笔记: 更新metadata

01 Jan 2025 Share to

更新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)?;

再次运行测试代码,成功。