1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
use super::{PlatformFee, QuoteGetSwapModeEnum, RoutePlanItem, vec_to_comma_string};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Request for a base64-encoded unsigned swap transaction to be used in POST
///
/// [Official API docs](https://dev.jup.ag/docs/api/ultra-api/order)
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UltraOrderRequest {
/// The mint address of the input token.
///
/// Example: `"So11111111111111111111111111111111111111112"` (SOL)
pub input_mint: String,
/// The mint address of the output token.
///
/// Example: `"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"`
pub output_mint: String,
/// The amount to input token to swap (raw, before decimals).
pub amount: u64,
/// The user's wallet address
///
/// Note: If the taker is not provided, there will still be an Order Response with no transaction field.
pub taker: Option<String>,
/// The referral account addres
pub referral_account: Option<String>,
/// referral fee in basis points (bps)
///
/// Possible values: >= 50 and <= 255
pub referral_fee: Option<u8>,
/// A list of Routers to exclude from routing.
///
/// Possible values: `[metis, jupiterz, hashflow, dflow, pyth, okx]`
#[serde(serialize_with = "vec_to_comma_string")]
pub exclude_routers: Option<Vec<String>>,
}
impl UltraOrderRequest {
/// Creates a new `UltraOrder` with the specified input mint, output mint, and amount.
///
/// # Arguments
/// * `input_mint` - The mint address of the input token (e.g., SOL mint).
/// * `output_mint` - The mint address of the output token (e.g., JUP mint).
/// * `amount` - The amount to swap (raw, before decimals). Meaning depends on `swap_mode`.
///
/// # Returns
/// A new `QuoteRequest` instance with None value for optional fields.
///
/// # Example
/// ```
/// let request = UltraOrderRequest::new(
/// "So11111111111111111111111111111111111111112", // SOL
/// "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", // JUP
/// 1_000_000_000 // 1 SOL (9 decimals)
/// );
pub fn new(input_mint: &str, output_mint: &str, amount: u64) -> Self {
UltraOrderRequest {
input_mint: input_mint.to_string(),
output_mint: output_mint.to_string(),
amount,
taker: None,
referral_account: None,
referral_fee: None,
exclude_routers: None,
}
}
/// add the taker account to the UltraOrder
///
/// # Arguments
/// * `taker` - Taker wallet address
///
/// # Example
/// ```
/// let request = UltraOrderRequest::new(
/// "So11111111111111111111111111111111111111112", // SOL
/// "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", // JUP
/// 1_000_000_000 // 1 SOL (9 decimals)
/// ).add_taker("taker wallet address");
pub fn add_taker(mut self, taker: &str) -> Self {
self.taker = Some(taker.to_string());
self
}
/// Add the referral account to the UltraOrder
///
/// # Arguments
/// * `referral_account` - The referral account address
///
/// # Returns
/// The updated UltraOrderRequest with referral account set
///
/// # Example
/// ```
/// let request = UltraOrderRequest::new(
/// "So11111111111111111111111111111111111111112", // SOL
/// "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", // JUP
/// 1_000_000_000 // 1 SOL (9 decimals)
/// ).add_referral_account("referral account address");
pub fn add_referral_account(mut self, referral_account: &str) -> Self {
self.referral_account = Some(referral_account.to_string());
self
}
/// Add the referral fee to the UltraOrder
///
/// # Arguments
/// * `fee` - Referral fee in basis points (bps)
///
/// # Returns
/// The updated UltraOrderRequest with referral fee set
///
/// # Panics
/// Panics if fee is less than 50 or greater than 255
///
/// # Example
/// ```
/// let request = UltraOrderRequest::new(
/// "So11111111111111111111111111111111111111112", // SOL
/// "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", // JUP
/// 1_000_000_000 // 1 SOL (9 decimals)
/// ).add_referral_fee(100); // 1% fee (100 bps)
pub fn add_referral_fee(mut self, fee: u8) -> Self {
assert!(fee >= 50, "Referral fee must be between 50 and 255 bps");
self.referral_fee = Some(fee);
self
}
/// Sets the list of Routers to exclude from routing.
///
///
/// # Arguments
/// * `exclude_dexes` - A vector of DEX names to exclude (e.g., `[metis, jupiterz, hashflow, dflow, pyth, okx]`).
///
/// # Returns
/// The modified `UltraOrderRequest` for chaining.
///
/// # Example
/// ```
/// let request = UltraOrderRequest::new(
/// "So11111111111111111111111111111111111111112",
/// "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN",
/// 1_000_000_000
/// )
/// .exclude_dexes(vec!["okx".to_string(), "pyth".to_string()]);
/// ```
pub fn exclude_routers(mut self, exclude_routers: Vec<String>) -> Self {
self.exclude_routers = Some(exclude_routers);
self
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UltraOrderResponse {
/// The input token mint address.
pub input_mint: String,
/// The output token mint address.
pub output_mint: String,
/// The raw input token amount.
pub in_amount: String,
/// The raw output token amount (excluding slippage or fees).
pub out_amount: String,
/// The worst-case output amount after slippage & fees.
///
/// Not used by `/swap`, but useful for displaying expectations.
pub other_amount_threshold: String,
/// Indicates the swap mode used (ExactIn or ExactOut).
pub swap_mode: QuoteGetSwapModeEnum,
/// The applied slippage in basis points.
pub slippage_bps: i32,
/// Estimated price impact as a percentage string.
pub price_impact_pct: String,
/// The detailed route plan (possibly multiple hops).
pub route_plan: Vec<RoutePlanItem>,
#[serde(default)]
pub fee_mint: Option<String>,
pub fee_bps: u8,
pub prioritization_fee_lamports: u64,
pub swap_type: String,
#[serde(default)]
pub transaction: Option<String>,
pub gasless: bool,
pub request_id: String,
pub total_time: u16,
#[serde(default)]
pub taker: Option<String>,
#[serde(default)]
pub quote_id: Option<String>,
#[serde(default)]
pub maker: Option<String>,
/// Platform fee info (if any was applied).
#[serde(default)]
pub platform_fee: Option<PlatformFee>,
#[serde(default)]
pub expire_at: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UltraExecuteOrderRequest {
/// The signed transaction to execute
pub signed_transaction: String,
/// Found in response of /order
pub request_id: String,
}
impl UltraExecuteOrderRequest {
// function to construct a new UltraExecuteOrderRequest
//
// # Arguments
// * signed_transaction - The signed transaction to execute
// * request_id - The request ID from the order response
pub fn new(signed_transaction: &str, request_id: &str) -> Self {
UltraExecuteOrderRequest {
signed_transaction: signed_transaction.to_string(),
request_id: request_id.to_string(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UltraExecuteOrderResponse {
pub status: Status,
#[serde(default)]
pub signature: Option<String>,
#[serde(default)]
pub slot: Option<String>,
#[serde(default)]
pub error: Option<String>,
pub code: u32,
#[serde(default)]
pub total_input_amount: Option<String>,
#[serde(default)]
pub total_output_amount: Option<String>,
#[serde(default)]
pub input_amount_result: Option<String>,
#[serde(default)]
pub output_amount_result: Option<String>,
#[serde(default)]
pub swap_events: Option<Vec<SwapEvent>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Status {
Success,
Failed,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SwapEvent {
pub input_mint: Option<String>,
pub input_amount: Option<String>,
pub output_mint: Option<String>,
pub output_amount: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenBalance {
pub amount: String,
pub ui_amount: f64,
pub slot: u64,
pub is_frozen: bool,
}
pub type TokenBalancesResponse = HashMap<String, TokenBalance>;
#[derive(Debug, Serialize, Deserialize)]
pub struct Shield {
pub warnings: HashMap<String, Vec<Warning>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Warning {
#[serde(rename = "type")]
pub warning_type: String,
pub message: String,
pub severity: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Router {
pub id: String,
pub name: String,
pub icon: String,
}