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