spl_token_2022/
onchain.rs1use {
5 crate::{
6 extension::{transfer_fee, transfer_hook, StateWithExtensions},
7 instruction,
8 state::Mint,
9 },
10 solana_program::{
11 account_info::AccountInfo, entrypoint::ProgramResult, instruction::AccountMeta,
12 program::invoke_signed, pubkey::Pubkey,
13 },
14 spl_transfer_hook_interface::onchain::add_extra_accounts_for_execute_cpi,
15};
16
17#[allow(clippy::too_many_arguments)]
20pub fn invoke_transfer_checked<'a>(
21 token_program_id: &Pubkey,
22 source_info: AccountInfo<'a>,
23 mint_info: AccountInfo<'a>,
24 destination_info: AccountInfo<'a>,
25 authority_info: AccountInfo<'a>,
26 additional_accounts: &[AccountInfo<'a>],
27 amount: u64,
28 decimals: u8,
29 seeds: &[&[&[u8]]],
30) -> ProgramResult {
31 let mut cpi_instruction = instruction::transfer_checked(
32 token_program_id,
33 source_info.key,
34 mint_info.key,
35 destination_info.key,
36 authority_info.key,
37 &[], amount,
39 decimals,
40 )?;
41
42 let mut cpi_account_infos = vec![
43 source_info.clone(),
44 mint_info.clone(),
45 destination_info.clone(),
46 authority_info.clone(),
47 ];
48
49 additional_accounts
51 .iter()
52 .filter(|ai| ai.is_signer)
53 .for_each(|ai| {
54 cpi_account_infos.push(ai.clone());
55 cpi_instruction
56 .accounts
57 .push(AccountMeta::new_readonly(*ai.key, ai.is_signer));
58 });
59
60 {
62 let mint_data = mint_info.try_borrow_data()?;
63 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
64 if let Some(program_id) = transfer_hook::get_program_id(&mint) {
65 add_extra_accounts_for_execute_cpi(
66 &mut cpi_instruction,
67 &mut cpi_account_infos,
68 &program_id,
69 source_info,
70 mint_info.clone(),
71 destination_info,
72 authority_info,
73 amount,
74 additional_accounts,
75 )?;
76 }
77 }
78
79 invoke_signed(&cpi_instruction, &cpi_account_infos, seeds)
80}
81
82#[allow(clippy::too_many_arguments)]
86pub fn invoke_transfer_checked_with_fee<'a>(
87 token_program_id: &Pubkey,
88 source_info: AccountInfo<'a>,
89 mint_info: AccountInfo<'a>,
90 destination_info: AccountInfo<'a>,
91 authority_info: AccountInfo<'a>,
92 additional_accounts: &[AccountInfo<'a>],
93 amount: u64,
94 decimals: u8,
95 fee: u64,
96 seeds: &[&[&[u8]]],
97) -> ProgramResult {
98 let mut cpi_instruction = transfer_fee::instruction::transfer_checked_with_fee(
99 token_program_id,
100 source_info.key,
101 mint_info.key,
102 destination_info.key,
103 authority_info.key,
104 &[], amount,
106 decimals,
107 fee,
108 )?;
109
110 let mut cpi_account_infos = vec![
111 source_info.clone(),
112 mint_info.clone(),
113 destination_info.clone(),
114 authority_info.clone(),
115 ];
116
117 additional_accounts
119 .iter()
120 .filter(|ai| ai.is_signer)
121 .for_each(|ai| {
122 cpi_account_infos.push(ai.clone());
123 cpi_instruction
124 .accounts
125 .push(AccountMeta::new_readonly(*ai.key, ai.is_signer));
126 });
127
128 {
130 let mint_data = mint_info.try_borrow_data()?;
131 let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
132 if let Some(program_id) = transfer_hook::get_program_id(&mint) {
133 add_extra_accounts_for_execute_cpi(
134 &mut cpi_instruction,
135 &mut cpi_account_infos,
136 &program_id,
137 source_info,
138 mint_info.clone(),
139 destination_info,
140 authority_info,
141 amount,
142 additional_accounts,
143 )?;
144 }
145 }
146
147 invoke_signed(&cpi_instruction, &cpi_account_infos, seeds)
148}