solana_tx_decoding/tx/
inner_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::pumpfun::process_pumpfun_event_instruction::process_pumpfun_event_instruction;
4use crate::instruction::pumpswap::process_pumpswap_swap_instruction::process_pumpswap_swap_instruction;
5use crate::instruction::raydium::process_raydium_ammv4_swap_instruction::process_raydium_ammv4_swap_instruction;
6use crate::instruction::raydium::process_raydium_cpmm_swap_instruction::process_raydium_cpmm_swap_instruction;
7use crate::instruction::raydium::process_raydium_launchpad_swap_instruction::process_raydium_launchpad_swap_instruction;
8use crate::types::instruction_type::InstructionType;
9use solana_central::Instruction;
10use solana_central::SwapTx;
11use solana_central::TokenCreation;
12use solana_central::constants::PUMP_CONSTANTS;
13use solana_sdk::pubkey::Pubkey;
14use solana_sdk::signature::Signature;
15use std::collections::HashMap;
16use std::collections::HashSet;
17use tokio::sync::broadcast::Sender;
18
19/// Handles inner instructions that result from program invocations. Processes swap instructions
20/// and token creation events from various protocols, sending results to broadcast channels just
21/// like `top_level_instructions_loop` does.
22pub fn inner_instructions_loop(
23  inner_instructions: &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  atomic_instruction_index: &mut u8,
33  signers: &HashSet<Pubkey>,
34  signature: &Signature,
35) {
36  // Check inner instructions if they exist
37  let mut instr_index = 0;
38  while instr_index < inner_instructions.len() {
39    let instruction = &inner_instructions[instr_index];
40
41    let (instruction_type, swap_direction) = classify_instruction(&instruction);
42    if instruction_type == InstructionType::RaydiumLaunchpadSwap {
43      // Event instruction is first instruction after the swap
44      let event = &inner_instructions[instr_index + 1];
45      let swap_tx = process_raydium_launchpad_swap_instruction(
46        instruction,
47        event,
48        swap_direction,
49        block_time,
50        slot,
51        index,
52        *atomic_instruction_index,
53        signers,
54        signature,
55      );
56      let _ = swap_tx_sender.send(swap_tx);
57    } else if instruction_type == InstructionType::RaydiumCpmmSwap {
58      // The transfers are the two instructions immediately after the swap
59      let transfers = &inner_instructions[instr_index + 1..instr_index + 3];
60      let swap_tx = process_raydium_cpmm_swap_instruction(
61        instruction,
62        transfers,
63        running_token_balances,
64        block_time,
65        slot,
66        index,
67        *atomic_instruction_index,
68        signers,
69        signature,
70      );
71      let _ = swap_tx_sender.send(swap_tx);
72    } else if instruction_type == InstructionType::RaydiumAmmV4Swap {
73      // The transfers are the two instructions immediately after the swap
74      let transfers = &inner_instructions[instr_index + 1..instr_index + 3];
75      let swap_tx = process_raydium_ammv4_swap_instruction(
76        instruction,
77        transfers,
78        ta_mint,
79        running_token_balances,
80        block_time,
81        slot,
82        index,
83        *atomic_instruction_index,
84        signers,
85        signature,
86      );
87      let _ = swap_tx_sender.send(swap_tx);
88    } else if instruction_type == InstructionType::PumpswapSwap {
89      // To find this event, look from the instructions following the swap until we find one that is for the pumpswap program
90      let mut event = None;
91      for i in instr_index + 1..inner_instructions.len() {
92        if account_keys[inner_instructions[i].program_id_index as usize]
93          == PUMP_CONSTANTS.pump_swap_program
94        {
95          event = Some(&inner_instructions[i]);
96          break;
97        }
98      }
99      let swap_tx = process_pumpswap_swap_instruction(
100          instruction,
101          event.expect(&format!("inner_instructions_loop: Unable to find pumpswap event following inner instruction swap, signature: {}", signature.to_string())),
102          swap_direction,
103          block_time,
104          slot,
105          index,
106          *atomic_instruction_index,
107          signers,
108          signature,
109        );
110      let _ = swap_tx_sender.send(swap_tx);
111    } else if instruction_type == InstructionType::PfBondingCurveSwap {
112      let swap_tx = process_pumpfun_event_instruction(
113        instruction,
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
134    *atomic_instruction_index += 1;
135    instr_index += 1;
136    // println!("Atomic instruction index (in inner): {:?}", *atomic_instruction_index);
137  }
138}