diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 808abe4ae14..f2b0a86dd70 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -2159,14 +2159,18 @@ where &multisig_signers, proof_location, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut instructions[0], + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; @@ -2213,14 +2217,18 @@ where context_state_accounts, source_decrypt_handles, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut instruction, + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; @@ -2286,14 +2294,18 @@ where context_state_accounts, &source_decrypt_handles, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut transfer_instruction, + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; @@ -2721,18 +2733,27 @@ where &multisig_signers, proof_location, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut instructions[0], + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; - self.process_ixs_with_additional_compute_budget(&instructions, TRANSFER_WITH_FEE_COMPUTE_BUDGET, signing_keypairs).await + self.process_ixs_with_additional_compute_budget( + &instructions, + TRANSFER_WITH_FEE_COMPUTE_BUDGET, + signing_keypairs, + ) + .await } /// Transfer tokens confidentially with fee using split proofs. @@ -2776,14 +2797,18 @@ where context_state_accounts, source_decrypt_handles, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut instruction, + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; @@ -2874,14 +2899,18 @@ where context_state_accounts, &source_decrypt_handles, )?; - offchain::resolve_extra_transfer_account_metas( + offchain::add_extra_account_metas( &mut transfer_instruction, + source_account, + self.get_address(), + destination_account, + source_authority, + u64::MAX, |address| { self.client .get_account(address) .map_ok(|opt| opt.map(|acc| acc.data)) }, - self.get_address(), ) .await .map_err(|_| TokenError::AccountNotFound)?; diff --git a/token/program-2022/src/offchain.rs b/token/program-2022/src/offchain.rs index 65451772151..e4493c9ea3c 100644 --- a/token/program-2022/src/offchain.rs +++ b/token/program-2022/src/offchain.rs @@ -112,6 +112,61 @@ where decimals, )?; + add_extra_account_metas( + &mut transfer_instruction, + source_pubkey, + mint_pubkey, + destination_pubkey, + authority_pubkey, + amount, + fetch_account_data_fn, + ) + .await?; + + Ok(transfer_instruction) +} + +/// Offchain helper to add required account metas to an instruction, including +/// the ones required by the transfer hook. +/// +/// To be client-agnostic and to avoid pulling in the full solana-sdk, this +/// simply takes a function that will return its data as `Future>` for +/// the given address. Can be called in the following way: +/// +/// ```rust,ignore +/// let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( +/// &spl_token_2022::id(), +/// source_pubkey, +/// mint_pubkey, +/// destination_pubkey, +/// authority_pubkey, +/// signer_pubkeys, +/// amount, +/// decimals, +/// )?; +/// add_extra_account_metas( +/// &mut transfer_instruction, +/// source_pubkey, +/// mint_pubkey, +/// destination_pubkey, +/// authority_pubkey, +/// amount, +/// fetch_account_data_fn, +/// ).await?; +/// ``` +pub async fn add_extra_account_metas( + instruction: &mut Instruction, + source_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + amount: u64, + fetch_account_data_fn: F, +) -> Result<(), AccountFetchError> +where + F: Fn(Pubkey) -> Fut, + Fut: Future, +{ let mint_data = fetch_account_data_fn(*mint_pubkey) .await? .ok_or(ProgramError::InvalidAccountData)?; @@ -119,7 +174,7 @@ where if let Some(program_id) = transfer_hook::get_program_id(&mint) { add_extra_account_metas_for_execute( - &mut transfer_instruction, + instruction, &program_id, source_pubkey, mint_pubkey, @@ -131,7 +186,7 @@ where .await?; } - Ok(transfer_instruction) + Ok(()) } #[cfg(test)]