Skip to main content

nautilus_model/defi/data/
mod.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
16//! DeFi (Decentralized Finance) data models and types.
17//!
18//! This module provides core data structures for working with decentralized finance protocols,
19//! including blockchain networks, tokens, liquidity pools, swaps, and other DeFi primitives.
20
21use std::fmt::Display;
22
23use nautilus_core::UnixNanos;
24
25use crate::{
26    data::HasTsInit,
27    defi::{Pool, pool_analysis::PoolSnapshot},
28    identifiers::InstrumentId,
29};
30
31pub mod block;
32pub mod collect;
33pub mod fee_protocol_collect;
34pub mod fee_protocol_update;
35pub mod flash;
36pub mod liquidity;
37pub mod swap;
38pub mod swap_trade_info;
39pub mod transaction;
40
41// Re-exports
42pub use block::Block;
43pub use collect::PoolFeeCollect;
44pub use fee_protocol_collect::PoolFeeProtocolCollect;
45pub use fee_protocol_update::PoolFeeProtocolUpdate;
46pub use flash::PoolFlash;
47pub use liquidity::{PoolLiquidityUpdate, PoolLiquidityUpdateType};
48pub use swap::PoolSwap;
49pub use transaction::Transaction;
50
51#[derive(Debug, Clone, PartialEq)]
52pub enum DexPoolData {
53    Swap(PoolSwap),
54    LiquidityUpdate(PoolLiquidityUpdate),
55    FeeCollect(PoolFeeCollect),
56    FeeProtocolUpdate(PoolFeeProtocolUpdate),
57    FeeProtocolCollect(PoolFeeProtocolCollect),
58    Flash(PoolFlash),
59}
60
61impl DexPoolData {
62    /// Returns the block number associated with this pool event.
63    #[must_use]
64    pub fn block_number(&self) -> u64 {
65        match self {
66            Self::Swap(s) => s.block,
67            Self::LiquidityUpdate(u) => u.block,
68            Self::FeeCollect(c) => c.block,
69            Self::FeeProtocolUpdate(u) => u.block,
70            Self::FeeProtocolCollect(c) => c.block,
71            Self::Flash(f) => f.block,
72        }
73    }
74
75    /// Returns the transaction index associated with this pool event.
76    #[must_use]
77    pub fn transaction_index(&self) -> u32 {
78        match self {
79            Self::Swap(s) => s.transaction_index,
80            Self::LiquidityUpdate(u) => u.transaction_index,
81            Self::FeeCollect(c) => c.transaction_index,
82            Self::FeeProtocolUpdate(u) => u.transaction_index,
83            Self::FeeProtocolCollect(c) => c.transaction_index,
84            Self::Flash(f) => f.transaction_index,
85        }
86    }
87
88    /// Returns the log index associated with this pool event.
89    #[must_use]
90    pub fn log_index(&self) -> u32 {
91        match self {
92            Self::Swap(s) => s.log_index,
93            Self::LiquidityUpdate(u) => u.log_index,
94            Self::FeeCollect(c) => c.log_index,
95            Self::FeeProtocolUpdate(u) => u.log_index,
96            Self::FeeProtocolCollect(c) => c.log_index,
97            Self::Flash(f) => f.log_index,
98        }
99    }
100}
101
102/// Represents DeFi-specific data events in a decentralized exchange ecosystem.
103#[cfg_attr(
104    feature = "python",
105    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
106)]
107#[cfg_attr(
108    feature = "python",
109    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.model")
110)]
111#[derive(Debug, Clone, PartialEq)]
112pub enum DefiData {
113    /// A block completion in a blockchain network.
114    Block(Block),
115    /// A DEX liquidity pool definition or update.
116    Pool(Pool),
117    /// A complete snapshot of a pool's state at a specific point in time.
118    PoolSnapshot(PoolSnapshot),
119    /// A token swap transaction on a decentralized exchange.
120    PoolSwap(PoolSwap),
121    /// A liquidity update event (mint/burn) in a DEX pool.
122    PoolLiquidityUpdate(PoolLiquidityUpdate),
123    /// A fee collection event from a DEX pool position.
124    PoolFeeCollect(PoolFeeCollect),
125    /// A protocol-fee configuration change in a DEX pool.
126    PoolFeeProtocolUpdate(PoolFeeProtocolUpdate),
127    /// A protocol-fee withdrawal from a DEX pool.
128    PoolFeeProtocolCollect(PoolFeeProtocolCollect),
129    /// A flash event
130    PoolFlash(PoolFlash),
131}
132
133impl DefiData {
134    /// Returns the block position associated with this DeFi data.
135    #[must_use]
136    pub fn block_position(&self) -> (u64, u32, u32) {
137        match self {
138            Self::Block(block) => (block.number, 0, 0),
139            Self::Pool(pool) => (pool.creation_block, 0, 0),
140            Self::PoolSnapshot(snapshot) => (
141                snapshot.block_position.number,
142                snapshot.block_position.transaction_index,
143                snapshot.block_position.log_index,
144            ),
145            Self::PoolSwap(swap) => (swap.block, swap.transaction_index, swap.log_index),
146            Self::PoolLiquidityUpdate(update) => {
147                (update.block, update.transaction_index, update.log_index)
148            }
149            Self::PoolFeeCollect(collect) => {
150                (collect.block, collect.transaction_index, collect.log_index)
151            }
152            Self::PoolFeeProtocolUpdate(update) => {
153                (update.block, update.transaction_index, update.log_index)
154            }
155            Self::PoolFeeProtocolCollect(collect) => {
156                (collect.block, collect.transaction_index, collect.log_index)
157            }
158            Self::PoolFlash(flash) => (flash.block, flash.transaction_index, flash.log_index),
159        }
160    }
161
162    /// Returns the block number associated with this DeFi data.
163    #[must_use]
164    pub fn block_number(&self) -> u64 {
165        self.block_position().0
166    }
167
168    /// Returns the transaction index associated with this DeFi data.
169    #[must_use]
170    pub fn transaction_index(&self) -> u32 {
171        self.block_position().1
172    }
173
174    /// Returns the log index associated with this DeFi data.
175    #[must_use]
176    pub fn log_index(&self) -> u32 {
177        self.block_position().2
178    }
179
180    /// Returns the event timestamp associated with this DeFi data.
181    #[must_use]
182    pub fn ts_event(&self) -> UnixNanos {
183        match self {
184            Self::Block(block) => block.timestamp,
185            Self::Pool(pool) => pool.ts_event,
186            Self::PoolSnapshot(snapshot) => snapshot.ts_event,
187            Self::PoolSwap(swap) => swap.ts_event,
188            Self::PoolLiquidityUpdate(update) => update.ts_event,
189            Self::PoolFeeCollect(collect) => collect.ts_event,
190            Self::PoolFeeProtocolUpdate(update) => update.ts_event,
191            Self::PoolFeeProtocolCollect(collect) => collect.ts_event,
192            Self::PoolFlash(flash) => flash.ts_event,
193        }
194    }
195
196    /// Returns the event timestamp associated with this DeFi data.
197    #[must_use]
198    pub fn timestamp(&self) -> UnixNanos {
199        self.ts_event()
200    }
201
202    /// Returns the initialization timestamp associated with this DeFi data.
203    #[must_use]
204    pub fn ts_init(&self) -> UnixNanos {
205        match self {
206            Self::Block(block) => block.timestamp,
207            Self::Pool(pool) => pool.ts_init,
208            Self::PoolSnapshot(snapshot) => snapshot.ts_init,
209            Self::PoolSwap(swap) => swap.ts_init,
210            Self::PoolLiquidityUpdate(update) => update.ts_init,
211            Self::PoolFeeCollect(collect) => collect.ts_init,
212            Self::PoolFeeProtocolUpdate(update) => update.ts_init,
213            Self::PoolFeeProtocolCollect(collect) => collect.ts_init,
214            Self::PoolFlash(flash) => flash.ts_init,
215        }
216    }
217
218    /// Returns the instrument ID associated with this DeFi data.
219    ///
220    /// # Panics
221    ///
222    /// Panics if the variant is a `Block` or `PoolSnapshot` where instrument IDs are not applicable.
223    #[must_use]
224    pub fn instrument_id(&self) -> InstrumentId {
225        match self {
226            Self::Block(_) => panic!("`InstrumentId` not applicable to `Block`"), // TBD?
227            Self::PoolSnapshot(snapshot) => snapshot.instrument_id,
228            Self::PoolSwap(swap) => swap.instrument_id,
229            Self::PoolLiquidityUpdate(update) => update.instrument_id,
230            Self::PoolFeeCollect(collect) => collect.instrument_id,
231            Self::PoolFeeProtocolUpdate(update) => update.instrument_id,
232            Self::PoolFeeProtocolCollect(collect) => collect.instrument_id,
233            Self::Pool(pool) => pool.instrument_id,
234            Self::PoolFlash(flash) => flash.instrument_id,
235        }
236    }
237}
238
239impl HasTsInit for DefiData {
240    fn ts_init(&self) -> UnixNanos {
241        self.ts_init()
242    }
243}
244
245impl HasTsInit for Block {
246    fn ts_init(&self) -> UnixNanos {
247        self.timestamp
248    }
249}
250
251impl HasTsInit for PoolSnapshot {
252    fn ts_init(&self) -> UnixNanos {
253        self.ts_init
254    }
255}
256
257impl HasTsInit for PoolSwap {
258    fn ts_init(&self) -> UnixNanos {
259        self.ts_init
260    }
261}
262
263impl HasTsInit for PoolLiquidityUpdate {
264    fn ts_init(&self) -> UnixNanos {
265        self.ts_init
266    }
267}
268
269impl HasTsInit for PoolFeeCollect {
270    fn ts_init(&self) -> UnixNanos {
271        self.ts_init
272    }
273}
274
275impl HasTsInit for PoolFeeProtocolUpdate {
276    fn ts_init(&self) -> UnixNanos {
277        self.ts_init
278    }
279}
280
281impl HasTsInit for PoolFeeProtocolCollect {
282    fn ts_init(&self) -> UnixNanos {
283        self.ts_init
284    }
285}
286
287impl HasTsInit for PoolFlash {
288    fn ts_init(&self) -> UnixNanos {
289        self.ts_init
290    }
291}
292
293impl Display for DefiData {
294    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295        match self {
296            Self::Block(b) => write!(f, "{b}"),
297            Self::Pool(p) => write!(f, "{p}"),
298            Self::PoolSnapshot(s) => write!(f, "PoolSnapshot(block={})", s.block_position.number),
299            Self::PoolSwap(s) => write!(f, "{s}"),
300            Self::PoolLiquidityUpdate(u) => write!(f, "{u}"),
301            Self::PoolFeeCollect(c) => write!(f, "{c}"),
302            Self::PoolFeeProtocolUpdate(u) => write!(f, "{u}"),
303            Self::PoolFeeProtocolCollect(c) => write!(f, "{c}"),
304            Self::PoolFlash(p) => write!(f, "{p}"),
305        }
306    }
307}
308
309impl From<Pool> for DefiData {
310    fn from(value: Pool) -> Self {
311        Self::Pool(value)
312    }
313}
314
315impl From<PoolSwap> for DefiData {
316    fn from(value: PoolSwap) -> Self {
317        Self::PoolSwap(value)
318    }
319}
320
321impl From<PoolLiquidityUpdate> for DefiData {
322    fn from(value: PoolLiquidityUpdate) -> Self {
323        Self::PoolLiquidityUpdate(value)
324    }
325}
326
327impl From<PoolFeeCollect> for DefiData {
328    fn from(value: PoolFeeCollect) -> Self {
329        Self::PoolFeeCollect(value)
330    }
331}
332
333impl From<PoolFeeProtocolUpdate> for DefiData {
334    fn from(value: PoolFeeProtocolUpdate) -> Self {
335        Self::PoolFeeProtocolUpdate(value)
336    }
337}
338
339impl From<PoolFeeProtocolCollect> for DefiData {
340    fn from(value: PoolFeeProtocolCollect) -> Self {
341        Self::PoolFeeProtocolCollect(value)
342    }
343}
344
345impl From<PoolSnapshot> for DefiData {
346    fn from(value: PoolSnapshot) -> Self {
347        Self::PoolSnapshot(value)
348    }
349}
350
351impl From<PoolFlash> for DefiData {
352    fn from(value: PoolFlash) -> Self {
353        Self::PoolFlash(value)
354    }
355}