1use crate::PROGRAM_ID;
2
3use super::PumpfunDecoder;
4
5pub mod admin_set_creator;
6pub mod admin_set_creator_event;
7pub mod admin_update_token_incentives;
8pub mod admin_update_token_incentives_event;
9pub mod buy;
10pub mod claim_token_incentives;
11pub mod claim_token_incentives_event;
12pub mod collect_creator_fee;
13pub mod collect_creator_fee_event;
14pub mod complete_event;
15pub mod complete_pump_amm_migration_event;
16pub mod create;
17pub mod create_event;
18pub mod extend_account;
19pub mod extend_account_event;
20pub mod initialize;
21pub mod migrate;
22pub mod sell;
23pub mod set_creator;
24pub mod set_creator_event;
25pub mod set_metaplex_creator;
26pub mod set_metaplex_creator_event;
27pub mod set_params;
28pub mod set_params_event;
29pub mod sync_user_volume_accumulator;
30pub mod sync_user_volume_accumulator_event;
31pub mod trade_event;
32pub mod update_global_authority;
33pub mod update_global_authority_event;
34
35#[derive(
36 carbon_core::InstructionType,
37 serde::Serialize,
38 serde::Deserialize,
39 PartialEq,
40 Eq,
41 Debug,
42 Clone,
43 Hash,
44)]
45pub enum PumpfunInstruction {
46 AdminSetCreator(admin_set_creator::AdminSetCreator),
47 AdminUpdateTokenIncentives(admin_update_token_incentives::AdminUpdateTokenIncentives),
48 Buy(buy::Buy),
49 ClaimTokenIncentives(claim_token_incentives::ClaimTokenIncentives),
50 CollectCreatorFee(collect_creator_fee::CollectCreatorFee),
51 Create(create::Create),
52 ExtendAccount(extend_account::ExtendAccount),
53 Initialize(initialize::Initialize),
54 Migrate(migrate::Migrate),
55 Sell(sell::Sell),
56 SetCreator(set_creator::SetCreator),
57 SetMetaplexCreator(set_metaplex_creator::SetMetaplexCreator),
58 SetParams(set_params::SetParams),
59 SyncUserVolumeAccumulator(sync_user_volume_accumulator::SyncUserVolumeAccumulator),
60 UpdateGlobalAuthority(update_global_authority::UpdateGlobalAuthority),
61 AdminSetCreatorEvent(admin_set_creator_event::AdminSetCreatorEvent),
62 AdminUpdateTokenIncentivesEvent(
63 admin_update_token_incentives_event::AdminUpdateTokenIncentivesEvent,
64 ),
65 ClaimTokenIncentivesEvent(claim_token_incentives_event::ClaimTokenIncentivesEvent),
66 CollectCreatorFeeEvent(collect_creator_fee_event::CollectCreatorFeeEvent),
67 CompleteEvent(complete_event::CompleteEvent),
68 CompletePumpAmmMigrationEvent(complete_pump_amm_migration_event::CompletePumpAmmMigrationEvent),
69 CreateEvent(create_event::CreateEvent),
70 ExtendAccountEvent(extend_account_event::ExtendAccountEvent),
71 SetCreatorEvent(set_creator_event::SetCreatorEvent),
72 SetMetaplexCreatorEvent(set_metaplex_creator_event::SetMetaplexCreatorEvent),
73 SetParamsEvent(set_params_event::SetParamsEvent),
74 SyncUserVolumeAccumulatorEvent(
75 sync_user_volume_accumulator_event::SyncUserVolumeAccumulatorEvent,
76 ),
77 TradeEvent(trade_event::TradeEvent),
78 UpdateGlobalAuthorityEvent(update_global_authority_event::UpdateGlobalAuthorityEvent),
79}
80
81impl carbon_core::instruction::InstructionDecoder<'_> for PumpfunDecoder {
82 type InstructionType = PumpfunInstruction;
83
84 fn decode_instruction(
85 &self,
86 instruction: &solana_instruction::Instruction,
87 ) -> Option<carbon_core::instruction::DecodedInstruction<Self::InstructionType>> {
88 if !instruction.program_id.eq(&PROGRAM_ID) {
89 return None;
90 }
91 carbon_core::try_decode_instructions!(instruction,
92 PumpfunInstruction::AdminSetCreator => admin_set_creator::AdminSetCreator,
93 PumpfunInstruction::AdminUpdateTokenIncentives => admin_update_token_incentives::AdminUpdateTokenIncentives,
94 PumpfunInstruction::Buy => buy::Buy,
95 PumpfunInstruction::ClaimTokenIncentives => claim_token_incentives::ClaimTokenIncentives,
96 PumpfunInstruction::CollectCreatorFee => collect_creator_fee::CollectCreatorFee,
97 PumpfunInstruction::Create => create::Create,
98 PumpfunInstruction::ExtendAccount => extend_account::ExtendAccount,
99 PumpfunInstruction::Initialize => initialize::Initialize,
100 PumpfunInstruction::Migrate => migrate::Migrate,
101 PumpfunInstruction::Sell => sell::Sell,
102 PumpfunInstruction::SetCreator => set_creator::SetCreator,
103 PumpfunInstruction::SetMetaplexCreator => set_metaplex_creator::SetMetaplexCreator,
104 PumpfunInstruction::SetParams => set_params::SetParams,
105 PumpfunInstruction::SyncUserVolumeAccumulator => sync_user_volume_accumulator::SyncUserVolumeAccumulator,
106 PumpfunInstruction::UpdateGlobalAuthority => update_global_authority::UpdateGlobalAuthority,
107 PumpfunInstruction::AdminSetCreatorEvent => admin_set_creator_event::AdminSetCreatorEvent,
108 PumpfunInstruction::AdminUpdateTokenIncentivesEvent => admin_update_token_incentives_event::AdminUpdateTokenIncentivesEvent,
109 PumpfunInstruction::ClaimTokenIncentivesEvent => claim_token_incentives_event::ClaimTokenIncentivesEvent,
110 PumpfunInstruction::CollectCreatorFeeEvent => collect_creator_fee_event::CollectCreatorFeeEvent,
111 PumpfunInstruction::CompleteEvent => complete_event::CompleteEvent,
112 PumpfunInstruction::CompletePumpAmmMigrationEvent => complete_pump_amm_migration_event::CompletePumpAmmMigrationEvent,
113 PumpfunInstruction::CreateEvent => create_event::CreateEvent,
114 PumpfunInstruction::ExtendAccountEvent => extend_account_event::ExtendAccountEvent,
115 PumpfunInstruction::SetCreatorEvent => set_creator_event::SetCreatorEvent,
116 PumpfunInstruction::SetMetaplexCreatorEvent => set_metaplex_creator_event::SetMetaplexCreatorEvent,
117 PumpfunInstruction::SetParamsEvent => set_params_event::SetParamsEvent,
118 PumpfunInstruction::SyncUserVolumeAccumulatorEvent => sync_user_volume_accumulator_event::SyncUserVolumeAccumulatorEvent,
119 PumpfunInstruction::TradeEvent => trade_event::TradeEvent,
120 PumpfunInstruction::UpdateGlobalAuthorityEvent => update_global_authority_event::UpdateGlobalAuthorityEvent,
121 )
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use alloc::{borrow::ToOwned, vec};
128 use carbon_core::{deserialize::ArrangeAccounts, instruction::InstructionDecoder};
129 use solana_instruction::AccountMeta;
130 use solana_pubkey::pubkey;
131
132 use super::*;
133
134 #[test]
135 fn test_decode_buy() {
136 let expected_ix = PumpfunInstruction::Buy(buy::Buy {
138 amount: 1761808330141,
139 max_sol_cost: 55000000,
140 });
141 let expected_accounts = vec![
142 AccountMeta {
143 pubkey: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
144 is_signer: false,
145 is_writable: false,
146 },
147 AccountMeta {
148 pubkey: pubkey!("68yFSZxzLWJXkxxRGydZ63C6mHx1NLEDWmwN9Lb5yySg"),
149 is_signer: false,
150 is_writable: true,
151 },
152 AccountMeta {
153 pubkey: pubkey!("ANY6GmWTnMdcve9ouPYRfTUaJEzi5pFHxaXDRReMveMo"),
154 is_signer: false,
155 is_writable: false,
156 },
157 AccountMeta {
158 pubkey: pubkey!("7BXEBYDN1RDb9gyp3ZXuYfk63rRrYsbwUjbVCTrM7kMq"),
159 is_signer: false,
160 is_writable: true,
161 },
162 AccountMeta {
163 pubkey: pubkey!("6s8yqaYzxYgkaguisExzrTsZVUe5zGqk5yVeFh2XZvpo"),
164 is_signer: false,
165 is_writable: true,
166 },
167 AccountMeta {
168 pubkey: pubkey!("8EDQQdDDJ7RuKgAAfubcWiUUakpSzRE9TBorhtqxM1Y2"),
169 is_signer: false,
170 is_writable: true,
171 },
172 AccountMeta {
173 pubkey: pubkey!("B52TW9jWxJfe84ovSe8eHtw7s8zu4ZAJ2LSkWE3cP2pd"),
174 is_signer: true,
175 is_writable: true,
176 },
177 AccountMeta {
178 pubkey: pubkey!("11111111111111111111111111111111"),
179 is_signer: false,
180 is_writable: false,
181 },
182 AccountMeta {
183 pubkey: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
184 is_signer: false,
185 is_writable: false,
186 },
187 AccountMeta {
188 pubkey: pubkey!("Av288QVHYUTtKQCyxFHMWPoF4gTLCowJpw6mQm2jjjPZ"),
189 is_signer: false,
190 is_writable: true,
191 },
192 AccountMeta {
193 pubkey: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
194 is_signer: false,
195 is_writable: false,
196 },
197 AccountMeta {
198 pubkey: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
199 is_signer: false,
200 is_writable: false,
201 },
202 AccountMeta {
203 pubkey: pubkey!("Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y"),
204 is_signer: false,
205 is_writable: false,
206 },
207 AccountMeta {
208 pubkey: pubkey!("A5YYvy72JYi6PhwHRNm6VPH1mt17a7MjUp2CdZf6xsKQ"),
209 is_signer: false,
210 is_writable: false,
211 },
212 ];
213 let expected_arranged_accounts = buy::BuyInstructionAccounts {
214 global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
215 fee_recipient: pubkey!("68yFSZxzLWJXkxxRGydZ63C6mHx1NLEDWmwN9Lb5yySg"),
216 mint: pubkey!("ANY6GmWTnMdcve9ouPYRfTUaJEzi5pFHxaXDRReMveMo"),
217 bonding_curve: pubkey!("7BXEBYDN1RDb9gyp3ZXuYfk63rRrYsbwUjbVCTrM7kMq"),
218 associated_bonding_curve: pubkey!("6s8yqaYzxYgkaguisExzrTsZVUe5zGqk5yVeFh2XZvpo"),
219 associated_user: pubkey!("8EDQQdDDJ7RuKgAAfubcWiUUakpSzRE9TBorhtqxM1Y2"),
220 user: pubkey!("B52TW9jWxJfe84ovSe8eHtw7s8zu4ZAJ2LSkWE3cP2pd"),
221 system_program: pubkey!("11111111111111111111111111111111"),
222 token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
223 creator_vault: pubkey!("Av288QVHYUTtKQCyxFHMWPoF4gTLCowJpw6mQm2jjjPZ"),
224 event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
225 program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
226 global_volume_accumulator: pubkey!("Hq2wp8uJ9jCPsYgNHex8RtqdvMPfVGoYwjvF1ATiwn2Y"),
227 user_volume_accumulator: pubkey!("A5YYvy72JYi6PhwHRNm6VPH1mt17a7MjUp2CdZf6xsKQ"),
228 };
229
230 let decoder = PumpfunDecoder;
232 let instruction = carbon_test_utils::read_instruction("tests/fixtures/buy_ix.json")
234 .expect("read fixture");
235 let decoded = decoder
236 .decode_instruction(&instruction)
237 .expect("decode instruction");
238 let decoded_arranged_accounts =
239 buy::Buy::arrange_accounts(&instruction.accounts).expect("aranage accounts");
240
241 assert_eq!(decoded.data, expected_ix);
243 assert_eq!(decoded.accounts, expected_accounts);
244 assert_eq!(decoded.program_id, PROGRAM_ID);
245 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
246 }
247
248 #[test]
249 fn test_decode_sell() {
250 let expected_ix = PumpfunInstruction::Sell(sell::Sell {
252 amount: 88888000000,
253 min_sol_output: 2361153,
254 });
255 let expected_accounts = vec![
256 AccountMeta {
257 pubkey: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
258 is_signer: false,
259 is_writable: false,
260 },
261 AccountMeta {
262 pubkey: pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
263 is_signer: false,
264 is_writable: true,
265 },
266 AccountMeta {
267 pubkey: pubkey!("AC69oJv1m7843mdRfoQDneZuyRxYrMq86i2mARMtpump"),
268 is_signer: false,
269 is_writable: false,
270 },
271 AccountMeta {
272 pubkey: pubkey!("623TpUDcZjKdmd9wybMveLKSSbgRs2hvwFjygzi4g15B"),
273 is_signer: false,
274 is_writable: true,
275 },
276 AccountMeta {
277 pubkey: pubkey!("5rQKu3z4SXShvQkNKSJu9mtsVmgM8AvLoeNbJGvTyQv6"),
278 is_signer: false,
279 is_writable: true,
280 },
281 AccountMeta {
282 pubkey: pubkey!("BFgJqMUhraJvzERrt2BbPqbqDcLgbiHMdfdPQAqLtPcR"),
283 is_signer: false,
284 is_writable: true,
285 },
286 AccountMeta {
287 pubkey: pubkey!("D8h8aUEaQnBRALrcTxLkaLLCQVCASnLVx17E3m6qfuPF"),
288 is_signer: true,
289 is_writable: true,
290 },
291 AccountMeta {
292 pubkey: pubkey!("11111111111111111111111111111111"),
293 is_signer: false,
294 is_writable: false,
295 },
296 AccountMeta {
297 pubkey: pubkey!("8rsczKQ9bVT6AcGoD4CqoKySbVErCoXwQH8h7ZjAsUqE"),
298 is_signer: false,
299 is_writable: true,
300 },
301 AccountMeta {
302 pubkey: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
303 is_signer: false,
304 is_writable: false,
305 },
306 AccountMeta {
307 pubkey: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
308 is_signer: false,
309 is_writable: false,
310 },
311 AccountMeta {
312 pubkey: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
313 is_signer: false,
314 is_writable: false,
315 },
316 ];
317
318 let expected_arranged_accounts = sell::SellInstructionAccounts {
319 global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
320 fee_recipient: pubkey!("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
321 mint: pubkey!("AC69oJv1m7843mdRfoQDneZuyRxYrMq86i2mARMtpump"),
322 bonding_curve: pubkey!("623TpUDcZjKdmd9wybMveLKSSbgRs2hvwFjygzi4g15B"),
323 associated_bonding_curve: pubkey!("5rQKu3z4SXShvQkNKSJu9mtsVmgM8AvLoeNbJGvTyQv6"),
324 associated_user: pubkey!("BFgJqMUhraJvzERrt2BbPqbqDcLgbiHMdfdPQAqLtPcR"),
325 user: pubkey!("D8h8aUEaQnBRALrcTxLkaLLCQVCASnLVx17E3m6qfuPF"),
326 system_program: pubkey!("11111111111111111111111111111111"),
327 token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
328 creator_vault: pubkey!("8rsczKQ9bVT6AcGoD4CqoKySbVErCoXwQH8h7ZjAsUqE"),
329 event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
330 program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
331 };
332
333 let decoder = PumpfunDecoder;
335 let instruction = carbon_test_utils::read_instruction("tests/fixtures/sell_ix.json")
336 .expect("read fixture");
337 let decoded = decoder
338 .decode_instruction(&instruction)
339 .expect("decode instruction");
340 let decoded_arranged_accounts =
341 sell::Sell::arrange_accounts(&instruction.accounts).expect("aranage accounts");
342
343 assert_eq!(decoded.data, expected_ix);
345 assert_eq!(decoded.accounts, expected_accounts);
346 assert_eq!(decoded.program_id, PROGRAM_ID);
347 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
348 }
349
350 #[test]
351 fn test_decode_create() {
352 let expected_ix = PumpfunInstruction::Create(create::Create {
354 name: "Mystical Cat".to_owned(),
355 symbol: "MC".to_owned(),
356 uri: "https://ipfs.io/ipfs/QmeXR4TB9NZVK279DAVDKevSLzrWSi9papnaknVPJ8AvHe".to_owned(),
357 creator: pubkey!("CkdtUhQdH2sHXJYTJTNFbF1K5W33WVgVHG7zffaMkEmv"),
358 });
359 let expected_accounts = vec![
360 AccountMeta::new(
361 pubkey!("AC69oJv1m7843mdRfoQDneZuyRxYrMq86i2mARMtpump"),
362 true,
363 ),
364 AccountMeta::new_readonly(
365 pubkey!("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
366 false,
367 ),
368 AccountMeta::new(
369 pubkey!("623TpUDcZjKdmd9wybMveLKSSbgRs2hvwFjygzi4g15B"),
370 false,
371 ),
372 AccountMeta::new(
373 pubkey!("5rQKu3z4SXShvQkNKSJu9mtsVmgM8AvLoeNbJGvTyQv6"),
374 false,
375 ),
376 AccountMeta::new_readonly(
377 pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
378 false,
379 ),
380 AccountMeta::new_readonly(
381 pubkey!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
382 false,
383 ),
384 AccountMeta::new(
385 pubkey!("311RNHU1xDgJfYvQLszzgnBjQ1fDg5Ddr2yR3ymmUCed"),
386 false,
387 ),
388 AccountMeta::new(
389 pubkey!("CkdtUhQdH2sHXJYTJTNFbF1K5W33WVgVHG7zffaMkEmv"),
390 true,
391 ),
392 AccountMeta::new_readonly(pubkey!("11111111111111111111111111111111"), false),
393 AccountMeta::new_readonly(
394 pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
395 false,
396 ),
397 AccountMeta::new_readonly(
398 pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
399 false,
400 ),
401 AccountMeta::new_readonly(
402 pubkey!("SysvarRent111111111111111111111111111111111"),
403 false,
404 ),
405 AccountMeta::new_readonly(
406 pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
407 false,
408 ),
409 AccountMeta::new_readonly(
410 pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
411 false,
412 ),
413 ];
414 let expected_arranged_accounts = create::CreateInstructionAccounts {
415 mint: pubkey!("AC69oJv1m7843mdRfoQDneZuyRxYrMq86i2mARMtpump"),
416 mint_authority: pubkey!("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"),
417 bonding_curve: pubkey!("623TpUDcZjKdmd9wybMveLKSSbgRs2hvwFjygzi4g15B"),
418 associated_bonding_curve: pubkey!("5rQKu3z4SXShvQkNKSJu9mtsVmgM8AvLoeNbJGvTyQv6"),
419 global: pubkey!("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"),
420 mpl_token_metadata: pubkey!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
421 metadata: pubkey!("311RNHU1xDgJfYvQLszzgnBjQ1fDg5Ddr2yR3ymmUCed"),
422 user: pubkey!("CkdtUhQdH2sHXJYTJTNFbF1K5W33WVgVHG7zffaMkEmv"),
423 system_program: pubkey!("11111111111111111111111111111111"),
424 token_program: pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
425 associated_token_program: pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
426 rent: pubkey!("SysvarRent111111111111111111111111111111111"),
427 event_authority: pubkey!("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"),
428 program: pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"),
429 };
430
431 let decoder = PumpfunDecoder;
433 let instruction = carbon_test_utils::read_instruction("tests/fixtures/create_ix.json")
434 .expect("read fixture");
435 let decoded = decoder
436 .decode_instruction(&instruction)
437 .expect("decode instruction");
438 let decoded_arranged_accounts =
439 create::Create::arrange_accounts(&instruction.accounts).expect("aranage accounts");
440
441 assert_eq!(decoded.data, expected_ix);
443 assert_eq!(decoded.accounts, expected_accounts);
444 assert_eq!(decoded.program_id, PROGRAM_ID);
445 assert_eq!(decoded_arranged_accounts, expected_arranged_accounts);
446 }
447}