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