Skip to main content

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    pool_analysis::PoolEventKind,
21    rpc::RpcLog,
22};
23
24use crate::{
25    events::{
26        burn::BurnEvent, collect::CollectEvent, fee_protocol_collect::FeeProtocolCollectEvent,
27        fee_protocol_update::FeeProtocolUpdateEvent, flash::FlashEvent,
28        initialize::InitializeEvent, mint::MintEvent, pool_created::PoolCreatedEvent,
29        swap::SwapEvent,
30    },
31    hypersync::HypersyncLog,
32};
33
34/// Extended DEX wrapper that adds provider-specific event parsing capabilities to the domain `Dex` model.
35#[derive(Debug, Clone)]
36pub struct DexExtended {
37    /// The core domain Dex object being extended.
38    pub dex: SharedDex,
39    // === HyperSync parsers ===
40    /// Function to parse pool creation events from HyperSync logs.
41    pub parse_pool_created_event_hypersync_fn:
42        Option<fn(HypersyncLog) -> anyhow::Result<PoolCreatedEvent>>,
43    /// Function to parse initialize events from HyperSync logs.
44    pub parse_initialize_event_hypersync_fn:
45        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<InitializeEvent>>,
46    /// Function to parse swap events from HyperSync logs.
47    pub parse_swap_event_hypersync_fn:
48        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<SwapEvent>>,
49    /// Function to parse mint events from HyperSync logs.
50    pub parse_mint_event_hypersync_fn:
51        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<MintEvent>>,
52    /// Function to parse burn events from HyperSync logs.
53    pub parse_burn_event_hypersync_fn:
54        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<BurnEvent>>,
55    /// Function to parse collect events from HyperSync logs.
56    pub parse_collect_event_hypersync_fn:
57        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<CollectEvent>>,
58    /// Function to parse flash events from HyperSync logs.
59    pub parse_flash_event_hypersync_fn:
60        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<FlashEvent>>,
61    /// Function to parse `SetFeeProtocol` events from HyperSync logs.
62    pub parse_fee_protocol_update_event_hypersync_fn:
63        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<FeeProtocolUpdateEvent>>,
64    /// Function to parse `CollectProtocol` events from HyperSync logs.
65    pub parse_fee_protocol_collect_event_hypersync_fn:
66        Option<fn(SharedDex, &HypersyncLog) -> anyhow::Result<FeeProtocolCollectEvent>>,
67    // === RPC parsers (hex-decode, standard Ethereum format) ===
68    /// Function to parse pool creation events from RPC logs.
69    pub parse_pool_created_event_rpc_fn: Option<fn(&RpcLog) -> anyhow::Result<PoolCreatedEvent>>,
70    /// Function to parse initialize events from RPC logs.
71    pub parse_initialize_event_rpc_fn:
72        Option<fn(SharedDex, &RpcLog) -> anyhow::Result<InitializeEvent>>,
73    /// Function to parse swap events from RPC logs.
74    pub parse_swap_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<SwapEvent>>,
75    /// Function to parse mint events from RPC logs.
76    pub parse_mint_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<MintEvent>>,
77    /// Function to parse burn events from RPC logs.
78    pub parse_burn_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<BurnEvent>>,
79    /// Function to parse collect events from RPC logs.
80    pub parse_collect_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<CollectEvent>>,
81    /// Function to parse flash events from RPC logs.
82    pub parse_flash_event_rpc_fn: Option<fn(SharedDex, &RpcLog) -> anyhow::Result<FlashEvent>>,
83    /// Function to parse `SetFeeProtocol` events from RPC logs.
84    pub parse_fee_protocol_update_event_rpc_fn:
85        Option<fn(SharedDex, &RpcLog) -> anyhow::Result<FeeProtocolUpdateEvent>>,
86    /// Function to parse `CollectProtocol` events from RPC logs.
87    pub parse_fee_protocol_collect_event_rpc_fn:
88        Option<fn(SharedDex, &RpcLog) -> anyhow::Result<FeeProtocolCollectEvent>>,
89}
90
91impl DexExtended {
92    /// Creates a new [`DexExtended`] wrapper around a domain `Dex` object.
93    #[must_use]
94    pub fn new(dex: Dex) -> Self {
95        Self {
96            dex: Arc::new(dex),
97            // HyperSync parsers
98            parse_pool_created_event_hypersync_fn: None,
99            parse_initialize_event_hypersync_fn: None,
100            parse_swap_event_hypersync_fn: None,
101            parse_mint_event_hypersync_fn: None,
102            parse_burn_event_hypersync_fn: None,
103            parse_collect_event_hypersync_fn: None,
104            parse_flash_event_hypersync_fn: None,
105            parse_fee_protocol_update_event_hypersync_fn: None,
106            parse_fee_protocol_collect_event_hypersync_fn: None,
107            // RPC parsers
108            parse_pool_created_event_rpc_fn: None,
109            parse_initialize_event_rpc_fn: None,
110            parse_swap_event_rpc_fn: None,
111            parse_mint_event_rpc_fn: None,
112            parse_burn_event_rpc_fn: None,
113            parse_collect_event_rpc_fn: None,
114            parse_flash_event_rpc_fn: None,
115            parse_fee_protocol_update_event_rpc_fn: None,
116            parse_fee_protocol_collect_event_rpc_fn: None,
117        }
118    }
119
120    /// Sets the function used to parse pool creation events from HyperSync logs.
121    pub fn set_pool_created_event_hypersync_parsing(
122        &mut self,
123        parse_fn: fn(HypersyncLog) -> anyhow::Result<PoolCreatedEvent>,
124    ) {
125        self.parse_pool_created_event_hypersync_fn = Some(parse_fn);
126    }
127
128    /// Sets the function used to parse initialize events from HyperSync logs.
129    pub fn set_initialize_event_hypersync_parsing(
130        &mut self,
131        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<InitializeEvent>,
132    ) {
133        self.parse_initialize_event_hypersync_fn = Some(parse_fn);
134    }
135
136    /// Sets the function used to parse swap events from HyperSync logs.
137    pub fn set_swap_event_hypersync_parsing(
138        &mut self,
139        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<SwapEvent>,
140    ) {
141        self.parse_swap_event_hypersync_fn = Some(parse_fn);
142    }
143
144    /// Sets the function used to parse mint events from HyperSync logs.
145    pub fn set_mint_event_hypersync_parsing(
146        &mut self,
147        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<MintEvent>,
148    ) {
149        self.parse_mint_event_hypersync_fn = Some(parse_fn);
150    }
151
152    /// Sets the function used to parse burn events from HyperSync logs.
153    pub fn set_burn_event_hypersync_parsing(
154        &mut self,
155        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<BurnEvent>,
156    ) {
157        self.parse_burn_event_hypersync_fn = Some(parse_fn);
158    }
159
160    /// Sets the function used to parse collect events from HyperSync logs.
161    pub fn set_collect_event_hypersync_parsing(
162        &mut self,
163        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<CollectEvent>,
164    ) {
165        self.parse_collect_event_hypersync_fn = Some(parse_fn);
166    }
167
168    /// Sets the function used to parse flash events from HyperSync logs.
169    pub fn set_flash_event_hypersync_parsing(
170        &mut self,
171        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<FlashEvent>,
172    ) {
173        self.parse_flash_event_hypersync_fn = Some(parse_fn);
174    }
175
176    /// Sets the function used to parse `SetFeeProtocol` events from HyperSync logs.
177    pub fn set_fee_protocol_update_event_hypersync_parsing(
178        &mut self,
179        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<FeeProtocolUpdateEvent>,
180    ) {
181        self.parse_fee_protocol_update_event_hypersync_fn = Some(parse_fn);
182    }
183
184    /// Sets the function used to parse `CollectProtocol` events from HyperSync logs.
185    pub fn set_fee_protocol_collect_event_hypersync_parsing(
186        &mut self,
187        parse_fn: fn(SharedDex, &HypersyncLog) -> anyhow::Result<FeeProtocolCollectEvent>,
188    ) {
189        self.parse_fee_protocol_collect_event_hypersync_fn = Some(parse_fn);
190    }
191
192    /// Sets the function used to parse pool creation events from RPC logs.
193    pub fn set_pool_created_event_rpc_parsing(
194        &mut self,
195        parse_fn: fn(&RpcLog) -> anyhow::Result<PoolCreatedEvent>,
196    ) {
197        self.parse_pool_created_event_rpc_fn = Some(parse_fn);
198    }
199
200    /// Sets the function used to parse initialize events from RPC logs.
201    pub fn set_initialize_event_rpc_parsing(
202        &mut self,
203        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<InitializeEvent>,
204    ) {
205        self.parse_initialize_event_rpc_fn = Some(parse_fn);
206    }
207
208    /// Sets the function used to parse swap events from RPC logs.
209    pub fn set_swap_event_rpc_parsing(
210        &mut self,
211        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<SwapEvent>,
212    ) {
213        self.parse_swap_event_rpc_fn = Some(parse_fn);
214    }
215
216    /// Sets the function used to parse mint events from RPC logs.
217    pub fn set_mint_event_rpc_parsing(
218        &mut self,
219        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<MintEvent>,
220    ) {
221        self.parse_mint_event_rpc_fn = Some(parse_fn);
222    }
223
224    /// Sets the function used to parse burn events from RPC logs.
225    pub fn set_burn_event_rpc_parsing(
226        &mut self,
227        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<BurnEvent>,
228    ) {
229        self.parse_burn_event_rpc_fn = Some(parse_fn);
230    }
231
232    /// Sets the function used to parse collect events from RPC logs.
233    pub fn set_collect_event_rpc_parsing(
234        &mut self,
235        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<CollectEvent>,
236    ) {
237        self.parse_collect_event_rpc_fn = Some(parse_fn);
238    }
239
240    /// Sets the function used to parse flash events from RPC logs.
241    pub fn set_flash_event_rpc_parsing(
242        &mut self,
243        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<FlashEvent>,
244    ) {
245        self.parse_flash_event_rpc_fn = Some(parse_fn);
246    }
247
248    /// Sets the function used to parse `SetFeeProtocol` events from RPC logs.
249    pub fn set_fee_protocol_update_event_rpc_parsing(
250        &mut self,
251        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<FeeProtocolUpdateEvent>,
252    ) {
253        self.parse_fee_protocol_update_event_rpc_fn = Some(parse_fn);
254    }
255
256    /// Sets the function used to parse `CollectProtocol` events from RPC logs.
257    pub fn set_fee_protocol_collect_event_rpc_parsing(
258        &mut self,
259        parse_fn: fn(SharedDex, &RpcLog) -> anyhow::Result<FeeProtocolCollectEvent>,
260    ) {
261        self.parse_fee_protocol_collect_event_rpc_fn = Some(parse_fn);
262    }
263
264    /// Parses a pool creation event from a HyperSync log.
265    ///
266    /// # Errors
267    ///
268    /// Returns an error if the DEX does not have a HyperSync pool creation event parser defined or if parsing fails.
269    pub fn parse_pool_created_event_hypersync(
270        &self,
271        log: HypersyncLog,
272    ) -> anyhow::Result<PoolCreatedEvent> {
273        if let Some(parse_fn) = &self.parse_pool_created_event_hypersync_fn {
274            parse_fn(log)
275        } else {
276            anyhow::bail!(
277                "HyperSync parsing of pool created event is not defined in this dex: {}:{}",
278                self.dex.chain,
279                self.dex.name,
280            )
281        }
282    }
283
284    /// Parses a swap event from a HyperSync log.
285    ///
286    /// # Errors
287    ///
288    /// Returns an error if the DEX does not have a HyperSync swap event parser defined or if parsing fails.
289    pub fn parse_swap_event_hypersync(&self, log: &HypersyncLog) -> anyhow::Result<SwapEvent> {
290        if let Some(parse_fn) = &self.parse_swap_event_hypersync_fn {
291            parse_fn(self.dex.clone(), log)
292        } else {
293            anyhow::bail!(
294                "HyperSync parsing of swap event is not defined in this dex: {}:{}",
295                self.dex.chain,
296                self.dex.name
297            )
298        }
299    }
300
301    /// Parses a mint event from a HyperSync log.
302    ///
303    /// # Errors
304    ///
305    /// Returns an error if the DEX does not have a HyperSync mint event parser defined or if parsing fails.
306    pub fn parse_mint_event_hypersync(&self, log: &HypersyncLog) -> anyhow::Result<MintEvent> {
307        if let Some(parse_fn) = &self.parse_mint_event_hypersync_fn {
308            parse_fn(self.dex.clone(), log)
309        } else {
310            anyhow::bail!(
311                "HyperSync parsing of mint event is not defined in this dex: {}:{}",
312                self.dex.chain,
313                self.dex.name
314            )
315        }
316    }
317
318    /// Parses a burn event from a HyperSync log.
319    ///
320    /// # Errors
321    ///
322    /// Returns an error if the DEX does not have a HyperSync burn event parser defined or if parsing fails.
323    pub fn parse_burn_event_hypersync(&self, log: &HypersyncLog) -> anyhow::Result<BurnEvent> {
324        if let Some(parse_fn) = &self.parse_burn_event_hypersync_fn {
325            parse_fn(self.dex.clone(), log)
326        } else {
327            anyhow::bail!(
328                "HyperSync parsing of burn event is not defined in this dex: {}:{}",
329                self.dex.chain,
330                self.dex.name
331            )
332        }
333    }
334
335    /// Parses an initialize event from a HyperSync log.
336    ///
337    /// # Errors
338    ///
339    /// Returns an error if the DEX does not have a HyperSync initialize event parser defined or if parsing fails.
340    pub fn parse_initialize_event_hypersync(
341        &self,
342        log: &HypersyncLog,
343    ) -> anyhow::Result<InitializeEvent> {
344        if let Some(parse_fn) = &self.parse_initialize_event_hypersync_fn {
345            parse_fn(self.dex.clone(), log)
346        } else {
347            anyhow::bail!(
348                "HyperSync parsing of initialize event is not defined in this dex: {}:{}",
349                self.dex.chain,
350                self.dex.name
351            )
352        }
353    }
354
355    /// Parses a collect event from a HyperSync log.
356    ///
357    /// # Errors
358    ///
359    /// Returns an error if the DEX does not have a HyperSync collect event parser defined or if parsing fails.
360    pub fn parse_collect_event_hypersync(
361        &self,
362        log: &HypersyncLog,
363    ) -> anyhow::Result<CollectEvent> {
364        if let Some(parse_fn) = &self.parse_collect_event_hypersync_fn {
365            parse_fn(self.dex.clone(), log)
366        } else {
367            anyhow::bail!(
368                "HyperSync parsing of collect event is not defined in this dex: {}:{}",
369                self.dex.chain,
370                self.dex.name
371            )
372        }
373    }
374
375    /// Parses a flash event from a HyperSync log.
376    ///
377    /// # Errors
378    ///
379    /// Returns an error if the DEX does not have a HyperSync flash event parser defined or if parsing fails.
380    pub fn parse_flash_event_hypersync(&self, log: &HypersyncLog) -> anyhow::Result<FlashEvent> {
381        if let Some(parse_fn) = &self.parse_flash_event_hypersync_fn {
382            parse_fn(self.dex.clone(), log)
383        } else {
384            anyhow::bail!(
385                "HyperSync parsing of flash event is not defined in this dex: {}:{}",
386                self.dex.chain,
387                self.dex.name
388            )
389        }
390    }
391
392    /// Parses a `SetFeeProtocol` event from a HyperSync log.
393    ///
394    /// # Errors
395    ///
396    /// Returns an error if the DEX does not have a HyperSync `SetFeeProtocol` event parser defined or if parsing fails.
397    pub fn parse_fee_protocol_update_event_hypersync(
398        &self,
399        log: &HypersyncLog,
400    ) -> anyhow::Result<FeeProtocolUpdateEvent> {
401        if let Some(parse_fn) = &self.parse_fee_protocol_update_event_hypersync_fn {
402            parse_fn(self.dex.clone(), log)
403        } else {
404            anyhow::bail!(
405                "HyperSync parsing of SetFeeProtocol event is not defined in this dex: {}:{}",
406                self.dex.chain,
407                self.dex.name
408            )
409        }
410    }
411
412    /// Parses a `CollectProtocol` event from a HyperSync log.
413    ///
414    /// # Errors
415    ///
416    /// Returns an error if the DEX does not have a HyperSync `CollectProtocol` event parser defined or if parsing fails.
417    pub fn parse_fee_protocol_collect_event_hypersync(
418        &self,
419        log: &HypersyncLog,
420    ) -> anyhow::Result<FeeProtocolCollectEvent> {
421        if let Some(parse_fn) = &self.parse_fee_protocol_collect_event_hypersync_fn {
422            parse_fn(self.dex.clone(), log)
423        } else {
424            anyhow::bail!(
425                "HyperSync parsing of CollectProtocol event is not defined in this dex: {}:{}",
426                self.dex.chain,
427                self.dex.name
428            )
429        }
430    }
431
432    /// Parses a pool creation event from an RPC log.
433    ///
434    /// # Errors
435    ///
436    /// Returns an error if the DEX does not have an RPC pool creation event parser defined or if parsing fails.
437    pub fn parse_pool_created_event_rpc(&self, log: &RpcLog) -> anyhow::Result<PoolCreatedEvent> {
438        if let Some(parse_fn) = &self.parse_pool_created_event_rpc_fn {
439            parse_fn(log)
440        } else {
441            anyhow::bail!(
442                "RPC parsing of pool created event is not defined in this dex: {}:{}",
443                self.dex.chain,
444                self.dex.name,
445            )
446        }
447    }
448
449    /// Parses a swap event from an RPC log.
450    ///
451    /// # Errors
452    ///
453    /// Returns an error if the DEX does not have an RPC swap event parser defined or if parsing fails.
454    pub fn parse_swap_event_rpc(&self, log: &RpcLog) -> anyhow::Result<SwapEvent> {
455        if let Some(parse_fn) = &self.parse_swap_event_rpc_fn {
456            parse_fn(self.dex.clone(), log)
457        } else {
458            anyhow::bail!(
459                "RPC parsing of swap event is not defined in this dex: {}:{}",
460                self.dex.chain,
461                self.dex.name
462            )
463        }
464    }
465
466    /// Parses a mint event from an RPC log.
467    ///
468    /// # Errors
469    ///
470    /// Returns an error if the DEX does not have an RPC mint event parser defined or if parsing fails.
471    pub fn parse_mint_event_rpc(&self, log: &RpcLog) -> anyhow::Result<MintEvent> {
472        if let Some(parse_fn) = &self.parse_mint_event_rpc_fn {
473            parse_fn(self.dex.clone(), log)
474        } else {
475            anyhow::bail!(
476                "RPC parsing of mint event is not defined in this dex: {}:{}",
477                self.dex.chain,
478                self.dex.name
479            )
480        }
481    }
482
483    /// Parses a burn event from an RPC log.
484    ///
485    /// # Errors
486    ///
487    /// Returns an error if the DEX does not have an RPC burn event parser defined or if parsing fails.
488    pub fn parse_burn_event_rpc(&self, log: &RpcLog) -> anyhow::Result<BurnEvent> {
489        if let Some(parse_fn) = &self.parse_burn_event_rpc_fn {
490            parse_fn(self.dex.clone(), log)
491        } else {
492            anyhow::bail!(
493                "RPC parsing of burn event is not defined in this dex: {}:{}",
494                self.dex.chain,
495                self.dex.name
496            )
497        }
498    }
499
500    /// Parses an initialize event from an RPC log.
501    ///
502    /// # Errors
503    ///
504    /// Returns an error if the DEX does not have an RPC initialize event parser defined or if parsing fails.
505    pub fn parse_initialize_event_rpc(&self, log: &RpcLog) -> anyhow::Result<InitializeEvent> {
506        if let Some(parse_fn) = &self.parse_initialize_event_rpc_fn {
507            parse_fn(self.dex.clone(), log)
508        } else {
509            anyhow::bail!(
510                "RPC parsing of initialize event is not defined in this dex: {}:{}",
511                self.dex.chain,
512                self.dex.name
513            )
514        }
515    }
516
517    /// Parses a collect event from an RPC log.
518    ///
519    /// # Errors
520    ///
521    /// Returns an error if the DEX does not have an RPC collect event parser defined or if parsing fails.
522    pub fn parse_collect_event_rpc(&self, log: &RpcLog) -> anyhow::Result<CollectEvent> {
523        if let Some(parse_fn) = &self.parse_collect_event_rpc_fn {
524            parse_fn(self.dex.clone(), log)
525        } else {
526            anyhow::bail!(
527                "RPC parsing of collect event is not defined in this dex: {}:{}",
528                self.dex.chain,
529                self.dex.name
530            )
531        }
532    }
533
534    /// Parses a flash event from an RPC log.
535    ///
536    /// # Errors
537    ///
538    /// Returns an error if the DEX does not have an RPC flash event parser defined or if parsing fails.
539    pub fn parse_flash_event_rpc(&self, log: &RpcLog) -> anyhow::Result<FlashEvent> {
540        if let Some(parse_fn) = &self.parse_flash_event_rpc_fn {
541            parse_fn(self.dex.clone(), log)
542        } else {
543            anyhow::bail!(
544                "RPC parsing of flash event is not defined in this dex: {}:{}",
545                self.dex.chain,
546                self.dex.name
547            )
548        }
549    }
550
551    /// Parses a `SetFeeProtocol` event from an RPC log.
552    ///
553    /// # Errors
554    ///
555    /// Returns an error if the DEX does not have an RPC `SetFeeProtocol` event parser defined or if parsing fails.
556    pub fn parse_fee_protocol_update_event_rpc(
557        &self,
558        log: &RpcLog,
559    ) -> anyhow::Result<FeeProtocolUpdateEvent> {
560        if let Some(parse_fn) = &self.parse_fee_protocol_update_event_rpc_fn {
561            parse_fn(self.dex.clone(), log)
562        } else {
563            anyhow::bail!(
564                "RPC parsing of SetFeeProtocol event is not defined in this dex: {}:{}",
565                self.dex.chain,
566                self.dex.name
567            )
568        }
569    }
570
571    /// Parses a `CollectProtocol` event from an RPC log.
572    ///
573    /// # Errors
574    ///
575    /// Returns an error if the DEX does not have an RPC `CollectProtocol` event parser defined or if parsing fails.
576    pub fn parse_fee_protocol_collect_event_rpc(
577        &self,
578        log: &RpcLog,
579    ) -> anyhow::Result<FeeProtocolCollectEvent> {
580        if let Some(parse_fn) = &self.parse_fee_protocol_collect_event_rpc_fn {
581            parse_fn(self.dex.clone(), log)
582        } else {
583            anyhow::bail!(
584                "RPC parsing of CollectProtocol event is not defined in this dex: {}:{}",
585                self.dex.chain,
586                self.dex.name
587            )
588        }
589    }
590
591    /// Checks if this DEX requires pool initialization events.
592    #[must_use]
593    pub fn needs_initialization(&self) -> bool {
594        self.dex.initialize_event.is_some()
595    }
596
597    /// Returns `true` if this DEX can discover pools from HyperSync `PoolCreated` logs.
598    ///
599    /// `sync-dex` streams `PoolCreated` logs to populate the pool set, so a DEX without this
600    /// parser cannot be synced.
601    #[must_use]
602    pub fn supports_pool_discovery(&self) -> bool {
603        self.parse_pool_created_event_hypersync_fn.is_some()
604    }
605
606    /// Returns the pool-event families required to build snapshots that this DEX cannot parse
607    /// from HyperSync logs.
608    ///
609    /// `analyze-pool(s)` sync and profile a pool's swap, liquidity, and fee events and seed the
610    /// starting price from `Initialize`, so a registered DEX missing any of these parsers cannot
611    /// produce snapshots. An empty result means analysis can run.
612    #[must_use]
613    pub fn missing_pool_analysis_parsers(&self) -> Vec<PoolEventKind> {
614        [
615            (
616                PoolEventKind::Initialize,
617                self.parse_initialize_event_hypersync_fn.is_some(),
618            ),
619            (
620                PoolEventKind::Swap,
621                self.parse_swap_event_hypersync_fn.is_some(),
622            ),
623            (
624                PoolEventKind::Mint,
625                self.parse_mint_event_hypersync_fn.is_some(),
626            ),
627            (
628                PoolEventKind::Burn,
629                self.parse_burn_event_hypersync_fn.is_some(),
630            ),
631            (
632                PoolEventKind::Collect,
633                self.parse_collect_event_hypersync_fn.is_some(),
634            ),
635        ]
636        .into_iter()
637        .filter_map(|(kind, present)| (!present).then_some(kind))
638        .collect()
639    }
640
641    /// Returns `true` if replay keeps this DEX's `fee_protocol` correct across replayed events.
642    ///
643    /// A snapshot-capable DEX that also parses `SetFeeProtocol` applies fee-protocol changes during
644    /// replay, so LP-versus-protocol fee splitting stays correct. A DEX without the parser still
645    /// produces usable snapshots but cannot track later `SetFeeProtocol` updates.
646    #[must_use]
647    pub fn supports_fee_protocol_replay(&self) -> bool {
648        self.missing_pool_analysis_parsers().is_empty()
649            && self.parse_fee_protocol_update_event_hypersync_fn.is_some()
650    }
651}
652
653impl Deref for DexExtended {
654    type Target = Dex;
655
656    fn deref(&self) -> &Self::Target {
657        &self.dex
658    }
659}