solana_exec/raydium/
push_raydium_cpmm_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::RaydiumCpmmPool;
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/// Create and add a Raydium CPMM swap instruction. If `use_manual_instruction_args` is true, uses
11/// exact amounts instead of slippage-based calculations.
12pub fn push_raydium_cpmm_swap_instruction(
13  swap_config: &SwapConfig,
14  // If true, use exact amounts (manual override) instead of slippage calculations
15  use_manual_instruction_args: bool,
16  mut minimum_amount_out: u64,
17  instructions: &mut Vec<Instruction>,
18  compute_unit_budget: &mut u32,
19  pool: &RaydiumCpmmPool,
20) {
21  /*
22  Raydium CPMM is 24 bytes swap length, 8 for discriminator, 8 for amount in, 8 for minimum amount
23  out u64 bytes
24  */
25  let mut data: Vec<u8> = Vec::with_capacity(17);
26  // Push swap exact in discriminator for raydium cpmm
27  data.extend_from_slice(&RAYDIUM_CONSTANTS.cpmm_swap_discriminators[0]);
28  // Calculate minimum amount out using slippage setup if the argument is not manually provided
29  if !use_manual_instruction_args {
30    minimum_amount_out = get_min_amount_out(swap_config, pool);
31  }
32  data.extend_from_slice(&swap_config.amount_in.to_le_bytes());
33  data.extend_from_slice(&minimum_amount_out.to_le_bytes());
34  let input_token_account;
35  let output_token_account;
36  let input_vault;
37  let output_vault;
38  let input_token_address;
39  let output_token_address;
40  if swap_config.direction == SwapDirection::AToB {
41    input_token_account =
42      get_associated_token_address(&swap_config.wallet, &pool.info.token_a_address);
43    output_token_account =
44      get_associated_token_address(&swap_config.wallet, &pool.info.token_b_address);
45    input_vault = pool.info.token_a_vault_address;
46    output_vault = pool.info.token_b_vault_address;
47    input_token_address = pool.info.token_a_address;
48    output_token_address = pool.info.token_b_address;
49  } else {
50    input_token_account =
51      get_associated_token_address(&swap_config.wallet, &pool.info.token_b_address);
52    output_token_account =
53      get_associated_token_address(&swap_config.wallet, &pool.info.token_a_address);
54    input_vault = pool.info.token_b_vault_address;
55    output_vault = pool.info.token_a_vault_address;
56    input_token_address = pool.info.token_b_address;
57    output_token_address = pool.info.token_a_address;
58  }
59
60  let accounts: Vec<AccountMeta> = vec![
61    AccountMeta::new(swap_config.wallet, true),
62    AccountMeta::new_readonly(RAYDIUM_CONSTANTS.cpmm_authority, false),
63    AccountMeta::new_readonly(pool.pool_config_account, false),
64    AccountMeta::new(pool.info.pool_address, false),
65    AccountMeta::new(input_token_account, false),
66    AccountMeta::new(output_token_account, false),
67    AccountMeta::new(input_vault, false),
68    AccountMeta::new(output_vault, false),
69    AccountMeta::new_readonly(SOLANA_PROGRAMS.token_program, false),
70    AccountMeta::new_readonly(SOLANA_PROGRAMS.token_program, false),
71    AccountMeta::new(input_token_address, false),
72    AccountMeta::new(output_token_address, false),
73    AccountMeta::new(pool.observation_state_account, false),
74  ];
75  instructions.push(Instruction {
76    program_id: RAYDIUM_CONSTANTS.cpmm_program,
77    accounts,
78    data,
79  });
80  *compute_unit_budget += COMPUTE_UNITS.raydium_cpmm_swap;
81}