solana_trader_client_rust/provider/http/
swap.rs

1use crate::{
2    common::signing::SubmitParams,
3    provider::utils::{
4        convert_address_lookup_table, convert_jupiter_instructions, convert_raydium_instructions,
5        create_transaction_message,
6    },
7};
8
9use super::HTTPClient;
10use anyhow::Result;
11use serde_json::json;
12use base64::{engine::general_purpose, Engine};
13use solana_sdk::{
14    message::{v0, VersionedMessage},
15    transaction::VersionedTransaction,
16};
17use solana_trader_proto::api;
18
19impl HTTPClient {
20    pub async fn post_raydium_swap(
21        &self,
22        request: &api::PostRaydiumSwapRequest,
23    ) -> Result<api::PostRaydiumSwapResponse> {
24        let response = self
25            .client
26            .post(format!("{}/api/v2/raydium/swap", self.base_url))
27            .json(&request)
28            .send()
29            .await?;
30
31        self.handle_response(response).await
32    }
33
34    pub async fn post_raydium_route_swap(
35        &self,
36        request: &api::PostRaydiumRouteSwapRequest,
37    ) -> Result<api::PostRaydiumRouteSwapResponse> {
38        let response = self
39            .client
40            .post(format!("{}/api/v2/raydium/route-swap", self.base_url))
41            .json(&request)
42            .send()
43            .await?;
44
45        self.handle_response(response).await
46    }
47
48    pub async fn post_raydium_swap_instructions(
49        &self,
50        request: &api::PostRaydiumSwapInstructionsRequest,
51    ) -> Result<api::PostRaydiumSwapInstructionsResponse> {
52        let response = self
53            .client
54            .post(format!(
55                "{}/api/v2/raydium/swap-instructions",
56                self.base_url
57            ))
58            .json(&request)
59            .send()
60            .await?;
61
62        self.handle_response(response).await
63    }
64
65    pub async fn submit_raydium_swap_instructions(
66        &self,
67        request: api::PostRaydiumSwapInstructionsRequest,
68        submit_opts: SubmitParams,
69        use_bundle: bool,
70    ) -> Result<Vec<String>> {
71        let swap_instructions = self.post_raydium_swap_instructions(&request).await?;
72
73        let instructions = convert_raydium_instructions(&swap_instructions.instructions)?;
74
75        let response = self
76            .client
77            .get(format!(
78                "{}/api/v2/system/blockhash?offset=0",
79                self.base_url
80            ))
81            .send()
82            .await?;
83
84        let blockhash_response: api::GetRecentBlockHashResponseV2 =
85            self.handle_response(response).await?;
86
87        let tx_message = create_transaction_message(instructions, &blockhash_response.block_hash)?;
88
89        self.sign_and_submit(vec![tx_message], submit_opts, use_bundle)
90            .await
91    }
92
93    pub async fn post_raydium_cpmm_swap(
94        &self,
95        request: &api::PostRaydiumCpmmSwapRequest,
96    ) -> Result<api::PostRaydiumCpmmSwapResponse> {
97        let response = self
98            .client
99            .post(format!("{}/api/v2/raydium/cpmm-swap", self.base_url))
100            .json(&request)
101            .send()
102            .await?;
103
104        self.handle_response(response).await
105    }
106
107    pub async fn post_raydium_clmm_swap(
108        &self,
109        request: &api::PostRaydiumSwapRequest,
110    ) -> Result<api::PostRaydiumSwapResponse> {
111        let response = self
112            .client
113            .post(format!("{}/api/v2/raydium/clmm-swap", self.base_url))
114            .json(&request)
115            .send()
116            .await?;
117
118        self.handle_response(response).await
119    }
120
121    pub async fn post_raydium_clmm_route_swap(
122        &self,
123        request: &api::PostRaydiumRouteSwapRequest,
124    ) -> Result<api::PostRaydiumRouteSwapResponse> {
125        let response = self
126            .client
127            .post(format!("{}/api/v2/raydium/clmm-route-swap", self.base_url))
128            .json(&request)
129            .send()
130            .await?;
131
132        self.handle_response(response).await
133    }
134
135    pub async fn post_jupiter_swap(
136        &self,
137        request: &api::PostJupiterSwapRequest,
138    ) -> Result<api::PostJupiterSwapResponse> {
139        let response = self
140            .client
141            .post(format!("{}/api/v2/jupiter/swap", self.base_url))
142            .json(&request)
143            .send()
144            .await?;
145
146        self.handle_response(response).await
147    }
148
149    pub async fn post_jupiter_route_swap(
150        &self,
151        request: &api::PostJupiterRouteSwapRequest,
152    ) -> Result<api::PostJupiterRouteSwapResponse> {
153        let response = self
154            .client
155            .post(format!("{}/api/v2/jupiter/route-swap", self.base_url))
156            .json(&request)
157            .send()
158            .await?;
159
160        self.handle_response(response).await
161    }
162
163    pub async fn post_jupiter_swap_instructions(
164        &self,
165        request: &api::PostJupiterSwapInstructionsRequest,
166    ) -> Result<api::PostJupiterSwapInstructionsResponse> {
167        let response = self
168            .client
169            .post(format!(
170                "{}/api/v2/jupiter/swap-instructions",
171                self.base_url
172            ))
173            .json(&request)
174            .send()
175            .await?;
176
177        self.handle_response(response).await
178    }
179
180    pub async fn submit_jupiter_swap_instructions(
181        &self,
182        request: api::PostJupiterSwapInstructionsRequest,
183        submit_opts: SubmitParams,
184        use_bundle: bool,
185    ) -> Result<Vec<String>> {
186        let keypair = self.get_keypair()?;
187
188        let swap_instructions = self.post_jupiter_swap_instructions(&request).await?;
189
190        let address_lookup_tables =
191            convert_address_lookup_table(&swap_instructions.address_lookup_table_addresses)?;
192
193        let instructions = convert_jupiter_instructions(&swap_instructions.instructions)?;
194
195        let response = self
196            .client
197            .get(format!(
198                "{}/api/v2/system/blockhash?offset=0",
199                self.base_url
200            ))
201            .send()
202            .await?;
203
204        let blockhash_response: api::GetRecentBlockHashResponseV2 =
205            self.handle_response(response).await?;
206
207        let message = VersionedMessage::V0(v0::Message::try_compile(
208            &self.public_key.unwrap(),
209            &instructions,
210            &address_lookup_tables,
211            blockhash_response.block_hash.parse()?,
212        )?);
213
214        let tx: VersionedTransaction = VersionedTransaction::try_new(message, &[keypair])?;
215
216        let tx_message = api::TransactionMessage {
217            content: general_purpose::STANDARD.encode(bincode::serialize(&tx)?),
218            is_cleanup: false,
219        };
220
221        self.sign_and_submit(vec![tx_message], submit_opts, use_bundle)
222            .await
223    }
224
225    pub async fn post_trade_swap(
226        &self,
227        request: &api::TradeSwapRequest,
228    ) -> Result<api::TradeSwapResponse> {
229        let response = self
230            .client
231            .post(format!("{}/api/v2/trade/swap", self.base_url))
232            .json(&request)
233            .send()
234            .await?;
235
236        self.handle_response(response).await
237    }
238
239    pub async fn post_route_trade_swap(
240        &self,
241        request: &api::RouteTradeSwapRequest,
242    ) -> Result<api::TradeSwapResponse> {
243        let response = self
244            .client
245            .post(format!("{}/api/v2/trade/route-swap", self.base_url))
246            .json(&request)
247            .send()
248            .await?;
249
250        self.handle_response(response).await
251    }
252
253    pub async fn post_pump_fun_swap(
254        &self,
255        user_address: String,
256        bonding_curve_address: String,
257        token_address: String,
258        token_amount: f64,
259        creator: String,
260        sol_threshold: f64,
261        is_buy: bool,
262        slippage: f64,
263        compute_limit: u32,
264        compute_price: u64,
265        tip: Option<u64>
266    ) -> anyhow::Result<api::PostPumpFunSwapResponse> {
267        let url = format!("{}/api/v2/pumpfun/swap", self.base_url);
268        println!("{}", url);
269        
270        let request_json = json!({
271            "userAddress": user_address,
272            "bondingCurveAddress": bonding_curve_address,
273            "tokenAddress": token_address,
274            "creator": creator,
275            "tokenAmount": token_amount,
276            "solThreshold": sol_threshold,
277            "isBuy": is_buy,
278            "slippage": slippage,
279            "computeLimit": compute_limit,
280            "computePrice": compute_price,
281            "tip": tip
282        });
283        
284        let response = self
285            .client
286            .post(&url)
287            .json(&request_json)
288            .send()
289            .await?;
290            
291        let result: api::PostPumpFunSwapResponse = self.handle_response(response).await?;
292        
293        Ok(result)
294    }
295
296    pub async fn post_pump_fun_swap_sol(
297        &self,
298        user_address: String,
299        bonding_curve_address: String,
300        token_address: String,
301        creator: String,
302        sol_amount: f64,
303        slippage: f64,
304        compute_limit: u32,
305        compute_price: u64,
306        tip: Option<u64>
307    ) -> anyhow::Result<api::PostPumpFunSwapResponse> {
308        let url = format!("{}/api/v2/pumpfun/swap-sol", self.base_url);
309        println!("{}", url);
310        
311        let request_json = json!({
312            "userAddress": user_address,
313            "bondingCurveAddress": bonding_curve_address,
314            "tokenAddress": token_address,
315            "creator": creator,
316            "solAmount": sol_amount,
317            "slippage": slippage,
318            "computeLimit": compute_limit,
319            "computePrice": compute_price,
320            "tip": tip
321        });
322        
323        let response = self
324            .client
325            .post(&url)
326            .json(&request_json)
327            .send()
328            .await?;
329            
330        let result: api::PostPumpFunSwapResponse = self.handle_response(response).await?;
331        
332        Ok(result)
333    }
334
335}