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    Bsc,
73    Unichain,
74}
75
76impl From<dto::Chain> for Chain {
77    fn from(value: dto::Chain) -> Self {
78        match value {
79            dto::Chain::Ethereum => Chain::Ethereum,
80            dto::Chain::Starknet => Chain::Starknet,
81            dto::Chain::ZkSync => Chain::ZkSync,
82            dto::Chain::Arbitrum => Chain::Arbitrum,
83            dto::Chain::Base => Chain::Base,
84            dto::Chain::Bsc => Chain::Bsc,
85            dto::Chain::Unichain => Chain::Unichain,
86        }
87    }
88}
89
90fn native_eth(chain: Chain) -> Token {
91    Token::new(
92        &Bytes::from_str("0x0000000000000000000000000000000000000000").unwrap(),
93        "ETH",
94        18,
95        0,
96        &[Some(2300)],
97        chain,
98        100,
99    )
100}
101
102fn native_bsc(chain: Chain) -> Token {
103    Token::new(
104        &Bytes::from_str("0x0000000000000000000000000000000000000000").unwrap(),
105        "BNB",
106        18,
107        0,
108        &[Some(2300)],
109        chain,
110        100,
111    )
112}
113
114fn wrapped_native_eth(chain: Chain, address: &str) -> Token {
115    Token::new(&Bytes::from_str(address).unwrap(), "WETH", 18, 0, &[Some(2300)], chain, 100)
116}
117
118fn wrapped_native_bsc(chain: Chain, address: &str) -> Token {
119    Token::new(&Bytes::from_str(address).unwrap(), "WBNB", 18, 0, &[Some(2300)], chain, 100)
120}
121
122impl Chain {
123    pub fn id(&self) -> u64 {
124        match self {
125            Chain::Ethereum => 1,
126            Chain::ZkSync => 324,
127            Chain::Arbitrum => 42161,
128            Chain::Starknet => 0,
129            Chain::Base => 8453,
130            Chain::Bsc => 56,
131            Chain::Unichain => 130,
132        }
133    }
134
135    /// Returns the native token for the chain.
136    pub fn native_token(&self) -> Token {
137        match self {
138            Chain::Ethereum => native_eth(Chain::Ethereum),
139            // It was decided that STRK token will be tracked as a dedicated AccountBalance on
140            // Starknet accounts and ETH balances will be tracked as a native balance.
141            Chain::Starknet => native_eth(Chain::Starknet),
142            Chain::ZkSync => native_eth(Chain::ZkSync),
143            Chain::Arbitrum => native_eth(Chain::Arbitrum),
144            Chain::Base => native_eth(Chain::Base),
145            Chain::Bsc => native_bsc(Chain::Bsc),
146            Chain::Unichain => native_eth(Chain::Unichain),
147        }
148    }
149
150    /// Returns the wrapped native token for the chain.
151    pub fn wrapped_native_token(&self) -> Token {
152        match self {
153            Chain::Ethereum => {
154                wrapped_native_eth(Chain::Ethereum, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
155            }
156            // Starknet does not have a wrapped native token
157            Chain::Starknet => {
158                wrapped_native_eth(Chain::Starknet, "0x0000000000000000000000000000000000000000")
159            }
160            Chain::ZkSync => {
161                wrapped_native_eth(Chain::ZkSync, "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")
162            }
163            Chain::Arbitrum => {
164                wrapped_native_eth(Chain::Arbitrum, "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
165            }
166            Chain::Base => {
167                wrapped_native_eth(Chain::Base, "0x4200000000000000000000000000000000000006")
168            }
169            Chain::Bsc => {
170                wrapped_native_bsc(Chain::Bsc, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c")
171            }
172            Chain::Unichain => {
173                wrapped_native_eth(Chain::Unichain, "0x4200000000000000000000000000000000000006")
174            }
175        }
176    }
177}
178
179#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Default)]
180pub struct ExtractorIdentity {
181    pub chain: Chain,
182    pub name: String,
183}
184
185impl ExtractorIdentity {
186    pub fn new(chain: Chain, name: &str) -> Self {
187        Self { chain, name: name.to_owned() }
188    }
189}
190
191impl std::fmt::Display for ExtractorIdentity {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        write!(f, "{}:{}", self.chain, self.name)
194    }
195}
196
197impl From<ExtractorIdentity> for dto::ExtractorIdentity {
198    fn from(value: ExtractorIdentity) -> Self {
199        dto::ExtractorIdentity { chain: value.chain.into(), name: value.name }
200    }
201}
202
203impl From<dto::ExtractorIdentity> for ExtractorIdentity {
204    fn from(value: dto::ExtractorIdentity) -> Self {
205        Self { chain: value.chain.into(), name: value.name }
206    }
207}
208
209#[derive(Debug, PartialEq, Clone)]
210pub struct ExtractionState {
211    pub name: String,
212    pub chain: Chain,
213    pub attributes: serde_json::Value,
214    pub cursor: Vec<u8>,
215    pub block_hash: Bytes,
216}
217
218impl ExtractionState {
219    pub fn new(
220        name: String,
221        chain: Chain,
222        attributes: Option<serde_json::Value>,
223        cursor: &[u8],
224        block_hash: Bytes,
225    ) -> Self {
226        ExtractionState {
227            name,
228            chain,
229            attributes: attributes.unwrap_or_default(),
230            cursor: cursor.to_vec(),
231            block_hash,
232        }
233    }
234}
235
236#[derive(PartialEq, Debug, Clone, Default, Deserialize, Serialize)]
237pub enum ImplementationType {
238    #[default]
239    Vm,
240    Custom,
241}
242
243#[derive(PartialEq, Debug, Clone, Default, Deserialize, Serialize)]
244pub enum FinancialType {
245    #[default]
246    Swap,
247    Psm,
248    Debt,
249    Leverage,
250}
251
252#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
253pub struct ProtocolType {
254    pub name: String,
255    pub financial_type: FinancialType,
256    pub attribute_schema: Option<serde_json::Value>,
257    pub implementation: ImplementationType,
258}
259
260impl ProtocolType {
261    pub fn new(
262        name: String,
263        financial_type: FinancialType,
264        attribute_schema: Option<serde_json::Value>,
265        implementation: ImplementationType,
266    ) -> Self {
267        ProtocolType { name, financial_type, attribute_schema, implementation }
268    }
269}
270
271#[derive(Debug, PartialEq, Default, Copy, Clone, Deserialize, Serialize)]
272pub enum ChangeType {
273    #[default]
274    Update,
275    Deletion,
276    Creation,
277}
278
279#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
280pub struct ContractId {
281    pub address: Address,
282    pub chain: Chain,
283}
284
285/// Uniquely identifies a contract on a specific chain.
286impl ContractId {
287    pub fn new(chain: Chain, address: Address) -> Self {
288        Self { address, chain }
289    }
290
291    pub fn address(&self) -> &Address {
292        &self.address
293    }
294}
295
296impl Display for ContractId {
297    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298        write!(f, "{:?}: 0x{}", self.chain, hex::encode(&self.address))
299    }
300}
301
302#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
303pub struct PaginationParams {
304    pub page: i64,
305    pub page_size: i64,
306}
307
308impl PaginationParams {
309    pub fn new(page: i64, page_size: i64) -> Self {
310        Self { page, page_size }
311    }
312
313    pub fn offset(&self) -> i64 {
314        self.page * self.page_size
315    }
316}
317
318impl From<&dto::PaginationParams> for PaginationParams {
319    fn from(value: &dto::PaginationParams) -> Self {
320        PaginationParams { page: value.page, page_size: value.page_size }
321    }
322}
323
324#[derive(Error, Debug, PartialEq)]
325pub enum MergeError {
326    #[error("Can't merge {0} from differring idendities: Expected {1}, got {2}")]
327    IdMismatch(String, String, String),
328    #[error("Can't merge {0} from different blocks: 0x{1:x} != 0x{2:x}")]
329    BlockMismatch(String, Bytes, Bytes),
330    #[error("Can't merge {0} from the same transaction: 0x{1:x}")]
331    SameTransaction(String, Bytes),
332    #[error("Can't merge {0} with lower transaction index: {1} > {2}")]
333    TransactionOrderError(String, u64, u64),
334}