From bf8d6cb37da87699dbbf544db1fb330e239cbd9e Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 18 Sep 2023 09:21:46 +0200 Subject: [PATCH] Jupiter: Ensure source account is initialized (#721) (cherry picked from commit 9b224eae1b0d37ee1565ab333083e018212d99c7) --- bin/cli/src/main.rs | 11 +++++++++-- lib/client/src/jupiter/v4.rs | 32 +++++++++++++++++++++----------- lib/client/src/jupiter/v6.rs | 35 ++++++++++++++++++++++------------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index a64ca3c1b..24641260e 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -192,8 +192,15 @@ async fn main() -> Result<(), anyhow::Error> { let output_mint = pubkey_from_cli(&cmd.output_mint); let client = MangoClient::new_for_existing_account(client, account, owner).await?; let txsig = client - .jupiter_v6() - .swap(input_mint, output_mint, cmd.amount, cmd.slippage_bps, false) + .jupiter_v4() + .swap( + input_mint, + output_mint, + cmd.amount, + cmd.slippage_bps, + mango_v4_client::JupiterSwapMode::ExactIn, + false, + ) .await?; println!("{}", txsig); } diff --git a/lib/client/src/jupiter/v4.rs b/lib/client/src/jupiter/v4.rs index 91bf8ed7f..eaa51cdfb 100644 --- a/lib/client/src/jupiter/v4.rs +++ b/lib/client/src/jupiter/v4.rs @@ -100,7 +100,7 @@ impl<'a> JupiterV4<'a> { input_mint: Pubkey, output_mint: Pubkey, amount: u64, - slippage: u64, + slippage_bps: u64, swap_mode: JupiterSwapMode, only_direct_routes: bool, ) -> anyhow::Result { @@ -115,7 +115,7 @@ impl<'a> JupiterV4<'a> { ("onlyDirectRoutes", only_direct_routes.to_string()), ("enforceSingleTx", "true".into()), ("filterTopNResult", "10".into()), - ("slippageBps", format!("{}", slippage)), + ("slippageBps", format!("{}", slippage_bps)), ( "swapMode", match swap_mode { @@ -227,14 +227,13 @@ impl<'a> JupiterV4<'a> { .map(util::to_writable_account_meta) .collect::>(); + let owner = self.mango_client.owner(); + let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint] .into_iter() .map(|mint| { util::to_writable_account_meta( - anchor_spl::associated_token::get_associated_token_address( - &self.mango_client.owner(), - &mint, - ), + anchor_spl::associated_token::get_associated_token_address(&owner, &mint), ) }) .collect::>(); @@ -265,13 +264,24 @@ impl<'a> JupiterV4<'a> { for ix in &jup_ixs[..jup_action_ix_begin] { instructions.push(ix.clone()); } + + // Ensure the source token account is created (jupiter takes care of the output account) + instructions.push( + spl_associated_token_account::instruction::create_associated_token_account_idempotent( + &owner, + &owner, + &source_token.mint_info.mint, + &Token::id(), + ), + ); + instructions.push(Instruction { program_id: mango_v4::id(), accounts: { let mut ams = anchor_lang::ToAccountMetas::to_account_metas( &mango_v4::accounts::FlashLoanBegin { account: self.mango_client.mango_account_address, - owner: self.mango_client.owner(), + owner, token_program: Token::id(), instructions: solana_sdk::sysvar::instructions::id(), }, @@ -296,7 +306,7 @@ impl<'a> JupiterV4<'a> { let mut ams = anchor_lang::ToAccountMetas::to_account_metas( &mango_v4::accounts::FlashLoanEnd { account: self.mango_client.mango_account_address, - owner: self.mango_client.owner(), + owner, token_program: Token::id(), }, None, @@ -319,7 +329,7 @@ impl<'a> JupiterV4<'a> { let mut address_lookup_tables = self.mango_client.mango_address_lookup_tables().await?; address_lookup_tables.extend(jup_alts.into_iter()); - let payer = self.mango_client.owner.pubkey(); // maybe use fee_payer? but usually it's the same + let payer = owner; // maybe use fee_payer? but usually it's the same Ok(TransactionBuilder { instructions, @@ -335,7 +345,7 @@ impl<'a> JupiterV4<'a> { input_mint: Pubkey, output_mint: Pubkey, amount: u64, - slippage: u64, + slippage_bps: u64, swap_mode: JupiterSwapMode, only_direct_routes: bool, ) -> anyhow::Result { @@ -344,7 +354,7 @@ impl<'a> JupiterV4<'a> { input_mint, output_mint, amount, - slippage, + slippage_bps, swap_mode, only_direct_routes, ) diff --git a/lib/client/src/jupiter/v6.rs b/lib/client/src/jupiter/v6.rs index 81a4b9c3b..dc8e3a065 100644 --- a/lib/client/src/jupiter/v6.rs +++ b/lib/client/src/jupiter/v6.rs @@ -10,7 +10,6 @@ use crate::MangoClient; use crate::{util, TransactionBuilder}; use anyhow::Context; -use solana_sdk::signer::Signer; use solana_sdk::{instruction::Instruction, signature::Signature}; #[derive(Deserialize, Serialize, Debug, Clone)] @@ -148,7 +147,7 @@ impl<'a> JupiterV6<'a> { input_mint: Pubkey, output_mint: Pubkey, amount: u64, - slippage: u64, + slippage_bps: u64, only_direct_routes: bool, ) -> anyhow::Result { let mut account = self.mango_client.mango_account().await?; @@ -189,7 +188,7 @@ impl<'a> JupiterV6<'a> { ("inputMint", input_mint.to_string()), ("outputMint", output_mint.to_string()), ("amount", format!("{}", amount)), - ("slippageBps", format!("{}", slippage)), + ("slippageBps", format!("{}", slippage_bps)), ("onlyDirectRoutes", only_direct_routes.to_string()), ( "maxAccounts", @@ -237,14 +236,13 @@ impl<'a> JupiterV6<'a> { .map(util::to_writable_account_meta) .collect::>(); + let owner = self.mango_client.owner(); + let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint] .into_iter() .map(|mint| { util::to_writable_account_meta( - anchor_spl::associated_token::get_associated_token_address( - &self.mango_client.owner(), - &mint, - ), + anchor_spl::associated_token::get_associated_token_address(&owner, &mint), ) }) .collect::>(); @@ -273,7 +271,7 @@ impl<'a> JupiterV6<'a> { .http_client .post("https://quote-api.jup.ag/v6/swap-instructions") .json(&SwapRequest { - user_public_key: self.mango_client.owner.pubkey().to_string(), + user_public_key: owner.to_string(), wrap_and_unwrap_sol: false, use_shared_accounts: true, fee_account: None, @@ -299,13 +297,24 @@ impl<'a> JupiterV6<'a> { for ix in &swap.setup_instructions.unwrap_or_default() { instructions.push(ix.try_into()?); } + + // Ensure the source token account is created (jupiter takes care of the output account) + instructions.push( + spl_associated_token_account::instruction::create_associated_token_account_idempotent( + &owner, + &owner, + &source_token.mint_info.mint, + &Token::id(), + ), + ); + instructions.push(Instruction { program_id: mango_v4::id(), accounts: { let mut ams = anchor_lang::ToAccountMetas::to_account_metas( &mango_v4::accounts::FlashLoanBegin { account: self.mango_client.mango_account_address, - owner: self.mango_client.owner(), + owner, token_program: Token::id(), instructions: solana_sdk::sysvar::instructions::id(), }, @@ -328,7 +337,7 @@ impl<'a> JupiterV6<'a> { let mut ams = anchor_lang::ToAccountMetas::to_account_metas( &mango_v4::accounts::FlashLoanEnd { account: self.mango_client.mango_account_address, - owner: self.mango_client.owner(), + owner, token_program: Token::id(), }, None, @@ -363,7 +372,7 @@ impl<'a> JupiterV6<'a> { .await?; address_lookup_tables.extend(jup_alts.into_iter()); - let payer = self.mango_client.owner.pubkey(); // maybe use fee_payer? but usually it's the same + let payer = owner; // maybe use fee_payer? but usually it's the same Ok(TransactionBuilder { instructions, @@ -379,7 +388,7 @@ impl<'a> JupiterV6<'a> { input_mint: Pubkey, output_mint: Pubkey, amount: u64, - slippage: u64, + slippage_bps: u64, only_direct_routes: bool, ) -> anyhow::Result { let route = self @@ -387,7 +396,7 @@ impl<'a> JupiterV6<'a> { input_mint, output_mint, amount, - slippage, + slippage_bps, only_direct_routes, ) .await?;