Skip to main content

token_acl_interface/
offchain.rs

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_pubkey = get_thaw_extra_account_metas_address(mint_pubkey, program_id);
133    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    // Check to make sure the provided keys are in the instruction
139    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    // Add only the extra accounts resolved from the validation state
173    instruction
174        .accounts
175        .extend_from_slice(&cpi_ix.accounts[5..]);
176
177    Ok(())
178}