1use serde::{Deserialize, Serialize};
2
3use crate::{
4 error::SdkErr,
5 meta::swappers::{SwapperMeta, SwapperType},
6};
7
8#[derive(Serialize, Deserialize, Debug)]
9#[serde(rename_all = "camelCase")]
10pub struct Token {
11 pub blockchain: String,
12 pub chain_id: Option<String>,
13 pub address: Option<String>,
14 pub symbol: String,
15 pub name: Option<String>,
16 pub decimals: u32,
17 pub image: String,
18 pub blockchain_image: String,
19 pub usd_price: Option<f64>,
20 pub is_popular: bool,
21}
22
23#[derive(Serialize, Deserialize, Debug, Clone)]
24pub struct Asset {
25 pub blockchain: String,
26 pub address: Option<String>,
27 pub symbol: String,
28}
29
30#[derive(Serialize, Deserialize, Debug)]
31#[serde(rename_all = "camelCase")]
32pub struct QuoteRequest {
33 pub from: Asset,
34 pub to: Asset,
35 pub amount: String,
36 pub swappers: Option<Vec<String>>,
37 pub swappers_exclude: Option<bool>,
38 pub swapper_groups: Option<Vec<String>>,
39 pub swappers_groups_exclude: Option<bool>,
40 pub messaging_protocols: Option<Vec<String>>,
41 pub source_contract: Option<String>,
42 pub destination_contract: Option<String>,
43 pub im_message: Option<String>,
44 pub contract_call: Option<bool>,
45}
46
47impl QuoteRequest {
48 pub fn into_qs(&self) -> Result<String, SdkErr> {
49 let from = match self.from.address.clone() {
50 None => format!("{}.{}", self.from.blockchain, self.from.symbol),
51 Some(address) => format!("{}.{}--{}", self.from.blockchain, self.from.symbol, address),
52 };
53 let to = match self.to.address.clone() {
54 None => format!("{}.{}", self.to.blockchain, self.to.symbol),
55 Some(address) => format!("{}.{}--{}", self.to.blockchain, self.to.symbol, address),
56 };
57
58 let request = QuoteRequestQs {
59 from,
60 to,
61 amount: self.amount.clone(),
62 contract_call: self.contract_call,
63 destination_contract: self.destination_contract.clone(),
64 im_message: self.im_message.clone(),
65 source_contract: self.source_contract.clone(),
66 messaging_protocols: match self.messaging_protocols.clone() {
67 Some(protocols) => Some(protocols.join(",")),
68 None => None,
69 },
70 swapper_groups: match self.swapper_groups.clone() {
71 Some(groups) => Some(groups.join(",")),
72 None => None,
73 },
74 swappers: match self.swappers.clone() {
75 Some(swappers) => Some(swappers.join(",")),
76 None => None,
77 },
78 swappers_exclude: self.swappers_exclude,
79 swappers_groups_exclude: self.swappers_groups_exclude,
80 };
81
82 let qs = serde_urlencoded::to_string(request)?;
83
84 Ok(qs)
85 }
86}
87
88#[derive(Serialize, Deserialize, Debug)]
89#[serde(rename_all = "camelCase")]
90struct QuoteRequestQs {
91 from: String,
92 to: String,
93 amount: String,
94 swappers: Option<String>,
95 swappers_exclude: Option<bool>,
96 swapper_groups: Option<String>,
97 swappers_groups_exclude: Option<bool>,
98 messaging_protocols: Option<String>,
99 source_contract: Option<String>,
100 destination_contract: Option<String>,
101 im_message: Option<String>,
102 contract_call: Option<bool>,
103}
104
105#[derive(Deserialize, Debug)]
106#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
107pub enum RoutingResultType {
108 Ok,
109 HighImpact,
110 NoRoute,
111 InputLimitIssue,
112}
113
114#[derive(Deserialize, Debug)]
115#[serde(rename_all = "camelCase")]
116pub struct QuoteResponse {
117 pub request_id: String,
118 pub result_type: RoutingResultType,
119 pub route: Option<QuoteSimulationResult>,
120 pub error: Option<String>,
121}
122
123#[derive(Deserialize, Debug)]
124#[serde(rename_all = "camelCase")]
125pub struct QuoteSimulationResult {
126 pub from: Token,
127 pub to: Token,
128 pub output_amount: String,
129 pub output_amount_min: String,
130 pub output_amount_usd: Option<f64>,
131 pub swapper: SwapperMeta,
132 pub path: Option<Vec<QuotePath>>,
133 pub fee: Vec<SwapFee>,
134 pub fee_usd: Option<f64>,
135 pub amount_restriction: Option<AmountRestriction>,
136 pub estimated_time_in_seconds: u64,
137}
138
139#[derive(Deserialize, Debug)]
140pub enum AmountRestrictionTypes {
141 INCLUSIVE,
142 EXCLUSIVE,
143}
144
145#[derive(Deserialize, Debug)]
146pub struct AmountRestriction {
147 pub min: Option<String>,
148 pub max: Option<String>,
149 pub r#type: AmountRestrictionTypes,
150}
151
152#[derive(Deserialize, Debug)]
153#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
154pub enum ExpenseType {
155 FromSourceWallet,
156 DecreaseFromOutput,
157 FromDestinationWallet,
158}
159
160#[derive(Deserialize, Debug)]
161#[serde(rename_all = "camelCase")]
162pub struct SwapFee {
163 pub name: String,
164 pub token: Token,
165 pub expense_type: ExpenseType,
166 pub amount: String,
167}
168
169#[derive(Deserialize, Debug)]
170#[serde(rename_all = "camelCase")]
171pub struct QuotePath {
172 pub from: Token,
173 pub to: Token,
174 pub swapper_type: SwapperType,
175 pub swapper: SwapperMeta,
176 pub expected_output: String,
177 pub estimated_time_in_seconds: u64,
178}