light_token/instruction/
close.rs

1use solana_account_info::AccountInfo;
2use solana_cpi::{invoke, invoke_signed};
3use solana_instruction::{AccountMeta, Instruction};
4use solana_program_error::ProgramError;
5use solana_pubkey::Pubkey;
6
7use crate::instruction::RENT_SPONSOR;
8
9/// # Create a close ctoken account instruction:
10/// ```rust
11/// # use solana_pubkey::Pubkey;
12/// # use light_token::instruction::{CloseAccount, LIGHT_TOKEN_PROGRAM_ID};
13/// # let account = Pubkey::new_unique();
14/// # let destination = Pubkey::new_unique();
15/// # let owner = Pubkey::new_unique();
16/// let instruction =
17///     CloseAccount::new(LIGHT_TOKEN_PROGRAM_ID, account, destination, owner)
18///     .instruction()?;
19/// # Ok::<(), solana_program_error::ProgramError>(())
20/// ```
21pub struct CloseAccount {
22    pub token_program: Pubkey,
23    pub account: Pubkey,
24    pub destination: Pubkey,
25    pub owner: Pubkey,
26    pub rent_sponsor: Pubkey,
27}
28
29impl CloseAccount {
30    pub fn new(token_program: Pubkey, account: Pubkey, destination: Pubkey, owner: Pubkey) -> Self {
31        Self {
32            token_program,
33            account,
34            destination,
35            owner,
36            rent_sponsor: RENT_SPONSOR,
37        }
38    }
39
40    pub fn custom_rent_sponsor(mut self, rent_sponsor: Pubkey) -> Self {
41        self.rent_sponsor = rent_sponsor;
42        self
43    }
44
45    pub fn instruction(self) -> Result<Instruction, ProgramError> {
46        // CloseAccount discriminator is 9 (no additional instruction data)
47        let data = vec![9u8];
48
49        let accounts = vec![
50            AccountMeta::new(self.account, false),
51            AccountMeta::new(self.destination, false),
52            AccountMeta::new(self.owner, true), // signer, mutable to receive write_top_up
53            AccountMeta::new(self.rent_sponsor, false),
54        ];
55
56        Ok(Instruction {
57            program_id: self.token_program,
58            accounts,
59            data,
60        })
61    }
62}
63
64/// # Close a ctoken account via CPI:
65/// ```rust,no_run
66/// # use light_token::instruction::CloseAccountCpi;
67/// # use solana_account_info::AccountInfo;
68/// # let token_program: AccountInfo = todo!();
69/// # let account: AccountInfo = todo!();
70/// # let destination: AccountInfo = todo!();
71/// # let owner: AccountInfo = todo!();
72/// // Use ctoken::RENT_SPONSOR or ctoken::rent_sponsor_pda() to get the protocol rent sponsor.
73/// # let rent_sponsor: AccountInfo = todo!();
74/// CloseAccountCpi {
75///     token_program,
76///     account,
77///     destination,
78///     owner,
79///     rent_sponsor,
80/// }
81/// .invoke()?;
82/// # Ok::<(), solana_program_error::ProgramError>(())
83/// ```
84pub struct CloseAccountCpi<'info> {
85    pub token_program: AccountInfo<'info>,
86    pub account: AccountInfo<'info>,
87    pub destination: AccountInfo<'info>,
88    pub owner: AccountInfo<'info>,
89    pub rent_sponsor: AccountInfo<'info>,
90}
91
92impl<'info> CloseAccountCpi<'info> {
93    pub fn instruction(&self) -> Result<Instruction, ProgramError> {
94        CloseAccount::from(self).instruction()
95    }
96
97    pub fn invoke(self) -> Result<(), ProgramError> {
98        let instruction = self.instruction()?;
99        let account_infos = [
100            self.account,
101            self.destination,
102            self.owner,
103            self.rent_sponsor,
104        ];
105        invoke(&instruction, &account_infos)
106    }
107
108    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
109        let instruction = self.instruction()?;
110        let account_infos = [
111            self.account,
112            self.destination,
113            self.owner,
114            self.rent_sponsor,
115        ];
116        invoke_signed(&instruction, &account_infos, signer_seeds)
117    }
118}
119
120impl<'info> From<&CloseAccountCpi<'info>> for CloseAccount {
121    fn from(account_infos: &CloseAccountCpi<'info>) -> Self {
122        Self {
123            token_program: *account_infos.token_program.key,
124            account: *account_infos.account.key,
125            destination: *account_infos.destination.key,
126            owner: *account_infos.owner.key,
127            rent_sponsor: *account_infos.rent_sponsor.key,
128        }
129    }
130}