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