carbon_pumpfun_decoder/instructions/
mod.rs

1use crate::PROGRAM_ID;
2
3use super::PumpfunDecoder;
4pub mod buy;
5pub mod complete_event;
6pub mod create;
7pub mod create_event;
8pub mod initialize;
9pub mod sell;
10pub mod set_params;
11pub mod set_params_event;
12pub mod trade_event;
13pub mod withdraw;
14
15#[derive(
16    carbon_core::InstructionType,
17    serde::Serialize,
18    serde::Deserialize,
19    PartialEq,
20    Eq,
21    Debug,
22    Clone,
23    Hash,
24)]
25pub enum PumpfunInstruction {
26    Buy(buy::Buy),
27    Create(create::Create),
28    Initialize(initialize::Initialize),
29    Sell(sell::Sell),
30    SetParams(set_params::SetParams),
31    Withdraw(withdraw::Withdraw),
32    CompleteEvent(complete_event::CompleteEvent),
33    CreateEvent(create_event::CreateEvent),
34    SetParamsEvent(set_params_event::SetParamsEvent),
35    TradeEvent(trade_event::TradeEvent),
36}
37
38impl<'a> carbon_core::instruction::InstructionDecoder<'a> for PumpfunDecoder {
39    type InstructionType = PumpfunInstruction;
40
41    fn decode_instruction(
42        &self,
43        instruction: &solana_sdk::instruction::Instruction,
44    ) -> Option<carbon_core::instruction::DecodedInstruction<Self::InstructionType>> {
45        if !instruction.program_id.eq(&PROGRAM_ID) {
46            return None;
47        }
48
49        carbon_core::try_decode_instructions!(instruction,
50            PumpfunInstruction::Buy => buy::Buy,
51            PumpfunInstruction::Create => create::Create,
52            PumpfunInstruction::Initialize => initialize::Initialize,
53            PumpfunInstruction::Sell => sell::Sell,
54            PumpfunInstruction::SetParams => set_params::SetParams,
55            PumpfunInstruction::Withdraw => withdraw::Withdraw,
56            PumpfunInstruction::CompleteEvent => complete_event::CompleteEvent,
57            PumpfunInstruction::CreateEvent => create_event::CreateEvent,
58            PumpfunInstruction::SetParamsEvent => set_params_event::SetParamsEvent,
59            PumpfunInstruction::TradeEvent => trade_event::TradeEvent,
60        )
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use carbon_core::{deserialize::ArrangeAccounts, instruction::InstructionDecoder};
67    use solana_sdk::{instruction::AccountMeta, pubkey};
68
69    use super::*;
70
71    #[test]
72    fn test_decode_buy() {
73        // Arrange
74        let expected_ix = PumpfunInstruction::Buy(buy::Buy {
75            amount: 2712969161192,
76            max_sol_cost: 204000000,
77        });
78        let expected_accounts = vec![
79            AccountMeta::new_readonly(
80                pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
81                false,
82            ),
83            AccountMeta::new(
84                pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
85                false,
86            ),
87            AccountMeta::new_readonly(
88                pubkey!("9p1PMtto471A7GvnRJVmDcuqUz3xDd1Lhu8vzrmpump"),
89                false,
90            ),
91            AccountMeta::new(
92                pubkey!("HWxwYxr4AV5ytUyT8pvjCEiUrXhwpbx365VpvQ6Bd6MZ"),
93                false,
94            ),
95            AccountMeta::new(
96                pubkey!("AUfg9aTAix7YarkHXSBMUyQPCTq55Gg1Z2NTe6utwwzG"),
97                false,
98            ),
99            AccountMeta::new(
100                pubkey!("4FLYmjhLuUb5ofNBo1PA9enF7HrPUSYUA1t55tUSFYa5"),
101                false,
102            ),
103            AccountMeta::new(
104                pubkey!("5ztadiszGPmBeGVcvmtPyqiHRA8SpU8mqNzPV1WeV88F"),
105                true,
106            ),
107            AccountMeta::new_readonly(pubkey!("11111111111111111111111111111111"), false),
108            AccountMeta::new_readonly(
109                pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
110                false,
111            ),
112            AccountMeta::new_readonly(
113                pubkey!("SysvarRent111111111111111111111111111111111"),
114                false,
115            ),
116            AccountMeta::new_readonly(
117                pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
118                false,
119            ),
120            AccountMeta::new_readonly(
121                pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
122                false,
123            ),
124        ];
125        let expected_arranged_accounts = buy::BuyInstructionAccounts {
126            global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
127            fee_recipient: pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
128            mint: pubkey!("9p1PMtto471A7GvnRJVmDcuqUz3xDd1Lhu8vzrmpump"),
129            bonding_curve: pubkey!("HWxwYxr4AV5ytUyT8pvjCEiUrXhwpbx365VpvQ6Bd6MZ"),
130            associated_bonding_curve: pubkey!("AUfg9aTAix7YarkHXSBMUyQPCTq55Gg1Z2NTe6utwwzG"),
131            associated_user: pubkey!("4FLYmjhLuUb5ofNBo1PA9enF7HrPUSYUA1t55tUSFYa5"),
132            user: pubkey!("5ztadiszGPmBeGVcvmtPyqiHRA8SpU8mqNzPV1WeV88F"),
133            system_program: pubkey!("11111111111111111111111111111111"),
134            token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
135            rent: pubkey!("SysvarRent111111111111111111111111111111111"),
136            event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
137            program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
138        };
139
140        // Act
141        let decoder = PumpfunDecoder;
142        let instruction = carbon_test_utils::read_instruction("tests/fixtures/buy_ix.json")
143            .expect("read fixture");
144        let decoded = decoder
145            .decode_instruction(&instruction)
146            .expect("decode instruction");
147        let decoded_arranged_accounts =
148            buy::Buy::arrange_accounts(&instruction.accounts).expect("aranage accounts");
149
150        // Assert
151        assert_eq!(decoded.data, expected_ix);
152        assert_eq!(decoded.accounts, expected_accounts);
153        assert_eq!(decoded.program_id, PROGRAM_ID);
154        assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
155    }
156
157    #[test]
158    fn test_decode_sell() {
159        // Arrange
160        let expected_ix = PumpfunInstruction::Sell(sell::Sell {
161            amount: 26705394300,
162            min_sol_output: 724522,
163        });
164        let expected_accounts = vec![
165            AccountMeta::new_readonly(
166                pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
167                false,
168            ),
169            AccountMeta::new(
170                pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
171                false,
172            ),
173            AccountMeta::new_readonly(
174                pubkey!("HXfFC4G1aJJo17KW56jJ2iaDLFXq6T8XZjPbQfhspump"),
175                false,
176            ),
177            AccountMeta::new(
178                pubkey!("8f12Y6z6CkMmcBqduvThRG2V873CP3eu2iBydqKGDX6y"),
179                false,
180            ),
181            AccountMeta::new(
182                pubkey!("GkSscwZJBhcFeB6hpWrnfrE73e5SawPmMuT55U1W4uqz"),
183                false,
184            ),
185            AccountMeta::new(
186                pubkey!("Bi6H7WPrZoJmqSauP38NuBaEttGraZkceR4p17ekoTwh"),
187                false,
188            ),
189            AccountMeta::new(
190                pubkey!("3bApZNQrP3T6Q1GvK1n1nUPHHnpnsbrEmdGyQyYLEbkP"),
191                true,
192            ),
193            AccountMeta::new_readonly(pubkey!("11111111111111111111111111111111"), false),
194            AccountMeta::new_readonly(
195                pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
196                false,
197            ),
198            AccountMeta::new_readonly(
199                pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
200                false,
201            ),
202            AccountMeta::new_readonly(
203                pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
204                false,
205            ),
206            AccountMeta::new_readonly(
207                pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
208                false,
209            ),
210        ];
211        let expected_arranged_accounts = sell::SellInstructionAccounts {
212            global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
213            fee_recipient: pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
214            mint: pubkey!("HXfFC4G1aJJo17KW56jJ2iaDLFXq6T8XZjPbQfhspump"),
215            bonding_curve: pubkey!("8f12Y6z6CkMmcBqduvThRG2V873CP3eu2iBydqKGDX6y"),
216            associated_bonding_curve: pubkey!("GkSscwZJBhcFeB6hpWrnfrE73e5SawPmMuT55U1W4uqz"),
217            associated_user: pubkey!("Bi6H7WPrZoJmqSauP38NuBaEttGraZkceR4p17ekoTwh"),
218            user: pubkey!("3bApZNQrP3T6Q1GvK1n1nUPHHnpnsbrEmdGyQyYLEbkP"),
219            system_program: pubkey!("11111111111111111111111111111111"),
220            associated_token_program: pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
221            token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
222            event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
223            program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
224        };
225
226        // Act
227        let decoder = PumpfunDecoder;
228        let instruction = carbon_test_utils::read_instruction("tests/fixtures/sell_ix.json")
229            .expect("read fixture");
230        let decoded = decoder
231            .decode_instruction(&instruction)
232            .expect("decode instruction");
233        let decoded_arranged_accounts =
234            sell::Sell::arrange_accounts(&instruction.accounts).expect("aranage accounts");
235
236        // Assert
237        assert_eq!(decoded.data, expected_ix);
238        assert_eq!(decoded.accounts, expected_accounts);
239        assert_eq!(decoded.program_id, PROGRAM_ID);
240        assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
241    }
242
243    #[test]
244    fn test_decode_create() {
245        // Arrange
246        let expected_ix = PumpfunInstruction::Create(create::Create {
247            name: "Super Elon Bros ".to_owned(),
248            symbol: "SEB".to_owned(),
249            uri: "https://ipfs.io/ipfs/QmVnjMrWqhMBsmeFnaje87XVxMKY9y7BRL2DtFYJazTGM5".to_owned(),
250            creator: pubkey!("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
251        });
252        let expected_accounts = vec![
253            AccountMeta::new(
254                pubkey!("5PweXK19JD4PkafHm9BmpgiTaMoQgKq9EXVkDagwpump"),
255                true,
256            ),
257            AccountMeta::new_readonly(
258                pubkey!("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
259                false,
260            ),
261            AccountMeta::new(
262                pubkey!("Chau1rGA8w4L43rAMUAKXGwq8hpPfGjUoHsiZJEyziKz"),
263                false,
264            ),
265            AccountMeta::new(
266                pubkey!("7JxriSri8PukwVQ6VQZ6ErpJ3Km1x6eWMnQeJ2Cd2148"),
267                false,
268            ),
269            AccountMeta::new_readonly(
270                pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
271                false,
272            ),
273            AccountMeta::new_readonly(
274                pubkey!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
275                false,
276            ),
277            AccountMeta::new(
278                pubkey!("Dzp1H2K6sNR8VAqXE9Q6eSdZckp7uQSJKR1FKY9SzFoS"),
279                false,
280            ),
281            AccountMeta::new(
282                pubkey!("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
283                true,
284            ),
285            AccountMeta::new_readonly(pubkey!("11111111111111111111111111111111"), false),
286            AccountMeta::new_readonly(
287                pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
288                false,
289            ),
290            AccountMeta::new_readonly(
291                pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
292                false,
293            ),
294            AccountMeta::new_readonly(
295                pubkey!("SysvarRent111111111111111111111111111111111"),
296                false,
297            ),
298            AccountMeta::new_readonly(
299                pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
300                false,
301            ),
302            AccountMeta::new_readonly(
303                pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
304                false,
305            ),
306        ];
307        let expected_arranged_accounts = create::CreateInstructionAccounts {
308            mint: pubkey!("5PweXK19JD4PkafHm9BmpgiTaMoQgKq9EXVkDagwpump"),
309            mint_authority: pubkey!("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
310            bonding_curve: pubkey!("Chau1rGA8w4L43rAMUAKXGwq8hpPfGjUoHsiZJEyziKz"),
311            associated_bonding_curve: pubkey!("7JxriSri8PukwVQ6VQZ6ErpJ3Km1x6eWMnQeJ2Cd2148"),
312            global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
313            mpl_token_metadata: pubkey!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
314            metadata: pubkey!("Dzp1H2K6sNR8VAqXE9Q6eSdZckp7uQSJKR1FKY9SzFoS"),
315            user: pubkey!("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
316            system_program: pubkey!("11111111111111111111111111111111"),
317            token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
318            associated_token_program: pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
319            rent: pubkey!("SysvarRent111111111111111111111111111111111"),
320            event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
321            program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
322        };
323
324        // Act
325        let decoder = PumpfunDecoder;
326        let instruction = carbon_test_utils::read_instruction("tests/fixtures/create_ix.json")
327            .expect("read fixture");
328        let decoded = decoder
329            .decode_instruction(&instruction)
330            .expect("decode instruction");
331        let decoded_arranged_accounts =
332            create::Create::arrange_accounts(&instruction.accounts).expect("aranage accounts");
333
334        // Assert
335        assert_eq!(decoded.data, expected_ix);
336        assert_eq!(decoded.accounts, expected_accounts);
337        assert_eq!(decoded.program_id, PROGRAM_ID);
338        assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
339    }
340
341    #[test]
342    fn test_decode_withdraw() {
343        // Arrange
344        let expected_ix = PumpfunInstruction::Withdraw(withdraw::Withdraw {});
345        let expected_accounts = vec![
346            AccountMeta::new_readonly(
347                pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
348                false,
349            ),
350            AccountMeta::new(
351                pubkey!("EGqbBGXmDA9QYd1XJkf3GDFoerQYeFW3FrQZZXRza9JL"),
352                false,
353            ),
354            AccountMeta::new_readonly(
355                pubkey!("8f8inBUeF6GCPQvN2qxu95uZMTjidZfS2RbYBrFSpump"),
356                false,
357            ),
358            AccountMeta::new(
359                pubkey!("DfcyEVHECKF9U14EzYqxeovufnndbN8qrDurVdJbkUwY"),
360                false,
361            ),
362            AccountMeta::new(
363                pubkey!("EQtzJCRiCpbEmKqZndvCQgGAXCFuGtP2FAZ2HYpH8F6F"),
364                false,
365            ),
366            AccountMeta::new(
367                pubkey!("7ngNZs9Ax61KJ8MKmQKFao73LB4jRRgrg4SZU3YsAbfY"),
368                false,
369            ),
370            AccountMeta::new(
371                pubkey!("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg"),
372                true,
373            ),
374            AccountMeta::new_readonly(pubkey!("11111111111111111111111111111111"), false),
375            AccountMeta::new_readonly(
376                pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
377                false,
378            ),
379            AccountMeta::new_readonly(
380                pubkey!("SysvarRent111111111111111111111111111111111"),
381                false,
382            ),
383            AccountMeta::new_readonly(
384                pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
385                false,
386            ),
387            AccountMeta::new_readonly(
388                pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
389                false,
390            ),
391        ];
392        let expected_arranged_accounts = withdraw::WithdrawInstructionAccounts {
393            global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
394            last_withdraw: pubkey!("EGqbBGXmDA9QYd1XJkf3GDFoerQYeFW3FrQZZXRza9JL"),
395            mint: pubkey!("8f8inBUeF6GCPQvN2qxu95uZMTjidZfS2RbYBrFSpump"),
396            bonding_curve: pubkey!("DfcyEVHECKF9U14EzYqxeovufnndbN8qrDurVdJbkUwY"),
397            associated_bonding_curve: pubkey!("EQtzJCRiCpbEmKqZndvCQgGAXCFuGtP2FAZ2HYpH8F6F"),
398            associated_user: pubkey!("7ngNZs9Ax61KJ8MKmQKFao73LB4jRRgrg4SZU3YsAbfY"),
399            user: pubkey!("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg"),
400            system_program: pubkey!("11111111111111111111111111111111"),
401            token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
402            rent: pubkey!("SysvarRent111111111111111111111111111111111"),
403            event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
404            program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
405        };
406
407        // Act
408        let decoder = PumpfunDecoder;
409        let instruction = carbon_test_utils::read_instruction("tests/fixtures/withdraw_ix.json")
410            .expect("read fixture");
411        let decoded = decoder
412            .decode_instruction(&instruction)
413            .expect("decode instruction");
414        let decoded_arranged_accounts =
415            withdraw::Withdraw::arrange_accounts(&instruction.accounts).expect("aranage accounts");
416
417        // Assert
418        assert_eq!(decoded.data, expected_ix);
419        assert_eq!(decoded.accounts, expected_accounts);
420        assert_eq!(decoded.program_id, PROGRAM_ID);
421        assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
422    }
423}