pump_sdk/
lib.rs

1mod bond_curve;
2mod global;
3
4use std::sync::Arc;
5
6use solana_network_sdk::{Solana, types::UnifiedError};
7use solana_sdk::pubkey::Pubkey;
8
9use crate::{bond_curve::BondCurve, global::PUMP_DOT_FUN_PROGRAM_ID};
10
11#[repr(C)]
12#[derive(Debug, Copy, Clone)]
13pub struct PumpPoolState {
14    pub token_mint: [u8; 32],       // Token mint address
15    pub bonding_curve: [u8; 32],    // Bonding curve address
16    pub virtual_token_reserve: u64, // Virtual token reserve
17    pub virtual_sol_reserve: u64,   // Virtual SOL reserve
18    pub real_token_reserve: u64,    // Real token reserve
19    pub real_sol_reserve: u64,      // Real SOL reserve
20    pub total_supply: u64,          // Total supply
21    pub current_progress: u64,      // Current progress (0-10000, 10000=100%)
22    pub curve_type: u8,             // Curve type
23    _padding1: u8,
24    pub fee_bps: u16,      // Fee (basis points)
25    pub creator: [u8; 32], // Creator
26    pub created_at: i64,   // Creation time
27    pub last_updated: i64, // Last update time
28    pub status: u8,        // Status (0=active, 1=complete, 2=rugged)
29    // Explicitly add padding bytes to ensure alignment
30    _padding2: [u8; 7],
31}
32
33#[derive(Debug, Clone)]
34pub struct PumpInfo {
35    pub token_mint: Pubkey,
36    pub bonding_curve: Pubkey,
37    pub virtual_token_reserve: u64,
38    pub virtual_sol_reserve: u64,
39    pub real_token_reserve: u64,
40    pub real_sol_reserve: u64,
41    pub total_supply: u64,
42    pub current_progress: f64,
43    pub curve_type: u8,
44    pub fee_bps: u16,
45    pub creator: Pubkey,
46    pub created_at: i64,
47    pub last_updated: i64,
48    pub status: u8,
49    pub price_sol: f64,
50    pub progress_percent: f64,
51}
52
53pub struct Pump {
54    pub solana: Arc<Solana>,
55}
56
57impl Pump {
58    /// Create Raydium
59    /// Example
60    /// ```rust
61    /// let sol = Solana::new(solana_network_sdk::types::Mode::MAIN);
62    /// let raydium = Raydium::new(Arc::new(sol));
63    /// ```
64    pub fn new(solana: Arc<Solana>) -> Self {
65        Self { solana: solana }
66    }
67
68    pub async fn get_pump_info(&self) -> Result<PumpInfo, String> {
69        let v = self
70            .solana
71            .get_account_data(PUMP_DOT_FUN_PROGRAM_ID)
72            .await
73            .map_err(|e| UnifiedError::Error(format!("{:?}", e)))
74            .unwrap();
75        let pump_info = Self::parse_pump_info(&v)
76            .map_err(|e| UnifiedError::Error(format!("{:?}", e)))
77            .unwrap();
78        Ok(pump_info)
79    }
80
81    /// Parse PUMP program data into PumpInfo struct
82    /// data: Account data retrieved from blockchain
83    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; // Skip padding byte
128        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        // Calculate price and progress
134        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.clone())
162    }
163}
164
165#[cfg(test)]
166mod test {
167    use std::sync::Arc;
168
169    use solana_network_sdk::Solana;
170    use solana_network_sdk::types::Mode::MAIN;
171
172    use crate::Pump;
173
174    #[tokio::test]
175    async fn test() -> Result<(), Box<dyn std::error::Error>> {
176        let solana = Solana::new(MAIN).unwrap();
177        let pump = Pump::new(Arc::new(solana));
178        let pump_info = pump.get_pump_info().await.unwrap();
179        println!("Pump Info: {:?}", pump_info);
180        Ok(())
181    }
182}