1use alloy_network::Network;
36use alloy_primitives::{Address, B256, I256, U256};
37use alloy_provider::Provider;
38use alloy_rpc_types::{BlockNumberOrTag, Filter, Log};
39use alloy_sol_types::SolEvent;
40
41#[cfg(feature = "v2")]
42use crate::v2_router::OdosV2Router;
43#[cfg(feature = "v3")]
44use crate::v3_router::OdosV3Router;
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct SwapEvent {
49 pub sender: Address,
51 pub input_token: Address,
53 pub input_amount: U256,
55 pub output_token: Address,
57 pub amount_out: U256,
59 pub slippage: I256,
61 pub referral_code: u64,
63 pub block_number: Option<u64>,
65 pub transaction_hash: Option<B256>,
67 pub log_index: Option<u64>,
69}
70
71#[derive(Debug, Clone)]
87pub struct SwapEventFilter {
88 router_address: Address,
89 from_block: Option<BlockNumberOrTag>,
90 to_block: Option<BlockNumberOrTag>,
91 sender: Option<Address>,
92}
93
94impl SwapEventFilter {
95 pub fn new(router_address: Address) -> Self {
97 Self {
98 router_address,
99 from_block: None,
100 to_block: None,
101 sender: None,
102 }
103 }
104
105 pub fn from_block(mut self, block: u64) -> Self {
107 self.from_block = Some(BlockNumberOrTag::Number(block));
108 self
109 }
110
111 pub fn from_latest(mut self) -> Self {
113 self.from_block = Some(BlockNumberOrTag::Latest);
114 self
115 }
116
117 pub fn to_block(mut self, block: u64) -> Self {
119 self.to_block = Some(BlockNumberOrTag::Number(block));
120 self
121 }
122
123 pub fn to_latest(mut self) -> Self {
125 self.to_block = Some(BlockNumberOrTag::Latest);
126 self
127 }
128
129 pub fn sender(mut self, sender: Address) -> Self {
131 self.sender = Some(sender);
132 self
133 }
134
135 #[cfg(feature = "v2")]
137 pub fn build_v2_filter(&self) -> Filter {
138 let mut filter = Filter::new()
139 .address(self.router_address)
140 .event_signature(OdosV2Router::Swap::SIGNATURE_HASH);
141
142 if let Some(from) = self.from_block {
143 filter = filter.from_block(from);
144 }
145
146 if let Some(to) = self.to_block {
147 filter = filter.to_block(to);
148 }
149
150 if let Some(sender) = self.sender {
152 filter = filter.topic1(sender.into_word());
153 }
154
155 filter
156 }
157
158 #[cfg(feature = "v3")]
160 pub fn build_v3_filter(&self) -> Filter {
161 let mut filter = Filter::new()
162 .address(self.router_address)
163 .event_signature(OdosV3Router::Swap::SIGNATURE_HASH);
164
165 if let Some(from) = self.from_block {
166 filter = filter.from_block(from);
167 }
168
169 if let Some(to) = self.to_block {
170 filter = filter.to_block(to);
171 }
172
173 if let Some(sender) = self.sender {
174 filter = filter.topic1(sender.into_word());
175 }
176
177 filter
178 }
179
180 #[cfg(feature = "v2")]
182 pub async fn get_v2_events<N, P>(
183 &self,
184 provider: &P,
185 ) -> Result<Vec<SwapEvent>, alloy_transport::TransportError>
186 where
187 N: Network,
188 P: Provider<N>,
189 {
190 let filter = self.build_v2_filter();
191 let logs = provider.get_logs(&filter).await?;
192
193 Ok(logs
194 .into_iter()
195 .filter_map(|log| Self::decode_v2_swap_log(&log))
196 .collect())
197 }
198
199 #[cfg(feature = "v3")]
201 pub async fn get_v3_events<N, P>(
202 &self,
203 provider: &P,
204 ) -> Result<Vec<SwapEvent>, alloy_transport::TransportError>
205 where
206 N: Network,
207 P: Provider<N>,
208 {
209 let filter = self.build_v3_filter();
210 let logs = provider.get_logs(&filter).await?;
211
212 Ok(logs
213 .into_iter()
214 .filter_map(|log| Self::decode_v3_swap_log(&log))
215 .collect())
216 }
217
218 #[cfg(feature = "v2")]
220 fn decode_v2_swap_log(log: &Log) -> Option<SwapEvent> {
221 let decoded = OdosV2Router::Swap::decode_log(&log.inner).ok()?;
222 Some(SwapEvent {
223 sender: decoded.data.sender,
224 input_token: decoded.data.inputToken,
225 input_amount: decoded.data.inputAmount,
226 output_token: decoded.data.outputToken,
227 amount_out: decoded.data.amountOut,
228 slippage: decoded.data.slippage,
229 referral_code: u64::from(decoded.data.referralCode),
230 block_number: log.block_number,
231 transaction_hash: log.transaction_hash,
232 log_index: log.log_index,
233 })
234 }
235
236 #[cfg(feature = "v3")]
238 fn decode_v3_swap_log(log: &Log) -> Option<SwapEvent> {
239 let decoded = OdosV3Router::Swap::decode_log(&log.inner).ok()?;
240 Some(SwapEvent {
241 sender: decoded.data.sender,
242 input_token: decoded.data.inputToken,
243 input_amount: decoded.data.inputAmount,
244 output_token: decoded.data.outputToken,
245 amount_out: decoded.data.amountOut,
246 slippage: decoded.data.slippage,
247 referral_code: decoded.data.referralCode,
248 block_number: log.block_number,
249 transaction_hash: log.transaction_hash,
250 log_index: log.log_index,
251 })
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
257pub struct SwapMultiEvent {
258 pub sender: Address,
260 pub tokens_in: Vec<Address>,
262 pub amounts_in: Vec<U256>,
264 pub tokens_out: Vec<Address>,
266 pub amounts_out: Vec<U256>,
268 pub block_number: Option<u64>,
270 pub transaction_hash: Option<B256>,
272 pub log_index: Option<u64>,
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use alloy_primitives::address;
280
281 #[test]
282 fn test_swap_event_filter_builder() {
283 let router = address!("cf5540fffcdc3d510b18bfca6d2b9987b0772559");
284 let sender = address!("742d35Cc6634C0532925a3b8D35f3e7a5edD29c0");
285
286 let filter = SwapEventFilter::new(router)
287 .from_block(18_000_000)
288 .to_block(18_100_000)
289 .sender(sender);
290
291 assert_eq!(filter.router_address, router);
292 assert_eq!(
293 filter.from_block,
294 Some(BlockNumberOrTag::Number(18_000_000))
295 );
296 assert_eq!(filter.to_block, Some(BlockNumberOrTag::Number(18_100_000)));
297 assert_eq!(filter.sender, Some(sender));
298 }
299
300 #[test]
301 fn test_swap_event_filter_latest_blocks() {
302 let router = address!("cf5540fffcdc3d510b18bfca6d2b9987b0772559");
303
304 let filter = SwapEventFilter::new(router).from_latest().to_latest();
305
306 assert_eq!(filter.from_block, Some(BlockNumberOrTag::Latest));
307 assert_eq!(filter.to_block, Some(BlockNumberOrTag::Latest));
308 }
309
310 #[cfg(feature = "v3")]
311 #[test]
312 fn test_build_v3_filter() {
313 let router = address!("cf5540fffcdc3d510b18bfca6d2b9987b0772559");
314
315 let filter = SwapEventFilter::new(router)
316 .from_block(18_000_000)
317 .build_v3_filter();
318
319 let _ = filter;
322 }
323}