Jacky Gu

Solana开发笔记: Token2022 - 放弃更新metadata权限

01 Jan 2025 Share to

Token2022 - 放弃更新metadata权限

创建指令

use anchor_lang::prelude::*;
use anchor_spl::token_2022::spl_token_2022::solana_zk_token_sdk::curve25519::scalar::Zeroable;
use spl_pod::optional_keys::OptionalNonZeroPubkey;
use crate::constants::MINT_SEEDS;
use crate::errors::ErrorCode;
use anchor_spl::token_2022::spl_token_2022;
use anchor_spl::{
  token_2022::{
    set_authority, SetAuthority,
    spl_token_2022::instruction::AuthorityType, 
  }, 
  token_interface::{
    Mint, Token2022
  }
};

#[derive(Accounts)]
#[instruction(token_name: String, token_symbol: String)]
pub struct RevokeUpdateMetadataAuthority<'info> {
  /// CHECK: Must be same as mint
  #[account(mut)]
  pub metadata: UncheckedAccount<'info>,
  #[account(
    seeds = [MINT_SEEDS.as_bytes(), token_name.as_bytes(), token_symbol.as_bytes()],
    bump,
  )]
  pub mint: Box<InterfaceAccount<'info, Mint>>,
  #[account(mut)]
  pub payer: Signer<'info>,
  pub system_program: Program<'info, System>,
  pub token_program: Program<'info, Token2022>,
}

impl<'info> RevokeUpdateMetadataAuthority<'info> {
  pub fn revoke_update_metadata_authority(ctx: Context<RevokeUpdateMetadataAuthority>, token_name: String, token_symbol: String) -> Result<()> {
    require!(spl_token_2022::ID == ctx.accounts.token_program.key(), ErrorCode::WrongTokenProgram);
    let seeds = &[MINT_SEEDS.as_bytes(), token_name.as_bytes(), token_symbol.as_bytes(), &[ctx.bumps.mint]];
    let signer = [&seeds[..]];

    // Revoke update metadata authority
    let mint_account_info = ctx.accounts.mint.to_account_info();
    let token_program_account_info = ctx.accounts.token_program.to_account_info();

    let ix = spl_token_metadata_interface::instruction::update_authority(
        &token_program_account_info.key(),
        &mint_account_info.key(), // metadata is same as mint
        &mint_account_info.key(),
        OptionalNonZeroPubkey::zeroed(),
    );
    anchor_lang::solana_program::program::invoke_signed(
        &ix,
        &[
            token_program_account_info,
            mint_account_info,
        ],
        &signer,
    )?;

    // Set update metadata pointer authority
    set_authority(
      CpiContext::new_with_signer(
          ctx.accounts.token_program.to_account_info(),
          SetAuthority {
              current_authority: ctx.accounts.mint.to_account_info(),
              account_or_mint: ctx.accounts.mint.to_account_info(),
          },
          &signer,
      ),
      AuthorityType::MetadataPointer,
      None,
    )?;
    Ok(())
  }
}

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

pub fn revoke_update_metadata_authority(ctx: Context<RevokeUpdateMetadataAuthority>, token_name: String, token_symbol: String) -> Result<()> {
    RevokeUpdateMetadataAuthority::revoke_update_metadata_authority(ctx, token_name, token_symbol)
}

编译部署

anchor build && anchor deploy

编写测试代码

  it("Revoke update authority", async () => {
    const context = {
      mint: mintAccount,
      metadata: mintAccount,
      payer: deployerAccount.publicKey,
      tokenProgram: TOKEN_2022_PROGRAM_ID,
    }
    const tx = await program.methods.revokeUpdateMetadataAuthority(metadataParams.name, metadataParams.symbol).accounts(context).signers([deployerAccount]).rpc();
    console.log("Revoke update authority tx:", tx);
  })