Skip to main content

pump_rust_client/sdk/
trade_tx.rs

1use solana_program::instruction::Instruction;
2
3use crate::constants;
4use crate::math::QuoteResult;
5use crate::token::{
6    create_associated_token_account_idempotent, unwrap_sol_instruction, wrap_sol_instructions,
7};
8
9use super::{
10    AmmQuoteSource, PumpSdk, Quote, TradeQuoteParams, TradeTxParams, TradeTxWithVenueParams,
11    TradeVenue,
12};
13
14impl PumpSdk {
15    /// Full buy or sell: bonding curve via [`Self::buy_v2_instructions`] /
16    /// [`Self::sell_v2_instructions`], or AMM with wSOL wrap/unwrap when the quote is native.
17    /// `None` if global fee recipients are missing.
18    pub fn trade_tx_instructions_with_venue(
19        &self,
20        params: TradeTxWithVenueParams<'_>,
21    ) -> Option<Vec<Instruction>> {
22        let TradeTxWithVenueParams {
23            mint,
24            base_token_program,
25            quote_token_program,
26            user,
27            is_buy,
28            venue,
29            base_amount,
30            sol_amount_threshold,
31        } = params;
32
33        match venue {
34            TradeVenue::BondingCurve {
35                global,
36                bonding_curve,
37            } => {
38                if is_buy {
39                    self.buy_v2_instructions(
40                        global,
41                        bonding_curve,
42                        mint,
43                        quote_token_program,
44                        user,
45                        base_amount,
46                        sol_amount_threshold,
47                    )
48                } else {
49                    self.sell_v2_instructions(
50                        global,
51                        bonding_curve,
52                        mint,
53                        quote_token_program,
54                        user,
55                        base_amount,
56                        sol_amount_threshold,
57                    )
58                }
59            }
60            TradeVenue::Amm {
61                pool,
62                amm_global,
63                pool_state,
64            } => {
65                debug_assert_eq!(mint, pool_state.base_mint);
66                let base_mint = pool_state.base_mint;
67                let quote_mint = pool_state.quote_mint;
68                let (protocol_fee_recipient, buyback_fee_recipient) =
69                    Self::amm_fee_recipients_pair(amm_global)?;
70                let coin_creator = pool_state.coin_creator;
71                let is_cashback_coin = pool_state.is_cashback_coin;
72                let uses_native_quote = quote_mint == constants::NATIVE_MINT;
73
74                let mut ixs: Vec<Instruction> = Vec::with_capacity(6);
75                if is_buy {
76                    ixs.push(create_associated_token_account_idempotent(
77                        &user,
78                        &user,
79                        &base_mint,
80                        &base_token_program,
81                    ));
82                    ixs.push(create_associated_token_account_idempotent(
83                        &user,
84                        &user,
85                        &quote_mint,
86                        &quote_token_program,
87                    ));
88                    if uses_native_quote {
89                        ixs.extend(wrap_sol_instructions(&user, sol_amount_threshold));
90                    }
91                    ixs.push(self.buy_amm_instruction_with_recipients(
92                        pool,
93                        base_mint,
94                        quote_mint,
95                        base_token_program,
96                        quote_token_program,
97                        user,
98                        coin_creator,
99                        protocol_fee_recipient,
100                        buyback_fee_recipient,
101                        is_cashback_coin,
102                        base_amount,
103                        sol_amount_threshold,
104                    ));
105                } else {
106                    ixs.push(create_associated_token_account_idempotent(
107                        &user,
108                        &user,
109                        &quote_mint,
110                        &quote_token_program,
111                    ));
112                    ixs.push(self.sell_amm_instruction_with_recipients(
113                        pool,
114                        base_mint,
115                        quote_mint,
116                        base_token_program,
117                        quote_token_program,
118                        user,
119                        coin_creator,
120                        protocol_fee_recipient,
121                        buyback_fee_recipient,
122                        is_cashback_coin,
123                        base_amount,
124                        sol_amount_threshold,
125                    ));
126                }
127                if uses_native_quote {
128                    ixs.push(unwrap_sol_instruction(&user));
129                }
130                Some(ixs)
131            }
132        }
133    }
134
135    /// [`Self::trade_tx_instructions_with_venue`] with routing from `bonding_curve.complete`.
136    pub fn trade_tx_instructions(&self, params: TradeTxParams<'_>) -> Option<Vec<Instruction>> {
137        let TradeTxParams {
138            mint,
139            base_token_program,
140            quote_token_program,
141            user,
142            is_buy,
143            base_amount,
144            sol_amount_threshold,
145            pump_global,
146            bonding_curve,
147            pump_pool,
148        } = params;
149
150        let venue = if bonding_curve.complete {
151            let p = pump_pool?;
152            TradeVenue::Amm {
153                pool: p.pool,
154                amm_global: p.amm_global,
155                pool_state: p.pool_state,
156            }
157        } else {
158            TradeVenue::BondingCurve {
159                global: pump_global,
160                bonding_curve,
161            }
162        };
163
164        self.trade_tx_instructions_with_venue(TradeTxWithVenueParams {
165            mint,
166            base_token_program,
167            quote_token_program,
168            user,
169            is_buy,
170            venue,
171            base_amount,
172            sol_amount_threshold,
173        })
174    }
175
176    /// Auto-routed quote: bonding curve via [`Self::buy_quote_bonding_curve_token_out`] /
177    /// [`Self::sell_quote_bonding_curve`], or AMM via [`Self::buy_quote_amm_token_out`] /
178    /// [`Self::sell_quote_amm`] using `bonding_curve.complete`. `None` when the curve is
179    /// complete and `pump_pool` was not supplied — mirrors [`Self::trade_tx_instructions`].
180    pub fn quote_trade(&self, params: TradeQuoteParams<'_>) -> Option<QuoteResult<Quote>> {
181        let TradeQuoteParams {
182            is_buy,
183            base_amount,
184            slippage_bps,
185            base_mint_supply,
186            pump_global,
187            pump_fee_config,
188            bonding_curve,
189            pump_pool,
190        } = params;
191
192        if bonding_curve.complete {
193            let p = pump_pool?;
194            let source = AmmQuoteSource::Pool {
195                pool: p.pool_state,
196                base_reserve: p.base_reserve,
197                quote_reserve: p.quote_reserve,
198                base_mint_supply,
199            };
200            Some(if is_buy {
201                self.buy_quote_amm_token_out(
202                    p.amm_global,
203                    p.amm_fee_config,
204                    source,
205                    base_amount,
206                    slippage_bps,
207                )
208            } else {
209                self.sell_quote_amm(
210                    p.amm_global,
211                    p.amm_fee_config,
212                    source,
213                    base_amount,
214                    slippage_bps,
215                )
216            })
217        } else {
218            Some(if is_buy {
219                self.buy_quote_bonding_curve_token_out(
220                    pump_global,
221                    pump_fee_config,
222                    bonding_curve,
223                    base_mint_supply,
224                    base_amount,
225                    slippage_bps,
226                )
227            } else {
228                self.sell_quote_bonding_curve(
229                    pump_global,
230                    pump_fee_config,
231                    bonding_curve,
232                    base_mint_supply,
233                    base_amount,
234                    slippage_bps,
235                )
236            })
237        }
238    }
239}