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