|
3 | 3 |
|
4 | 4 | use {
|
5 | 5 | crate::{
|
6 |
| - extension::{transfer_hook, StateWithExtensions}, |
| 6 | + extension::{transfer_fee, transfer_hook, StateWithExtensions}, |
7 | 7 | instruction,
|
8 | 8 | state::Mint,
|
9 | 9 | },
|
@@ -78,3 +78,70 @@ pub fn invoke_transfer_checked<'a>(
|
78 | 78 |
|
79 | 79 | invoke_signed(&cpi_instruction, &cpi_account_infos, seeds)
|
80 | 80 | }
|
| 81 | + |
| 82 | +/// Helper to CPI into token-2022 on-chain, looking through the additional |
| 83 | +/// account infos to create the proper instruction with the proper account infos |
| 84 | +#[allow(clippy::too_many_arguments)] |
| 85 | +pub fn invoke_transfer_checked_with_fee<'a>( |
| 86 | + token_program_id: &Pubkey, |
| 87 | + source_info: AccountInfo<'a>, |
| 88 | + mint_info: AccountInfo<'a>, |
| 89 | + destination_info: AccountInfo<'a>, |
| 90 | + authority_info: AccountInfo<'a>, |
| 91 | + additional_accounts: &[AccountInfo<'a>], |
| 92 | + amount: u64, |
| 93 | + decimals: u8, |
| 94 | + fee: u64, |
| 95 | + seeds: &[&[&[u8]]], |
| 96 | +) -> ProgramResult { |
| 97 | + let mut cpi_instruction = transfer_fee::instruction::transfer_checked_with_fee( |
| 98 | + token_program_id, |
| 99 | + source_info.key, |
| 100 | + mint_info.key, |
| 101 | + destination_info.key, |
| 102 | + authority_info.key, |
| 103 | + &[], // add them later, to avoid unnecessary clones |
| 104 | + amount, |
| 105 | + decimals, |
| 106 | + fee, |
| 107 | + )?; |
| 108 | + |
| 109 | + let mut cpi_account_infos = vec![ |
| 110 | + source_info.clone(), |
| 111 | + mint_info.clone(), |
| 112 | + destination_info.clone(), |
| 113 | + authority_info.clone(), |
| 114 | + ]; |
| 115 | + |
| 116 | + // if it's a signer, it might be a multisig signer, throw it in! |
| 117 | + additional_accounts |
| 118 | + .iter() |
| 119 | + .filter(|ai| ai.is_signer) |
| 120 | + .for_each(|ai| { |
| 121 | + cpi_account_infos.push(ai.clone()); |
| 122 | + cpi_instruction |
| 123 | + .accounts |
| 124 | + .push(AccountMeta::new_readonly(*ai.key, ai.is_signer)); |
| 125 | + }); |
| 126 | + |
| 127 | + // scope the borrowing to avoid a double-borrow during CPI |
| 128 | + { |
| 129 | + let mint_data = mint_info.try_borrow_data()?; |
| 130 | + let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?; |
| 131 | + if let Some(program_id) = transfer_hook::get_program_id(&mint) { |
| 132 | + add_extra_accounts_for_execute_cpi( |
| 133 | + &mut cpi_instruction, |
| 134 | + &mut cpi_account_infos, |
| 135 | + &program_id, |
| 136 | + source_info, |
| 137 | + mint_info.clone(), |
| 138 | + destination_info, |
| 139 | + authority_info, |
| 140 | + amount, |
| 141 | + additional_accounts, |
| 142 | + )?; |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + invoke_signed(&cpi_instruction, &cpi_account_infos, seeds) |
| 147 | +} |
0 commit comments