use super::program_ids;
use super::utils::*;
use crate::core::events::*;
use solana_sdk::{pubkey::Pubkey, signature::Signature};
pub mod discriminators {
pub const BUY: [u8; 8] = [102, 6, 61, 18, 1, 218, 235, 234];
pub const SELL: [u8; 8] = [51, 230, 133, 164, 1, 127, 131, 173];
pub const CREATE_POOL: [u8; 8] = [233, 146, 209, 142, 207, 104, 64, 188];
pub const BUY_EXACT_QUOTE_IN: [u8; 8] = [198, 46, 21, 82, 180, 217, 232, 112];
pub const DEPOSIT: [u8; 8] = [242, 35, 198, 137, 82, 225, 242, 182];
pub const WITHDRAW: [u8; 8] = [183, 18, 70, 156, 148, 109, 161, 34];
}
pub const PROGRAM_ID_PUBKEY: Pubkey = program_ids::PUMPSWAP_PROGRAM_ID;
pub fn parse_instruction(
instruction_data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if instruction_data.len() < 8 {
return None;
}
let discriminator: [u8; 8] = instruction_data[0..8].try_into().ok()?;
let data = &instruction_data[8..];
match discriminator {
discriminators::BUY => {
parse_buy_instruction(data, accounts, signature, slot, tx_index, block_time_us)
}
discriminators::BUY_EXACT_QUOTE_IN => parse_buy_exact_quote_in_instruction(
data,
accounts,
signature,
slot,
tx_index,
block_time_us,
),
discriminators::SELL => {
parse_sell_instruction(data, accounts, signature, slot, tx_index, block_time_us)
}
discriminators::CREATE_POOL => {
parse_create_pool_instruction(data, accounts, signature, slot, tx_index, block_time_us)
}
discriminators::DEPOSIT => {
parse_deposit_instruction(data, accounts, signature, slot, tx_index, block_time_us)
}
discriminators::WITHDRAW => {
parse_withdraw_instruction(data, accounts, signature, slot, tx_index, block_time_us)
}
_ => None,
}
}
#[allow(dead_code)]
fn parse_buy_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 13 {
return None;
}
let (base_amount, quote_amount) = if data.len() >= 16 {
(read_u64_le(data, 0).unwrap_or(0), read_u64_le(data, 8).unwrap_or(0))
} else {
(0, 0)
};
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
let mut ev = PumpSwapBuyEvent {
metadata,
pool: get_account(accounts, 0).unwrap_or_default(),
user: get_account(accounts, 1).unwrap_or_default(),
base_mint: get_account(accounts, 3).unwrap_or_default(),
quote_mint: get_account(accounts, 4).unwrap_or_default(),
user_base_token_account: get_account(accounts, 5).unwrap_or_default(),
user_quote_token_account: get_account(accounts, 6).unwrap_or_default(),
pool_base_token_account: get_account(accounts, 7).unwrap_or_default(),
pool_quote_token_account: get_account(accounts, 8).unwrap_or_default(),
protocol_fee_recipient: get_account(accounts, 9).unwrap_or_default(),
protocol_fee_recipient_token_account: get_account(accounts, 10).unwrap_or_default(),
base_token_program: get_account(accounts, 11).unwrap_or_default(),
quote_token_program: get_account(accounts, 12).unwrap_or_default(),
base_amount_out: base_amount,
max_quote_amount_in: quote_amount,
..Default::default()
};
if accounts.len() >= 19 {
ev.coin_creator_vault_ata = get_account(accounts, 17).unwrap_or_default();
ev.coin_creator_vault_authority = get_account(accounts, 18).unwrap_or_default();
}
Some(DexEvent::PumpSwapBuy(ev))
}
#[allow(dead_code)]
fn parse_buy_exact_quote_in_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 13 {
return None;
}
let (quote_amount, base_amount) = if data.len() >= 16 {
(read_u64_le(data, 0).unwrap_or(0), read_u64_le(data, 8).unwrap_or(0))
} else {
(0, 0)
};
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
let mut ev = PumpSwapBuyEvent {
metadata,
pool: get_account(accounts, 0).unwrap_or_default(),
user: get_account(accounts, 1).unwrap_or_default(),
base_mint: get_account(accounts, 3).unwrap_or_default(),
quote_mint: get_account(accounts, 4).unwrap_or_default(),
user_base_token_account: get_account(accounts, 5).unwrap_or_default(),
user_quote_token_account: get_account(accounts, 6).unwrap_or_default(),
pool_base_token_account: get_account(accounts, 7).unwrap_or_default(),
pool_quote_token_account: get_account(accounts, 8).unwrap_or_default(),
protocol_fee_recipient: get_account(accounts, 9).unwrap_or_default(),
protocol_fee_recipient_token_account: get_account(accounts, 10).unwrap_or_default(),
base_token_program: get_account(accounts, 11).unwrap_or_default(),
quote_token_program: get_account(accounts, 12).unwrap_or_default(),
base_amount_out: base_amount,
max_quote_amount_in: quote_amount,
..Default::default()
};
if accounts.len() >= 19 {
ev.coin_creator_vault_ata = get_account(accounts, 17).unwrap_or_default();
ev.coin_creator_vault_authority = get_account(accounts, 18).unwrap_or_default();
}
Some(DexEvent::PumpSwapBuy(ev))
}
#[allow(dead_code)]
fn parse_sell_instruction(
data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 13 {
return None;
}
let (base_amount, quote_amount) = if data.len() >= 16 {
(read_u64_le(data, 0).unwrap_or(0), read_u64_le(data, 8).unwrap_or(0))
} else {
(0, 0)
};
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
let mut ev = PumpSwapSellEvent {
metadata,
pool: get_account(accounts, 0).unwrap_or_default(),
user: get_account(accounts, 1).unwrap_or_default(),
base_mint: get_account(accounts, 3).unwrap_or_default(),
quote_mint: get_account(accounts, 4).unwrap_or_default(),
user_base_token_account: get_account(accounts, 5).unwrap_or_default(),
user_quote_token_account: get_account(accounts, 6).unwrap_or_default(),
pool_base_token_account: get_account(accounts, 7).unwrap_or_default(),
pool_quote_token_account: get_account(accounts, 8).unwrap_or_default(),
protocol_fee_recipient: get_account(accounts, 9).unwrap_or_default(),
protocol_fee_recipient_token_account: get_account(accounts, 10).unwrap_or_default(),
base_token_program: get_account(accounts, 11).unwrap_or_default(),
quote_token_program: get_account(accounts, 12).unwrap_or_default(),
base_amount_in: base_amount,
min_quote_amount_out: quote_amount,
..Default::default()
};
if accounts.len() >= 19 {
ev.coin_creator_vault_ata = get_account(accounts, 17).unwrap_or_default();
ev.coin_creator_vault_authority = get_account(accounts, 18).unwrap_or_default();
}
Some(DexEvent::PumpSwapSell(ev))
}
#[allow(dead_code)]
fn parse_create_pool_instruction(
_data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 5 {
return None;
}
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
Some(DexEvent::PumpSwapCreatePool(PumpSwapCreatePoolEvent {
metadata,
creator: get_account(accounts, 0).unwrap_or_default(),
base_mint: get_account(accounts, 2).unwrap_or_default(),
quote_mint: get_account(accounts, 3).unwrap_or_default(),
..Default::default()
}))
}
#[allow(dead_code)]
fn parse_deposit_instruction(
_data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 8 {
return None;
}
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
Some(DexEvent::PumpSwapLiquidityAdded(PumpSwapLiquidityAdded {
metadata,
pool: get_account(accounts, 0).unwrap_or_default(),
user: get_account(accounts, 1).unwrap_or_default(),
user_base_token_account: get_account(accounts, 4).unwrap_or_default(),
user_quote_token_account: get_account(accounts, 5).unwrap_or_default(),
user_pool_token_account: get_account(accounts, 6).unwrap_or_default(),
..Default::default()
}))
}
#[allow(dead_code)]
fn parse_withdraw_instruction(
_data: &[u8],
accounts: &[Pubkey],
signature: Signature,
slot: u64,
tx_index: u64,
block_time_us: Option<i64>,
) -> Option<DexEvent> {
if accounts.len() < 8 {
return None;
}
let metadata = create_metadata(signature, slot, tx_index, block_time_us.unwrap_or_default(), 0);
Some(DexEvent::PumpSwapLiquidityRemoved(PumpSwapLiquidityRemoved {
metadata,
pool: get_account(accounts, 0).unwrap_or_default(),
user: get_account(accounts, 1).unwrap_or_default(),
user_base_token_account: get_account(accounts, 4).unwrap_or_default(),
user_quote_token_account: get_account(accounts, 5).unwrap_or_default(),
user_pool_token_account: get_account(accounts, 6).unwrap_or_default(),
..Default::default()
}))
}