nautilus_blockchain/exchanges/
extended.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{ops::Deref, sync::Arc};
17
18use nautilus_model::defi::{
19    dex::{Dex, SharedDex},
20    rpc::RpcLog,
21};
22
23use crate::{
24    events::{
25        burn::BurnEvent, collect::CollectEvent, flash::FlashEvent, initialize::InitializeEvent,
26        mint::MintEvent, pool_created::PoolCreatedEvent, swap::SwapEvent,
27    },
28    hypersync::HypersyncLog,
29};
30
31/// Extended DEX wrapper that adds provider-specific event parsing capabilities to the domain `Dex` model.
32#[derive(Debug, Clone)]
33pub struct DexExtended {
34    /// The core domain Dex object being extended.
35    pub dex: SharedDex,
36    // === HyperSync parsers ===
37    /// Function to parse pool creation events from HyperSync logs.
38    pub parse_pool_created_event_hypersync_fn:
39        Option<fn(HypersyncLog) -> anyhow::Result<PoolCreatedEvent>>,
40    /// Function to parse initialize events from HyperSync logs.
41    pub parse_initialize_event_hypersync_fn:
42        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<InitializeEvent>>,
43    /// Function to parse swap events from HyperSync logs.
44    pub parse_swap_event_hypersync_fn:
45        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<SwapEvent>>,
46    /// Function to parse mint events from HyperSync logs.
47    pub parse_mint_event_hypersync_fn:
48        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<MintEvent>>,
49    /// Function to parse burn events from HyperSync logs.
50    pub parse_burn_event_hypersync_fn:
51        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<BurnEvent>>,
52    /// Function to parse collect events from HyperSync logs.
53    pub parse_collect_event_hypersync_fn:
54        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<CollectEvent>>,
55    /// Function to parse flash events from HyperSync logs.
56    pub parse_flash_event_hypersync_fn:
57        Option<fn(SharedDex, HypersyncLog) -> anyhow::Result<FlashEvent>>,
58    // === RPC parsers (hex-decode, standard Ethereum format) ===
59    /// Function to parse pool creation events from RPC logs.
60    pub parse_pool_created_event_rpc_fn: Option<fn(&RpcLog) -> anyhow::Result<PoolCreatedEvent>>,
61    /// Function to parse initialize events from RPC logs.
62    pub parse_initialize_event_rpc_fn:
63        Option<fn(SharedDex, &RpcLog) -> anyhow::Result<InitializeEvent>>,
64    /// Function to parse swap events from RPC logs.
65    pub parse_swap_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<SwapEvent>>,
66    /// Function to parse mint events from RPC logs.
67    pub parse_mint_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<MintEvent>>,
68    /// Function to parse burn events from RPC logs.
69    pub parse_burn_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<BurnEvent>>,
70    /// Function to parse collect events from RPC logs.
71    pub parse_collect_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<CollectEvent>>,
72    /// Function to parse flash events from RPC logs.
73    pub parse_flash_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<FlashEvent>>,
74}
75
76impl DexExtended {
77    /// Creates a new [`DexExtended`] wrapper around a domain `Dex` object.
78    #[must_use]
79    pub fn new(dex: Dex) -> Self {
80        Self {
81            dex: Arc::new(dex),
82            // HyperSync parsers
83            parse_pool_created_event_hypersync_fn: None,
84            parse_initialize_event_hypersync_fn: None,
85            parse_swap_event_hypersync_fn: None,
86            parse_mint_event_hypersync_fn: None,
87            parse_burn_event_hypersync_fn: None,
88            parse_collect_event_hypersync_fn: None,
89            parse_flash_event_hypersync_fn: None,
90            // RPC parsers
91            parse_pool_created_event_rpc_fn: None,
92            parse_initialize_event_rpc_fn: None,
93            parse_swap_event_rpc_fn: None,
94            parse_mint_event_rpc_fn: None,
95            parse_burn_event_rpc_fn: None,
96            parse_collect_event_rpc_fn: None,
97            parse_flash_event_rpc_fn: None,
98        }
99    }
100
101    // ==================== HyperSync Parser Setters ====================
102
103    /// Sets the function used to parse pool creation events from HyperSync logs.
104    pub fn set_pool_created_event_hypersync_parsing(
105        &mut self,
106        parse_fn: fn(HypersyncLog) -> anyhow::Result<PoolCreatedEvent>,
107    ) {
108        self.parse_pool_created_event_hypersync_fn = Some(parse_fn);
109    }
110
111    /// Sets the function used to parse initialize events from HyperSync logs.
112    pub fn set_initialize_event_hypersync_parsing(
113        &mut self,
114        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<InitializeEvent>,
115    ) {
116        self.parse_initialize_event_hypersync_fn = Some(parse_fn);
117    }
118
119    /// Sets the function used to parse swap events from HyperSync logs.
120    pub fn set_swap_event_hypersync_parsing(
121        &mut self,
122        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<SwapEvent>,
123    ) {
124        self.parse_swap_event_hypersync_fn = Some(parse_fn);
125    }
126
127    /// Sets the function used to parse mint events from HyperSync logs.
128    pub fn set_mint_event_hypersync_parsing(
129        &mut self,
130        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<MintEvent>,
131    ) {
132        self.parse_mint_event_hypersync_fn = Some(parse_fn);
133    }
134
135    /// Sets the function used to parse burn events from HyperSync logs.
136    pub fn set_burn_event_hypersync_parsing(
137        &mut self,
138        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<BurnEvent>,
139    ) {
140        self.parse_burn_event_hypersync_fn = Some(parse_fn);
141    }
142
143    /// Sets the function used to parse collect events from HyperSync logs.
144    pub fn set_collect_event_hypersync_parsing(
145        &mut self,
146        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<CollectEvent>,
147    ) {
148        self.parse_collect_event_hypersync_fn = Some(parse_fn);
149    }
150
151    /// Sets the function used to parse flash events from HyperSync logs.
152    pub fn set_flash_event_hypersync_parsing(
153        &mut self,
154        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<FlashEvent>,
155    ) {
156        self.parse_flash_event_hypersync_fn = Some(parse_fn);
157    }
158
159    // ==================== RPC Parser Setters ====================
160
161    /// Sets the function used to parse pool creation events from RPC logs.
162    pub fn set_pool_created_event_rpc_parsing(
163        &mut self,
164        parse_fn: fn(&RpcLog) -> anyhow::Result<PoolCreatedEvent>,
165    ) {
166        self.parse_pool_created_event_rpc_fn = Some(parse_fn);
167    }
168
169    /// Sets the function used to parse initialize events from RPC logs.
170    pub fn set_initialize_event_rpc_parsing(
171        &mut self,
172        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<InitializeEvent>,
173    ) {
174        self.parse_initialize_event_rpc_fn = Some(parse_fn);
175    }
176
177    /// Sets the function used to parse swap events from RPC logs.
178    pub fn set_swap_event_rpc_parsing(
179        &mut self,
180        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<SwapEvent>,
181    ) {
182        self.parse_swap_event_rpc_fn = Some(parse_fn);
183    }
184
185    /// Sets the function used to parse mint events from RPC logs.
186    pub fn set_mint_event_rpc_parsing(
187        &mut self,
188        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<MintEvent>,
189    ) {
190        self.parse_mint_event_rpc_fn = Some(parse_fn);
191    }
192
193    /// Sets the function used to parse burn events from RPC logs.
194    pub fn set_burn_event_rpc_parsing(
195        &mut self,
196        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<BurnEvent>,
197    ) {
198        self.parse_burn_event_rpc_fn = Some(parse_fn);
199    }
200
201    /// Sets the function used to parse collect events from RPC logs.
202    pub fn set_collect_event_rpc_parsing(
203        &mut self,
204        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<CollectEvent>,
205    ) {
206        self.parse_collect_event_rpc_fn = Some(parse_fn);
207    }
208
209    /// Sets the function used to parse flash events from RPC logs.
210    pub fn set_flash_event_rpc_parsing(
211        &mut self,
212        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<FlashEvent>,
213    ) {
214        self.parse_flash_event_rpc_fn = Some(parse_fn);
215    }
216
217    // ==================== HyperSync Parser Dispatch Methods ====================
218
219    /// Parses a pool creation event from a HyperSync log.
220    ///
221    /// # Errors
222    ///
223    /// Returns an error if the DEX does not have a HyperSync pool creation event parser defined or if parsing fails.
224    pub fn parse_pool_created_event_hypersync(
225        &self,
226        log: HypersyncLog,
227    ) -> anyhow::Result<PoolCreatedEvent> {
228        if let Some(parse_fn) = &self.parse_pool_created_event_hypersync_fn {
229            parse_fn(log)
230        } else {
231            anyhow::bail!(
232                "HyperSync parsing of pool created event is not defined in this dex: {}:{}",
233                self.dex.chain,
234                self.dex.name,
235            )
236        }
237    }
238
239    /// Parses a swap event from a HyperSync log.
240    ///
241    /// # Errors
242    ///
243    /// Returns an error if the DEX does not have a HyperSync swap event parser defined or if parsing fails.
244    pub fn parse_swap_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<SwapEvent> {
245        if let Some(parse_fn) = &self.parse_swap_event_hypersync_fn {
246            parse_fn(self.dex.clone(), log)
247        } else {
248            anyhow::bail!(
249                "HyperSync parsing of swap event is not defined in this dex: {}:{}",
250                self.dex.chain,
251                self.dex.name
252            )
253        }
254    }
255
256    /// Parses a mint event from a HyperSync log.
257    ///
258    /// # Errors
259    ///
260    /// Returns an error if the DEX does not have a HyperSync mint event parser defined or if parsing fails.
261    pub fn parse_mint_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<MintEvent> {
262        if let Some(parse_fn) = &self.parse_mint_event_hypersync_fn {
263            parse_fn(self.dex.clone(), log)
264        } else {
265            anyhow::bail!(
266                "HyperSync parsing of mint event is not defined in this dex: {}:{}",
267                self.dex.chain,
268                self.dex.name
269            )
270        }
271    }
272
273    /// Parses a burn event from a HyperSync log.
274    ///
275    /// # Errors
276    ///
277    /// Returns an error if the DEX does not have a HyperSync burn event parser defined or if parsing fails.
278    pub fn parse_burn_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<BurnEvent> {
279        if let Some(parse_fn) = &self.parse_burn_event_hypersync_fn {
280            parse_fn(self.dex.clone(), log)
281        } else {
282            anyhow::bail!(
283                "HyperSync parsing of burn event is not defined in this dex: {}:{}",
284                self.dex.chain,
285                self.dex.name
286            )
287        }
288    }
289
290    /// Parses an initialize event from a HyperSync log.
291    ///
292    /// # Errors
293    ///
294    /// Returns an error if the DEX does not have a HyperSync initialize event parser defined or if parsing fails.
295    pub fn parse_initialize_event_hypersync(
296        &self,
297        log: HypersyncLog,
298    ) -> anyhow::Result<InitializeEvent> {
299        if let Some(parse_fn) = &self.parse_initialize_event_hypersync_fn {
300            parse_fn(self.dex.clone(), log)
301        } else {
302            anyhow::bail!(
303                "HyperSync parsing of initialize event is not defined in this dex: {}:{}",
304                self.dex.chain,
305                self.dex.name
306            )
307        }
308    }
309
310    /// Parses a collect event from a HyperSync log.
311    ///
312    /// # Errors
313    ///
314    /// Returns an error if the DEX does not have a HyperSync collect event parser defined or if parsing fails.
315    pub fn parse_collect_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<CollectEvent> {
316        if let Some(parse_fn) = &self.parse_collect_event_hypersync_fn {
317            parse_fn(self.dex.clone(), log)
318        } else {
319            anyhow::bail!(
320                "HyperSync parsing of collect event is not defined in this dex: {}:{}",
321                self.dex.chain,
322                self.dex.name
323            )
324        }
325    }
326
327    /// Parses a flash event from a HyperSync log.
328    ///
329    /// # Errors
330    ///
331    /// Returns an error if the DEX does not have a HyperSync flash event parser defined or if parsing fails.
332    pub fn parse_flash_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<FlashEvent> {
333        if let Some(parse_fn) = &self.parse_flash_event_hypersync_fn {
334            parse_fn(self.dex.clone(), log)
335        } else {
336            anyhow::bail!(
337                "HyperSync parsing of flash event is not defined in this dex: {}:{}",
338                self.dex.chain,
339                self.dex.name
340            )
341        }
342    }
343
344    // ==================== RPC Parser Dispatch Methods ====================
345
346    /// Parses a pool creation event from an RPC log.
347    ///
348    /// # Errors
349    ///
350    /// Returns an error if the DEX does not have an RPC pool creation event parser defined or if parsing fails.
351    pub fn parse_pool_created_event_rpc(&self, log: &RpcLog) -> anyhow::Result<PoolCreatedEvent> {
352        if let Some(parse_fn) = &self.parse_pool_created_event_rpc_fn {
353            parse_fn(log)
354        } else {
355            anyhow::bail!(
356                "RPC parsing of pool created event is not defined in this dex: {}:{}",
357                self.dex.chain,
358                self.dex.name,
359            )
360        }
361    }
362
363    /// Parses a swap event from an RPC log.
364    ///
365    /// # Errors
366    ///
367    /// Returns an error if the DEX does not have an RPC swap event parser defined or if parsing fails.
368    pub fn parse_swap_event_rpc(&self, log: &RpcLog) -> anyhow::Result<SwapEvent> {
369        if let Some(parse_fn) = &self.parse_swap_event_rpc_fn {
370            parse_fn(self.dex.clone(), log)
371        } else {
372            anyhow::bail!(
373                "RPC parsing of swap event is not defined in this dex: {}:{}",
374                self.dex.chain,
375                self.dex.name
376            )
377        }
378    }
379
380    /// Parses a mint event from an RPC log.
381    ///
382    /// # Errors
383    ///
384    /// Returns an error if the DEX does not have an RPC mint event parser defined or if parsing fails.
385    pub fn parse_mint_event_rpc(&self, log: &RpcLog) -> anyhow::Result<MintEvent> {
386        if let Some(parse_fn) = &self.parse_mint_event_rpc_fn {
387            parse_fn(self.dex.clone(), log)
388        } else {
389            anyhow::bail!(
390                "RPC parsing of mint event is not defined in this dex: {}:{}",
391                self.dex.chain,
392                self.dex.name
393            )
394        }
395    }
396
397    /// Parses a burn event from an RPC log.
398    ///
399    /// # Errors
400    ///
401    /// Returns an error if the DEX does not have an RPC burn event parser defined or if parsing fails.
402    pub fn parse_burn_event_rpc(&self, log: &RpcLog) -> anyhow::Result<BurnEvent> {
403        if let Some(parse_fn) = &self.parse_burn_event_rpc_fn {
404            parse_fn(self.dex.clone(), log)
405        } else {
406            anyhow::bail!(
407                "RPC parsing of burn event is not defined in this dex: {}:{}",
408                self.dex.chain,
409                self.dex.name
410            )
411        }
412    }
413
414    /// Parses an initialize event from an RPC log.
415    ///
416    /// # Errors
417    ///
418    /// Returns an error if the DEX does not have an RPC initialize event parser defined or if parsing fails.
419    pub fn parse_initialize_event_rpc(&self, log: &RpcLog) -> anyhow::Result<InitializeEvent> {
420        if let Some(parse_fn) = &self.parse_initialize_event_rpc_fn {
421            parse_fn(self.dex.clone(), log)
422        } else {
423            anyhow::bail!(
424                "RPC parsing of initialize event is not defined in this dex: {}:{}",
425                self.dex.chain,
426                self.dex.name
427            )
428        }
429    }
430
431    /// Parses a collect event from an RPC log.
432    ///
433    /// # Errors
434    ///
435    /// Returns an error if the DEX does not have an RPC collect event parser defined or if parsing fails.
436    pub fn parse_collect_event_rpc(&self, log: &RpcLog) -> anyhow::Result<CollectEvent> {
437        if let Some(parse_fn) = &self.parse_collect_event_rpc_fn {
438            parse_fn(self.dex.clone(), log)
439        } else {
440            anyhow::bail!(
441                "RPC parsing of collect event is not defined in this dex: {}:{}",
442                self.dex.chain,
443                self.dex.name
444            )
445        }
446    }
447
448    /// Parses a flash event from an RPC log.
449    ///
450    /// # Errors
451    ///
452    /// Returns an error if the DEX does not have an RPC flash event parser defined or if parsing fails.
453    pub fn parse_flash_event_rpc(&self, log: &RpcLog) -> anyhow::Result<FlashEvent> {
454        if let Some(parse_fn) = &self.parse_flash_event_rpc_fn {
455            parse_fn(self.dex.clone(), log)
456        } else {
457            anyhow::bail!(
458                "RPC parsing of flash event is not defined in this dex: {}:{}",
459                self.dex.chain,
460                self.dex.name
461            )
462        }
463    }
464
465    // ==================== Utility Methods ====================
466
467    /// Checks if this DEX requires pool initialization events.
468    #[must_use]
469    pub fn needs_initialization(&self) -> bool {
470        self.dex.initialize_event.is_some()
471    }
472}
473
474impl Deref for DexExtended {
475    type Target = Dex;
476
477    fn deref(&self) -> &Self::Target {
478        &self.dex
479    }
480}