1mod amm;
2mod bond_curve;
3mod global;
4
5use std::{str::FromStr, sync::Arc};
6
7use solana_network_client::SolanaClient;
8use solana_sdk::pubkey::Pubkey;
9
10use crate::{bond_curve::BondCurve, global::PUMP_DOT_FUN_PROGRAM_ID};
11
12#[repr(C)]
13#[derive(Debug, Copy, Clone)]
14pub struct PumpPoolState {
15 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,
25 pub fee_bps: u16, pub creator: [u8; 32], pub created_at: i64, pub last_updated: i64, pub status: u8, _padding2: [u8; 7],
32}
33
34#[derive(Debug, Clone)]
35pub struct PumpInfo {
36 pub token_mint: Pubkey,
37 pub bonding_curve: Pubkey,
38 pub virtual_token_reserve: u64,
39 pub virtual_sol_reserve: u64,
40 pub real_token_reserve: u64,
41 pub real_sol_reserve: u64,
42 pub total_supply: u64,
43 pub current_progress: f64,
44 pub curve_type: u8,
45 pub fee_bps: u16,
46 pub creator: Pubkey,
47 pub created_at: i64,
48 pub last_updated: i64,
49 pub status: u8,
50 pub price_sol: f64,
51 pub progress_percent: f64,
52}
53
54pub struct Pump {
55 pub solana_client: Arc<SolanaClient>,
56}
57
58impl Pump {
59 pub fn new(solana_client: Arc<SolanaClient>) -> Self {
60 Self { solana_client }
61 }
62
63 pub async fn get_pump_info(&self) -> Result<PumpInfo, String> {
64 let v = self
65 .solana_client
66 .client_arc()
67 .get_account_data(
68 &Pubkey::from_str(PUMP_DOT_FUN_PROGRAM_ID)
69 .map_err(|e| format!("{:?}", e))
70 .unwrap(),
71 )
72 .await
73 .map_err(|e| format!("{:?}", e))
74 .unwrap();
75 let pump_info = Self::parse_pump_info(&v)
76 .map_err(|e| format!("{:?}", e))
77 .unwrap();
78 Ok(pump_info)
79 }
80
81 fn parse_pump_info(data: &[u8]) -> Result<PumpInfo, String> {
84 const DISCRIMINATOR_LEN: usize = 8;
85 if data.len() < DISCRIMINATOR_LEN + 180 {
86 return Err(format!(
87 "Pump pool data too short. Expected at least {}, got {}",
88 DISCRIMINATOR_LEN + 180,
89 data.len()
90 ));
91 }
92 let mut offset = DISCRIMINATOR_LEN;
93 let read_pubkey = |data: &[u8], o: &mut usize| -> Pubkey {
94 let pk = Pubkey::new_from_array(data[*o..*o + 32].try_into().unwrap());
95 *o += 32;
96 pk
97 };
98 let read_u64 = |data: &[u8], o: &mut usize| -> u64 {
99 let v = u64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
100 *o += 8;
101 v
102 };
103 let read_u8 = |data: &[u8], o: &mut usize| -> u8 {
104 let v = data[*o];
105 *o += 1;
106 v
107 };
108 let read_u16 = |data: &[u8], o: &mut usize| -> u16 {
109 let v = u16::from_le_bytes(data[*o..*o + 2].try_into().unwrap());
110 *o += 2;
111 v
112 };
113 let read_i64 = |data: &[u8], o: &mut usize| -> i64 {
114 let v = i64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
115 *o += 8;
116 v
117 };
118 let token_mint = read_pubkey(data, &mut offset);
119 let bonding_curve = read_pubkey(data, &mut offset);
120 let virtual_token_reserve = read_u64(data, &mut offset);
121 let virtual_sol_reserve = read_u64(data, &mut offset);
122 let real_token_reserve = read_u64(data, &mut offset);
123 let real_sol_reserve = read_u64(data, &mut offset);
124 let total_supply = read_u64(data, &mut offset);
125 let current_progress_raw = read_u64(data, &mut offset);
126 let curve_type = read_u8(data, &mut offset);
127 offset += 1; let fee_bps = read_u16(data, &mut offset);
129 let creator = read_pubkey(data, &mut offset);
130 let created_at = read_i64(data, &mut offset);
131 let last_updated = read_i64(data, &mut offset);
132 let status = read_u8(data, &mut offset);
133 let price_sol = if virtual_token_reserve > 0 {
135 virtual_sol_reserve as f64 / virtual_token_reserve as f64
136 } else {
137 0.0
138 };
139 let current_progress = current_progress_raw as f64 / 10000.0;
140 Ok(PumpInfo {
141 token_mint,
142 bonding_curve,
143 virtual_token_reserve,
144 virtual_sol_reserve,
145 real_token_reserve,
146 real_sol_reserve,
147 total_supply,
148 current_progress,
149 curve_type,
150 fee_bps,
151 creator,
152 created_at,
153 last_updated,
154 status,
155 price_sol,
156 progress_percent: current_progress * 100.0,
157 })
158 }
159
160 pub fn create_bond_curve(&self) -> BondCurve {
161 BondCurve::new(self.solana_client.clone())
162 }
163}
164
165#[cfg(test)]
166mod test {
167 use solana_network_client::SolanaClient;
168 use std::sync::Arc;
169
170 use crate::Pump;
171
172 #[tokio::test]
173 async fn test() -> Result<(), Box<dyn std::error::Error>> {
174 let solana_client = SolanaClient::new(solana_network_client::Mode::MAIN).unwrap();
175 let pump = Pump::new(Arc::new(solana_client));
176 let pump_info = pump.get_pump_info().await.unwrap();
177 println!("Pump Info: {:?}", pump_info);
178 Ok(())
179 }
180}