1use spl_discriminator::SplDiscriminate;
2pub use spl_tlv_account_resolution::state::{AccountDataResult, AccountFetchError};
3
4use crate::{
5 get_freeze_extra_account_metas_address,
6 instruction::{can_freeze_permissionless, CanFreezePermissionlessInstruction},
7};
8
9use {
10 crate::{
11 error::ThawFreezeGateError,
12 get_thaw_extra_account_metas_address,
13 instruction::{can_thaw_permissionless, CanThawPermissionlessInstruction},
14 },
15 solana_instruction::{AccountMeta, Instruction},
16 solana_pubkey::Pubkey,
17 spl_tlv_account_resolution::state::ExtraAccountMetaList,
18 std::future::Future,
19};
20
21#[allow(clippy::too_many_arguments)]
22pub async fn add_extra_account_metas_for_freeze<F, Fut>(
23 instruction: &mut Instruction,
24 program_id: &Pubkey,
25 signer_pubkey: &Pubkey,
26 token_account_pubkey: &Pubkey,
27 mint_pubkey: &Pubkey,
28 token_account_owner: &Pubkey,
29 flag_account_pubkey: &Pubkey,
30 fetch_account_data_fn: F,
31) -> Result<(), ThawFreezeGateError>
32where
33 F: Fn(Pubkey) -> Fut,
34 Fut: Future<Output = AccountDataResult>,
35{
36 let extra_metas_pubkey = get_freeze_extra_account_metas_address(mint_pubkey, program_id);
37
38 add_extra_account_metas_for_permissionless_ix::<_, _, CanFreezePermissionlessInstruction, _>(
39 instruction,
40 program_id,
41 signer_pubkey,
42 token_account_pubkey,
43 mint_pubkey,
44 token_account_owner,
45 &extra_metas_pubkey,
46 &flag_account_pubkey,
47 fetch_account_data_fn,
48 |program_id,
49 signer_pubkey,
50 token_account_pubkey,
51 mint_pubkey,
52 token_account_owner,
53 flag_account_pubkey| {
54 can_freeze_permissionless(
55 program_id,
56 signer_pubkey,
57 token_account_pubkey,
58 mint_pubkey,
59 token_account_owner,
60 &flag_account_pubkey,
61 )
62 },
63 )
64 .await
65}
66
67#[allow(clippy::too_many_arguments)]
68pub async fn add_extra_account_metas_for_thaw<F, Fut>(
69 instruction: &mut Instruction,
70 program_id: &Pubkey,
71 signer_pubkey: &Pubkey,
72 token_account_pubkey: &Pubkey,
73 mint_pubkey: &Pubkey,
74 token_account_owner: &Pubkey,
75 flag_account_pubkey: &Pubkey,
76 fetch_account_data_fn: F,
77) -> Result<(), ThawFreezeGateError>
78where
79 F: Fn(Pubkey) -> Fut,
80 Fut: Future<Output = AccountDataResult>,
81{
82 let extra_metas_pubkey = get_thaw_extra_account_metas_address(mint_pubkey, program_id);
83
84 add_extra_account_metas_for_permissionless_ix::<_, _, CanThawPermissionlessInstruction, _>(
85 instruction,
86 program_id,
87 signer_pubkey,
88 token_account_pubkey,
89 mint_pubkey,
90 token_account_owner,
91 &extra_metas_pubkey,
92 &flag_account_pubkey,
93 fetch_account_data_fn,
94 |program_id,
95 signer_pubkey,
96 token_account_pubkey,
97 mint_pubkey,
98 token_account_owner,
99 flag_account_pubkey| {
100 can_thaw_permissionless(
101 program_id,
102 signer_pubkey,
103 token_account_pubkey,
104 mint_pubkey,
105 token_account_owner,
106 flag_account_pubkey,
107 )
108 },
109 )
110 .await
111}
112
113#[allow(clippy::too_many_arguments)]
114async fn add_extra_account_metas_for_permissionless_ix<F, Fut, T, F2>(
115 instruction: &mut Instruction,
116 program_id: &Pubkey,
117 signer_pubkey: &Pubkey,
118 token_account_pubkey: &Pubkey,
119 mint_pubkey: &Pubkey,
120 token_account_owner: &Pubkey,
121 extra_metas_pubkey: &Pubkey,
122 flag_account_pubkey: &Pubkey,
123 fetch_account_data_fn: F,
124 cpi_ix_builder_fn: F2,
125) -> Result<(), ThawFreezeGateError>
126where
127 F: Fn(Pubkey) -> Fut,
128 F2: Fn(&Pubkey, &Pubkey, &Pubkey, &Pubkey, &Pubkey, &Pubkey) -> Instruction,
129 Fut: Future<Output = AccountDataResult>,
130 T: SplDiscriminate,
131{
132 let validate_state_data = fetch_account_data_fn(*extra_metas_pubkey)
134 .await
135 .map_err(|_| ThawFreezeGateError::MissingExtraAccountMeta)?
136 .ok_or(ThawFreezeGateError::MissingExtraAccountMeta)?;
137
138 if [
140 program_id,
141 signer_pubkey,
142 token_account_pubkey,
143 mint_pubkey,
144 token_account_owner,
145 ]
146 .iter()
147 .any(|&key| !instruction.accounts.iter().any(|meta| meta.pubkey == *key))
148 {
149 Err(ThawFreezeGateError::MissingAccountMeta)?;
150 }
151
152 let mut cpi_ix = cpi_ix_builder_fn(
153 program_id,
154 signer_pubkey,
155 token_account_pubkey,
156 mint_pubkey,
157 token_account_owner,
158 flag_account_pubkey,
159 );
160 cpi_ix
161 .accounts
162 .push(AccountMeta::new_readonly(*extra_metas_pubkey, false));
163
164 ExtraAccountMetaList::add_to_instruction::<T, _, _>(
165 &mut cpi_ix,
166 fetch_account_data_fn,
167 &validate_state_data,
168 )
169 .await
170 .map_err(Into::into)?;
171
172 instruction
174 .accounts
175 .extend_from_slice(&cpi_ix.accounts[5..]);
176
177 Ok(())
178}