1use anchor_lang::{InstructionData, ToAccountMetas};
2use solana_program::{
3 instruction::{AccountMeta, Instruction},
4 pubkey::Pubkey,
5 system_program,
6};
7
8use crate::state::{BondingCurve, Global};
9use crate::token::create_associated_token_account_idempotent;
10use crate::{
11 constants, pda, pump::client, pump::types::OptionBool,
12 pump_agent_payments::client as agent_client,
13};
14
15use super::{CreateCoinParams, PumpSdk};
16
17struct V2TradeAccounts {
22 quote_mint: Pubkey,
23 base_token_program: Pubkey,
24 bonding_curve: Pubkey,
25 creator_vault: Pubkey,
26 user_volume_accumulator: Pubkey,
27 associated_quote_fee_recipient: Pubkey,
28 associated_quote_buyback_fee_recipient: Pubkey,
29 associated_base_bonding_curve: Pubkey,
30 associated_quote_bonding_curve: Pubkey,
31 associated_base_user: Pubkey,
32 associated_quote_user: Pubkey,
33 associated_creator_vault: Pubkey,
34 associated_user_volume_accumulator: Pubkey,
35}
36
37impl V2TradeAccounts {
38 fn derive(
39 base_mint: Pubkey,
40 quote_mint: Pubkey,
41 quote_token_program: Pubkey,
42 user: Pubkey,
43 creator: Pubkey,
44 fee_recipient: Pubkey,
45 buyback_fee_recipient: Pubkey,
46 ) -> Self {
47 let base_token_program = constants::SPL_TOKEN_2022_PROGRAM_ID;
48 let quote_mint = if quote_mint == Pubkey::default() {
49 constants::NATIVE_MINT
50 } else {
51 quote_mint
52 };
53 let bonding_curve = pda::pump::bonding_curve(&base_mint).0;
54 let creator_vault = pda::pump::creator_vault(&creator).0;
55 let user_volume_accumulator = pda::pump::user_volume_accumulator(&user).0;
56 let ata = |owner: &Pubkey, token_program: &Pubkey, mint: &Pubkey| {
57 pda::associated_token(owner, token_program, mint).0
58 };
59 Self {
60 quote_mint,
61 base_token_program,
62 bonding_curve,
63 creator_vault,
64 user_volume_accumulator,
65 associated_quote_fee_recipient: ata(&fee_recipient, "e_token_program, "e_mint),
66 associated_quote_buyback_fee_recipient: ata(
67 &buyback_fee_recipient,
68 "e_token_program,
69 "e_mint,
70 ),
71 associated_base_bonding_curve: ata(&bonding_curve, &base_token_program, &base_mint),
72 associated_quote_bonding_curve: ata(&bonding_curve, "e_token_program, "e_mint),
73 associated_base_user: ata(&user, &base_token_program, &base_mint),
74 associated_quote_user: ata(&user, "e_token_program, "e_mint),
75 associated_creator_vault: ata(&creator_vault, "e_token_program, "e_mint),
76 associated_user_volume_accumulator: ata(
77 &user_volume_accumulator,
78 "e_token_program,
79 "e_mint,
80 ),
81 }
82 }
83}
84
85impl PumpSdk {
86 pub fn create_v2_instruction(
94 &self,
95 mint: Pubkey,
96 user: Pubkey,
97 name: impl Into<String>,
98 symbol: impl Into<String>,
99 uri: impl Into<String>,
100 creator: Pubkey,
101 quote_mint: Pubkey,
102 mayhem_mode: bool,
103 cashback: bool,
104 ) -> Instruction {
105 let token_program = constants::SPL_TOKEN_2022_PROGRAM_ID;
106 let bonding_curve = pda::pump::bonding_curve(&mint).0;
107 let accounts = client::accounts::CreateV2 {
108 mint,
109 mint_authority: pda::pump::mint_authority().0,
110 bonding_curve,
111 associated_bonding_curve: pda::associated_token(&bonding_curve, &token_program, &mint)
112 .0,
113 global: pda::pump::global().0,
114 user,
115 system_program: system_program::ID,
116 token_program,
117 associated_token_program: constants::SPL_ATA_PROGRAM_ID,
118 mayhem_program_id: constants::MAYHEM_PROGRAM_ID,
119 global_params: pda::mayhem::global_params().0,
120 sol_vault: pda::mayhem::sol_vault().0,
121 mayhem_state: pda::mayhem::mayhem_state(&mint).0,
122 mayhem_token_vault: pda::mayhem::mayhem_token_vault(&mint).0,
123 event_authority: pda::pump::event_authority().0,
124 program: crate::pump::ID,
125 };
126 let args = client::args::CreateV2 {
127 name: name.into(),
128 symbol: symbol.into(),
129 uri: uri.into(),
130 creator,
131 is_mayhem_mode: mayhem_mode,
132 is_cashback_enabled: OptionBool(cashback),
133 };
134 let mut metas = accounts.to_account_metas(None);
135 let resolved_quote_mint = if quote_mint == Pubkey::default() {
136 constants::NATIVE_MINT
137 } else {
138 quote_mint
139 };
140 if resolved_quote_mint != constants::NATIVE_MINT {
141 let quote_token_program = constants::SPL_TOKEN_PROGRAM_ID;
142 let associated_quote_bonding_curve =
143 pda::associated_token(&bonding_curve, "e_token_program, &resolved_quote_mint).0;
144 metas.push(AccountMeta::new_readonly(resolved_quote_mint, false));
145 metas.push(AccountMeta::new(associated_quote_bonding_curve, false));
146 metas.push(AccountMeta::new_readonly(quote_token_program, false));
147 }
148 Instruction {
149 program_id: crate::pump::ID,
150 accounts: metas,
151 data: args.data(),
152 }
153 }
154
155 pub fn buy_v2_instruction(
157 &self,
158 global: &Global,
159 bonding_curve: &BondingCurve,
160 base_mint: Pubkey,
161 quote_token_program: Pubkey,
162 user: Pubkey,
163 amount: u64,
164 max_sol_cost: u64,
165 ) -> Option<Instruction> {
166 let (fee_recipient, buyback_fee_recipient) =
167 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
168 Some(self.buy_v2_instruction_with_recipients(
169 base_mint,
170 bonding_curve.quote_mint,
171 quote_token_program,
172 user,
173 bonding_curve.creator,
174 fee_recipient,
175 buyback_fee_recipient,
176 amount,
177 max_sol_cost,
178 ))
179 }
180
181 pub(crate) fn buy_v2_instruction_with_recipients(
182 &self,
183 base_mint: Pubkey,
184 quote_mint: Pubkey,
185 quote_token_program: Pubkey,
186 user: Pubkey,
187 creator: Pubkey,
188 fee_recipient: Pubkey,
189 buyback_fee_recipient: Pubkey,
190 amount: u64,
191 max_sol_cost: u64,
192 ) -> Instruction {
193 let a = V2TradeAccounts::derive(
194 base_mint,
195 quote_mint,
196 quote_token_program,
197 user,
198 creator,
199 fee_recipient,
200 buyback_fee_recipient,
201 );
202 let accounts = client::accounts::BuyV2 {
203 global: pda::pump::global().0,
204 base_mint,
205 quote_mint: a.quote_mint,
206 base_token_program: a.base_token_program,
207 quote_token_program,
208 associated_token_program: constants::SPL_ATA_PROGRAM_ID,
209 fee_recipient,
210 associated_quote_fee_recipient: a.associated_quote_fee_recipient,
211 buyback_fee_recipient,
212 associated_quote_buyback_fee_recipient: a.associated_quote_buyback_fee_recipient,
213 bonding_curve: a.bonding_curve,
214 associated_base_bonding_curve: a.associated_base_bonding_curve,
215 associated_quote_bonding_curve: a.associated_quote_bonding_curve,
216 user,
217 associated_base_user: a.associated_base_user,
218 associated_quote_user: a.associated_quote_user,
219 creator_vault: a.creator_vault,
220 associated_creator_vault: a.associated_creator_vault,
221 sharing_config: pda::pump::sharing_config(&base_mint).0,
222 global_volume_accumulator: pda::pump::global_volume_accumulator().0,
223 user_volume_accumulator: a.user_volume_accumulator,
224 associated_user_volume_accumulator: a.associated_user_volume_accumulator,
225 fee_config: pda::pump::fee_config().0,
226 fee_program: constants::FEE_PROGRAM_ID,
227 system_program: system_program::ID,
228 event_authority: pda::pump::event_authority().0,
229 program: crate::pump::ID,
230 };
231 let args = client::args::BuyV2 {
232 amount,
233 max_sol_cost,
234 };
235 Instruction {
236 program_id: crate::pump::ID,
237 accounts: accounts.to_account_metas(None),
238 data: args.data(),
239 }
240 }
241
242 pub fn buy_v2_instructions(
244 &self,
245 global: &Global,
246 bonding_curve: &BondingCurve,
247 base_mint: Pubkey,
248 quote_token_program: Pubkey,
249 user: Pubkey,
250 amount: u64,
251 max_sol_cost: u64,
252 ) -> Option<Vec<Instruction>> {
253 let base_token_program = constants::SPL_TOKEN_2022_PROGRAM_ID;
254 let (fee_recipient, buyback_fee_recipient) =
255 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
256 let quote_mint = bonding_curve.quote_mint;
257 let creator = bonding_curve.creator;
258 let mut instructions = Self::user_trade_atas(
259 user,
260 base_mint,
261 bonding_curve,
262 base_token_program,
263 quote_token_program,
264 true,
265 );
266 instructions.push(self.buy_v2_instruction_with_recipients(
267 base_mint,
268 quote_mint,
269 quote_token_program,
270 user,
271 creator,
272 fee_recipient,
273 buyback_fee_recipient,
274 amount,
275 max_sol_cost,
276 ));
277 Some(instructions)
278 }
279
280 pub fn buy_exact_quote_in_v2_instruction(
282 &self,
283 global: &Global,
284 bonding_curve: &BondingCurve,
285 base_mint: Pubkey,
286 quote_token_program: Pubkey,
287 user: Pubkey,
288 spendable_quote_in: u64,
289 min_tokens_out: u64,
290 ) -> Option<Instruction> {
291 let (fee_recipient, buyback_fee_recipient) =
292 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
293 Some(self.buy_exact_quote_in_v2_instruction_with_recipients(
294 base_mint,
295 bonding_curve.quote_mint,
296 quote_token_program,
297 user,
298 bonding_curve.creator,
299 fee_recipient,
300 buyback_fee_recipient,
301 spendable_quote_in,
302 min_tokens_out,
303 ))
304 }
305
306 pub(crate) fn buy_exact_quote_in_v2_instruction_with_recipients(
307 &self,
308 base_mint: Pubkey,
309 quote_mint: Pubkey,
310 quote_token_program: Pubkey,
311 user: Pubkey,
312 creator: Pubkey,
313 fee_recipient: Pubkey,
314 buyback_fee_recipient: Pubkey,
315 spendable_quote_in: u64,
316 min_tokens_out: u64,
317 ) -> Instruction {
318 let a = V2TradeAccounts::derive(
319 base_mint,
320 quote_mint,
321 quote_token_program,
322 user,
323 creator,
324 fee_recipient,
325 buyback_fee_recipient,
326 );
327 let accounts = client::accounts::BuyExactQuoteInV2 {
328 global: pda::pump::global().0,
329 base_mint,
330 quote_mint: a.quote_mint,
331 base_token_program: a.base_token_program,
332 quote_token_program,
333 associated_token_program: constants::SPL_ATA_PROGRAM_ID,
334 fee_recipient,
335 associated_quote_fee_recipient: a.associated_quote_fee_recipient,
336 buyback_fee_recipient,
337 associated_quote_buyback_fee_recipient: a.associated_quote_buyback_fee_recipient,
338 bonding_curve: a.bonding_curve,
339 associated_base_bonding_curve: a.associated_base_bonding_curve,
340 associated_quote_bonding_curve: a.associated_quote_bonding_curve,
341 user,
342 associated_base_user: a.associated_base_user,
343 associated_quote_user: a.associated_quote_user,
344 creator_vault: a.creator_vault,
345 associated_creator_vault: a.associated_creator_vault,
346 sharing_config: pda::pump::sharing_config(&base_mint).0,
347 global_volume_accumulator: pda::pump::global_volume_accumulator().0,
348 user_volume_accumulator: a.user_volume_accumulator,
349 associated_user_volume_accumulator: a.associated_user_volume_accumulator,
350 fee_config: pda::pump::fee_config().0,
351 fee_program: constants::FEE_PROGRAM_ID,
352 system_program: system_program::ID,
353 event_authority: pda::pump::event_authority().0,
354 program: crate::pump::ID,
355 };
356 let args = client::args::BuyExactQuoteInV2 {
357 spendable_quote_in,
358 min_tokens_out,
359 };
360 Instruction {
361 program_id: crate::pump::ID,
362 accounts: accounts.to_account_metas(None),
363 data: args.data(),
364 }
365 }
366
367 pub fn buy_exact_quote_in_v2_instructions(
369 &self,
370 global: &Global,
371 bonding_curve: &BondingCurve,
372 base_mint: Pubkey,
373 quote_token_program: Pubkey,
374 user: Pubkey,
375 spendable_quote_in: u64,
376 min_tokens_out: u64,
377 ) -> Option<Vec<Instruction>> {
378 let base_token_program = constants::SPL_TOKEN_2022_PROGRAM_ID;
379 let (fee_recipient, buyback_fee_recipient) =
380 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
381 let quote_mint = bonding_curve.quote_mint;
382 let creator = bonding_curve.creator;
383 let mut instructions = Self::user_trade_atas(
384 user,
385 base_mint,
386 bonding_curve,
387 base_token_program,
388 quote_token_program,
389 true,
390 );
391 instructions.push(self.buy_exact_quote_in_v2_instruction_with_recipients(
392 base_mint,
393 quote_mint,
394 quote_token_program,
395 user,
396 creator,
397 fee_recipient,
398 buyback_fee_recipient,
399 spendable_quote_in,
400 min_tokens_out,
401 ));
402 Some(instructions)
403 }
404
405 pub fn sell_v2_instruction(
407 &self,
408 global: &Global,
409 bonding_curve: &BondingCurve,
410 base_mint: Pubkey,
411 quote_token_program: Pubkey,
412 user: Pubkey,
413 amount: u64,
414 min_sol_output: u64,
415 ) -> Option<Instruction> {
416 let (fee_recipient, buyback_fee_recipient) =
417 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
418 Some(self.sell_v2_instruction_with_recipients(
419 base_mint,
420 bonding_curve.quote_mint,
421 quote_token_program,
422 user,
423 bonding_curve.creator,
424 fee_recipient,
425 buyback_fee_recipient,
426 amount,
427 min_sol_output,
428 ))
429 }
430
431 pub(crate) fn sell_v2_instruction_with_recipients(
432 &self,
433 base_mint: Pubkey,
434 quote_mint: Pubkey,
435 quote_token_program: Pubkey,
436 user: Pubkey,
437 creator: Pubkey,
438 fee_recipient: Pubkey,
439 buyback_fee_recipient: Pubkey,
440 amount: u64,
441 min_sol_output: u64,
442 ) -> Instruction {
443 let a = V2TradeAccounts::derive(
444 base_mint,
445 quote_mint,
446 quote_token_program,
447 user,
448 creator,
449 fee_recipient,
450 buyback_fee_recipient,
451 );
452 let accounts = client::accounts::SellV2 {
453 global: pda::pump::global().0,
454 base_mint,
455 quote_mint: a.quote_mint,
456 base_token_program: a.base_token_program,
457 quote_token_program,
458 associated_token_program: constants::SPL_ATA_PROGRAM_ID,
459 fee_recipient,
460 associated_quote_fee_recipient: a.associated_quote_fee_recipient,
461 buyback_fee_recipient,
462 associated_quote_buyback_fee_recipient: a.associated_quote_buyback_fee_recipient,
463 bonding_curve: a.bonding_curve,
464 associated_base_bonding_curve: a.associated_base_bonding_curve,
465 associated_quote_bonding_curve: a.associated_quote_bonding_curve,
466 user,
467 associated_base_user: a.associated_base_user,
468 associated_quote_user: a.associated_quote_user,
469 creator_vault: a.creator_vault,
470 associated_creator_vault: a.associated_creator_vault,
471 sharing_config: pda::pump::sharing_config(&base_mint).0,
472 user_volume_accumulator: a.user_volume_accumulator,
473 associated_user_volume_accumulator: a.associated_user_volume_accumulator,
474 fee_config: pda::pump::fee_config().0,
475 fee_program: constants::FEE_PROGRAM_ID,
476 system_program: system_program::ID,
477 event_authority: pda::pump::event_authority().0,
478 program: crate::pump::ID,
479 };
480 let args = client::args::SellV2 {
481 amount,
482 min_sol_output,
483 };
484 Instruction {
485 program_id: crate::pump::ID,
486 accounts: accounts.to_account_metas(None),
487 data: args.data(),
488 }
489 }
490
491 pub fn sell_v2_instructions(
493 &self,
494 global: &Global,
495 bonding_curve: &BondingCurve,
496 base_mint: Pubkey,
497 quote_token_program: Pubkey,
498 user: Pubkey,
499 amount: u64,
500 min_sol_output: u64,
501 ) -> Option<Vec<Instruction>> {
502 let (fee_recipient, buyback_fee_recipient) =
503 Self::pump_fee_recipients_pair(global, bonding_curve.is_mayhem_mode)?;
504 let quote_mint = bonding_curve.quote_mint;
505 let creator = bonding_curve.creator;
506 let mut instructions = Self::user_trade_atas(
507 user,
508 base_mint,
509 bonding_curve,
510 constants::SPL_TOKEN_2022_PROGRAM_ID,
511 quote_token_program,
512 false,
513 );
514 instructions.push(self.sell_v2_instruction_with_recipients(
515 base_mint,
516 quote_mint,
517 quote_token_program,
518 user,
519 creator,
520 fee_recipient,
521 buyback_fee_recipient,
522 amount,
523 min_sol_output,
524 ));
525 Some(instructions)
526 }
527
528 pub fn create_v2_and_buy_instruction(
533 &self,
534 mint: Pubkey,
535 user: Pubkey,
536 name: impl Into<String>,
537 symbol: impl Into<String>,
538 uri: impl Into<String>,
539 creator: Pubkey,
540 mayhem_mode: bool,
541 cashback: bool,
542 tokenized_agent_buyback_bps: Option<u16>,
543 global: &Global,
544 amount: u64,
545 max_sol_cost: u64,
546 ) -> Option<Vec<Instruction>> {
547 let quote_token_program = constants::SPL_TOKEN_PROGRAM_ID;
548 let bonding_curve_preview = BondingCurve {
549 creator,
550 is_cashback_coin: cashback,
551 is_mayhem_mode: mayhem_mode,
552 quote_mint: constants::NATIVE_MINT,
553 ..Default::default()
554 };
555 let buy_v2_instructions = self.buy_v2_instructions(
556 global,
557 &bonding_curve_preview,
558 mint,
559 quote_token_program,
560 user,
561 amount,
562 max_sol_cost,
563 )?;
564 let mut instructions = vec![self.create_v2_instruction(
565 mint,
566 user,
567 name,
568 symbol,
569 uri,
570 creator,
571 Pubkey::default(),
572 mayhem_mode,
573 cashback,
574 )];
575
576 instructions.extend(buy_v2_instructions);
577
578 if let Some(buyback_bps) = tokenized_agent_buyback_bps {
579 instructions.push(self.agent_initialize_instruction(mint, user, creator, buyback_bps));
580 }
581
582 Some(instructions)
583 }
584
585 pub fn agent_initialize_instruction(
589 &self,
590 mint: Pubkey,
591 user: Pubkey,
592 creator: Pubkey,
593 buyback_bps: u16,
594 ) -> Instruction {
595 let accounts = agent_client::accounts::AgentInitialize {
596 authority: user,
597 bonding_curve: pda::pump::bonding_curve(&mint).0,
598 global_config: pda::pump_agent_payments::global_config().0,
599 mint,
600 token_agent_payments: pda::pump_agent_payments::token_agent_payments(&mint).0,
601 system_program: system_program::ID,
602 event_authority: pda::pump_agent_payments::event_authority().0,
603 program: crate::pump_agent_payments::ID,
604 sharing_fee_config: pda::pump::sharing_config(&mint).0,
605 };
606 let args = agent_client::args::AgentInitialize {
607 authority: creator,
608 buyback_bps,
609 };
610 Instruction {
611 program_id: crate::pump_agent_payments::ID,
612 accounts: accounts.to_account_metas(None),
613 data: args.data(),
614 }
615 }
616
617 pub fn extend_account_ix(&self, mint: Pubkey, user: Pubkey) -> Instruction {
618 let accounts = client::accounts::ExtendAccount {
619 account: pda::pump::bonding_curve(&mint).0,
620 user,
621 system_program: system_program::ID,
622 event_authority: pda::pump::event_authority().0,
623 program: crate::pump::ID,
624 };
625 Instruction {
626 program_id: crate::pump::ID,
627 accounts: accounts.to_account_metas(None),
628 data: client::args::ExtendAccount.data(),
629 }
630 }
631
632 pub fn create_coin_instructions(
636 &self,
637 params: CreateCoinParams<'_>,
638 ) -> Option<Vec<Instruction>> {
639 let CreateCoinParams {
640 mint,
641 user,
642 creator,
643 name,
644 symbol,
645 uri,
646 mayhem_mode,
647 cashback,
648 global,
649 token_amount,
650 max_sol_cost,
651 tokenized_agent_buyback_bps,
652 } = params;
653 let quote_token_program = constants::SPL_TOKEN_PROGRAM_ID;
654 let bonding_curve_preview = BondingCurve {
655 creator,
656 is_cashback_coin: cashback,
657 is_mayhem_mode: mayhem_mode,
658 quote_mint: constants::NATIVE_MINT,
659 ..Default::default()
660 };
661
662 let mut ixs: Vec<Instruction> = vec![self.create_v2_instruction(
663 mint,
664 user,
665 name,
666 symbol,
667 uri,
668 creator,
669 Pubkey::default(),
670 mayhem_mode,
671 cashback,
672 )];
673 ixs.extend(self.buy_v2_instructions(
674 global,
675 &bonding_curve_preview,
676 mint,
677 quote_token_program,
678 user,
679 token_amount,
680 max_sol_cost,
681 )?);
682 if let Some(buyback_bps) = tokenized_agent_buyback_bps {
683 ixs.push(self.agent_initialize_instruction(mint, user, creator, buyback_bps));
684 }
685 Some(ixs)
686 }
687
688 fn user_trade_atas(
696 user: Pubkey,
697 base_mint: Pubkey,
698 bonding_curve: &BondingCurve,
699 base_token_program: Pubkey,
700 quote_token_program: Pubkey,
701 include_base: bool,
702 ) -> Vec<Instruction> {
703 let mut ixs = vec![];
704 if include_base {
705 ixs.push(create_associated_token_account_idempotent(
706 &user,
707 &user,
708 &base_mint,
709 &base_token_program,
710 ));
711 }
712 let bonding_curve_has_non_sol_quote = bonding_curve.quote_mint != Pubkey::default()
713 && bonding_curve.quote_mint != constants::NATIVE_MINT;
714 if bonding_curve_has_non_sol_quote {
717 ixs.push(create_associated_token_account_idempotent(
718 &user,
719 &user,
720 &bonding_curve.quote_mint,
721 "e_token_program,
722 ));
723 ixs.push(create_associated_token_account_idempotent(
724 &user,
725 &bonding_curve.creator,
726 &bonding_curve.quote_mint,
727 "e_token_program,
728 ));
729 let bonding_curve_pda = pda::pump::bonding_curve(&base_mint).0;
731 ixs.push(create_associated_token_account_idempotent(
732 &user,
733 &bonding_curve_pda,
734 &bonding_curve.quote_mint,
735 "e_token_program,
736 ));
737 if bonding_curve.is_cashback_coin {
738 let user_volume_accumulator = pda::pump::user_volume_accumulator(&user).0;
739 ixs.push(create_associated_token_account_idempotent(
740 &user,
741 &user_volume_accumulator,
742 &bonding_curve.quote_mint,
743 "e_token_program,
744 ));
745 }
746 }
747 ixs
748 }
749}