1use std::{collections::HashMap, str::FromStr};
5
6use crate::route_plan_with_metadata::RoutePlanWithMetadata;
7use crate::serde_helpers::field_as_string;
8use anyhow::{anyhow, Error};
9use rust_decimal::Decimal;
10use serde::{Deserialize, Serialize};
11use solana_sdk::pubkey::Pubkey;
12
13#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
14#[serde(rename_all = "camelCase")]
15pub struct SwapInfo {
17 #[serde(with = "field_as_string")]
18 pub amm_key: Pubkey,
19 pub label: String,
20 #[serde(with = "field_as_string")]
21 pub input_mint: Pubkey,
22 #[serde(with = "field_as_string")]
23 pub output_mint: Pubkey,
24 #[serde(with = "field_as_string")]
26 pub in_amount: u64,
27 #[serde(with = "field_as_string")]
29 pub out_amount: u64,
30 #[serde(with = "field_as_string")]
31 pub fee_amount: u64,
32 #[serde(with = "field_as_string")]
33 pub fee_mint: Pubkey,
34}
35
36#[derive(Serialize, Deserialize, Default, PartialEq, Clone, Debug)]
37pub enum SwapMode {
38 #[default]
39 ExactIn,
40 ExactOut,
41}
42
43impl FromStr for SwapMode {
44 type Err = Error;
45
46 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
47 match s {
48 "ExactIn" => Ok(Self::ExactIn),
49 "ExactOut" => Ok(Self::ExactOut),
50 _ => Err(anyhow!("{} is not a valid SwapMode", s)),
51 }
52 }
53}
54
55#[derive(Serialize, Debug, Clone, Default)]
56pub struct ComputeUnitScore {
57 pub max_penalty_bps: Option<f64>,
58}
59
60#[derive(Serialize, Debug, Default, Clone)]
61#[serde(rename_all = "camelCase")]
62pub struct QuoteRequest {
63 #[serde(with = "field_as_string")]
64 pub input_mint: Pubkey,
65 #[serde(with = "field_as_string")]
66 pub output_mint: Pubkey,
67 #[serde(with = "field_as_string")]
69 pub amount: u64,
70 pub swap_mode: Option<SwapMode>,
74 pub slippage_bps: u16,
76 pub auto_slippage: Option<bool>,
80 pub max_auto_slippage_bps: Option<u16>,
82 pub compute_auto_slippage: bool,
83 pub auto_slippage_collision_usd_value: Option<u32>,
85 pub minimize_slippage: Option<bool>,
87 pub platform_fee_bps: Option<u8>,
89 pub dexes: Option<Dexes>,
90 pub excluded_dexes: Option<Dexes>,
91 pub only_direct_routes: Option<bool>,
93 pub as_legacy_transaction: Option<bool>,
95 pub restrict_intermediate_tokens: Option<bool>,
98 pub max_accounts: Option<usize>,
102 pub quote_type: Option<String>,
104 pub quote_args: Option<HashMap<String, String>>,
106 pub prefer_liquid_dexes: Option<bool>,
108 pub compute_unit_score: Option<ComputeUnitScore>,
110 pub routing_constraints: Option<String>,
112 pub token_category_based_intermediate_tokens: Option<bool>,
114}
115
116#[derive(Serialize, Debug, Default, Clone)]
119#[serde(rename_all = "camelCase")]
120pub struct InternalQuoteRequest {
121 #[serde(with = "field_as_string")]
122 pub input_mint: Pubkey,
123 #[serde(with = "field_as_string")]
124 pub output_mint: Pubkey,
125 #[serde(with = "field_as_string")]
127 pub amount: u64,
128 pub swap_mode: Option<SwapMode>,
132 pub slippage_bps: u16,
134 pub auto_slippage: Option<bool>,
138 pub max_auto_slippage_bps: Option<u16>,
140 pub compute_auto_slippage: bool,
141 pub auto_slippage_collision_usd_value: Option<u32>,
143 pub minimize_slippage: Option<bool>,
145 pub platform_fee_bps: Option<u8>,
147 pub dexes: Option<Dexes>,
148 pub excluded_dexes: Option<Dexes>,
149 pub only_direct_routes: Option<bool>,
151 pub as_legacy_transaction: Option<bool>,
153 pub restrict_intermediate_tokens: Option<bool>,
156 pub max_accounts: Option<usize>,
160 pub quote_type: Option<String>,
162 pub prefer_liquid_dexes: Option<bool>,
164}
165
166impl From<QuoteRequest> for InternalQuoteRequest {
167 fn from(request: QuoteRequest) -> Self {
168 InternalQuoteRequest {
169 input_mint: request.input_mint,
170 output_mint: request.output_mint,
171 amount: request.amount,
172 swap_mode: request.swap_mode,
173 slippage_bps: request.slippage_bps,
174 auto_slippage: request.auto_slippage,
175 max_auto_slippage_bps: request.max_auto_slippage_bps,
176 compute_auto_slippage: request.compute_auto_slippage,
177 auto_slippage_collision_usd_value: request.auto_slippage_collision_usd_value,
178 minimize_slippage: request.minimize_slippage,
179 platform_fee_bps: request.platform_fee_bps,
180 dexes: request.dexes,
181 excluded_dexes: request.excluded_dexes,
182 only_direct_routes: request.only_direct_routes,
183 as_legacy_transaction: request.as_legacy_transaction,
184 restrict_intermediate_tokens: request.restrict_intermediate_tokens,
185 max_accounts: request.max_accounts,
186 quote_type: request.quote_type,
187 prefer_liquid_dexes: request.prefer_liquid_dexes,
188 }
189 }
190}
191
192type Dexes = String;
194
195#[derive(Serialize, Deserialize, Clone, Debug)]
196#[serde(rename_all = "camelCase")]
197pub struct PlatformFee {
198 #[serde(with = "field_as_string")]
199 pub amount: u64,
200 pub fee_bps: u8,
201}
202
203#[derive(Serialize, Deserialize, Clone, Debug)]
204#[serde(rename_all = "camelCase")]
205pub struct QuoteResponse {
206 #[serde(with = "field_as_string")]
207 pub input_mint: Pubkey,
208 #[serde(with = "field_as_string")]
209 pub in_amount: u64,
210 #[serde(with = "field_as_string")]
211 pub output_mint: Pubkey,
212 #[serde(with = "field_as_string")]
213 pub out_amount: u64,
214 #[serde(with = "field_as_string")]
216 pub other_amount_threshold: u64,
217 pub swap_mode: SwapMode,
218 pub slippage_bps: u16,
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub computed_auto_slippage: Option<u16>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub uses_quote_minimizing_slippage: Option<bool>,
223 pub platform_fee: Option<PlatformFee>,
224 pub price_impact_pct: Decimal,
225 pub route_plan: RoutePlanWithMetadata,
226 #[serde(default)]
227 pub context_slot: u64,
228 #[serde(default)]
229 pub time_taken: f64,
230}