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        mut tokens: Vec<Token>,
121    ) -> Self {
122        tokens.sort_unstable_by_key(|t| t.address.clone());
123        let id = Bytes::from(core_model.id.as_str());
124        ProtocolComponent::new(
125            id.clone(),
126            core_model.protocol_system,
127            core_model.protocol_type_name,
128            core_model.chain.into(),
129            tokens,
130            core_model.contract_ids,
131            core_model.static_attributes,
132            core_model.creation_tx,
133            core_model.created_at,
134        )
135    }
136}
137
138impl From<ProtocolComponent> for tycho_common::models::protocol::ProtocolComponent {
139    fn from(component: ProtocolComponent) -> Self {
140        tycho_common::models::protocol::ProtocolComponent {
141            id: hex::encode(component.id),
142            protocol_system: component.protocol_system,
143            protocol_type_name: component.protocol_type_name,
144            chain: component.chain,
145            tokens: component
146                .tokens
147                .into_iter()
148                .map(|t| t.address)
149                .collect(),
150            static_attributes: component.static_attributes,
151            change: Default::default(),
152            creation_tx: component.creation_tx,
153            created_at: component.created_at,
154            contract_addresses: component.contract_ids,
155        }
156    }
157}
158
159pub trait TryFromWithBlock<T, H>
160where
161    H: HeaderLike,
162{
163    type Error;
164
165    fn try_from_with_header(
166        value: T,
167        block: H,
168        account_balances: &HashMap<Bytes, HashMap<Bytes, Bytes>>,
169        all_tokens: &HashMap<Bytes, Token>,
170        decoder_context: &DecoderContext,
171    ) -> impl Future<Output = Result<Self, Self::Error>> + Send + Sync
172    where
173        Self: Sized;
174}
175
176#[derive(Debug, Clone)]
177pub struct Update {
178    pub block_number_or_timestamp: u64,
179    /// Synchronization state per protocol
180    pub sync_states: HashMap<String, SynchronizerState>,
181    /// The new and updated states of this block
182    pub states: HashMap<String, Box<dyn ProtocolSim>>,
183    /// The new pairs that were added in this block
184    pub new_pairs: HashMap<String, ProtocolComponent>,
185    /// The pairs that were removed in this block
186    pub removed_pairs: HashMap<String, ProtocolComponent>,
187}
188
189impl Update {
190    pub fn new(
191        block_number: u64,
192        states: HashMap<String, Box<dyn ProtocolSim>>,
193        new_pairs: HashMap<String, ProtocolComponent>,
194    ) -> Self {
195        Update {
196            block_number_or_timestamp: block_number,
197            sync_states: HashMap::new(),
198            states,
199            new_pairs,
200            removed_pairs: HashMap::new(),
201        }
202    }
203
204    pub fn set_removed_pairs(mut self, pairs: HashMap<String, ProtocolComponent>) -> Self {
205        self.removed_pairs = pairs;
206        self
207    }
208
209    pub fn set_sync_states(mut self, sync_states: HashMap<String, SynchronizerState>) -> Self {
210        self.sync_states = sync_states;
211        self
212    }
213
214    pub fn merge(mut self, other: Update) -> Self {
215        self.states.extend(other.states);
216        self.new_pairs.extend(other.new_pairs);
217        self.removed_pairs
218            .extend(other.removed_pairs);
219        self
220    }
221}