solana_tx_decoding/tx/
top_level_instructions_loop.rs

1use crate::instruction::classify_instruction::classify_instruction;
2use crate::instruction::pumpfun::process_pf_bonding_curve_create_instruction::process_pf_bonding_curve_create_instruction;
3use crate::instruction::pumpswap::process_pumpswap_swap_instruction::process_pumpswap_swap_instruction;
4use crate::instruction::raydium::process_raydium_ammv4_swap_instruction::process_raydium_ammv4_swap_instruction;
5use crate::instruction::raydium::process_raydium_cpmm_swap_instruction::process_raydium_cpmm_swap_instruction;
6use crate::instruction::raydium::process_raydium_launchpad_swap_instruction::process_raydium_launchpad_swap_instruction;
7use crate::tx::inner_instructions_loop::inner_instructions_loop;
8use crate::types::instruction_type::InstructionType;
9use solana_central::Instruction;
10use solana_central::SwapTx;
11use solana_central::TokenCreation;
12use solana_sdk::pubkey::Pubkey;
13use solana_sdk::signature::Signature;
14use std::collections::HashMap;
15use std::collections::HashSet;
16use tokio::sync::broadcast::Sender;
17
18/// Process top-level instructions in a transaction. Iterates through top-level instructions,
19/// classifies them, and processes swap/creation instructions. Also calls `inner_instructions_loop`
20/// to process the inner instructions that belong to each top level instruction.
21pub fn top_level_instructions_loop(
22  top_level_instructions: &Vec<Instruction>,
23  inner_instructions: &HashMap<u8, Vec<Instruction>>,
24  account_keys: &Vec<Pubkey>,
25  ta_mint: &HashMap<u8, Pubkey>,
26  running_token_balances: &mut HashMap<u8, u64>,
27  swap_tx_sender: &Sender<SwapTx>,
28  token_create_sender: &Sender<TokenCreation>,
29  block_time: u64,
30  slot: u64,
31  index: u64,
32  signers: &HashSet<Pubkey>,
33  signature: &Signature,
34) {
35  let mut atomic_instruction_index = 0;
36  for (instr_index, instruction) in top_level_instructions.iter().enumerate() {
37    let instr_index = instr_index as u8;
38    let (instruction_type, swap_direction) = classify_instruction(&instruction);
39    // println!("Instruction type: {:?}", instruction_type);
40    // println!("Instruction type: {:?}", instruction_type);
41    // println!("Atomic instruction index: {:?}", atomic_instruction_index);
42    if instruction_type == InstructionType::None {
43      // Bump by 1, if its not none it will be bumped by 1 again adn the length of the inners
44      atomic_instruction_index += 1;
45      if let Some(inner_instructions) = inner_instructions.get(&instr_index) {
46        inner_instructions_loop(
47          inner_instructions,
48          account_keys,
49          ta_mint,
50          running_token_balances,
51          swap_tx_sender,
52          token_create_sender,
53          block_time,
54          slot,
55          index,
56          &mut atomic_instruction_index,
57          signers,
58          signature,
59        );
60      }
61    } else if instruction_type == InstructionType::RaydiumLaunchpadSwap {
62      let event = &inner_instructions.get(&instr_index).unwrap()[0];
63      let swap_tx = process_raydium_launchpad_swap_instruction(
64        instruction,
65        event,
66        swap_direction,
67        block_time,
68        slot,
69        index,
70        atomic_instruction_index,
71        signers,
72        signature,
73      );
74      let _ = swap_tx_sender.send(swap_tx);
75    } else if instruction_type == InstructionType::RaydiumCpmmSwap {
76      let transfers = inner_instructions.get(&instr_index).unwrap();
77      let swap_tx = process_raydium_cpmm_swap_instruction(
78        instruction,
79        transfers,
80        running_token_balances,
81        block_time,
82        slot,
83        index,
84        atomic_instruction_index,
85        signers,
86        signature,
87      );
88      let _ = swap_tx_sender.send(swap_tx);
89    } else if instruction_type == InstructionType::RaydiumAmmV4Swap {
90      let transfers = inner_instructions.get(&instr_index).unwrap();
91      let swap_tx = process_raydium_ammv4_swap_instruction(
92        instruction,
93        transfers,
94        ta_mint,
95        running_token_balances,
96        block_time,
97        slot,
98        index,
99        atomic_instruction_index,
100        signers,
101        signature,
102      );
103      let _ = swap_tx_sender.send(swap_tx);
104    } else if instruction_type == InstructionType::PumpswapSwap {
105      let event = inner_instructions
106        .get(&instr_index)
107        .unwrap()
108        .last()
109        .unwrap();
110      let swap_tx = process_pumpswap_swap_instruction(
111        instruction,
112        event,
113        swap_direction,
114        block_time,
115        slot,
116        index,
117        atomic_instruction_index,
118        signers,
119        signature,
120      );
121      let _ = swap_tx_sender.send(swap_tx);
122    } else if instruction_type == InstructionType::PfBondingCurveCreate {
123      let creation = process_pf_bonding_curve_create_instruction(
124        instruction,
125        block_time,
126        slot,
127        index,
128        atomic_instruction_index,
129        signature,
130      );
131      let _ = token_create_sender.send(creation);
132    }
133    // Add to atomic instruction index if not None since the top level swaps don't iterate through
134    if instruction_type != InstructionType::None {
135      let a = inner_instructions.get(&instr_index).unwrap().len() as u8;
136      // println!("Inner instructions length: {:?}", a);
137      atomic_instruction_index += a + 1;
138    }
139    // Pf bonding curve is not in here. Its not possible for a pf swap event be in a top level instruction
140  }
141}