Jupiter: Ensure source account is initialized (#721)

This commit is contained in:
Christian Kamm 2023-09-18 09:21:46 +02:00 committed by GitHub
parent 40ad0b7b66
commit 9b224eae1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 26 deletions

View File

@ -192,8 +192,15 @@ async fn main() -> Result<(), anyhow::Error> {
let output_mint = pubkey_from_cli(&cmd.output_mint); let output_mint = pubkey_from_cli(&cmd.output_mint);
let client = MangoClient::new_for_existing_account(client, account, owner).await?; let client = MangoClient::new_for_existing_account(client, account, owner).await?;
let txsig = client let txsig = client
.jupiter_v6() .jupiter_v4()
.swap(input_mint, output_mint, cmd.amount, cmd.slippage_bps, false) .swap(
input_mint,
output_mint,
cmd.amount,
cmd.slippage_bps,
mango_v4_client::JupiterSwapMode::ExactIn,
false,
)
.await?; .await?;
println!("{}", txsig); println!("{}", txsig);
} }

View File

@ -100,7 +100,7 @@ impl<'a> JupiterV4<'a> {
input_mint: Pubkey, input_mint: Pubkey,
output_mint: Pubkey, output_mint: Pubkey,
amount: u64, amount: u64,
slippage: u64, slippage_bps: u64,
swap_mode: JupiterSwapMode, swap_mode: JupiterSwapMode,
only_direct_routes: bool, only_direct_routes: bool,
) -> anyhow::Result<QueryRoute> { ) -> anyhow::Result<QueryRoute> {
@ -115,7 +115,7 @@ impl<'a> JupiterV4<'a> {
("onlyDirectRoutes", only_direct_routes.to_string()), ("onlyDirectRoutes", only_direct_routes.to_string()),
("enforceSingleTx", "true".into()), ("enforceSingleTx", "true".into()),
("filterTopNResult", "10".into()), ("filterTopNResult", "10".into()),
("slippageBps", format!("{}", slippage)), ("slippageBps", format!("{}", slippage_bps)),
( (
"swapMode", "swapMode",
match swap_mode { match swap_mode {
@ -227,14 +227,13 @@ impl<'a> JupiterV4<'a> {
.map(util::to_writable_account_meta) .map(util::to_writable_account_meta)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let owner = self.mango_client.owner();
let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint] let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint]
.into_iter() .into_iter()
.map(|mint| { .map(|mint| {
util::to_writable_account_meta( util::to_writable_account_meta(
anchor_spl::associated_token::get_associated_token_address( anchor_spl::associated_token::get_associated_token_address(&owner, &mint),
&self.mango_client.owner(),
&mint,
),
) )
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -265,13 +264,24 @@ impl<'a> JupiterV4<'a> {
for ix in &jup_ixs[..jup_action_ix_begin] { for ix in &jup_ixs[..jup_action_ix_begin] {
instructions.push(ix.clone()); 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 { instructions.push(Instruction {
program_id: mango_v4::id(), program_id: mango_v4::id(),
accounts: { accounts: {
let mut ams = anchor_lang::ToAccountMetas::to_account_metas( let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
&mango_v4::accounts::FlashLoanBegin { &mango_v4::accounts::FlashLoanBegin {
account: self.mango_client.mango_account_address, account: self.mango_client.mango_account_address,
owner: self.mango_client.owner(), owner,
token_program: Token::id(), token_program: Token::id(),
instructions: solana_sdk::sysvar::instructions::id(), instructions: solana_sdk::sysvar::instructions::id(),
}, },
@ -296,7 +306,7 @@ impl<'a> JupiterV4<'a> {
let mut ams = anchor_lang::ToAccountMetas::to_account_metas( let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
&mango_v4::accounts::FlashLoanEnd { &mango_v4::accounts::FlashLoanEnd {
account: self.mango_client.mango_account_address, account: self.mango_client.mango_account_address,
owner: self.mango_client.owner(), owner,
token_program: Token::id(), token_program: Token::id(),
}, },
None, None,
@ -319,7 +329,7 @@ impl<'a> JupiterV4<'a> {
let mut address_lookup_tables = self.mango_client.mango_address_lookup_tables().await?; let mut address_lookup_tables = self.mango_client.mango_address_lookup_tables().await?;
address_lookup_tables.extend(jup_alts.into_iter()); 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 { Ok(TransactionBuilder {
instructions, instructions,
@ -335,7 +345,7 @@ impl<'a> JupiterV4<'a> {
input_mint: Pubkey, input_mint: Pubkey,
output_mint: Pubkey, output_mint: Pubkey,
amount: u64, amount: u64,
slippage: u64, slippage_bps: u64,
swap_mode: JupiterSwapMode, swap_mode: JupiterSwapMode,
only_direct_routes: bool, only_direct_routes: bool,
) -> anyhow::Result<Signature> { ) -> anyhow::Result<Signature> {
@ -344,7 +354,7 @@ impl<'a> JupiterV4<'a> {
input_mint, input_mint,
output_mint, output_mint,
amount, amount,
slippage, slippage_bps,
swap_mode, swap_mode,
only_direct_routes, only_direct_routes,
) )

View File

@ -10,7 +10,6 @@ use crate::MangoClient;
use crate::{util, TransactionBuilder}; use crate::{util, TransactionBuilder};
use anyhow::Context; use anyhow::Context;
use solana_sdk::signer::Signer;
use solana_sdk::{instruction::Instruction, signature::Signature}; use solana_sdk::{instruction::Instruction, signature::Signature};
#[derive(Deserialize, Serialize, Debug, Clone)] #[derive(Deserialize, Serialize, Debug, Clone)]
@ -148,7 +147,7 @@ impl<'a> JupiterV6<'a> {
input_mint: Pubkey, input_mint: Pubkey,
output_mint: Pubkey, output_mint: Pubkey,
amount: u64, amount: u64,
slippage: u64, slippage_bps: u64,
only_direct_routes: bool, only_direct_routes: bool,
) -> anyhow::Result<QuoteResponse> { ) -> anyhow::Result<QuoteResponse> {
let mut account = self.mango_client.mango_account().await?; let mut account = self.mango_client.mango_account().await?;
@ -189,7 +188,7 @@ impl<'a> JupiterV6<'a> {
("inputMint", input_mint.to_string()), ("inputMint", input_mint.to_string()),
("outputMint", output_mint.to_string()), ("outputMint", output_mint.to_string()),
("amount", format!("{}", amount)), ("amount", format!("{}", amount)),
("slippageBps", format!("{}", slippage)), ("slippageBps", format!("{}", slippage_bps)),
("onlyDirectRoutes", only_direct_routes.to_string()), ("onlyDirectRoutes", only_direct_routes.to_string()),
( (
"maxAccounts", "maxAccounts",
@ -237,14 +236,13 @@ impl<'a> JupiterV6<'a> {
.map(util::to_writable_account_meta) .map(util::to_writable_account_meta)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let owner = self.mango_client.owner();
let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint] let token_ams = [source_token.mint_info.mint, target_token.mint_info.mint]
.into_iter() .into_iter()
.map(|mint| { .map(|mint| {
util::to_writable_account_meta( util::to_writable_account_meta(
anchor_spl::associated_token::get_associated_token_address( anchor_spl::associated_token::get_associated_token_address(&owner, &mint),
&self.mango_client.owner(),
&mint,
),
) )
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -273,7 +271,7 @@ impl<'a> JupiterV6<'a> {
.http_client .http_client
.post("https://quote-api.jup.ag/v6/swap-instructions") .post("https://quote-api.jup.ag/v6/swap-instructions")
.json(&SwapRequest { .json(&SwapRequest {
user_public_key: self.mango_client.owner.pubkey().to_string(), user_public_key: owner.to_string(),
wrap_and_unwrap_sol: false, wrap_and_unwrap_sol: false,
use_shared_accounts: true, use_shared_accounts: true,
fee_account: None, fee_account: None,
@ -299,13 +297,24 @@ impl<'a> JupiterV6<'a> {
for ix in &swap.setup_instructions.unwrap_or_default() { for ix in &swap.setup_instructions.unwrap_or_default() {
instructions.push(ix.try_into()?); 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 { instructions.push(Instruction {
program_id: mango_v4::id(), program_id: mango_v4::id(),
accounts: { accounts: {
let mut ams = anchor_lang::ToAccountMetas::to_account_metas( let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
&mango_v4::accounts::FlashLoanBegin { &mango_v4::accounts::FlashLoanBegin {
account: self.mango_client.mango_account_address, account: self.mango_client.mango_account_address,
owner: self.mango_client.owner(), owner,
token_program: Token::id(), token_program: Token::id(),
instructions: solana_sdk::sysvar::instructions::id(), instructions: solana_sdk::sysvar::instructions::id(),
}, },
@ -328,7 +337,7 @@ impl<'a> JupiterV6<'a> {
let mut ams = anchor_lang::ToAccountMetas::to_account_metas( let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
&mango_v4::accounts::FlashLoanEnd { &mango_v4::accounts::FlashLoanEnd {
account: self.mango_client.mango_account_address, account: self.mango_client.mango_account_address,
owner: self.mango_client.owner(), owner,
token_program: Token::id(), token_program: Token::id(),
}, },
None, None,
@ -363,7 +372,7 @@ impl<'a> JupiterV6<'a> {
.await?; .await?;
address_lookup_tables.extend(jup_alts.into_iter()); 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 { Ok(TransactionBuilder {
instructions, instructions,
@ -379,7 +388,7 @@ impl<'a> JupiterV6<'a> {
input_mint: Pubkey, input_mint: Pubkey,
output_mint: Pubkey, output_mint: Pubkey,
amount: u64, amount: u64,
slippage: u64, slippage_bps: u64,
only_direct_routes: bool, only_direct_routes: bool,
) -> anyhow::Result<Signature> { ) -> anyhow::Result<Signature> {
let route = self let route = self
@ -387,7 +396,7 @@ impl<'a> JupiterV6<'a> {
input_mint, input_mint,
output_mint, output_mint,
amount, amount,
slippage, slippage_bps,
only_direct_routes, only_direct_routes,
) )
.await?; .await?;