tycho_common/models/
mod.rs

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