Jacky Gu

Solana开发笔记: 丢弃update metadata权限

01 Jan 2025 Share to

丢弃update metadata权限

创建revoke update metadata指令

instructions中添加revoke_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 RevokeUpdateMetadata<'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,
    constraint = !metadata.to_account_info().data_is_empty() @ ErrorCode::InvalidMetadata
  )]
  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> RevokeUpdateMetadata<'info> {
  pub fn revoke_update_metadata(ctx: Context<RevokeUpdateMetadata>, 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: None,
        primary_sale_happened: None,
        is_mutable: Some(false),
      },
    );

    invoke_signed(
        &update_ix,
        &[
            ctx.accounts.metadata.to_account_info(),
            ctx.accounts.mint.to_account_info(),
        ],
        &signer
    )?;
    Ok(())
  }
}

在lib.rs中调用上面的指令

    pub fn revoke_update_metadata(ctx: Context<RevokeUpdateMetadata>, metadata: Box<TokenMetadata>) -> Result<()> {
        RevokeUpdateMetadata::revoke_update_metadata(ctx, metadata)
    }

编译部署

anchor build && anchor deploy

编写测试代码

  it("revoke update metadata authority", async () => {
    // Prepare context for revoking update metadata authority
    const context = {
      mint: mintAccount,
      payer: deployerAccount.publicKey,
      metadata: metadataAccountPda,
      tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
    };

    // Call revoke_update_metadata instruction
    const tx = await program.methods
      .revokeUpdateMetadata(metadataParams)
      .accounts(context)
      .signers([deployerAccount])
      .rpc();

    console.log("Revoke update metadata authority transaction signature:", tx);

    // Attempt to update metadata should now fail
    try {
      const newMetadata = {
        name: metadataParams.name,
        symbol: metadataParams.symbol,
        uri: "https://node1.irys.xyz/updated_token_metadata_after_revoke",
        decimals: 9,
      };

      const updateContext = {
        mint: mintAccount,
        payer: deployerAccount.publicKey,
        metadata: metadataAccountPda,
        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
      };

      const updateTx = await program.methods
        .updateTokenMetadata(newMetadata)
        .accounts(updateContext)
        .signers([deployerAccount])
        .rpc();

      console.log("Update token metadata unexpectedly succeeded after revoking authority");
    } catch (error) {
      console.log("Update token metadata failed as expected:", error);
    }
  })

运行以上测试代码,会发现出错,因为mint的update metadata已经无法更新。