nautilus_model/defi/
dex.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Posei Systems Pty Ltd. All rights reserved.
3//  https://poseitrader.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::{borrow::Cow, fmt::Display, sync::Arc};
17
18use serde::{Deserialize, Serialize};
19
20use crate::{
21    defi::{amm::Pool, chain::Chain},
22    identifiers::{InstrumentId, Symbol, Venue},
23    instruments::{Instrument, any::InstrumentAny, currency_pair::CurrencyPair},
24    types::{currency::Currency, fixed::FIXED_PRECISION, price::Price, quantity::Quantity},
25};
26
27/// Represents different types of Automated Market Makers (AMMs) in DeFi protocols.
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29#[non_exhaustive]
30pub enum AmmType {
31    /// Constant Product Automated Market Maker.
32    CPAMM,
33    /// Concentrated Liquidity Automated Market Maker.
34    CLAMM,
35    /// Concentrated liquidity AMM **with hooks** (e.g. upcoming Uniswap v4).
36    CLAMEnhanced,
37    /// Specialized Constant-Sum AMM for low-volatility assets (Curve-style “StableSwap”).
38    StableSwap,
39    /// AMM with customizable token weights (e.g., Balancer style).
40    WeightedPool,
41    /// Advanced pool type that can nest other pools (Balancer V3).
42    ComposablePool,
43}
44
45/// Represents a decentralized exchange (DEX) in a blockchain ecosystem.
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub struct Dex {
48    /// The blockchain network where this DEX operates.
49    pub chain: Chain,
50    /// The name of the DEX protocol.
51    pub name: Cow<'static, str>,
52    /// The blockchain address of the DEX factory contract.
53    pub factory: Cow<'static, str>,
54    /// The event signature or identifier used to detect pool creation events.
55    pub pool_created_event: Cow<'static, str>,
56    /// The event signature or identifier used to detect swap events.
57    pub swap_created_event: Cow<'static, str>,
58    /// The event signature or identifier used to detect mint events.
59    pub mint_created_event: Cow<'static, str>,
60    /// The event signature or identifier used to detect burn events.
61    pub burn_created_event: Cow<'static, str>,
62    /// The type of automated market maker (AMM) algorithm used by this DEX.
63    pub amm_type: AmmType,
64    /// Collection of liquidity pools managed by this DEX.
65    #[allow(dead_code)] // TBD
66    pairs: Vec<Pool>,
67}
68
69/// A thread-safe shared pointer to a `Dex`, enabling efficient reuse across multiple components.
70pub type SharedDex = Arc<Dex>;
71
72impl Dex {
73    /// Creates a new [`Dex`] instance with the specified properties.
74    #[must_use]
75    #[allow(clippy::too_many_arguments)]
76    pub fn new(
77        chain: Chain,
78        name: impl Into<Cow<'static, str>>,
79        factory: impl Into<Cow<'static, str>>,
80        amm_type: AmmType,
81        pool_created_event: impl Into<Cow<'static, str>>,
82        swap_created_event: impl Into<Cow<'static, str>>,
83        mint_created_event: impl Into<Cow<'static, str>>,
84        burn_created_event: impl Into<Cow<'static, str>>,
85    ) -> Self {
86        Self {
87            chain,
88            name: name.into(),
89            factory: factory.into(),
90            pool_created_event: pool_created_event.into(),
91            swap_created_event: swap_created_event.into(),
92            mint_created_event: mint_created_event.into(),
93            burn_created_event: burn_created_event.into(),
94            amm_type,
95            pairs: vec![],
96        }
97    }
98
99    /// Returns a unique identifier for this DEX, combining chain and protocol name.
100    pub fn id(&self) -> String {
101        format!(
102            "{}:{}",
103            self.chain.name,
104            self.name.to_lowercase().replace(' ', "_")
105        )
106    }
107}
108
109impl Display for Dex {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        write!(f, "Dex(chain={}, name={})", self.chain, self.name)
112    }
113}
114
115impl From<Pool> for CurrencyPair {
116    fn from(p: Pool) -> Self {
117        let symbol = Symbol::from(format!("{}/{}", p.token0.symbol, p.token1.symbol));
118        let id = InstrumentId::new(symbol, Venue::from(p.dex.id()));
119
120        let size_precision = p.token0.decimals.min(FIXED_PRECISION);
121        let price_precision = p.token1.decimals.min(FIXED_PRECISION);
122
123        let price_increment = Price::new(10f64.powi(-(price_precision as i32)), price_precision);
124        let size_increment = Quantity::new(10f64.powi(-(size_precision as i32)), size_precision);
125
126        CurrencyPair::new(
127            id,
128            symbol,
129            Currency::from(p.token0.symbol.as_str()),
130            Currency::from(p.token1.symbol.as_str()),
131            price_precision,
132            size_precision,
133            price_increment,
134            size_increment,
135            None,
136            None,
137            None,
138            None,
139            None,
140            None,
141            None,
142            None,
143            None,
144            None,
145            None,
146            0.into(),
147            0.into(),
148        )
149    }
150}
151
152impl From<Pool> for InstrumentAny {
153    fn from(p: Pool) -> Self {
154        CurrencyPair::from(p).into_any()
155    }
156}