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(())
}
}
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);
})