jupiter_swap_api_client/
quote.rs

1//! Quote data structure for quoting and quote response
2//!
3
4use 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")]
15/// Swap information of each Swap occurred in the route paths
16pub 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    /// An estimation of the input amount into the AMM
25    #[serde(with = "field_as_string")]
26    pub in_amount: u64,
27    /// An estimation of the output amount into the AMM
28    #[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    /// The amount to swap, have to factor in the token decimals.
68    #[serde(with = "field_as_string")]
69    pub amount: u64,
70    /// (ExactIn or ExactOut) Defaults to ExactIn.
71    /// ExactOut is for supporting use cases where you need an exact token amount, like payments.
72    /// In this case the slippage is on the input token.
73    pub swap_mode: Option<SwapMode>,
74    /// Allowed slippage in basis points
75    pub slippage_bps: u16,
76    /// Default is false.
77    /// By setting this to true, our API will suggest smart slippage info that you can use.
78    /// slippageBps is what we suggest you to use. Additionally, you should check out max_auto_slippage_bps and auto_slippage_collision_usd_value.
79    pub auto_slippage: Option<bool>,
80    /// The max amount of slippage in basis points that you are willing to accept for auto slippage.
81    pub max_auto_slippage_bps: Option<u16>,
82    pub compute_auto_slippage: bool,
83    /// The max amount of USD value that you are willing to accept for auto slippage.
84    pub auto_slippage_collision_usd_value: Option<u32>,
85    /// Quote with a greater amount to find the route to minimize slippage
86    pub minimize_slippage: Option<bool>,
87    /// Platform fee in basis points
88    pub platform_fee_bps: Option<u8>,
89    pub dexes: Option<Dexes>,
90    pub excluded_dexes: Option<Dexes>,
91    /// Quote only direct routes
92    pub only_direct_routes: Option<bool>,
93    /// Quote fit into legacy transaction
94    pub as_legacy_transaction: Option<bool>,
95    /// Restrict intermediate tokens to a top token set that has stable liquidity.
96    /// This will help to ease potential high slippage error rate when swapping with minimal impact on pricing.
97    pub restrict_intermediate_tokens: Option<bool>,
98    /// Find a route given a maximum number of accounts involved,
99    /// this might dangerously limit routing ending up giving a bad price.
100    /// The max is an estimation and not the exact count
101    pub max_accounts: Option<usize>,
102    /// Quote type to be used for routing, switches the algorithm
103    pub quote_type: Option<String>,
104    /// Extra args which are quote type specific to allow controlling settings from the top level
105    pub quote_args: Option<HashMap<String, String>>,
106    /// enable only full liquid markets as intermediate tokens
107    pub prefer_liquid_dexes: Option<bool>,
108    /// Use the compute unit score to pick a route
109    pub compute_unit_score: Option<ComputeUnitScore>,
110    /// Routing constraints
111    pub routing_constraints: Option<String>,
112    /// Token category based intermediates token
113    pub token_category_based_intermediate_tokens: Option<bool>,
114}
115
116// Essentially the same as QuoteRequest, but without the extra args
117// as we pass the extra args separately
118#[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    /// The amount to swap, have to factor in the token decimals.
126    #[serde(with = "field_as_string")]
127    pub amount: u64,
128    /// (ExactIn or ExactOut) Defaults to ExactIn.
129    /// ExactOut is for supporting use cases where you need an exact token amount, like payments.
130    /// In this case the slippage is on the input token.
131    pub swap_mode: Option<SwapMode>,
132    /// Allowed slippage in basis points
133    pub slippage_bps: u16,
134    /// Default is false.
135    /// By setting this to true, our API will suggest smart slippage info that you can use.
136    /// slippageBps is what we suggest you to use. Additionally, you should check out max_auto_slippage_bps and auto_slippage_collision_usd_value.
137    pub auto_slippage: Option<bool>,
138    /// The max amount of slippage in basis points that you are willing to accept for auto slippage.
139    pub max_auto_slippage_bps: Option<u16>,
140    pub compute_auto_slippage: bool,
141    /// The max amount of USD value that you are willing to accept for auto slippage.
142    pub auto_slippage_collision_usd_value: Option<u32>,
143    /// Quote with a greater amount to find the route to minimize slippage
144    pub minimize_slippage: Option<bool>,
145    /// Platform fee in basis points
146    pub platform_fee_bps: Option<u8>,
147    pub dexes: Option<Dexes>,
148    pub excluded_dexes: Option<Dexes>,
149    /// Quote only direct routes
150    pub only_direct_routes: Option<bool>,
151    /// Quote fit into legacy transaction
152    pub as_legacy_transaction: Option<bool>,
153    /// Restrict intermediate tokens to a top token set that has stable liquidity.
154    /// This will help to ease potential high slippage error rate when swapping with minimal impact on pricing.
155    pub restrict_intermediate_tokens: Option<bool>,
156    /// Find a route given a maximum number of accounts involved,
157    /// this might dangerously limit routing ending up giving a bad price.
158    /// The max is an estimation and not the exact count
159    pub max_accounts: Option<usize>,
160    // Quote type to be used for routing, switches the algorithm
161    pub quote_type: Option<String>,
162    // enable only full liquid markets as intermediate tokens
163    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
192/// Comma delimited list of dex labels
193type 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    /// Not used by build transaction
215    #[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}