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