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