Skip to main content

tycho_simulation/protocol/
models.rs

1//! Pair Properties and ProtocolState
2//!
3//! This module contains the `ProtocolComponent` struct, which represents the
4//! properties of a trading pair. It also contains the `Pair` struct, which
5//! represents a trading pair with its properties and corresponding state.
6//!
7//! Additionally, it contains the `GetAmountOutResult` struct, which
8//! represents the result of getting the amount out of a trading pair.
9//!
10//! The `ProtocolComponent` struct has two fields: `address` and `tokens`.
11//! `address` is the address of the trading pair and `tokens` is a vector
12//! of `ERC20Token` representing the tokens of the trading pair.
13//!
14//! Generally this struct contains immutable properties of the pair. These
15//! are attributes that will never change - not even through governance.
16//!
17//! This is in contrast to `ProtocolState`, which includes ideally only
18//! attributes that can change.
19//!
20//! The `Pair` struct combines the former two: `ProtocolComponent` and
21//! `ProtocolState` into a single struct.
22//!
23//! # Note:
24//! It's worth emphasizing that although the term "pair" used in this
25//! module refers to a trading pair, it does not necessarily imply two
26//! tokens only. Some pairs might have more than two tokens.
27use std::{collections::HashMap, default::Default, future::Future};
28
29use chrono::NaiveDateTime;
30use serde::{Deserialize, Serialize};
31use tycho_client::feed::{HeaderLike, SynchronizerState};
32use tycho_common::{
33    models::{token::Token, Chain},
34    simulation::protocol_sim::ProtocolSim,
35    Bytes,
36};
37
38/// Context struct containing attributes for decoders
39///
40/// This struct can be extended to include additional attributes for other decoders in the future
41#[derive(Debug, Clone)]
42pub struct DecoderContext {
43    pub adapter_path: Option<String>,
44    pub vm_traces: Option<bool>,
45}
46
47impl DecoderContext {
48    pub fn new() -> Self {
49        Self { adapter_path: None, vm_traces: None }
50    }
51
52    pub fn vm_adapter_path<S: Into<String>>(mut self, path: S) -> Self {
53        self.adapter_path = Some(path.into());
54        self
55    }
56
57    pub fn vm_traces(mut self, trace: bool) -> Self {
58        self.vm_traces = Some(trace);
59        self
60    }
61}
62
63impl Default for DecoderContext {
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69/// ProtocolComponent struct represents the properties of a trading pair
70///
71/// # Fields
72///
73/// * `address`: String, the address of the trading pair
74/// * `tokens`: `Vec<ERC20Token>`, the tokens of the trading pair
75#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76pub struct ProtocolComponent {
77    #[deprecated(since = "0.73.0", note = "Use `id` instead")]
78    pub address: Bytes,
79    pub id: Bytes,
80    pub tokens: Vec<Token>,
81    pub protocol_system: String,
82    pub protocol_type_name: String,
83    pub chain: Chain,
84    pub contract_ids: Vec<Bytes>,
85    pub static_attributes: HashMap<String, Bytes>,
86    pub creation_tx: Bytes,
87    pub created_at: NaiveDateTime,
88}
89
90impl ProtocolComponent {
91    #[allow(deprecated)]
92    #[allow(clippy::too_many_arguments)]
93    pub fn new(
94        id: Bytes,
95        protocol_system: String,
96        protocol_type_name: String,
97        chain: Chain,
98        tokens: Vec<Token>,
99        contract_ids: Vec<Bytes>,
100        static_attributes: HashMap<String, Bytes>,
101        creation_tx: Bytes,
102        created_at: NaiveDateTime,
103    ) -> Self {
104        ProtocolComponent {
105            address: Default::default(),
106            id,
107            tokens,
108            protocol_system,
109            protocol_type_name,
110            chain,
111            contract_ids,
112            static_attributes,
113            creation_tx,
114            created_at,
115        }
116    }
117
118    pub fn from_with_tokens(
119        core_model: tycho_common::dto::ProtocolComponent,
120        tokens: Vec<Token>,
121    ) -> Self {
122        let id = Bytes::from(core_model.id.as_str());
123        ProtocolComponent::new(
124            id.clone(),
125            core_model.protocol_system,
126            core_model.protocol_type_name,
127            core_model.chain.into(),
128            tokens,
129            core_model.contract_ids,
130            core_model.static_attributes,
131            core_model.creation_tx,
132            core_model.created_at,
133        )
134    }
135}
136
137impl From<ProtocolComponent> for tycho_common::models::protocol::ProtocolComponent {
138    fn from(component: ProtocolComponent) -> Self {
139        tycho_common::models::protocol::ProtocolComponent {
140            id: hex::encode(component.id),
141            protocol_system: component.protocol_system,
142            protocol_type_name: component.protocol_type_name,
143            chain: component.chain,
144            tokens: component
145                .tokens
146                .into_iter()
147                .map(|t| t.address)
148                .collect(),
149            static_attributes: component.static_attributes,
150            change: Default::default(),
151            creation_tx: component.creation_tx,
152            created_at: component.created_at,
153            contract_addresses: component.contract_ids,
154        }
155    }
156}
157
158pub trait TryFromWithBlock<T, H>
159where
160    H: HeaderLike,
161{
162    type Error;
163
164    fn try_from_with_header(
165        value: T,
166        block: H,
167        account_balances: &HashMap<Bytes, HashMap<Bytes, Bytes>>,
168        all_tokens: &HashMap<Bytes, Token>,
169        decoder_context: &DecoderContext,
170    ) -> impl Future<Output = Result<Self, Self::Error>> + Send + Sync
171    where
172        Self: Sized;
173}
174
175#[derive(Debug, Clone)]
176pub struct Update {
177    pub block_number_or_timestamp: u64,
178    /// Synchronization state per protocol
179    pub sync_states: HashMap<String, SynchronizerState>,
180    /// The new and updated states of this block
181    pub states: HashMap<String, Box<dyn ProtocolSim>>,
182    /// The new pairs that were added in this block
183    pub new_pairs: HashMap<String, ProtocolComponent>,
184    /// The pairs that were removed in this block
185    pub removed_pairs: HashMap<String, ProtocolComponent>,
186}
187
188impl Update {
189    pub fn new(
190        block_number: u64,
191        states: HashMap<String, Box<dyn ProtocolSim>>,
192        new_pairs: HashMap<String, ProtocolComponent>,
193    ) -> Self {
194        Update {
195            block_number_or_timestamp: block_number,
196            sync_states: HashMap::new(),
197            states,
198            new_pairs,
199            removed_pairs: HashMap::new(),
200        }
201    }
202
203    pub fn set_removed_pairs(mut self, pairs: HashMap<String, ProtocolComponent>) -> Self {
204        self.removed_pairs = pairs;
205        self
206    }
207
208    pub fn set_sync_states(mut self, sync_states: HashMap<String, SynchronizerState>) -> Self {
209        self.sync_states = sync_states;
210        self
211    }
212
213    pub fn merge(mut self, other: Update) -> Self {
214        self.states.extend(other.states);
215        self.new_pairs.extend(other.new_pairs);
216        self.removed_pairs
217            .extend(other.removed_pairs);
218        self
219    }
220}