1use std::fmt::Display;
2
3use alloy_network::TransactionBuilder;
4use alloy_primitives::{Address, U256, hex};
5use alloy_rpc_types::TransactionRequest;
6use serde::{Deserialize, Serialize};
7
8pub const ASSEMBLE_URL: &str = "https://api.odos.xyz/sor/assemble";
9
10#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
12#[serde(rename_all = "camelCase")]
13pub struct AssembleRequest {
14 pub user_addr: String,
15 pub path_id: String,
16 pub simulate: bool,
17 pub receiver: Option<Address>,
18}
19
20impl Display for AssembleRequest {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(
23 f,
24 "AssembleRequest {{ user_addr: {}, path_id: {}, simulate: {}, receiver: {} }}",
25 self.user_addr,
26 self.path_id,
27 self.simulate,
28 self.receiver
29 .as_ref()
30 .map_or("None".to_string(), |s| s.to_string())
31 )
32 }
33}
34
35#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
37#[serde(rename_all = "camelCase")]
38pub struct AssemblyResponse {
39 pub transaction: TransactionData,
40 pub simulation: Option<Simulation>,
41}
42
43impl Display for AssemblyResponse {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(
46 f,
47 "AssemblyResponse {{ transaction: {}, simulation: {} }}",
48 self.transaction,
49 self.simulation
50 .as_ref()
51 .map_or("None".to_string(), |s| s.to_string())
52 )
53 }
54}
55
56#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
58#[serde(rename_all = "camelCase")]
59pub struct TransactionData {
60 pub to: Address,
61 pub from: Address,
62 pub data: String,
63 pub value: String,
64 pub gas: i128,
65 pub gas_price: u128,
66 pub chain_id: u64,
67 pub nonce: u64,
68}
69
70impl TryFrom<TransactionData> for TransactionRequest {
72 type Error = hex::FromHexError;
73
74 fn try_from(data: TransactionData) -> Result<Self, Self::Error> {
75 let input = hex::decode(&data.data)?;
76 let value = parse_value(&data.value);
77
78 Ok(TransactionRequest::default()
79 .with_input(input)
80 .with_value(value))
81 }
82}
83
84impl Display for TransactionData {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(
87 f,
88 "TransactionData {{ to: {}, from: {}, data: {}, value: {}, gas: {}, gas_price: {}, chain_id: {}, nonce: {} }}",
89 self.to,
90 self.from,
91 self.data,
92 self.value,
93 self.gas,
94 self.gas_price,
95 self.chain_id,
96 self.nonce
97 )
98 }
99}
100
101#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
103#[serde(rename_all = "camelCase")]
104pub struct Simulation {
105 is_success: bool,
106 amounts_out: Vec<String>,
107 gas_estimate: i64,
108 simulation_error: SimulationError,
109}
110
111impl Simulation {
112 pub fn is_success(&self) -> bool {
113 self.is_success
114 }
115
116 pub fn error_message(&self) -> &str {
117 &self.simulation_error.error_message
118 }
119}
120
121impl Display for Simulation {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(
124 f,
125 "Simulation {{ is_success: {}, amounts_out: {:?}, gas_estimate: {}, simulation_error: {} }}",
126 self.is_success,
127 self.amounts_out,
128 self.gas_estimate,
129 self.simulation_error.error_message
130 )
131 }
132}
133
134#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
136#[serde(rename_all = "camelCase")]
137pub struct SimulationError {
138 r#type: String,
139 error_message: String,
140}
141
142impl SimulationError {
143 pub fn error_message(&self) -> &str {
144 &self.error_message
145 }
146}
147
148impl Display for SimulationError {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 write!(f, "Simulation error: {}", self.error_message)
151 }
152}
153
154pub fn parse_value(value: &str) -> U256 {
155 if value == "0" {
156 return U256::ZERO;
157 }
158
159 U256::from_str_radix(value, 10).unwrap_or_else(|_| {
160 let value = if let Some(value) = value.strip_prefix("0x") {
162 value
163 } else {
164 value
165 };
166 U256::from_str_radix(value, 16).unwrap_or(U256::ZERO)
167 })
168}