pump_sdk/
lib.rs

1mod bond_curve;
2mod global;
3mod amm;
4
5use std::sync::Arc;
6
7use solana_network_sdk::{Solana, types::UnifiedError};
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],       // Token mint address
16    pub bonding_curve: [u8; 32],    // Bonding curve address
17    pub virtual_token_reserve: u64, // Virtual token reserve
18    pub virtual_sol_reserve: u64,   // Virtual SOL reserve
19    pub real_token_reserve: u64,    // Real token reserve
20    pub real_sol_reserve: u64,      // Real SOL reserve
21    pub total_supply: u64,          // Total supply
22    pub current_progress: u64,      // Current progress (0-10000, 10000=100%)
23    pub curve_type: u8,             // Curve type
24    _padding1: u8,
25    pub fee_bps: u16,      // Fee (basis points)
26    pub creator: [u8; 32], // Creator
27    pub created_at: i64,   // Creation time
28    pub last_updated: i64, // Last update time
29    pub status: u8,        // Status (0=active, 1=complete, 2=rugged)
30    // Explicitly add padding bytes to ensure alignment
31    _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: Arc<Solana>,
56}
57
58impl Pump {
59    /// Create Raydium
60    /// Example
61    /// ```rust
62    /// let sol = Solana::new(solana_network_sdk::types::Mode::MAIN);
63    /// let raydium = Raydium::new(Arc::new(sol));
64    /// ```
65    pub fn new(solana: Arc<Solana>) -> Self {
66        Self { solana: solana }
67    }
68
69    pub async fn get_pump_info(&self) -> Result<PumpInfo, String> {
70        let v = self
71            .solana
72            .get_account_data(PUMP_DOT_FUN_PROGRAM_ID)
73            .await
74            .map_err(|e| UnifiedError::Error(format!("{:?}", e)))
75            .unwrap();
76        let pump_info = Self::parse_pump_info(&v)
77            .map_err(|e| UnifiedError::Error(format!("{:?}", e)))
78            .unwrap();
79        Ok(pump_info)
80    }
81
82    /// Parse PUMP program data into PumpInfo struct
83    /// data: Account data retrieved from blockchain
84    fn parse_pump_info(data: &[u8]) -> Result<PumpInfo, String> {
85        const DISCRIMINATOR_LEN: usize = 8;
86        if data.len() < DISCRIMINATOR_LEN + 180 {
87            return Err(format!(
88                "Pump pool data too short. Expected at least {}, got {}",
89                DISCRIMINATOR_LEN + 180,
90                data.len()
91            ));
92        }
93        let mut offset = DISCRIMINATOR_LEN;
94        let read_pubkey = |data: &[u8], o: &mut usize| -> Pubkey {
95            let pk = Pubkey::new_from_array(data[*o..*o + 32].try_into().unwrap());
96            *o += 32;
97            pk
98        };
99        let read_u64 = |data: &[u8], o: &mut usize| -> u64 {
100            let v = u64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
101            *o += 8;
102            v
103        };
104        let read_u8 = |data: &[u8], o: &mut usize| -> u8 {
105            let v = data[*o];
106            *o += 1;
107            v
108        };
109        let read_u16 = |data: &[u8], o: &mut usize| -> u16 {
110            let v = u16::from_le_bytes(data[*o..*o + 2].try_into().unwrap());
111            *o += 2;
112            v
113        };
114        let read_i64 = |data: &[u8], o: &mut usize| -> i64 {
115            let v = i64::from_le_bytes(data[*o..*o + 8].try_into().unwrap());
116            *o += 8;
117            v
118        };
119        let token_mint = read_pubkey(data, &mut offset);
120        let bonding_curve = read_pubkey(data, &mut offset);
121        let virtual_token_reserve = read_u64(data, &mut offset);
122        let virtual_sol_reserve = read_u64(data, &mut offset);
123        let real_token_reserve = read_u64(data, &mut offset);
124        let real_sol_reserve = read_u64(data, &mut offset);
125        let total_supply = read_u64(data, &mut offset);
126        let current_progress_raw = read_u64(data, &mut offset);
127        let curve_type = read_u8(data, &mut offset);
128        offset += 1; // Skip padding byte
129        let fee_bps = read_u16(data, &mut offset);
130        let creator = read_pubkey(data, &mut offset);
131        let created_at = read_i64(data, &mut offset);
132        let last_updated = read_i64(data, &mut offset);
133        let status = read_u8(data, &mut offset);
134        // Calculate price and progress
135        let price_sol = if virtual_token_reserve > 0 {
136            virtual_sol_reserve as f64 / virtual_token_reserve as f64
137        } else {
138            0.0
139        };
140        let current_progress = current_progress_raw as f64 / 10000.0;
141        Ok(PumpInfo {
142            token_mint,
143            bonding_curve,
144            virtual_token_reserve,
145            virtual_sol_reserve,
146            real_token_reserve,
147            real_sol_reserve,
148            total_supply,
149            current_progress,
150            curve_type,
151            fee_bps,
152            creator,
153            created_at,
154            last_updated,
155            status,
156            price_sol,
157            progress_percent: current_progress * 100.0,
158        })
159    }
160
161    pub fn create_bond_curve(&self) -> BondCurve {
162        BondCurve::new(self.solana.clone())
163    }
164}
165
166#[cfg(test)]
167mod test {
168    use std::sync::Arc;
169
170    use solana_network_sdk::Solana;
171    use solana_network_sdk::types::Mode::MAIN;
172
173    use crate::Pump;
174
175    #[tokio::test]
176    async fn test() -> Result<(), Box<dyn std::error::Error>> {
177        let solana = Solana::new(MAIN).unwrap();
178        let pump = Pump::new(Arc::new(solana));
179        let pump_info = pump.get_pump_info().await.unwrap();
180        println!("Pump Info: {:?}", pump_info);
181        Ok(())
182    }
183}