solana_tx_decoding/instruction/raydium/
process_raydium_cpmm_swap_instruction.rs

1use solana_central::Instruction;
2use solana_central::Pools;
3use solana_central::SwapDirection;
4use solana_central::SwapTx;
5use solana_central::constants::LAMPORTS_PER_SOL;
6use solana_central::get_cpmm_fee_amount_from_config_account;
7use solana_sdk::pubkey::Pubkey;
8use solana_sdk::signature::Signature;
9use std::collections::HashMap;
10use std::collections::HashSet;
11
12/// Process a Raydium Cpmm swap instruction and create a SwapTx. Assumes the instruction has been
13/// validated as a valid Raydium Cpmm swap. Uses token transfer instructions that follow the swap
14/// to determine swap amounts.
15pub fn process_raydium_cpmm_swap_instruction(
16  // The swap instruction itself
17  instruction: &Instruction,
18  // The 2 token transfers (into one vault, out of the other vault) that come after the swap
19  transfers: &[Instruction],
20  running_token_balances: &mut HashMap<u8, u64>,
21  block_time: u64,
22  slot: u64,
23  index: u64,
24  atomic_instruction_index: u8,
25  signers: &HashSet<Pubkey>,
26  signature: &Signature,
27) -> SwapTx {
28  let market_address = instruction.tx_account_keys[instruction.accounts[3] as usize];
29  let input_token_mint = instruction.tx_account_keys[instruction.accounts[10] as usize];
30  let output_token_mint = instruction.tx_account_keys[instruction.accounts[11] as usize];
31  let input_token_vault = instruction.accounts[6];
32  let output_token_vault = instruction.accounts[7];
33
34  // Pool's input token balance will go up as the user sends funds to the pool
35  let swapped_amount_in = u64::from_le_bytes(transfers[0].data[1..9].try_into().unwrap());
36  if let Some(running_token_balance) = running_token_balances.get_mut(&input_token_vault) {
37    *running_token_balance += swapped_amount_in;
38  }
39
40  // Pool's output token balance will go down as the pool sends funds to the user
41  let swapped_amount_received = u64::from_le_bytes(transfers[1].data[1..9].try_into().unwrap());
42  if let Some(running_token_balance) = running_token_balances.get_mut(&output_token_vault) {
43    *running_token_balance -= swapped_amount_received;
44  }
45
46  let direction;
47  let token_a_address;
48  let token_b_address;
49  let token_a_vault_address;
50  let token_b_vault_address;
51
52  // Lexiographic base58 encoded string sorting happens here
53  // input mint is token a, output mint is token b, direction is token a to token b
54  if input_token_mint < output_token_mint {
55    token_a_address = input_token_mint;
56    token_a_vault_address = input_token_vault;
57    token_b_address = output_token_mint;
58    token_b_vault_address = output_token_vault;
59    direction = SwapDirection::AToB;
60  }
61  // input mint is token b, output mint is token a, direction is token b to token a
62  else {
63    token_a_address = output_token_mint;
64    token_a_vault_address = output_token_vault;
65    token_b_address = input_token_mint;
66    token_b_vault_address = input_token_vault;
67    direction = SwapDirection::BToA;
68  }
69
70  // The fee config is the third account
71
72  let fee_fraction_lp = get_cpmm_fee_amount_from_config_account(
73    instruction.tx_account_keys[instruction.accounts[2] as usize],
74    &market_address,
75  );
76
77  let pool_token_a_vault_amount = running_token_balances[&token_a_vault_address];
78  let pool_token_b_vault_amount = running_token_balances[&token_b_vault_address];
79  let price_b_a_lp =
80    LAMPORTS_PER_SOL * pool_token_b_vault_amount as u128 / pool_token_a_vault_amount as u128;
81  let price_a_b_lp =
82    LAMPORTS_PER_SOL * pool_token_a_vault_amount as u128 / pool_token_b_vault_amount as u128;
83
84  SwapTx {
85    pool: Pools::RaydiumCpmm,
86    direction,
87    block_time,
88    slot,
89    index,
90    atomic_instruction_index,
91    // Raydium CPMM fees are 0.25% fixed rate
92    fee_fraction_lp,
93    swapped_amount_in,
94    swapped_amount_received,
95    pool_token_a_vault_amount,
96    pool_token_b_vault_amount,
97    price_a_b_lp,
98    price_b_a_lp,
99    token_a_address,
100    token_b_address,
101    market_address,
102    signature: signature.clone(),
103    signers: signers.clone(),
104  }
105}