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 hypersync_client::simple_types::Log;
19use nautilus_model::{
20    defi::{
21        dex::{Dex, SharedDex},
22        token::Token,
23    },
24    enums::OrderSide,
25    types::{Price, Quantity},
26};
27
28use crate::events::{
29    burn::BurnEvent, collect::CollectEvent, initialize::InitializeEvent, mint::MintEvent,
30    pool_created::PoolCreatedEvent, swap::SwapEvent,
31};
32
33type ConvertTradeDataFn =
34    fn(&Token, &Token, &SwapEvent) -> anyhow::Result<(OrderSide, Quantity, Price)>;
35
36/// Extended DEX wrapper that adds provider-specific event parsing capabilities to the domain `Dex` model.
37#[derive(Debug, Clone)]
38pub struct DexExtended {
39    /// The core domain Dex object being extended.
40    pub dex: SharedDex,
41    /// Function to parse pool creation events.
42    pub parse_pool_created_event_fn: Option<fn(Log) -> anyhow::Result<PoolCreatedEvent>>,
43    /// Function to parse initialize events.
44    pub parse_initialize_event_fn: Option<fn(SharedDex, Log) -> anyhow::Result<InitializeEvent>>,
45    /// Function to parse swap events.
46    pub parse_swap_event_fn: Option<fn(SharedDex, Log) -> anyhow::Result<SwapEvent>>,
47    /// Function to parse mint events.
48    pub parse_mint_event_fn: Option<fn(SharedDex, Log) -> anyhow::Result<MintEvent>>,
49    /// Function to parse burn events.
50    pub parse_burn_event_fn: Option<fn(SharedDex, Log) -> anyhow::Result<BurnEvent>>,
51    /// Function to parse collect events.
52    pub parse_collect_event_fn: Option<fn(SharedDex, Log) -> anyhow::Result<CollectEvent>>,
53    /// Function to convert to trade data.
54    pub convert_to_trade_data_fn: Option<ConvertTradeDataFn>,
55}
56
57impl DexExtended {
58    /// Creates a new [`DexExtended`] wrapper around a domain `Dex` object.
59    #[must_use]
60    pub fn new(dex: Dex) -> Self {
61        Self {
62            dex: Arc::new(dex),
63            parse_pool_created_event_fn: None,
64            parse_initialize_event_fn: None,
65            parse_swap_event_fn: None,
66            parse_mint_event_fn: None,
67            parse_burn_event_fn: None,
68            parse_collect_event_fn: None,
69            convert_to_trade_data_fn: None,
70        }
71    }
72
73    /// Sets the function used to parse pool creation events for this Dex.
74    pub fn set_pool_created_event_parsing(
75        &mut self,
76        parse_pool_created_event: fn(Log) -> anyhow::Result<PoolCreatedEvent>,
77    ) {
78        self.parse_pool_created_event_fn = Some(parse_pool_created_event);
79    }
80
81    /// Sets the function used to parse initialize events for this Dex.
82    pub fn set_initialize_event_parsing(
83        &mut self,
84        parse_initialize_event: fn(SharedDex, Log) -> anyhow::Result<InitializeEvent>,
85    ) {
86        self.parse_initialize_event_fn = Some(parse_initialize_event);
87    }
88
89    /// Sets the function used to parse swap events for this Dex.
90    pub fn set_swap_event_parsing(
91        &mut self,
92        parse_swap_event: fn(SharedDex, Log) -> anyhow::Result<SwapEvent>,
93    ) {
94        self.parse_swap_event_fn = Some(parse_swap_event);
95    }
96
97    /// Sets the function used to parse mint events for this Dex.
98    pub fn set_mint_event_parsing(
99        &mut self,
100        parse_mint_event: fn(SharedDex, Log) -> anyhow::Result<MintEvent>,
101    ) {
102        self.parse_mint_event_fn = Some(parse_mint_event);
103    }
104
105    /// Sets the function used to parse burn events for this Dex.
106    pub fn set_burn_event_parsing(
107        &mut self,
108        parse_burn_event: fn(SharedDex, Log) -> anyhow::Result<BurnEvent>,
109    ) {
110        self.parse_burn_event_fn = Some(parse_burn_event);
111    }
112
113    /// Sets the function used to parse collect events for this Dex.
114    pub fn set_collect_event_parsing(
115        &mut self,
116        parse_collect_event: fn(SharedDex, Log) -> anyhow::Result<CollectEvent>,
117    ) {
118        self.parse_collect_event_fn = Some(parse_collect_event);
119    }
120
121    /// Sets the function used to convert trade data for this Dex.
122    pub fn set_convert_trade_data(&mut self, convert_trade_data: ConvertTradeDataFn) {
123        self.convert_to_trade_data_fn = Some(convert_trade_data);
124    }
125
126    /// Parses a pool creation event log using this DEX's specific parsing function.
127    ///
128    /// # Errors
129    ///
130    /// Returns an error if the DEX does not have a pool creation event parser defined or if parsing fails.
131    pub fn parse_pool_created_event(&self, log: Log) -> anyhow::Result<PoolCreatedEvent> {
132        if let Some(parse_pool_created_event_fn) = &self.parse_pool_created_event_fn {
133            parse_pool_created_event_fn(log)
134        } else {
135            anyhow::bail!(
136                "Parsing of pool created event in not defined in this dex: {}:{}",
137                self.dex.chain,
138                self.dex.name,
139            )
140        }
141    }
142
143    /// Parses a swap event log using this DEX's specific parsing function.
144    ///
145    /// # Errors
146    ///
147    /// Returns an error if the DEX does not have a swap event parser defined or if parsing fails.
148    pub fn parse_swap_event(&self, log: Log) -> anyhow::Result<SwapEvent> {
149        if let Some(parse_swap_event_fn) = &self.parse_swap_event_fn {
150            parse_swap_event_fn(self.dex.clone(), log)
151        } else {
152            anyhow::bail!(
153                "Parsing of swap event in not defined in this dex: {}:{}",
154                self.dex.chain,
155                self.dex.name
156            )
157        }
158    }
159
160    /// Convert to trade data from a log using this DEX's specific parsing function.
161    ///
162    /// # Errors
163    ///
164    /// Returns an error if the DEX does not have a trade data converter defined or if conversion fails.
165    pub fn convert_to_trade_data(
166        &self,
167        token0: &Token,
168        token1: &Token,
169        swap_event: &SwapEvent,
170    ) -> anyhow::Result<(OrderSide, Quantity, Price)> {
171        if let Some(convert_to_trade_data_fn) = &self.convert_to_trade_data_fn {
172            convert_to_trade_data_fn(token0, token1, swap_event)
173        } else {
174            anyhow::bail!(
175                "Converting to trade data is not defined in this dex: {}:{}",
176                self.dex.chain,
177                self.dex.name
178            )
179        }
180    }
181
182    /// Parses a mint event log using this DEX's specific parsing function.
183    ///
184    /// # Errors
185    ///
186    /// Returns an error if the DEX does not have a mint event parser defined or if parsing fails.
187    pub fn parse_mint_event(&self, log: Log) -> anyhow::Result<MintEvent> {
188        if let Some(parse_mint_event_fn) = &self.parse_mint_event_fn {
189            parse_mint_event_fn(self.dex.clone(), log)
190        } else {
191            anyhow::bail!(
192                "Parsing of mint event in not defined in this dex: {}:{}",
193                self.dex.chain,
194                self.dex.name
195            )
196        }
197    }
198
199    /// Parses a burn event log using this DEX's specific parsing function.
200    ///
201    /// # Errors
202    ///
203    /// Returns an error if the DEX does not have a burn event parser defined or if parsing fails.
204    pub fn parse_burn_event(&self, log: Log) -> anyhow::Result<BurnEvent> {
205        if let Some(parse_burn_event_fn) = &self.parse_burn_event_fn {
206            parse_burn_event_fn(self.dex.clone(), log)
207        } else {
208            anyhow::bail!(
209                "Parsing of burn event in not defined in this dex: {}",
210                self.dex.name
211            )
212        }
213    }
214
215    /// Checks if this DEX requires pool initialization events.
216    pub fn needs_initialization(&self) -> bool {
217        self.dex.initialize_event.is_some()
218    }
219
220    /// Parses an event log into an `InitializeEvent` struct.
221    pub fn parse_initialize_event(&self, log: Log) -> anyhow::Result<InitializeEvent> {
222        if let Some(parse_initialize_event_fn) = &self.parse_initialize_event_fn {
223            parse_initialize_event_fn(self.dex.clone(), log)
224        } else {
225            anyhow::bail!(
226                "Parsing of initialize event in not defined in this dex: {}",
227                self.dex.name
228            )
229        }
230    }
231
232    /// Parses a collect event log using this DEX's specific parsing function.
233    ///
234    /// # Errors
235    ///
236    /// Returns an error if the DEX does not have a collect event parser defined or if parsing fails.
237    pub fn parse_collect_event(&self, log: Log) -> anyhow::Result<CollectEvent> {
238        if let Some(parse_collect_event_fn) = &self.parse_collect_event_fn {
239            parse_collect_event_fn(self.dex.clone(), log)
240        } else {
241            anyhow::bail!(
242                "Parsing of collect event in not defined in this dex: {}:{}",
243                self.dex.chain,
244                self.dex.name
245            )
246        }
247    }
248}
249
250impl Deref for DexExtended {
251    type Target = Dex;
252
253    fn deref(&self) -> &Self::Target {
254        &self.dex
255    }
256}