1use std::{fmt::Debug, marker::PhantomData};
6
7use alloy_contract::CallBuilder;
8use alloy_network::{Ethereum, Network};
9use alloy_primitives::{Address, Bytes, U256};
10use alloy_provider::Provider;
11use alloy_sol_types::{sol, SolInterface};
12
13use crate::SwapInputs;
14
15use IOdosRouterV3::{inputTokenInfo, outputTokenInfo, swapReferralInfo, swapTokenInfo};
17use OdosV3Router::{swapCall, OdosV3RouterCalls, OdosV3RouterInstance, Swap, SwapMulti};
18
19#[derive(Debug, Clone)]
51pub struct V3Router<N: Network = Ethereum, P: Provider<N> = alloy_provider::RootProvider<N>> {
52 instance: OdosV3RouterInstance<P, N>,
53}
54
55impl<N: Network, P: Provider<N>> V3Router<N, P> {
56 pub fn new(address: Address, provider: P) -> Self {
58 Self {
59 instance: OdosV3RouterInstance::new(address, provider),
60 }
61 }
62
63 pub async fn owner(&self) -> Result<Address, alloy_contract::Error> {
65 self.instance.owner().call().await
66 }
67
68 pub async fn liquidator_address(&self) -> Result<Address, alloy_contract::Error> {
70 self.instance.liquidatorAddress().call().await
71 }
72
73 pub fn build_swap_router_funds_call(
75 &self,
76 input_token_info: inputTokenInfo,
77 output_token_info: outputTokenInfo,
78 inputs: &SwapInputs,
79 from: Address,
80 ) -> CallBuilder<&P, PhantomData<OdosV3Router::swapRouterFundsCall>, N> {
81 self.instance
82 .swapRouterFunds(
83 vec![input_token_info],
84 vec![output_token_info],
85 inputs.path_definition().clone(),
86 inputs.executor(),
87 )
88 .from(from)
89 }
90
91 pub fn transfer_router_funds(
93 &self,
94 from: Address,
95 token: Address,
96 amount: U256,
97 output_recipient: Address,
98 ) -> CallBuilder<&P, PhantomData<OdosV3Router::transferRouterFundsCall>, N> {
99 self.instance
100 .transferRouterFunds(vec![token], vec![amount], output_recipient)
101 .from(from)
102 }
103
104 pub fn transfer_router_funds_calldata(
106 &self,
107 from: Address,
108 token: Address,
109 amount: U256,
110 output_recipient: Address,
111 ) -> Vec<u8> {
112 self.transfer_router_funds(from, token, amount, output_recipient)
113 .calldata()
114 .to_vec()
115 }
116}
117
118sol!(
120 #[allow(clippy::too_many_arguments)]
121 #[allow(missing_docs)]
122 #[sol(rpc)]
123 OdosV3Router,
124 "abis/v3.json"
125);
126
127impl Debug for OdosV3Router::swapRouterFundsReturn {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, "amountsOut: {:?}", self.amountsOut)
130 }
131}
132
133impl Debug for inputTokenInfo {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.debug_struct("inputTokenInfo")
136 .field("tokenAddress", &self.tokenAddress)
137 .field("amountIn", &self.amountIn)
138 .field("receiver", &self.receiver)
139 .finish()
140 }
141}
142
143impl Debug for outputTokenInfo {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.debug_struct("outputTokenInfo")
146 .field("tokenAddress", &self.tokenAddress)
147 .field("amountQuote", &self.amountQuote)
148 .field("amountMin", &self.amountMin)
149 .field("receiver", &self.receiver)
150 .finish()
151 }
152}
153
154impl Debug for swapCall {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 f.debug_struct("swapCall")
157 .field("executor", &self.executor)
158 .field("pathDefinition", &self.pathDefinition)
159 .field("referralInfo", &self.referralInfo)
160 .field("tokenInfo", &self.tokenInfo)
161 .finish()
162 }
163}
164
165impl Debug for swapReferralInfo {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("swapReferralInfo")
168 .field("code", &self.code)
169 .field("fee", &self.fee)
170 .field("feeRecipient", &self.feeRecipient)
171 .finish()
172 }
173}
174
175impl Debug for SwapMulti {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 f.debug_struct("SwapMulti")
178 .field("sender", &self.sender)
179 .field("amountsIn", &self.amountsIn)
180 .field("tokensIn", &self.tokensIn)
181 .field("amountsOut", &self.amountsOut)
182 .field("tokensOut", &self.tokensOut)
183 .finish()
184 }
185}
186
187impl Debug for Swap {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 f.debug_struct("Swap")
190 .field("sender", &self.sender)
191 .field("inputAmount", &self.inputAmount)
192 .field("inputToken", &self.inputToken)
193 .field("amountOut", &self.amountOut)
194 .field("outputToken", &self.outputToken)
195 .field("slippage", &self.slippage)
196 .field("referralCode", &self.referralCode)
197 .finish()
198 }
199}
200
201impl Debug for swapTokenInfo {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 f.debug_struct("swapTokenInfo")
204 .field("inputToken", &self.inputToken)
205 .field("inputAmount", &self.inputAmount)
206 .field("inputReceiver", &self.inputReceiver)
207 .field("outputToken", &self.outputToken)
208 .field("outputQuote", &self.outputQuote)
209 .field("outputMin", &self.outputMin)
210 .field("outputReceiver", &self.outputReceiver)
211 .finish()
212 }
213}
214
215impl TryFrom<&Bytes> for OdosV3RouterCalls {
216 type Error = alloy_sol_types::Error;
217
218 fn try_from(input: &Bytes) -> Result<Self, Self::Error> {
219 OdosV3RouterCalls::abi_decode(input)
220 }
221}