丢弃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已经无法更新。