mod amm;
mod bond_curve;
mod global;
use std::{str::FromStr, sync::Arc};
use solana_network_client::SolanaClient;
use solana_sdk::pubkey::Pubkey;
use crate::{bond_curve::BondCurve, global::PUMP_DOT_FUN_PROGRAM_ID};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PumpPoolState {
pub token_mint: [u8; 32], pub bonding_curve: [u8; 32], pub virtual_token_reserve: u64, pub virtual_sol_reserve: u64, pub real_token_reserve: u64, pub real_sol_reserve: u64, pub total_supply: u64, pub current_progress: u64, pub curve_type: u8, _padding1: u8,
pub fee_bps: u16, pub creator: [u8; 32], pub created_at: i64, pub last_updated: i64, pub status: u8, _padding2: [u8; 7],
}
#[derive(Debug, Clone)]
pub struct PumpInfo {
pub token_mint: Pubkey,
pub bonding_curve: Pubkey,
pub virtual_token_reserve: u64,
pub virtual_sol_reserve: u64,
pub real_token_reserve: u64,
pub real_sol_reserve: u64,
pub total_supply: u64,
pub current_progress: f64,
pub curve_type: u8,
pub fee_bps: u16,
pub creator: Pubkey,
pub created_at: i64,
pub last_updated: i64,
pub status: u8,
pub price_sol: f64,
pub progress_percent: f64,
}
pub struct Pump {
pub solana_client: Arc<SolanaClient>,
}
impl Pump {
pub fn new(solana_client: Arc<SolanaClient>) -> Self {
Self { solana_client }
}
pub async fn get_pump_info(&self) -> Result<PumpInfo, String> {
let v = self
.solana_client
.client_arc()
.get_account_data(
&Pubkey::from_str(PUMP_DOT_FUN_PROGRAM_ID)
.map_err(|e| format!("{:?}", e))
.unwrap(),
)
.await
.map_err(|e| format!("{:?}", e))
.unwrap();
let pump_info = Self::parse_pump_info(&v)
.map_err(|e| format!("{:?}", e))
.unwrap();
Ok(pump_info)
}
fn parse_pump_info(data: &[u8]) -> Result<PumpInfo, String> {
const DISCRIMINATOR_LEN: usize = 8;
if data.len() < DISCRIMINATOR_LEN + 180 {
return Err(format!(
"Pump pool data too short. Expected at least {}, got {}",
DISCRIMINATOR_LEN + 180,
data.len()
));
}
let mut offset = DISCRIMINATOR_LEN;
let read_pubkey = |data: &[u8], o: &mut usize| -> Pubkey {
let pk = Pubkey::new_from_array(data[*o..*o + 32].try_into().unwrap());
*o += 32;
pk
};
let read_u64 = |data: &[u8], o: &mut usize| -> u64 {
let v = u64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
*o += 8;
v
};
let read_u8 = |data: &[u8], o: &mut usize| -> u8 {
let v = data[*o];
*o += 1;
v
};
let read_u16 = |data: &[u8], o: &mut usize| -> u16 {
let v = u16::from_le_bytes(data[*o..*o + 2].try_into().unwrap());
*o += 2;
v
};
let read_i64 = |data: &[u8], o: &mut usize| -> i64 {
let v = i64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
*o += 8;
v
};
let token_mint = read_pubkey(data, &mut offset);
let bonding_curve = read_pubkey(data, &mut offset);
let virtual_token_reserve = read_u64(data, &mut offset);
let virtual_sol_reserve = read_u64(data, &mut offset);
let real_token_reserve = read_u64(data, &mut offset);
let real_sol_reserve = read_u64(data, &mut offset);
let total_supply = read_u64(data, &mut offset);
let current_progress_raw = read_u64(data, &mut offset);
let curve_type = read_u8(data, &mut offset);
offset += 1; let fee_bps = read_u16(data, &mut offset);
let creator = read_pubkey(data, &mut offset);
let created_at = read_i64(data, &mut offset);
let last_updated = read_i64(data, &mut offset);
let status = read_u8(data, &mut offset);
let price_sol = if virtual_token_reserve > 0 {
virtual_sol_reserve as f64 / virtual_token_reserve as f64
} else {
0.0
};
let current_progress = current_progress_raw as f64 / 10000.0;
Ok(PumpInfo {
token_mint,
bonding_curve,
virtual_token_reserve,
virtual_sol_reserve,
real_token_reserve,
real_sol_reserve,
total_supply,
current_progress,
curve_type,
fee_bps,
creator,
created_at,
last_updated,
status,
price_sol,
progress_percent: current_progress * 100.0,
})
}
pub fn create_bond_curve(&self) -> BondCurve {
BondCurve::new(self.solana_client.clone())
}
}
#[cfg(test)]
mod test {
use solana_network_client::SolanaClient;
use std::sync::Arc;
use crate::Pump;
#[tokio::test]
async fn test() -> Result<(), Box<dyn std::error::Error>> {
let solana_client = SolanaClient::new(solana_network_client::Mode::MAIN).unwrap();
let pump = Pump::new(Arc::new(solana_client));
let pump_info = pump.get_pump_info().await.unwrap();
println!("Pump Info: {:?}", pump_info);
Ok(())
}
}