use crate::core::events::{
EventMetadata, PumpSwapGlobalConfig, PumpSwapGlobalConfigAccountEvent, PumpSwapPool,
PumpSwapPoolAccountEvent,
};
use crate::DexEvent;
use super::token::AccountData;
use super::utils::*;
pub mod discriminators {
pub const GLOBAL_CONFIG_ACCOUNT: &[u8] = &[149, 8, 156, 202, 160, 252, 176, 217];
pub const POOL_ACCOUNT: &[u8] = &[241, 154, 109, 4, 17, 177, 109, 188];
}
pub const GLOBAL_CONFIG_SIZE: usize = 32 + 8 + 8 + 1 + 32 * 8 + 8 + 32;
pub const POOL_SIZE: usize = 244;
pub fn parse_global_config(account: &AccountData, metadata: EventMetadata) -> Option<DexEvent> {
if account.data.len() < GLOBAL_CONFIG_SIZE + 8 {
return None;
}
if !has_discriminator(&account.data, discriminators::GLOBAL_CONFIG_ACCOUNT) {
return None;
}
let data = &account.data[8..];
let mut offset = 0;
let admin = read_pubkey(data, offset)?;
offset += 32;
let lp_fee_basis_points = read_u64_le(data, offset)?;
offset += 8;
let protocol_fee_basis_points = read_u64_le(data, offset)?;
offset += 8;
let disable_flags = read_u8(data, offset)?;
offset += 1;
let mut protocol_fee_recipients = [solana_sdk::pubkey::Pubkey::default(); 8];
for i in 0..8 {
protocol_fee_recipients[i] = read_pubkey(data, offset)?;
offset += 32;
}
let coin_creator_fee_basis_points = read_u64_le(data, offset)?;
offset += 8;
let admin_set_coin_creator_authority = read_pubkey(data, offset)?;
offset += 32;
let whitelist_pda = read_pubkey(data, offset)?;
offset += 32;
let reserved_fee_recipient = read_pubkey(data, offset)?;
offset += 32;
let mayhem_mode_enabled = read_u8(data, offset)? != 0;
offset += 1;
let mut reserved_fee_recipients = [solana_sdk::pubkey::Pubkey::default(); 7];
for i in 0..7 {
reserved_fee_recipients[i] = read_pubkey(data, offset)?;
offset += 32;
}
let global_config = PumpSwapGlobalConfig {
admin,
lp_fee_basis_points,
protocol_fee_basis_points,
disable_flags,
protocol_fee_recipients,
coin_creator_fee_basis_points,
admin_set_coin_creator_authority,
whitelist_pda,
reserved_fee_recipient,
mayhem_mode_enabled,
reserved_fee_recipients,
};
Some(DexEvent::PumpSwapGlobalConfigAccount(PumpSwapGlobalConfigAccountEvent {
metadata,
pubkey: account.pubkey,
executable: account.executable,
lamports: account.lamports,
owner: account.owner,
rent_epoch: account.rent_epoch,
global_config,
}))
}
pub fn parse_pool(account: &AccountData, metadata: EventMetadata) -> Option<DexEvent> {
if account.data.len() < POOL_SIZE + 8 {
return None;
}
if !has_discriminator(&account.data, discriminators::POOL_ACCOUNT) {
return None;
}
let data = &account.data[8..];
let mut offset = 0;
let pool_bump = read_u8(data, offset)?;
offset += 1;
let index = read_u16_le(data, offset)?;
offset += 2;
let creator = read_pubkey(data, offset)?;
offset += 32;
let base_mint = read_pubkey(data, offset)?;
offset += 32;
let quote_mint = read_pubkey(data, offset)?;
offset += 32;
let lp_mint = read_pubkey(data, offset)?;
offset += 32;
let pool_base_token_account = read_pubkey(data, offset)?;
offset += 32;
let pool_quote_token_account = read_pubkey(data, offset)?;
offset += 32;
let lp_supply = read_u64_le(data, offset)?;
offset += 8;
let coin_creator = read_pubkey(data, offset)?;
offset += 32;
let is_mayhem_mode = read_u8(data, offset)? != 0;
offset += 1;
let is_cashback_coin = read_u8(data, offset)? != 0;
let pool = PumpSwapPool {
pool_bump,
index,
creator,
base_mint,
quote_mint,
lp_mint,
pool_base_token_account,
pool_quote_token_account,
lp_supply,
coin_creator,
is_mayhem_mode,
is_cashback_coin,
};
Some(DexEvent::PumpSwapPoolAccount(PumpSwapPoolAccountEvent {
metadata,
pubkey: account.pubkey,
executable: account.executable,
lamports: account.lamports,
owner: account.owner,
rent_epoch: account.rent_epoch,
pool,
}))
}
pub fn is_global_config_account(data: &[u8]) -> bool {
has_discriminator(data, discriminators::GLOBAL_CONFIG_ACCOUNT)
}
pub fn is_pool_account(data: &[u8]) -> bool {
has_discriminator(data, discriminators::POOL_ACCOUNT)
}
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::pubkey::Pubkey;
#[test]
fn parse_pool_reads_mayhem_and_cashback_flags() {
let pubkeys = [
Pubkey::new_unique(),
Pubkey::new_unique(),
Pubkey::new_unique(),
Pubkey::new_unique(),
Pubkey::new_unique(),
Pubkey::new_unique(),
];
let mut data = Vec::with_capacity(8 + POOL_SIZE);
data.extend_from_slice(discriminators::POOL_ACCOUNT);
data.push(7); data.extend_from_slice(&42u16.to_le_bytes()); for key in pubkeys {
data.extend_from_slice(key.as_ref());
}
data.extend_from_slice(&123456789u64.to_le_bytes()); let coin_creator = Pubkey::new_unique();
data.extend_from_slice(coin_creator.as_ref());
data.push(1); data.push(1); data.extend_from_slice(&[0u8; 7]);
let account = AccountData {
pubkey: Pubkey::new_unique(),
owner: Pubkey::new_unique(),
data,
executable: false,
lamports: 1,
rent_epoch: 0,
};
let metadata = EventMetadata::default();
let event = parse_pool(&account, metadata).expect("pool account should parse");
let DexEvent::PumpSwapPoolAccount(event) = event else {
panic!("expected PumpSwapPoolAccount");
};
assert_eq!(event.pool.pool_bump, 7);
assert_eq!(event.pool.index, 42);
assert_eq!(event.pool.creator, pubkeys[0]);
assert_eq!(event.pool.base_mint, pubkeys[1]);
assert_eq!(event.pool.quote_mint, pubkeys[2]);
assert_eq!(event.pool.lp_mint, pubkeys[3]);
assert_eq!(event.pool.pool_base_token_account, pubkeys[4]);
assert_eq!(event.pool.pool_quote_token_account, pubkeys[5]);
assert_eq!(event.pool.lp_supply, 123456789);
assert_eq!(event.pool.coin_creator, coin_creator);
assert!(event.pool.is_mayhem_mode);
assert!(event.pool.is_cashback_coin);
}
}