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}