nautilus_blockchain/exchanges/
extended.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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    /// Sets the function used to parse pool creation events from HyperSync logs.
102    pub fn set_pool_created_event_hypersync_parsing(
103        &mut self,
104        parse_fn: fn(HypersyncLog) -> anyhow::Result<PoolCreatedEvent>,
105    ) {
106        self.parse_pool_created_event_hypersync_fn = Some(parse_fn);
107    }
108
109    /// Sets the function used to parse initialize events from HyperSync logs.
110    pub fn set_initialize_event_hypersync_parsing(
111        &mut self,
112        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<InitializeEvent>,
113    ) {
114        self.parse_initialize_event_hypersync_fn = Some(parse_fn);
115    }
116
117    /// Sets the function used to parse swap events from HyperSync logs.
118    pub fn set_swap_event_hypersync_parsing(
119        &mut self,
120        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<SwapEvent>,
121    ) {
122        self.parse_swap_event_hypersync_fn = Some(parse_fn);
123    }
124
125    /// Sets the function used to parse mint events from HyperSync logs.
126    pub fn set_mint_event_hypersync_parsing(
127        &mut self,
128        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<MintEvent>,
129    ) {
130        self.parse_mint_event_hypersync_fn = Some(parse_fn);
131    }
132
133    /// Sets the function used to parse burn events from HyperSync logs.
134    pub fn set_burn_event_hypersync_parsing(
135        &mut self,
136        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<BurnEvent>,
137    ) {
138        self.parse_burn_event_hypersync_fn = Some(parse_fn);
139    }
140
141    /// Sets the function used to parse collect events from HyperSync logs.
142    pub fn set_collect_event_hypersync_parsing(
143        &mut self,
144        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<CollectEvent>,
145    ) {
146        self.parse_collect_event_hypersync_fn = Some(parse_fn);
147    }
148
149    /// Sets the function used to parse flash events from HyperSync logs.
150    pub fn set_flash_event_hypersync_parsing(
151        &mut self,
152        parse_fn: fn(SharedDex, HypersyncLog) -> anyhow::Result<FlashEvent>,
153    ) {
154        self.parse_flash_event_hypersync_fn = Some(parse_fn);
155    }
156
157    /// Sets the function used to parse pool creation events from RPC logs.
158    pub fn set_pool_created_event_rpc_parsing(
159        &mut self,
160        parse_fn: fn(&RpcLog) -> anyhow::Result<PoolCreatedEvent>,
161    ) {
162        self.parse_pool_created_event_rpc_fn = Some(parse_fn);
163    }
164
165    /// Sets the function used to parse initialize events from RPC logs.
166    pub fn set_initialize_event_rpc_parsing(
167        &mut self,
168        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<InitializeEvent>,
169    ) {
170        self.parse_initialize_event_rpc_fn = Some(parse_fn);
171    }
172
173    /// Sets the function used to parse swap events from RPC logs.
174    pub fn set_swap_event_rpc_parsing(
175        &mut self,
176        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<SwapEvent>,
177    ) {
178        self.parse_swap_event_rpc_fn = Some(parse_fn);
179    }
180
181    /// Sets the function used to parse mint events from RPC logs.
182    pub fn set_mint_event_rpc_parsing(
183        &mut self,
184        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<MintEvent>,
185    ) {
186        self.parse_mint_event_rpc_fn = Some(parse_fn);
187    }
188
189    /// Sets the function used to parse burn events from RPC logs.
190    pub fn set_burn_event_rpc_parsing(
191        &mut self,
192        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<BurnEvent>,
193    ) {
194        self.parse_burn_event_rpc_fn = Some(parse_fn);
195    }
196
197    /// Sets the function used to parse collect events from RPC logs.
198    pub fn set_collect_event_rpc_parsing(
199        &mut self,
200        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<CollectEvent>,
201    ) {
202        self.parse_collect_event_rpc_fn = Some(parse_fn);
203    }
204
205    /// Sets the function used to parse flash events from RPC logs.
206    pub fn set_flash_event_rpc_parsing(
207        &mut self,
208        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<FlashEvent>,
209    ) {
210        self.parse_flash_event_rpc_fn = Some(parse_fn);
211    }
212
213    /// Parses a pool creation event from a HyperSync log.
214    ///
215    /// # Errors
216    ///
217    /// Returns an error if the DEX does not have a HyperSync pool creation event parser defined or if parsing fails.
218    pub fn parse_pool_created_event_hypersync(
219        &self,
220        log: HypersyncLog,
221    ) -> anyhow::Result<PoolCreatedEvent> {
222        if let Some(parse_fn) = &self.parse_pool_created_event_hypersync_fn {
223            parse_fn(log)
224        } else {
225            anyhow::bail!(
226                "HyperSync parsing of pool created event is not defined in this dex: {}:{}",
227                self.dex.chain,
228                self.dex.name,
229            )
230        }
231    }
232
233    /// Parses a swap event from a HyperSync log.
234    ///
235    /// # Errors
236    ///
237    /// Returns an error if the DEX does not have a HyperSync swap event parser defined or if parsing fails.
238    pub fn parse_swap_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<SwapEvent> {
239        if let Some(parse_fn) = &self.parse_swap_event_hypersync_fn {
240            parse_fn(self.dex.clone(), log)
241        } else {
242            anyhow::bail!(
243                "HyperSync parsing of swap event is not defined in this dex: {}:{}",
244                self.dex.chain,
245                self.dex.name
246            )
247        }
248    }
249
250    /// Parses a mint event from a HyperSync log.
251    ///
252    /// # Errors
253    ///
254    /// Returns an error if the DEX does not have a HyperSync mint event parser defined or if parsing fails.
255    pub fn parse_mint_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<MintEvent> {
256        if let Some(parse_fn) = &self.parse_mint_event_hypersync_fn {
257            parse_fn(self.dex.clone(), log)
258        } else {
259            anyhow::bail!(
260                "HyperSync parsing of mint event is not defined in this dex: {}:{}",
261                self.dex.chain,
262                self.dex.name
263            )
264        }
265    }
266
267    /// Parses a burn event from a HyperSync log.
268    ///
269    /// # Errors
270    ///
271    /// Returns an error if the DEX does not have a HyperSync burn event parser defined or if parsing fails.
272    pub fn parse_burn_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<BurnEvent> {
273        if let Some(parse_fn) = &self.parse_burn_event_hypersync_fn {
274            parse_fn(self.dex.clone(), log)
275        } else {
276            anyhow::bail!(
277                "HyperSync parsing of burn event is not defined in this dex: {}:{}",
278                self.dex.chain,
279                self.dex.name
280            )
281        }
282    }
283
284    /// Parses an initialize event from a HyperSync log.
285    ///
286    /// # Errors
287    ///
288    /// Returns an error if the DEX does not have a HyperSync initialize event parser defined or if parsing fails.
289    pub fn parse_initialize_event_hypersync(
290        &self,
291        log: HypersyncLog,
292    ) -> anyhow::Result<InitializeEvent> {
293        if let Some(parse_fn) = &self.parse_initialize_event_hypersync_fn {
294            parse_fn(self.dex.clone(), log)
295        } else {
296            anyhow::bail!(
297                "HyperSync parsing of initialize event is not defined in this dex: {}:{}",
298                self.dex.chain,
299                self.dex.name
300            )
301        }
302    }
303
304    /// Parses a collect event from a HyperSync log.
305    ///
306    /// # Errors
307    ///
308    /// Returns an error if the DEX does not have a HyperSync collect event parser defined or if parsing fails.
309    pub fn parse_collect_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<CollectEvent> {
310        if let Some(parse_fn) = &self.parse_collect_event_hypersync_fn {
311            parse_fn(self.dex.clone(), log)
312        } else {
313            anyhow::bail!(
314                "HyperSync parsing of collect event is not defined in this dex: {}:{}",
315                self.dex.chain,
316                self.dex.name
317            )
318        }
319    }
320
321    /// Parses a flash event from a HyperSync log.
322    ///
323    /// # Errors
324    ///
325    /// Returns an error if the DEX does not have a HyperSync flash event parser defined or if parsing fails.
326    pub fn parse_flash_event_hypersync(&self, log: HypersyncLog) -> anyhow::Result<FlashEvent> {
327        if let Some(parse_fn) = &self.parse_flash_event_hypersync_fn {
328            parse_fn(self.dex.clone(), log)
329        } else {
330            anyhow::bail!(
331                "HyperSync parsing of flash event is not defined in this dex: {}:{}",
332                self.dex.chain,
333                self.dex.name
334            )
335        }
336    }
337
338    /// Parses a pool creation event from an RPC log.
339    ///
340    /// # Errors
341    ///
342    /// Returns an error if the DEX does not have an RPC pool creation event parser defined or if parsing fails.
343    pub fn parse_pool_created_event_rpc(&self, log: &RpcLog) -> anyhow::Result<PoolCreatedEvent> {
344        if let Some(parse_fn) = &self.parse_pool_created_event_rpc_fn {
345            parse_fn(log)
346        } else {
347            anyhow::bail!(
348                "RPC parsing of pool created event is not defined in this dex: {}:{}",
349                self.dex.chain,
350                self.dex.name,
351            )
352        }
353    }
354
355    /// Parses a swap event from an RPC log.
356    ///
357    /// # Errors
358    ///
359    /// Returns an error if the DEX does not have an RPC swap event parser defined or if parsing fails.
360    pub fn parse_swap_event_rpc(&self, log: &RpcLog) -> anyhow::Result<SwapEvent> {
361        if let Some(parse_fn) = &self.parse_swap_event_rpc_fn {
362            parse_fn(self.dex.clone(), log)
363        } else {
364            anyhow::bail!(
365                "RPC parsing of swap event is not defined in this dex: {}:{}",
366                self.dex.chain,
367                self.dex.name
368            )
369        }
370    }
371
372    /// Parses a mint event from an RPC log.
373    ///
374    /// # Errors
375    ///
376    /// Returns an error if the DEX does not have an RPC mint event parser defined or if parsing fails.
377    pub fn parse_mint_event_rpc(&self, log: &RpcLog) -> anyhow::Result<MintEvent> {
378        if let Some(parse_fn) = &self.parse_mint_event_rpc_fn {
379            parse_fn(self.dex.clone(), log)
380        } else {
381            anyhow::bail!(
382                "RPC parsing of mint event is not defined in this dex: {}:{}",
383                self.dex.chain,
384                self.dex.name
385            )
386        }
387    }
388
389    /// Parses a burn event from an RPC log.
390    ///
391    /// # Errors
392    ///
393    /// Returns an error if the DEX does not have an RPC burn event parser defined or if parsing fails.
394    pub fn parse_burn_event_rpc(&self, log: &RpcLog) -> anyhow::Result<BurnEvent> {
395        if let Some(parse_fn) = &self.parse_burn_event_rpc_fn {
396            parse_fn(self.dex.clone(), log)
397        } else {
398            anyhow::bail!(
399                "RPC parsing of burn event is not defined in this dex: {}:{}",
400                self.dex.chain,
401                self.dex.name
402            )
403        }
404    }
405
406    /// Parses an initialize event from an RPC log.
407    ///
408    /// # Errors
409    ///
410    /// Returns an error if the DEX does not have an RPC initialize event parser defined or if parsing fails.
411    pub fn parse_initialize_event_rpc(&self, log: &RpcLog) -> anyhow::Result<InitializeEvent> {
412        if let Some(parse_fn) = &self.parse_initialize_event_rpc_fn {
413            parse_fn(self.dex.clone(), log)
414        } else {
415            anyhow::bail!(
416                "RPC parsing of initialize event is not defined in this dex: {}:{}",
417                self.dex.chain,
418                self.dex.name
419            )
420        }
421    }
422
423    /// Parses a collect event from an RPC log.
424    ///
425    /// # Errors
426    ///
427    /// Returns an error if the DEX does not have an RPC collect event parser defined or if parsing fails.
428    pub fn parse_collect_event_rpc(&self, log: &RpcLog) -> anyhow::Result<CollectEvent> {
429        if let Some(parse_fn) = &self.parse_collect_event_rpc_fn {
430            parse_fn(self.dex.clone(), log)
431        } else {
432            anyhow::bail!(
433                "RPC parsing of collect event is not defined in this dex: {}:{}",
434                self.dex.chain,
435                self.dex.name
436            )
437        }
438    }
439
440    /// Parses a flash event from an RPC log.
441    ///
442    /// # Errors
443    ///
444    /// Returns an error if the DEX does not have an RPC flash event parser defined or if parsing fails.
445    pub fn parse_flash_event_rpc(&self, log: &RpcLog) -> anyhow::Result<FlashEvent> {
446        if let Some(parse_fn) = &self.parse_flash_event_rpc_fn {
447            parse_fn(self.dex.clone(), log)
448        } else {
449            anyhow::bail!(
450                "RPC parsing of flash event is not defined in this dex: {}:{}",
451                self.dex.chain,
452                self.dex.name
453            )
454        }
455    }
456
457    /// Checks if this DEX requires pool initialization events.
458    #[must_use]
459    pub fn needs_initialization(&self) -> bool {
460        self.dex.initialize_event.is_some()
461    }
462}
463
464impl Deref for DexExtended {
465    type Target = Dex;
466
467    fn deref(&self) -> &Self::Target {
468        &self.dex
469    }
470}