tycho_common/models/
mod.rs

1pub mod blockchain;
2pub mod contract;
3pub mod protocol;
4pub mod token;
5
6use std::{collections::HashMap, fmt::Display, str::FromStr, sync::Arc};
7
8use serde::{Deserialize, Serialize};
9use strum_macros::{Display, EnumString};
10use thiserror::Error;
11use token::CurrencyToken;
12
13use crate::{dto, Bytes};
14
15/// Address hash literal type to uniquely identify contracts/accounts on a
16/// blockchain.
17pub type Address = Bytes;
18
19/// Block hash literal type to uniquely identify a block in the chain and
20/// likely across chains.
21pub type BlockHash = Bytes;
22
23/// Transaction hash literal type to uniquely identify a transaction in the
24/// chain and likely across chains.
25pub type TxHash = Bytes;
26
27/// Smart contract code is represented as a byte vector containing opcodes.
28pub type Code = Bytes;
29
30/// The hash of a contract's code is used to identify it.
31pub type CodeHash = Bytes;
32
33/// The balance of an account is a big endian serialised integer of variable size.
34pub type Balance = Bytes;
35
36/// Key literal type of the contract store.
37pub type StoreKey = Bytes;
38
39/// Key literal type of the attribute store.
40pub type AttrStoreKey = String;
41
42/// Value literal type of the contract store.
43pub type StoreVal = Bytes;
44
45/// A binary key-value store for an account.
46pub type ContractStore = HashMap<StoreKey, StoreVal>;
47pub type ContractStoreDeltas = HashMap<StoreKey, Option<StoreVal>>;
48
49/// Multiple binary key-value stores grouped by account address.
50pub type AccountToContractStore = HashMap<Address, ContractStore>;
51pub type AccountToContractStoreDeltas = HashMap<Address, ContractStoreDeltas>;
52
53/// Component id literal type to uniquely identify a component.
54pub type ComponentId = String;
55
56/// Protocol system literal type to uniquely identify a protocol system.
57pub type ProtocolSystem = String;
58
59/// Entry point id literal type to uniquely identify an entry point.
60pub type EntryPointId = String;
61
62#[derive(
63    Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString, Display, Default,
64)]
65#[serde(rename_all = "lowercase")]
66#[strum(serialize_all = "lowercase")]
67pub enum Chain {
68    #[default]
69    Ethereum,
70    Starknet,
71    ZkSync,
72    Arbitrum,
73    Base,
74    Unichain,
75}
76
77impl From<dto::Chain> for Chain {
78    fn from(value: dto::Chain) -> Self {
79        match value {
80            dto::Chain::Ethereum => Chain::Ethereum,
81            dto::Chain::Starknet => Chain::Starknet,
82            dto::Chain::ZkSync => Chain::ZkSync,
83            dto::Chain::Arbitrum => Chain::Arbitrum,
84            dto::Chain::Base => Chain::Base,
85            dto::Chain::Unichain => Chain::Unichain,
86        }
87    }
88}
89
90fn native_eth(chain: Chain) -> CurrencyToken {
91    CurrencyToken::new(
92        &Bytes::from_str("0x0000000000000000000000000000000000000000").unwrap(),
93        "ETH",
94        18,
95        0,
96        &[Some(2300)],
97        chain,
98        100,
99    )
100}
101
102impl Chain {
103    /// Returns the native token symbol for the chain.
104    pub fn native_token(&self) -> CurrencyToken {
105        match self {
106            Chain::Ethereum => native_eth(Chain::Ethereum),
107            // It was decided that STRK token will be tracked as a dedicated AccountBalance on
108            // Starknet accounts and ETH balances will be tracked as a native balance.
109            Chain::Starknet => native_eth(Chain::Starknet),
110            Chain::ZkSync => native_eth(Chain::ZkSync),
111            Chain::Arbitrum => native_eth(Chain::Arbitrum),
112            Chain::Base => native_eth(Chain::Base),
113            Chain::Unichain => native_eth(Chain::Unichain),
114        }
115    }
116}
117
118#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Default)]
119pub struct ExtractorIdentity {
120    pub chain: Chain,
121    pub name: String,
122}
123
124impl ExtractorIdentity {
125    pub fn new(chain: Chain, name: &str) -> Self {
126        Self { chain, name: name.to_owned() }
127    }
128}
129
130impl std::fmt::Display for ExtractorIdentity {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        write!(f, "{}:{}", self.chain, self.name)
133    }
134}
135
136#[derive(Debug, PartialEq, Clone)]
137pub struct ExtractionState {
138    pub name: String,
139    pub chain: Chain,
140    pub attributes: serde_json::Value,
141    pub cursor: Vec<u8>,
142    pub block_hash: Bytes,
143}
144
145impl ExtractionState {
146    pub fn new(
147        name: String,
148        chain: Chain,
149        attributes: Option<serde_json::Value>,
150        cursor: &[u8],
151        block_hash: Bytes,
152    ) -> Self {
153        ExtractionState {
154            name,
155            chain,
156            attributes: attributes.unwrap_or_default(),
157            cursor: cursor.to_vec(),
158            block_hash,
159        }
160    }
161}
162
163// TODO: replace with types from dto on extractor
164#[typetag::serde(tag = "type")]
165pub trait NormalisedMessage:
166    std::any::Any + std::fmt::Debug + std::fmt::Display + Send + Sync + 'static
167{
168    fn source(&self) -> ExtractorIdentity;
169
170    fn drop_state(&self) -> Arc<dyn NormalisedMessage>;
171
172    fn as_any(&self) -> &dyn std::any::Any;
173}
174
175#[derive(PartialEq, Debug, Clone, Default, Deserialize, Serialize)]
176pub enum ImplementationType {
177    #[default]
178    Vm,
179    Custom,
180}
181
182#[derive(PartialEq, Debug, Clone, Default, Deserialize, Serialize)]
183pub enum FinancialType {
184    #[default]
185    Swap,
186    Psm,
187    Debt,
188    Leverage,
189}
190
191#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
192pub struct ProtocolType {
193    pub name: String,
194    pub financial_type: FinancialType,
195    pub attribute_schema: Option<serde_json::Value>,
196    pub implementation: ImplementationType,
197}
198
199impl ProtocolType {
200    pub fn new(
201        name: String,
202        financial_type: FinancialType,
203        attribute_schema: Option<serde_json::Value>,
204        implementation: ImplementationType,
205    ) -> Self {
206        ProtocolType { name, financial_type, attribute_schema, implementation }
207    }
208}
209
210#[derive(Debug, PartialEq, Default, Copy, Clone, Deserialize, Serialize)]
211pub enum ChangeType {
212    #[default]
213    Update,
214    Deletion,
215    Creation,
216}
217
218#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
219pub struct ContractId {
220    pub address: Address,
221    pub chain: Chain,
222}
223
224/// Uniquely identifies a contract on a specific chain.
225impl ContractId {
226    pub fn new(chain: Chain, address: Address) -> Self {
227        Self { address, chain }
228    }
229
230    pub fn address(&self) -> &Address {
231        &self.address
232    }
233}
234
235impl Display for ContractId {
236    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237        write!(f, "{:?}: 0x{}", self.chain, hex::encode(&self.address))
238    }
239}
240
241#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
242pub struct PaginationParams {
243    pub page: i64,
244    pub page_size: i64,
245}
246
247impl PaginationParams {
248    pub fn new(page: i64, page_size: i64) -> Self {
249        Self { page, page_size }
250    }
251
252    pub fn offset(&self) -> i64 {
253        self.page * self.page_size
254    }
255}
256
257impl From<&dto::PaginationParams> for PaginationParams {
258    fn from(value: &dto::PaginationParams) -> Self {
259        PaginationParams { page: value.page, page_size: value.page_size }
260    }
261}
262
263#[derive(Error, Debug, PartialEq)]
264pub enum MergeError {
265    #[error("Can't merge {0} from differring idendities: Expected {1}, got {2}")]
266    IdMismatch(String, String, String),
267    #[error("Can't merge {0} from different blocks: 0x{1:x} != 0x{2:x}")]
268    BlockMismatch(String, Bytes, Bytes),
269    #[error("Can't merge {0} from the same transaction: 0x{1:x}")]
270    SameTransaction(String, Bytes),
271    #[error("Can't merge {0} with lower transaction index: {1} > {2}")]
272    TransactionOrderError(String, u64, u64),
273}