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 carbon_core::instruction::InstructionDecoder<'_> for PumpfunDecoder {
39 type InstructionType = PumpfunInstruction;
40
41 fn decode_instruction(
42 &self,
43 instruction: &solana_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_instruction::AccountMeta;
68 use solana_pubkey::Pubkey;
69
70 use super::*;
71
72 #[test]
73 fn test_decode_buy() {
74 let expected_ix = PumpfunInstruction::Buy(buy::Buy {
76 amount: 2712969161192,
77 max_sol_cost: 204000000,
78 });
79 let expected_accounts = vec![
80 AccountMeta::new_readonly(
81 Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
82 false,
83 ),
84 AccountMeta::new(
85 Pubkey::from_str_const("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
86 false,
87 ),
88 AccountMeta::new_readonly(
89 Pubkey::from_str_const("9p1PMtto471A7GvnRJVmDcuqUz3xDd1Lhu8vzrmpump"),
90 false,
91 ),
92 AccountMeta::new(
93 Pubkey::from_str_const("HWxwYxr4AV5ytUyT8pvjCEiUrXhwpbx365VpvQ6Bd6MZ"),
94 false,
95 ),
96 AccountMeta::new(
97 Pubkey::from_str_const("AUfg9aTAix7YarkHXSBMUyQPCTq55Gg1Z2NTe6utwwzG"),
98 false,
99 ),
100 AccountMeta::new(
101 Pubkey::from_str_const("4FLYmjhLuUb5ofNBo1PA9enF7HrPUSYUA1t55tUSFYa5"),
102 false,
103 ),
104 AccountMeta::new(
105 Pubkey::from_str_const("5ztadiszGPmBeGVcvmtPyqiHRA8SpU8mqNzPV1WeV88F"),
106 true,
107 ),
108 AccountMeta::new_readonly(
109 Pubkey::from_str_const("11111111111111111111111111111111"),
110 false,
111 ),
112 AccountMeta::new_readonly(
113 Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
114 false,
115 ),
116 AccountMeta::new_readonly(
117 Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
118 false,
119 ),
120 AccountMeta::new_readonly(
121 Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
122 false,
123 ),
124 AccountMeta::new_readonly(
125 Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
126 false,
127 ),
128 ];
129 let expected_arranged_accounts = buy::BuyInstructionAccounts {
130 global: Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
131 fee_recipient: Pubkey::from_str_const("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
132 mint: Pubkey::from_str_const("9p1PMtto471A7GvnRJVmDcuqUz3xDd1Lhu8vzrmpump"),
133 bonding_curve: Pubkey::from_str_const("HWxwYxr4AV5ytUyT8pvjCEiUrXhwpbx365VpvQ6Bd6MZ"),
134 associated_bonding_curve: Pubkey::from_str_const(
135 "AUfg9aTAix7YarkHXSBMUyQPCTq55Gg1Z2NTe6utwwzG",
136 ),
137 associated_user: Pubkey::from_str_const("4FLYmjhLuUb5ofNBo1PA9enF7HrPUSYUA1t55tUSFYa5"),
138 user: Pubkey::from_str_const("5ztadiszGPmBeGVcvmtPyqiHRA8SpU8mqNzPV1WeV88F"),
139 system_program: Pubkey::from_str_const("11111111111111111111111111111111"),
140 token_program: Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
141 rent: Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
142 event_authority: Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
143 program: Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
144 };
145
146 let decoder = PumpfunDecoder;
148 let instruction = carbon_test_utils::read_instruction("tests/fixtures/buy_ix.json")
149 .expect("read fixture");
150 let decoded = decoder
151 .decode_instruction(&instruction)
152 .expect("decode instruction");
153 let decoded_arranged_accounts =
154 buy::Buy::arrange_accounts(&instruction.accounts).expect("aranage accounts");
155
156 assert_eq!(decoded.data, expected_ix);
158 assert_eq!(decoded.accounts, expected_accounts);
159 assert_eq!(decoded.program_id, PROGRAM_ID);
160 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
161 }
162
163 #[test]
164 fn test_decode_sell() {
165 let expected_ix = PumpfunInstruction::Sell(sell::Sell {
167 amount: 26705394300,
168 min_sol_output: 724522,
169 });
170 let expected_accounts = vec![
171 AccountMeta::new_readonly(
172 Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
173 false,
174 ),
175 AccountMeta::new(
176 Pubkey::from_str_const("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
177 false,
178 ),
179 AccountMeta::new_readonly(
180 Pubkey::from_str_const("HXfFC4G1aJJo17KW56jJ2iaDLFXq6T8XZjPbQfhspump"),
181 false,
182 ),
183 AccountMeta::new(
184 Pubkey::from_str_const("8f12Y6z6CkMmcBqduvThRG2V873CP3eu2iBydqKGDX6y"),
185 false,
186 ),
187 AccountMeta::new(
188 Pubkey::from_str_const("GkSscwZJBhcFeB6hpWrnfrE73e5SawPmMuT55U1W4uqz"),
189 false,
190 ),
191 AccountMeta::new(
192 Pubkey::from_str_const("Bi6H7WPrZoJmqSauP38NuBaEttGraZkceR4p17ekoTwh"),
193 false,
194 ),
195 AccountMeta::new(
196 Pubkey::from_str_const("3bApZNQrP3T6Q1GvK1n1nUPHHnpnsbrEmdGyQyYLEbkP"),
197 true,
198 ),
199 AccountMeta::new_readonly(
200 Pubkey::from_str_const("11111111111111111111111111111111"),
201 false,
202 ),
203 AccountMeta::new_readonly(
204 Pubkey::from_str_const("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
205 false,
206 ),
207 AccountMeta::new_readonly(
208 Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
209 false,
210 ),
211 AccountMeta::new_readonly(
212 Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
213 false,
214 ),
215 AccountMeta::new_readonly(
216 Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
217 false,
218 ),
219 ];
220 let expected_arranged_accounts = sell::SellInstructionAccounts {
221 global: Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
222 fee_recipient: Pubkey::from_str_const("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
223 mint: Pubkey::from_str_const("HXfFC4G1aJJo17KW56jJ2iaDLFXq6T8XZjPbQfhspump"),
224 bonding_curve: Pubkey::from_str_const("8f12Y6z6CkMmcBqduvThRG2V873CP3eu2iBydqKGDX6y"),
225 associated_bonding_curve: Pubkey::from_str_const(
226 "GkSscwZJBhcFeB6hpWrnfrE73e5SawPmMuT55U1W4uqz",
227 ),
228 associated_user: Pubkey::from_str_const("Bi6H7WPrZoJmqSauP38NuBaEttGraZkceR4p17ekoTwh"),
229 user: Pubkey::from_str_const("3bApZNQrP3T6Q1GvK1n1nUPHHnpnsbrEmdGyQyYLEbkP"),
230 system_program: Pubkey::from_str_const("11111111111111111111111111111111"),
231 associated_token_program: Pubkey::from_str_const(
232 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
233 ),
234 token_program: Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
235 event_authority: Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
236 program: Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
237 };
238
239 let decoder = PumpfunDecoder;
241 let instruction = carbon_test_utils::read_instruction("tests/fixtures/sell_ix.json")
242 .expect("read fixture");
243 let decoded = decoder
244 .decode_instruction(&instruction)
245 .expect("decode instruction");
246 let decoded_arranged_accounts =
247 sell::Sell::arrange_accounts(&instruction.accounts).expect("aranage accounts");
248
249 assert_eq!(decoded.data, expected_ix);
251 assert_eq!(decoded.accounts, expected_accounts);
252 assert_eq!(decoded.program_id, PROGRAM_ID);
253 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
254 }
255
256 #[test]
257 fn test_decode_create() {
258 let expected_ix = PumpfunInstruction::Create(create::Create {
260 name: "Super Elon Bros ".to_owned(),
261 symbol: "SEB".to_owned(),
262 uri: "https://ipfs.io/ipfs/QmVnjMrWqhMBsmeFnaje87XVxMKY9y7BRL2DtFYJazTGM5".to_owned(),
263 creator: Pubkey::from_str_const("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
264 });
265 let expected_accounts = vec![
266 AccountMeta::new(
267 Pubkey::from_str_const("5PweXK19JD4PkafHm9BmpgiTaMoQgKq9EXVkDagwpump"),
268 true,
269 ),
270 AccountMeta::new_readonly(
271 Pubkey::from_str_const("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
272 false,
273 ),
274 AccountMeta::new(
275 Pubkey::from_str_const("Chau1rGA8w4L43rAMUAKXGwq8hpPfGjUoHsiZJEyziKz"),
276 false,
277 ),
278 AccountMeta::new(
279 Pubkey::from_str_const("7JxriSri8PukwVQ6VQZ6ErpJ3Km1x6eWMnQeJ2Cd2148"),
280 false,
281 ),
282 AccountMeta::new_readonly(
283 Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
284 false,
285 ),
286 AccountMeta::new_readonly(
287 Pubkey::from_str_const("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
288 false,
289 ),
290 AccountMeta::new(
291 Pubkey::from_str_const("Dzp1H2K6sNR8VAqXE9Q6eSdZckp7uQSJKR1FKY9SzFoS"),
292 false,
293 ),
294 AccountMeta::new(
295 Pubkey::from_str_const("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
296 true,
297 ),
298 AccountMeta::new_readonly(
299 Pubkey::from_str_const("11111111111111111111111111111111"),
300 false,
301 ),
302 AccountMeta::new_readonly(
303 Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
304 false,
305 ),
306 AccountMeta::new_readonly(
307 Pubkey::from_str_const("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
308 false,
309 ),
310 AccountMeta::new_readonly(
311 Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
312 false,
313 ),
314 AccountMeta::new_readonly(
315 Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
316 false,
317 ),
318 AccountMeta::new_readonly(
319 Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
320 false,
321 ),
322 ];
323 let expected_arranged_accounts = create::CreateInstructionAccounts {
324 mint: Pubkey::from_str_const("5PweXK19JD4PkafHm9BmpgiTaMoQgKq9EXVkDagwpump"),
325 mint_authority: Pubkey::from_str_const("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
326 bonding_curve: Pubkey::from_str_const("Chau1rGA8w4L43rAMUAKXGwq8hpPfGjUoHsiZJEyziKz"),
327 associated_bonding_curve: Pubkey::from_str_const(
328 "7JxriSri8PukwVQ6VQZ6ErpJ3Km1x6eWMnQeJ2Cd2148",
329 ),
330 global: Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
331 mpl_token_metadata: Pubkey::from_str_const(
332 "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
333 ),
334 metadata: Pubkey::from_str_const("Dzp1H2K6sNR8VAqXE9Q6eSdZckp7uQSJKR1FKY9SzFoS"),
335 user: Pubkey::from_str_const("7a9xQF38YVW58TPeHavvXiVpqynCxY2GcohsZxdUZCX1"),
336 system_program: Pubkey::from_str_const("11111111111111111111111111111111"),
337 token_program: Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
338 associated_token_program: Pubkey::from_str_const(
339 "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
340 ),
341 rent: Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
342 event_authority: Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
343 program: Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
344 };
345
346 let decoder = PumpfunDecoder;
348 let instruction = carbon_test_utils::read_instruction("tests/fixtures/create_ix.json")
349 .expect("read fixture");
350 let decoded = decoder
351 .decode_instruction(&instruction)
352 .expect("decode instruction");
353 let decoded_arranged_accounts =
354 create::Create::arrange_accounts(&instruction.accounts).expect("aranage accounts");
355
356 assert_eq!(decoded.data, expected_ix);
358 assert_eq!(decoded.accounts, expected_accounts);
359 assert_eq!(decoded.program_id, PROGRAM_ID);
360 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
361 }
362
363 #[test]
364 fn test_decode_withdraw() {
365 let expected_ix = PumpfunInstruction::Withdraw(withdraw::Withdraw {});
367 let expected_accounts = vec![
368 AccountMeta::new_readonly(
369 Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
370 false,
371 ),
372 AccountMeta::new(
373 Pubkey::from_str_const("EGqbBGXmDA9QYd1XJkf3GDFoerQYeFW3FrQZZXRza9JL"),
374 false,
375 ),
376 AccountMeta::new_readonly(
377 Pubkey::from_str_const("8f8inBUeF6GCPQvN2qxu95uZMTjidZfS2RbYBrFSpump"),
378 false,
379 ),
380 AccountMeta::new(
381 Pubkey::from_str_const("DfcyEVHECKF9U14EzYqxeovufnndbN8qrDurVdJbkUwY"),
382 false,
383 ),
384 AccountMeta::new(
385 Pubkey::from_str_const("EQtzJCRiCpbEmKqZndvCQgGAXCFuGtP2FAZ2HYpH8F6F"),
386 false,
387 ),
388 AccountMeta::new(
389 Pubkey::from_str_const("7ngNZs9Ax61KJ8MKmQKFao73LB4jRRgrg4SZU3YsAbfY"),
390 false,
391 ),
392 AccountMeta::new(
393 Pubkey::from_str_const("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg"),
394 true,
395 ),
396 AccountMeta::new_readonly(
397 Pubkey::from_str_const("11111111111111111111111111111111"),
398 false,
399 ),
400 AccountMeta::new_readonly(
401 Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
402 false,
403 ),
404 AccountMeta::new_readonly(
405 Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
406 false,
407 ),
408 AccountMeta::new_readonly(
409 Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
410 false,
411 ),
412 AccountMeta::new_readonly(
413 Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
414 false,
415 ),
416 ];
417 let expected_arranged_accounts = withdraw::WithdrawInstructionAccounts {
418 global: Pubkey::from_str_const("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
419 last_withdraw: Pubkey::from_str_const("EGqbBGXmDA9QYd1XJkf3GDFoerQYeFW3FrQZZXRza9JL"),
420 mint: Pubkey::from_str_const("8f8inBUeF6GCPQvN2qxu95uZMTjidZfS2RbYBrFSpump"),
421 bonding_curve: Pubkey::from_str_const("DfcyEVHECKF9U14EzYqxeovufnndbN8qrDurVdJbkUwY"),
422 associated_bonding_curve: Pubkey::from_str_const(
423 "EQtzJCRiCpbEmKqZndvCQgGAXCFuGtP2FAZ2HYpH8F6F",
424 ),
425 associated_user: Pubkey::from_str_const("7ngNZs9Ax61KJ8MKmQKFao73LB4jRRgrg4SZU3YsAbfY"),
426 user: Pubkey::from_str_const("39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg"),
427 system_program: Pubkey::from_str_const("11111111111111111111111111111111"),
428 token_program: Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
429 rent: Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"),
430 event_authority: Pubkey::from_str_const("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
431 program: Pubkey::from_str_const("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
432 };
433
434 let decoder = PumpfunDecoder;
436 let instruction = carbon_test_utils::read_instruction("tests/fixtures/withdraw_ix.json")
437 .expect("read fixture");
438 let decoded = decoder
439 .decode_instruction(&instruction)
440 .expect("decode instruction");
441 let decoded_arranged_accounts =
442 withdraw::Withdraw::arrange_accounts(&instruction.accounts).expect("aranage accounts");
443
444 assert_eq!(decoded.data, expected_ix);
446 assert_eq!(decoded.accounts, expected_accounts);
447 assert_eq!(decoded.program_id, PROGRAM_ID);
448 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
449 }
450}