tycho_common/traits.rs
1use core::fmt::Debug;
2use std::{collections::HashMap, sync::Arc};
3
4use async_trait::async_trait;
5
6use crate::{
7 models::{
8 blockchain::{Block, BlockTag, EntryPointWithTracingParams, TracedEntryPoint},
9 contract::AccountDelta,
10 token::{Token, TokenQuality, TransferCost, TransferTax},
11 Address, Balance, BlockHash, StoreKey,
12 },
13 Bytes,
14};
15
16/// A struct representing a request to get an account state.
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct StorageSnapshotRequest {
19 // The address of the account to get the state of.
20 pub address: Address,
21 // The specific slots to get the state of. If `None`, the entire account state will be
22 // returned.
23 pub slots: Option<Vec<StoreKey>>,
24}
25
26/// Trait for getting multiple account states from chain data.
27#[cfg_attr(feature = "test-utils", mockall::automock(type Error = String;))]
28#[async_trait]
29pub trait AccountExtractor {
30 type Error: Debug;
31
32 /// Get the account states at the end of the given block (after all transactions in the block
33 /// have been applied).
34 ///
35 /// # Arguments
36 ///
37 /// * `block`: The block at which to retrieve the account states.
38 /// * `requests`: A slice of `StorageSnapshotRequest` objects, each containing an address and
39 /// optional slots.
40 /// Note: If the `slots` field is `None`, the function will return the entire account state.
41 /// That could be a lot of data, so use with caution.
42 ///
43 /// returns: Result<HashMap<Bytes, AccountDelta, RandomState>, Self::Error>
44 /// A result containing a HashMap where the keys are `Bytes` (addresses) and the values are
45 /// `AccountDelta` objects.
46 async fn get_accounts_at_block(
47 &self,
48 block: &Block,
49 requests: &[StorageSnapshotRequest],
50 ) -> Result<HashMap<Bytes, AccountDelta>, Self::Error>; //TODO: do not return `AccountUpdate` but `Account`
51}
52
53/// Trait for analyzing a token, including its quality, transfer cost, and transfer tax.
54#[async_trait]
55pub trait TokenAnalyzer: Send + Sync {
56 type Error;
57
58 /// Analyzes the quality of a token given its address and a block tag.
59 ///
60 /// # Parameters
61 /// * `token` - The address of the token to analyze.
62 /// * `block` - The block tag at which the analysis should be performed.
63 ///
64 /// # Returns
65 /// A result containing:
66 /// * `TokenQuality` - The quality assessment of the token (either `Good` or `Bad`).
67 /// * `Option<TransferCost>` - The average cost per transfer, if available.
68 /// * `Option<TransferTax>` - The transfer tax, if applicable.
69 ///
70 /// On failure, returns `Self::Error`.
71 async fn analyze(
72 &self,
73 token: Bytes,
74 block: BlockTag,
75 ) -> Result<(TokenQuality, Option<TransferCost>, Option<TransferTax>), Self::Error>;
76}
77
78/// Trait for finding an address that owns a specific token. This is useful for detecting
79/// bad tokens by identifying addresses with enough balance to simulate transactions.
80#[async_trait]
81pub trait TokenOwnerFinding: Send + Sync + Debug {
82 /// Finds an address that holds at least `min_balance` of the specified token.
83 ///
84 /// # Parameters
85 /// * `token` - The address of the token to search for.
86 /// * `min_balance` - The minimum balance required for the address to be considered.
87 ///
88 /// # Returns
89 /// A result containing:
90 /// * `Option<(Address, Balance)>` - The address and its actual balance if an owner is found.
91 /// If no address meets the criteria, returns `None`.
92 /// On failure, returns a string representing an error message.
93 async fn find_owner(
94 &self,
95 token: Address,
96 min_balance: Balance,
97 ) -> Result<Option<(Address, Balance)>, String>; // TODO: introduce custom error type
98}
99
100/// Trait for retrieving additional information about tokens, such as the number of decimals
101/// and the token symbol, to help construct `CurrencyToken` objects.
102#[async_trait]
103pub trait TokenPreProcessor: Send + Sync {
104 /// Given a list of token addresses, this function retrieves additional metadata for each token.
105 ///
106 /// # Parameters
107 /// * `addresses` - A vector of token addresses to process.
108 /// * `token_finder` - A reference to a `TokenOwnerFinding` implementation to help find token
109 /// owners.
110 /// * `block` - The block tag at which the information should be retrieved.
111 ///
112 /// # Returns
113 /// A vector of `CurrencyToken` objects, each containing the processed information for the
114 /// token.
115 async fn get_tokens(
116 &self,
117 addresses: Vec<Bytes>,
118 token_finder: Arc<dyn TokenOwnerFinding>,
119 block: BlockTag,
120 ) -> Vec<Token>;
121}
122
123/// Trait for tracing blockchain transaction execution.
124#[cfg_attr(feature = "test-utils", mockall::automock(type Error = String;))]
125#[async_trait]
126pub trait EntryPointTracer: Sync {
127 type Error: Debug;
128
129 /// Traces the execution of a list of entry points at a specific block.
130 ///
131 /// # Parameters
132 /// * `block_hash` - The hash of the block at which to perform the trace. The trace will use the
133 /// state of the blockchain at this block.
134 /// * `entry_points` - A list of entry points to trace with their data.
135 ///
136 /// # Returns
137 /// Returns a vector of `TracedEntryPoint`, where each element contains:
138 /// * `retriggers` - A set of (address, storage slot) pairs representing storage locations that
139 /// could alter tracing results. If any of these storage slots change, the set of called
140 /// contract might be outdated.
141 /// * `accessed_slots` - A map of all contract addresses that were called during the trace with
142 /// a list of storage slots that were accessed (read or written).
143 async fn trace(
144 &self,
145 block_hash: BlockHash,
146 entry_points: Vec<EntryPointWithTracingParams>,
147 ) -> Result<Vec<TracedEntryPoint>, Self::Error>;
148}