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