solana_exec/pumpfun/
push_pumpfun_swap_instruction.rs1use crate::constants::COMPUTE_UNITS;
2use crate::pumpfun::get_pf_a_amount_out_no_price_impact::get_pf_a_amount_out_no_price_impact;
3use crate::pumpfun::get_pf_max_b_amount_in_no_price_impact::get_pf_max_b_amount_in_no_price_impact;
4use crate::types::swap_config::SwapConfig;
5use crate::utilities::get_min_amount_out::get_min_amount_out;
6use solana_central::CentralContext;
7use solana_central::PfBondingCurve;
8use solana_central::PoolTrait;
9use solana_central::SwapDirection;
10use solana_central::constants::PUMP_SWAP_FEE_VAULTS;
11use solana_central::constants::{PUMP_CONSTANTS, SOLANA_PROGRAMS};
12use solana_sdk::instruction::{AccountMeta, Instruction};
13use solana_sdk::pubkey::Pubkey;
14use spl_associated_token_account::get_associated_token_address;
15use std::sync::Arc;
16
17pub fn push_pumpfun_swap_instruction(
21 swap_config: &SwapConfig,
22 central_context: &Arc<CentralContext>,
23 instructions: &mut Vec<Instruction>,
24 compute_unit_budget: &mut u32,
25 pool: &PfBondingCurve,
26) {
27 if swap_config.slippage_lp == u64::MAX && swap_config.direction == SwapDirection::BToA {
28 println!(
29 "pumpfun_innerinstructions: Infinite slippage is not allowed for pumpfun buy \
30 direction swaps (B to A, quote to base) because it authorizes the protocol to take all of the \
31 base tokens available in the wallet. Base token address: {}",
32 pool.token_a_address()
33 );
34 }
35 let mut data: Vec<u8> = Vec::with_capacity(24);
42 let index_zero_arg: u64;
51 let index_one_arg: u64;
52 if swap_config.direction == SwapDirection::AToB {
53 let a_amount_in = swap_config.amount_in;
54 let min_b_amount_out = get_min_amount_out(swap_config, pool);
55 index_zero_arg = a_amount_in;
56 index_one_arg = min_b_amount_out;
57 data.extend_from_slice(&PUMP_CONSTANTS.sell_instruction_discriminator);
58 *compute_unit_budget += COMPUTE_UNITS.pf_bonding_curve_sell;
59 }
60 else {
63 let b_amount_in = swap_config.amount_in;
64 let a_amount_out = get_pf_a_amount_out_no_price_impact(
65 b_amount_in,
66 pool.total_swap_fee_lp(¢ral_context),
67 pool.virtual_token_reserves,
68 pool.virtual_sol_reserves,
69 );
70 let max_b_amount_in = get_pf_max_b_amount_in_no_price_impact(
71 a_amount_out,
72 pool.virtual_token_reserves,
73 pool.virtual_sol_reserves,
74 swap_config.slippage_lp,
75 );
76 index_zero_arg = a_amount_out;
77 index_one_arg = max_b_amount_in;
78 data.extend_from_slice(&PUMP_CONSTANTS.buy_instruction_discriminator);
79 *compute_unit_budget += COMPUTE_UNITS.pf_bonding_curve_buy;
80 }
81 data.extend_from_slice(&index_zero_arg.to_le_bytes());
82 data.extend_from_slice(&index_one_arg.to_le_bytes());
83
84 let mut accounts: Vec<AccountMeta> = vec![
85 AccountMeta::new_readonly(PUMP_CONSTANTS.bonding_curve_global_config, false),
86 AccountMeta::new(PUMP_SWAP_FEE_VAULTS[0], false),
87 AccountMeta::new_readonly(pool.token_address, false),
88 AccountMeta::new(pool.bonding_curve_address, false),
89 AccountMeta::new(pool.bonding_curve_associated_token_account_address, false),
90 AccountMeta::new(
91 get_associated_token_address(&swap_config.wallet, &pool.token_address),
92 false,
93 ),
94 AccountMeta::new(swap_config.wallet, true),
95 AccountMeta::new_readonly(SOLANA_PROGRAMS.system_program, false),
96 ];
97 if swap_config.direction == SwapDirection::AToB {
99 accounts.push(AccountMeta::new(pool.creator_vault_address, false));
100 accounts.push(AccountMeta::new_readonly(
101 SOLANA_PROGRAMS.token_program,
102 false,
103 ));
104 }
105 else {
107 accounts.push(AccountMeta::new_readonly(
108 SOLANA_PROGRAMS.token_program,
109 false,
110 ));
111 accounts.push(AccountMeta::new(pool.creator_vault_address, false));
112 }
113 accounts.push(AccountMeta::new_readonly(
115 PUMP_CONSTANTS.bonding_curve_event_authority,
116 false,
117 ));
118 accounts.push(AccountMeta::new_readonly(
119 PUMP_CONSTANTS.bonding_curve_program,
120 false,
121 ));
122
123 if swap_config.direction == SwapDirection::BToA {
125 accounts.push(AccountMeta::new(
126 PUMP_CONSTANTS.bonding_curve_global_volume_accumulator,
127 false,
128 ));
129
130 let user_volume_accumulator = Pubkey::find_program_address(
132 &[b"user_volume_accumulator", swap_config.wallet.as_ref()],
133 &PUMP_CONSTANTS.bonding_curve_program,
134 )
135 .0;
136 accounts.push(AccountMeta::new(user_volume_accumulator, false));
137 }
138
139 accounts.push(AccountMeta::new_readonly(
140 PUMP_CONSTANTS.bonding_curve_fee_config,
141 false,
142 ));
143 accounts.push(AccountMeta::new_readonly(PUMP_CONSTANTS.fee_program, false));
144
145 instructions.push(Instruction {
146 program_id: PUMP_CONSTANTS.bonding_curve_program,
147 accounts,
148 data,
149 });
150}