solana_tx_decoding/instruction/pumpswap/
process_pumpswap_swap_instruction.rs

1use solana_central::protocol_idls::pumpswap::{
2  PumpswapBuyEventIdl, PumpswapSellEventIdl,
3};
4use borsh::BorshDeserialize;
5use solana_central::constants::LAMPORTS_PER_SOL;
6use solana_central::Instruction;
7use solana_central::Pools;
8use solana_central::SwapDirection;
9use solana_central::SwapTx;
10use solana_sdk::pubkey::Pubkey;
11use solana_sdk::signature::Signature;
12use std::collections::HashSet;
13
14/// Process a Pumpswap swap instruction and create a SwapTx. Assumes the instruction has been
15/// validated as a valid Pumpswap swap. Needs the event instruction that follows the swap
16/// instruction to extract swap details.
17pub fn process_pumpswap_swap_instruction(
18  instruction: &Instruction,
19  swap_event_instruction: &Instruction,
20  direction: SwapDirection,
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 token_a_address = instruction.tx_account_keys[instruction.accounts[3] as usize];
29  let token_b_address = instruction.tx_account_keys[instruction.accounts[4] as usize];
30  let market_address = instruction.tx_account_keys[instruction.accounts[0] as usize];
31
32  let swapped_amount_in;
33  let swapped_amount_received;
34  let pool_token_a_vault_amount;
35  let pool_token_b_vault_amount;
36  let fee_fraction_lp;
37
38  let event_len = swap_event_instruction.data.len();
39
40  // Sell instruction by pumpswap
41  if direction == SwapDirection::AToB {
42    let decoded_event = PumpswapSellEventIdl::try_from_slice(&swap_event_instruction.data).unwrap();
43
44    swapped_amount_in = decoded_event.base_amount_in;
45    // user quote amount out is the amount of quote token the user actually received
46    swapped_amount_received = decoded_event.user_quote_amount_out;
47    // Token vault balances in the event are confirmed to be pre balances
48    pool_token_a_vault_amount = decoded_event.pool_base_token_reserves + swapped_amount_in;
49    // Out of the token vault comes out the user owed, protocol fee, and creator fee
50    pool_token_b_vault_amount = decoded_event.pool_quote_token_reserves
51      - swapped_amount_received
52      - decoded_event.protocol_fee
53      - decoded_event.coin_creator_fee;
54    let total_fee =
55      decoded_event.lp_fee + decoded_event.protocol_fee + decoded_event.coin_creator_fee;
56    // amount out is only what user receives out
57    // Divison by zero check for zero swapped amounts
58    fee_fraction_lp = if swapped_amount_received + total_fee == 0 {
59      0
60    } else {
61      (total_fee as u128 * LAMPORTS_PER_SOL / (swapped_amount_received + total_fee) as u128) as u64
62    };
63  }
64  // Buy instruction by pumpswap - check event length for backward compatibility
65  else {
66
67    if 
68    // buy
69    event_len == 416 || 
70    // old without ix_name
71    event_len == 401 || 
72    // buy_exact_quote_in event length
73    event_len == 431 {
74      let decoded_event =
75        PumpswapBuyEventIdl::try_from_slice(&swap_event_instruction.data[..401]).unwrap();
76      if event_len == 431 {
77        // Buy exact quote in events have quote amount is as the total amount the user swaps in.
78        // Flipped around garbage protocol
79        swapped_amount_in = decoded_event.quote_amount_in;
80      }
81      else {
82        swapped_amount_in = decoded_event.user_quote_amount_in;
83      }
84      swapped_amount_received = decoded_event.base_amount_out;
85      pool_token_b_vault_amount =
86        decoded_event.pool_quote_token_reserves + decoded_event.quote_amount_in_with_lp_fee;
87      pool_token_a_vault_amount = decoded_event.pool_base_token_reserves - swapped_amount_received;
88      let total_fee =
89        decoded_event.lp_fee + decoded_event.protocol_fee + decoded_event.coin_creator_fee;
90      fee_fraction_lp = if swapped_amount_in == 0 {
91        0
92      } else {
93        (total_fee as u128 * LAMPORTS_PER_SOL / swapped_amount_in as u128) as u64
94      };
95    }
96    else {
97      panic!(
98        "Pumpswap: Found a buy event, but data length {} is not recognized (expected 401 or 416), tx signature: {}",
99        event_len, signature
100      );
101    }
102  }
103
104  let price_a_b_lp =
105    pool_token_a_vault_amount as u128 * LAMPORTS_PER_SOL / pool_token_b_vault_amount as u128;
106  let price_b_a_lp =
107    pool_token_b_vault_amount as u128 * LAMPORTS_PER_SOL / pool_token_a_vault_amount as u128;
108
109  SwapTx {
110    pool: Pools::PumpswapAmm,
111    direction,
112    block_time,
113    slot,
114    index,
115    atomic_instruction_index,
116    fee_fraction_lp,
117    swapped_amount_in,
118    swapped_amount_received,
119    pool_token_a_vault_amount,
120    pool_token_b_vault_amount,
121    price_a_b_lp,
122    price_b_a_lp,
123    token_a_address,
124    token_b_address,
125    market_address,
126    signature: signature.clone(),
127    signers: signers.clone(),
128  }
129}