carbon_pumpfun_decoder/instructions/
mod.rs

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        // Arrange
109        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        // Act
191        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
201        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        // Arrange
210        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        // Act
293        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
303        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        // Arrange
312        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        // Act
391        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
401        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}