token_acl/instructions/
delete_config.rs1use solana_cpi::invoke_signed;
2use solana_program::{account_info::AccountInfo, pubkey::Pubkey};
3use solana_program_error::{ProgramError, ProgramResult};
4use spl_token_2022::{extension::PodStateWithExtensions, instruction::AuthorityType, pod::PodMint};
5
6use crate::{
7 error::TokenAclError,
8 state::{load_mint_config, MintConfig},
9};
10
11pub struct DeleteConfig<'a> {
12 pub authority: &'a AccountInfo<'a>,
13 pub receiver: &'a AccountInfo<'a>,
14 pub mint: &'a AccountInfo<'a>,
15 pub mint_config: &'a AccountInfo<'a>,
16 pub token_program: &'a AccountInfo<'a>,
17}
18
19impl DeleteConfig<'_> {
20 pub const DISCRIMINATOR: u8 = 3;
21
22 pub fn process(&self, remaining_data: &[u8]) -> ProgramResult {
23 if remaining_data.len() != 32 {
24 return Err(ProgramError::InvalidInstructionData);
25 }
26 let new_freeze_authority =
27 Pubkey::try_from(remaining_data).map_err(|_| ProgramError::InvalidInstructionData)?;
28
29 let mint_data = self.mint.data.borrow_mut();
32 let mint = PodStateWithExtensions::<PodMint>::unpack(&mint_data);
33 let set_freeze_authority = mint.and_then(|mint| Ok(mint.base.freeze_authority.unwrap_or(Pubkey::default()) == *self.mint_config.key)).unwrap_or(false);
34 drop(mint_data);
35
36 let bump_seed = {
37 let data = &mut self.mint_config.data.borrow_mut();
38 let config = load_mint_config(data)?;
39
40 if config.freeze_authority != *self.authority.key {
41 return Err(TokenAclError::InvalidAuthority.into());
42 }
43
44 if config.mint != *self.mint.key {
45 return Err(TokenAclError::InvalidTokenMint.into());
46 }
47
48 [config.bump]
49 };
50
51 if set_freeze_authority {
52 let seeds = [MintConfig::SEED_PREFIX, self.mint.key.as_ref(), &bump_seed];
53
54 let ix = spl_token_2022::instruction::set_authority(
55 self.token_program.key,
56 self.mint.key,
57 Some(&new_freeze_authority),
58 AuthorityType::FreezeAccount,
59 self.mint_config.key,
60 &[],
61 )?;
62 invoke_signed(
63 &ix,
64 &[self.mint.clone(), self.mint_config.clone()],
65 &[&seeds],
66 )?;
67 }
68
69 **self.receiver.try_borrow_mut_lamports()? += self.mint_config.lamports();
70 **self.mint_config.try_borrow_mut_lamports()? = 0;
71 self.mint_config.realloc(0, false)?;
72 self.mint_config.assign(&Pubkey::default());
73
74 Ok(())
75 }
76}
77
78impl<'a> TryFrom<&'a [AccountInfo<'a>]> for DeleteConfig<'a> {
79 type Error = ProgramError;
80
81 fn try_from(accounts: &'a [AccountInfo<'a>]) -> Result<Self, Self::Error> {
82 let [authority, receiver, mint, mint_config, token_program] = &accounts else {
83 return Err(ProgramError::InvalidInstructionData);
84 };
85
86 if !authority.is_signer {
87 return Err(TokenAclError::InvalidAuthority.into());
88 }
89
90 if !spl_token_2022::check_id(token_program.key) {
91 return Err(TokenAclError::InvalidTokenProgram.into());
92 }
93
94 Ok(Self {
95 authority,
96 receiver,
97 mint,
98 mint_config,
99 token_program,
100 })
101 }
102}