solana_exec/raydium/
push_raydium_ammv4_swap_instruction.rs

1use crate::constants::COMPUTE_UNITS;
2use crate::types::swap_config::SwapConfig;
3use crate::utilities::get_min_amount_out::get_min_amount_out;
4use solana_central::RaydiumAmmV4Pool;
5use solana_central::SwapDirection;
6use solana_central::constants::{RAYDIUM_CONSTANTS, SOLANA_PROGRAMS};
7use solana_sdk::instruction::{AccountMeta, Instruction};
8use spl_associated_token_account::get_associated_token_address;
9
10/// Builds a Raydium AMMv4 swap instruction based on the swap config and adds it to the
11/// instructions vector. If `use_manual_instruction_args` is true, uses exact amounts instead of
12/// slippage-based calculations.
13pub fn push_raydium_ammv4_swap_instruction(
14  swap_config: &SwapConfig,
15  // If true, use exact amounts (manual override) instead of slippage calculations
16  use_manual_instruction_args: bool,
17  mut minimum_amount_out: u64,
18  instructions: &mut Vec<Instruction>,
19  compute_unit_budget: &mut u32,
20  pool: &RaydiumAmmV4Pool,
21) {
22  /*
23  Data length for raydium ammv4 is 17 bytes. First byte is the instruction discriminator for the
24  swap, 9 for swapBaaseIn which is what we'l be using, next 8 bytes are a u64 amountIn, next 8 bytes
25  are u65 minimumAmountOut
26  */
27  let mut data: Vec<u8> = Vec::with_capacity(17);
28  // Push one byte discriminator of 9 for swap base in instruction
29  data.push(9);
30  // Calculate minimum amount out using slippage setup if the argument is not manually provided
31  if !use_manual_instruction_args {
32    minimum_amount_out = get_min_amount_out(swap_config, pool);
33  }
34  data.extend_from_slice(&swap_config.amount_in.to_le_bytes());
35  data.extend_from_slice(&minimum_amount_out.to_le_bytes());
36  let source_token_account;
37  let destination_token_account;
38  if swap_config.direction == SwapDirection::AToB {
39    source_token_account =
40      get_associated_token_address(&swap_config.wallet, &pool.info.token_a_address);
41    destination_token_account =
42      get_associated_token_address(&swap_config.wallet, &pool.info.token_b_address);
43  } else {
44    source_token_account =
45      get_associated_token_address(&swap_config.wallet, &pool.info.token_b_address);
46    destination_token_account =
47      get_associated_token_address(&swap_config.wallet, &pool.info.token_a_address);
48  }
49
50  let accounts: Vec<AccountMeta> = vec![
51    AccountMeta::new_readonly(SOLANA_PROGRAMS.token_program, false),
52    AccountMeta::new(pool.info.pool_address, false),
53    AccountMeta::new_readonly(RAYDIUM_CONSTANTS.amm_authority, false),
54    AccountMeta::new(pool.info.pool_address, false),
55    AccountMeta::new(pool.info.token_a_vault_address, false),
56    AccountMeta::new(pool.info.token_b_vault_address, false),
57    AccountMeta::new(pool.info.pool_address, false),
58    AccountMeta::new(pool.info.pool_address, false),
59    AccountMeta::new(pool.info.pool_address, false),
60    AccountMeta::new(pool.info.pool_address, false),
61    AccountMeta::new(pool.info.pool_address, false),
62    AccountMeta::new(pool.info.pool_address, false),
63    AccountMeta::new(pool.info.pool_address, false),
64    AccountMeta::new(pool.info.pool_address, false),
65    AccountMeta::new(source_token_account, false),
66    AccountMeta::new(destination_token_account, false),
67    AccountMeta::new(swap_config.wallet, true),
68  ];
69  instructions.push(Instruction {
70    program_id: RAYDIUM_CONSTANTS.amm_program,
71    accounts,
72    data,
73  });
74  *compute_unit_budget += COMPUTE_UNITS.raydium_ammv4_swap;
75}