Skip to main content

nautilus_common/messages/defi/
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) specific messages.
17
18use std::any::Any;
19
20use nautilus_core::{UUID4, UnixNanos};
21use nautilus_model::{
22    defi::Blockchain,
23    identifiers::{ClientId, Venue},
24};
25use serde::{Deserialize, Serialize};
26
27pub mod request;
28pub mod subscribe;
29pub mod unsubscribe;
30
31// Re-exports
32pub use request::RequestPoolSnapshot;
33pub use subscribe::{
34    SubscribeBlocks, SubscribePool, SubscribePoolFeeCollects, SubscribePoolFlashEvents,
35    SubscribePoolLiquidityUpdates, SubscribePoolSwaps,
36};
37pub use unsubscribe::{
38    UnsubscribeBlocks, UnsubscribePool, UnsubscribePoolFeeCollects, UnsubscribePoolFlashEvents,
39    UnsubscribePoolLiquidityUpdates, UnsubscribePoolSwaps,
40};
41
42#[derive(Clone, Debug, Serialize, Deserialize)]
43pub enum DefiDataCommand {
44    Request(DefiRequestCommand),
45    Subscribe(DefiSubscribeCommand),
46    Unsubscribe(DefiUnsubscribeCommand),
47}
48
49impl PartialEq for DefiDataCommand {
50    fn eq(&self, other: &Self) -> bool {
51        self.command_id() == other.command_id()
52    }
53}
54
55impl DefiDataCommand {
56    /// Converts the command to a dyn Any trait object for messaging.
57    pub fn as_any(&self) -> &dyn Any {
58        self
59    }
60
61    pub fn command_id(&self) -> UUID4 {
62        match self {
63            Self::Request(cmd) => *cmd.request_id(),
64            Self::Subscribe(cmd) => cmd.command_id(),
65            Self::Unsubscribe(cmd) => cmd.command_id(),
66        }
67    }
68
69    pub fn client_id(&self) -> Option<&ClientId> {
70        match self {
71            Self::Request(cmd) => cmd.client_id(),
72            Self::Subscribe(cmd) => cmd.client_id(),
73            Self::Unsubscribe(cmd) => cmd.client_id(),
74        }
75    }
76
77    pub fn venue(&self) -> Option<&Venue> {
78        match self {
79            Self::Request(cmd) => cmd.venue(),
80            Self::Subscribe(cmd) => cmd.venue(),
81            Self::Unsubscribe(cmd) => cmd.venue(),
82        }
83    }
84
85    pub fn ts_init(&self) -> UnixNanos {
86        match self {
87            Self::Request(cmd) => cmd.ts_init(),
88            Self::Subscribe(cmd) => cmd.ts_init(),
89            Self::Unsubscribe(cmd) => cmd.ts_init(),
90        }
91    }
92}
93
94#[derive(Clone, Debug, Serialize, Deserialize)]
95pub enum DefiSubscribeCommand {
96    Blocks(SubscribeBlocks),
97    Pool(SubscribePool),
98    PoolSwaps(SubscribePoolSwaps),
99    PoolLiquidityUpdates(SubscribePoolLiquidityUpdates),
100    PoolFeeCollects(SubscribePoolFeeCollects),
101    PoolFlashEvents(SubscribePoolFlashEvents),
102}
103
104impl PartialEq for DefiSubscribeCommand {
105    fn eq(&self, other: &Self) -> bool {
106        self.command_id() == other.command_id()
107    }
108}
109
110impl DefiSubscribeCommand {
111    /// Converts the command to a dyn Any trait object for messaging.
112    pub fn as_any(&self) -> &dyn Any {
113        self
114    }
115
116    /// Returns the blockchain associated with this command.
117    ///
118    /// # Panics
119    ///
120    /// Panics if the instrument ID's venue cannot be parsed as a valid blockchain venue
121    /// for `Pool`, `PoolSwaps`, `PoolLiquidityUpdates`, `PoolFeeCollects`, or `PoolFlashEvents` commands.
122    pub fn blockchain(&self) -> Blockchain {
123        match self {
124            Self::Blocks(cmd) => cmd.chain,
125            Self::Pool(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
126            Self::PoolSwaps(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
127            Self::PoolLiquidityUpdates(cmd) => {
128                cmd.instrument_id.blockchain().expect("Invalid venue")
129            }
130            Self::PoolFeeCollects(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
131            Self::PoolFlashEvents(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
132        }
133    }
134
135    pub fn command_id(&self) -> UUID4 {
136        match self {
137            Self::Blocks(cmd) => cmd.command_id,
138            Self::Pool(cmd) => cmd.command_id,
139            Self::PoolSwaps(cmd) => cmd.command_id,
140            Self::PoolLiquidityUpdates(cmd) => cmd.command_id,
141            Self::PoolFeeCollects(cmd) => cmd.command_id,
142            Self::PoolFlashEvents(cmd) => cmd.command_id,
143        }
144    }
145
146    pub fn client_id(&self) -> Option<&ClientId> {
147        match self {
148            Self::Blocks(cmd) => cmd.client_id.as_ref(),
149            Self::Pool(cmd) => cmd.client_id.as_ref(),
150            Self::PoolSwaps(cmd) => cmd.client_id.as_ref(),
151            Self::PoolLiquidityUpdates(cmd) => cmd.client_id.as_ref(),
152            Self::PoolFeeCollects(cmd) => cmd.client_id.as_ref(),
153            Self::PoolFlashEvents(cmd) => cmd.client_id.as_ref(),
154        }
155    }
156
157    // TODO: TBD
158    pub fn venue(&self) -> Option<&Venue> {
159        match self {
160            Self::Blocks(_) => None,
161            Self::Pool(_) => None,
162            Self::PoolSwaps(_) => None,
163            Self::PoolLiquidityUpdates(_) => None,
164            Self::PoolFeeCollects(_) => None,
165            Self::PoolFlashEvents(_) => None,
166        }
167    }
168
169    pub fn ts_init(&self) -> UnixNanos {
170        match self {
171            Self::Blocks(cmd) => cmd.ts_init,
172            Self::PoolSwaps(cmd) => cmd.ts_init,
173            Self::PoolLiquidityUpdates(cmd) => cmd.ts_init,
174            Self::Pool(cmd) => cmd.ts_init,
175            Self::PoolFeeCollects(cmd) => cmd.ts_init,
176            Self::PoolFlashEvents(cmd) => cmd.ts_init,
177        }
178    }
179}
180
181#[derive(Clone, Debug, Serialize, Deserialize)]
182pub enum DefiUnsubscribeCommand {
183    Blocks(UnsubscribeBlocks),
184    Pool(UnsubscribePool),
185    PoolSwaps(UnsubscribePoolSwaps),
186    PoolLiquidityUpdates(UnsubscribePoolLiquidityUpdates),
187    PoolFeeCollects(UnsubscribePoolFeeCollects),
188    PoolFlashEvents(UnsubscribePoolFlashEvents),
189}
190
191impl PartialEq for DefiUnsubscribeCommand {
192    fn eq(&self, other: &Self) -> bool {
193        self.command_id() == other.command_id()
194    }
195}
196
197impl DefiUnsubscribeCommand {
198    /// Converts the command to a dyn Any trait object for messaging.
199    pub fn as_any(&self) -> &dyn Any {
200        self
201    }
202
203    /// Returns the blockchain associated with this command.
204    ///
205    /// # Panics
206    ///
207    /// Panics if the instrument ID's venue cannot be parsed as a valid blockchain venue
208    /// for `Pool`, `PoolSwaps`, `PoolLiquidityUpdates`, `PoolFeeCollects`, or `PoolFlashEvents` commands.
209    pub fn blockchain(&self) -> Blockchain {
210        match self {
211            Self::Blocks(cmd) => cmd.chain,
212            Self::Pool(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
213            Self::PoolSwaps(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
214            Self::PoolLiquidityUpdates(cmd) => {
215                cmd.instrument_id.blockchain().expect("Invalid venue")
216            }
217            Self::PoolFeeCollects(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
218            Self::PoolFlashEvents(cmd) => cmd.instrument_id.blockchain().expect("Invalid venue"),
219        }
220    }
221
222    pub fn command_id(&self) -> UUID4 {
223        match self {
224            Self::Blocks(cmd) => cmd.command_id,
225            Self::Pool(cmd) => cmd.command_id,
226            Self::PoolSwaps(cmd) => cmd.command_id,
227            Self::PoolLiquidityUpdates(cmd) => cmd.command_id,
228            Self::PoolFeeCollects(cmd) => cmd.command_id,
229            Self::PoolFlashEvents(cmd) => cmd.command_id,
230        }
231    }
232
233    pub fn client_id(&self) -> Option<&ClientId> {
234        match self {
235            Self::Blocks(cmd) => cmd.client_id.as_ref(),
236            Self::Pool(cmd) => cmd.client_id.as_ref(),
237            Self::PoolSwaps(cmd) => cmd.client_id.as_ref(),
238            Self::PoolLiquidityUpdates(cmd) => cmd.client_id.as_ref(),
239            Self::PoolFeeCollects(cmd) => cmd.client_id.as_ref(),
240            Self::PoolFlashEvents(cmd) => cmd.client_id.as_ref(),
241        }
242    }
243
244    // TODO: TBD
245    pub fn venue(&self) -> Option<&Venue> {
246        match self {
247            Self::Blocks(_) => None,
248            Self::Pool(_) => None,
249            Self::PoolSwaps(_) => None,
250            Self::PoolLiquidityUpdates(_) => None,
251            Self::PoolFeeCollects(_) => None,
252            Self::PoolFlashEvents(_) => None,
253        }
254    }
255
256    pub fn ts_init(&self) -> UnixNanos {
257        match self {
258            Self::Blocks(cmd) => cmd.ts_init,
259            Self::Pool(cmd) => cmd.ts_init,
260            Self::PoolSwaps(cmd) => cmd.ts_init,
261            Self::PoolLiquidityUpdates(cmd) => cmd.ts_init,
262            Self::PoolFeeCollects(cmd) => cmd.ts_init,
263            Self::PoolFlashEvents(cmd) => cmd.ts_init,
264        }
265    }
266}
267
268#[derive(Clone, Debug, Serialize, Deserialize)]
269pub enum DefiRequestCommand {
270    PoolSnapshot(RequestPoolSnapshot),
271}
272
273impl PartialEq for DefiRequestCommand {
274    fn eq(&self, other: &Self) -> bool {
275        self.request_id() == other.request_id()
276    }
277}
278
279impl DefiRequestCommand {
280    /// Converts the command to a dyn Any trait object for messaging.
281    pub fn as_any(&self) -> &dyn Any {
282        self
283    }
284
285    pub fn request_id(&self) -> &UUID4 {
286        match self {
287            Self::PoolSnapshot(cmd) => &cmd.request_id,
288        }
289    }
290
291    pub fn client_id(&self) -> Option<&ClientId> {
292        match self {
293            Self::PoolSnapshot(cmd) => cmd.client_id.as_ref(),
294        }
295    }
296
297    pub fn venue(&self) -> Option<&Venue> {
298        match self {
299            Self::PoolSnapshot(cmd) => Some(&cmd.instrument_id.venue),
300        }
301    }
302
303    pub fn ts_init(&self) -> UnixNanos {
304        match self {
305            Self::PoolSnapshot(cmd) => cmd.ts_init,
306        }
307    }
308}