tycho_common/storage.rs
1//! Storage traits used by Tycho
2use std::{collections::HashMap, fmt::Display};
3
4use async_trait::async_trait;
5use chrono::NaiveDateTime;
6use thiserror::Error;
7
8use crate::{
9 dto,
10 models::{
11 blockchain::{Block, Transaction},
12 contract::{Account, AccountBalance, AccountDelta},
13 protocol::{
14 ComponentBalance, ProtocolComponent, ProtocolComponentState,
15 ProtocolComponentStateDelta, QualityRange,
16 },
17 token::CurrencyToken,
18 Address, BlockHash, Chain, ComponentId, ContractId, ExtractionState, PaginationParams,
19 ProtocolType, TxHash,
20 },
21 Bytes,
22};
23
24/// Identifies a block in storage.
25#[derive(Debug, Clone, PartialEq, Hash, Eq)]
26pub enum BlockIdentifier {
27 /// Identifies the block by its position on a specified chain.
28 ///
29 /// This form of identification has potential risks as it may become
30 /// ambiguous in certain situations. For example, if the block has not been
31 /// finalised, there exists a possibility of forks occurring. As a result,
32 /// the same number could refer to different blocks on different forks.
33 Number((Chain, i64)),
34
35 /// Identifies a block by its hash.
36 ///
37 /// The hash should be unique across multiple chains. Preferred method if
38 /// the block is very recent.
39 Hash(BlockHash),
40
41 /// Latest stored block for the target chain
42 ///
43 /// Returns the block with the highest block number on the target chain.
44 Latest(Chain),
45}
46
47impl Display for BlockIdentifier {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "{self:?}")
50 }
51}
52
53#[derive(Error, Debug, PartialEq)]
54pub enum StorageError {
55 #[error("Could not find {0} with id `{1}`!")]
56 NotFound(String, String),
57 #[error("The entity {0} with id {1} was already present!")]
58 DuplicateEntry(String, String),
59 #[error("Could not find related {0} for {1} with id `{2}`!")]
60 NoRelatedEntity(String, String, String),
61 #[error("DecodeError: {0}")]
62 DecodeError(String),
63 #[error("Unexpected storage error: {0}")]
64 Unexpected(String),
65 #[error("Currently unsupported operation: {0}")]
66 Unsupported(String),
67 #[error("Write cache unexpectedly dropped notification channel!")]
68 WriteCacheGoneAway(),
69 #[error("Invalid block range encountered")]
70 InvalidBlockRange(),
71}
72
73/// Storage methods for chain specific objects.
74///
75/// This trait abstracts the specific implementation details of a blockchain's
76/// entities, allowing the user to add and retrieve blocks and transactions in a
77/// generic way.
78///
79/// For traceability protocol components and contracts changes are linked to
80/// blocks of their respective chain if applicable. This means while indexing we
81/// need to keep a lightweight and cross chain compatible representation of
82/// blocks and transactions in storage.
83///
84/// It's defined generically over two associated types:
85///
86/// * `Block`: represents a block in the blockchain.
87/// * `Transaction`: represents a transaction within a block.
88#[async_trait]
89pub trait ChainGateway {
90 /// Upserts a new block to the blockchain's storage.
91 ///
92 /// Ignores any existing tx, if the new entry has different attributes
93 /// no error is raised and the old entry is kept.
94 ///
95 /// # Parameters
96 /// - `new`: An instance of `Self::Block`, representing the new block to be stored.
97 ///
98 /// # Returns
99 /// - Empty ok result indicates success. Failure might occur if the block is already present.
100 async fn upsert_block(&self, new: &[Block]) -> Result<(), StorageError>;
101 /// Retrieves a block from storage.
102 ///
103 /// # Parameters
104 /// - `id`: Block's unique identifier of type `BlockIdentifier`.
105 ///
106 /// # Returns
107 /// - An Ok result containing the block. Might fail if the block does not exist yet.
108 async fn get_block(&self, id: &BlockIdentifier) -> Result<Block, StorageError>;
109 /// Upserts a transaction to storage.
110 ///
111 /// Ignores any existing tx, if the new entry has different attributes
112 /// no error is raised and the old entry is kept.
113 ///
114 /// # Parameters
115 /// - `new`: An instance of `Self::Transaction`, representing the new transaction to be stored.
116 ///
117 /// # Returns
118 /// - Empty ok result indicates success. Failure might occur if the
119 /// corresponding block does not exists yet, or if the transaction already
120 /// exists.
121 async fn upsert_tx(&self, new: &[Transaction]) -> Result<(), StorageError>;
122
123 /// Tries to retrieve a transaction from the blockchain's storage using its
124 /// hash.
125 ///
126 /// # Parameters
127 /// - `hash`: The byte slice representing the hash of the transaction to be retrieved.
128 ///
129 /// # Returns
130 /// - An Ok result containing the transaction. Might fail if the transaction does not exist yet.
131 async fn get_tx(&self, hash: &TxHash) -> Result<Transaction, StorageError>;
132
133 /// Reverts the blockchain storage to a previous version.
134 ///
135 /// Reverting state signifies deleting database history. Only the main branch will be kept.
136 ///
137 /// Blocks that are greater than the provided block (`to`) are deleted and any versioned rows
138 /// which were invalidated in the deleted blocks are updated to be valid again.
139 ///
140 /// # Parameters
141 /// - `to` The version to revert to. Given a block uses VersionKind::Last behaviour.
142 /// - `db` The database gateway.
143 ///
144 /// # Returns
145 /// - An Ok if the revert is successful, or a `StorageError` if not.
146 async fn revert_state(&self, to: &BlockIdentifier) -> Result<(), StorageError>;
147}
148
149/// Store and retrieve state of Extractors.
150///
151/// Sometimes extractors may wish to persist their state across restart. E.g.
152/// substreams based extractors need to store the cursor, so they can continue
153/// processing where they left off.
154///
155/// Extractors are uniquely identified by a name and the respective chain which
156/// they are indexing.
157#[async_trait]
158pub trait ExtractionStateGateway {
159 /// Retrieves the state of an extractor instance from a storage.
160 ///
161 /// # Parameters
162 /// - `name` A unique name for the extractor instance.
163 /// - `chain` The chain this extractor is indexing.
164 ///
165 /// # Returns
166 /// Ok if the corrsponding state was retrieved successfully, Err in
167 /// case the state was not found.
168 async fn get_state(&self, name: &str, chain: &Chain) -> Result<ExtractionState, StorageError>;
169
170 /// Saves the state of an extractor instance to a storage.
171 ///
172 /// Creates an entry if not present yet, or updates an already existing
173 /// entry.
174 ///
175 /// # Parameters
176 /// - `state` The state of the extractor that needs to be saved.
177 ///
178 /// # Returns
179 /// Ok, if state was stored successfully, Err if the state is not valid.
180 async fn save_state(&self, state: &ExtractionState) -> Result<(), StorageError>;
181}
182
183/// Point in time as either block or timestamp. If a block is chosen it
184/// timestamp attribute is used.
185#[derive(Debug, Clone, PartialEq, Hash, Eq)]
186pub enum BlockOrTimestamp {
187 Block(BlockIdentifier),
188 Timestamp(NaiveDateTime),
189}
190
191// TODO: remove once deprecated chain field is removed from VersionParam
192#[allow(deprecated)]
193impl TryFrom<&dto::VersionParam> for BlockOrTimestamp {
194 type Error = anyhow::Error;
195
196 fn try_from(version: &dto::VersionParam) -> Result<Self, Self::Error> {
197 match (&version.timestamp, &version.block) {
198 (_, Some(block)) => {
199 // If a full block is provided, we prioritize hash over number and chain
200 let block_identifier = match (&block.hash, &block.chain, &block.number) {
201 (Some(hash), _, _) => BlockIdentifier::Hash(hash.clone()),
202 (_, Some(chain), Some(number)) => {
203 BlockIdentifier::Number((Chain::from(*chain), *number))
204 }
205 _ => {
206 return Err(anyhow::format_err!("Insufficient block information".to_owned()))
207 }
208 };
209 Ok(BlockOrTimestamp::Block(block_identifier))
210 }
211 (Some(timestamp), None) => Ok(BlockOrTimestamp::Timestamp(*timestamp)),
212 (None, None) => {
213 Err(anyhow::format_err!("Missing timestamp or block identifier".to_owned()))
214 }
215 }
216 }
217}
218
219/// References certain states within a single block.
220///
221/// **Note:** Not all methods that take a version will support all version kinds,
222/// the versions here are included for completeness and to document the
223/// retrieval behaviour that is possible with the storage layout. Please refer
224/// to the individual implementation for information about which version kinds
225/// it supports.
226#[derive(Debug, Clone, Default)]
227pub enum VersionKind {
228 /// Represents the final state within a specific block. Essentially, it
229 /// retrieves the state subsequent to the execution of the last transaction
230 /// executed in that block.
231 #[default]
232 Last,
233 /// Represents the initial state of a specific block. In other words,
234 /// it is the state before any transaction has been executed within that block.
235 First,
236 /// Represents a specific transactions indexed position within a block.
237 /// It includes the state after executing the transaction at that index.
238 Index(i64),
239}
240
241/// A version desribes the state of the DB at a exact point in time.
242/// See the module level docs for more information on how versioning works.
243#[derive(Debug, Clone)]
244pub struct Version(pub BlockOrTimestamp, pub VersionKind);
245
246impl Version {
247 pub fn from_block_number(chain: Chain, number: i64) -> Self {
248 Self(BlockOrTimestamp::Block(BlockIdentifier::Number((chain, number))), VersionKind::Last)
249 }
250 pub fn from_ts(ts: NaiveDateTime) -> Self {
251 Self(BlockOrTimestamp::Timestamp(ts), VersionKind::Last)
252 }
253}
254
255// Helper type to retrieve entities with their total retrievable count.
256#[derive(Debug)]
257pub struct WithTotal<T> {
258 pub entity: T,
259 pub total: Option<i64>,
260}
261
262/// Store and retrieve protocol related structs.
263///
264/// This trait defines how to retrieve protocol components, state as well as
265/// tokens from storage.
266#[async_trait]
267pub trait ProtocolGateway {
268 /// Retrieve ProtocolComponent from the db
269 ///
270 /// # Parameters
271 /// - `chain` The chain of the component
272 /// - `system` Allows to optionally filter by system.
273 /// - `id` Allows to optionally filter by id.
274 ///
275 /// # Returns
276 /// Ok, if found else Err
277 async fn get_protocol_components(
278 &self,
279 chain: &Chain,
280 system: Option<String>,
281 ids: Option<&[&str]>,
282 min_tvl: Option<f64>,
283 pagination_params: Option<&PaginationParams>,
284 ) -> Result<WithTotal<Vec<ProtocolComponent>>, StorageError>;
285
286 /// Retrieves owners of tokens
287 ///
288 /// Queries for owners (protocol components) of tokens that have a certain minimum
289 /// balance and returns a maximum aggregate of those in case there are multiple
290 /// owners.
291 ///
292 /// # Parameters
293 /// - `chain` The chain of the component
294 /// - `tokens` The tokens to query for, any component with at least one of these tokens is
295 /// returned.
296 /// - `min_balance` A minimum balance we expect the component to have on any of the tokens
297 /// mentioned in `tokens`.
298 async fn get_token_owners(
299 &self,
300 chain: &Chain,
301 tokens: &[Address],
302 min_balance: Option<f64>,
303 ) -> Result<HashMap<Address, (ComponentId, Bytes)>, StorageError>;
304
305 async fn add_protocol_components(&self, new: &[ProtocolComponent]) -> Result<(), StorageError>;
306
307 async fn delete_protocol_components(
308 &self,
309 to_delete: &[ProtocolComponent],
310 block_ts: NaiveDateTime,
311 ) -> Result<(), StorageError>;
312
313 /// Stores new found ProtocolTypes.
314 ///
315 /// # Parameters
316 /// - `new` The new protocol types.
317 ///
318 /// # Returns
319 /// Ok if stored successfully.
320 async fn add_protocol_types(
321 &self,
322 new_protocol_types: &[ProtocolType],
323 ) -> Result<(), StorageError>;
324
325 /// Retrieve protocol component states
326 ///
327 /// This resource is versioned, the version can be specified by either block
328 /// or timestamp, for off-chain components, a block version will error.
329 ///
330 /// As the state is retained on a transaction basis on blockchain systems, a
331 /// single version may relate to more than one state. In these cases a
332 /// versioned result is returned, if requesting `Version:All` with the
333 /// latest entry being the state at the end of the block and the first entry
334 /// represents the first change to the state within the block.
335 ///
336 /// # Parameters
337 /// - `chain` The chain of the component
338 /// - `system` The protocol system this component belongs to
339 /// - `ids` The external ids of the components e.g. addresses, or the pairs
340 /// - `at` The version at which the state is valid at.
341 async fn get_protocol_states(
342 &self,
343 chain: &Chain,
344 at: Option<Version>,
345 system: Option<String>,
346 ids: Option<&[&str]>,
347 retrieve_balances: bool,
348 pagination_params: Option<&PaginationParams>,
349 ) -> Result<WithTotal<Vec<ProtocolComponentState>>, StorageError>;
350
351 async fn update_protocol_states(
352 &self,
353 new: &[(TxHash, ProtocolComponentStateDelta)],
354 ) -> Result<(), StorageError>;
355
356 /// Retrieves a tokens from storage
357 ///
358 /// # Parameters
359 /// - `chain` The chain this token is implemented on.
360 /// - `address` The address for the token within the chain.
361 ///
362 /// # Returns
363 /// Ok if the results could be retrieved from the storage, else errors.
364 async fn get_tokens(
365 &self,
366 chain: Chain,
367 address: Option<&[&Address]>,
368 quality: QualityRange,
369 traded_n_days_ago: Option<NaiveDateTime>,
370 pagination_params: Option<&PaginationParams>,
371 ) -> Result<WithTotal<Vec<CurrencyToken>>, StorageError>;
372
373 /// Saves multiple component balances to storage.
374 ///
375 /// # Parameters
376 /// - `component_balances` The component balances to insert.
377 /// - `chain` The chain of the component balances to be inserted.
378 /// - `block_ts` The timestamp of the block that the balances are associated with.
379 ///
380 /// # Return
381 /// Ok if all component balances could be inserted, Err if at least one token failed to
382 /// insert.
383 async fn add_component_balances(
384 &self,
385 component_balances: &[ComponentBalance],
386 ) -> Result<(), StorageError>;
387
388 /// Saves multiple tokens to storage.
389 ///
390 /// Inserts token into storage. Tokens and their properties are assumed to
391 /// be immutable.
392 ///
393 /// # Parameters
394 /// - `token` The tokens to insert.
395 ///
396 /// # Return
397 /// Ok if all tokens could be inserted, Err if at least one token failed to
398 /// insert.
399 async fn add_tokens(&self, tokens: &[CurrencyToken]) -> Result<(), StorageError>;
400
401 /// Updates multiple tokens in storage.
402 ///
403 /// Updates token in storage. Will warn if one of the tokens does not exist in the
404 /// database. Currently assumes that token addresses are unique across chains.
405 /// -
406 ///
407 /// # Parameters
408 /// - `token` The tokens to update.
409 ///
410 /// # Return
411 /// Ok if all tokens could be inserted, Err if at least one token failed to
412 /// insert.
413 async fn update_tokens(&self, tokens: &[CurrencyToken]) -> Result<(), StorageError>;
414
415 /// Retrieve protocol state changes
416 ///
417 /// Fetches all state changes that occurred for the given chain
418 ///
419 /// # Parameters
420 /// - `chain` The chain of the component
421 /// - `start_version` The version at which to start looking for changes at.
422 /// - `end_version` The version at which to stop looking for changes.
423 ///
424 /// # Return
425 /// A list of ProtocolStateDeltas containing all state changes, Err if no changes were found.
426 async fn get_protocol_states_delta(
427 &self,
428 chain: &Chain,
429 start_version: Option<&BlockOrTimestamp>,
430 end_version: &BlockOrTimestamp,
431 ) -> Result<Vec<ProtocolComponentStateDelta>, StorageError>;
432
433 /// Retrieve protocol component balance changes
434 ///
435 /// Fetches all balance changes that occurred for the given protocol system
436 ///
437 /// # Parameters
438 /// - `chain` The chain of the component
439 /// - `start_version` The version at which to start looking for changes at.
440 /// - `target_version` The version at which to stop looking for changes.
441 ///
442 /// # Return
443 /// A vec containing ComponentBalance objects for changed components.
444 async fn get_balance_deltas(
445 &self,
446 chain: &Chain,
447 start_version: Option<&BlockOrTimestamp>,
448 target_version: &BlockOrTimestamp,
449 ) -> Result<Vec<ComponentBalance>, StorageError>;
450
451 async fn get_component_balances(
452 &self,
453 chain: &Chain,
454 ids: Option<&[&str]>,
455 version: Option<&Version>,
456 ) -> Result<HashMap<String, HashMap<Bytes, ComponentBalance>>, StorageError>;
457
458 async fn get_token_prices(&self, chain: &Chain) -> Result<HashMap<Bytes, f64>, StorageError>;
459
460 async fn upsert_component_tvl(
461 &self,
462 chain: &Chain,
463 tvl_values: &HashMap<String, f64>,
464 ) -> Result<(), StorageError>;
465
466 /// Retrieve a list of actively supported protocol systems
467 ///
468 /// Fetches the list of protocol systems supported by the Tycho indexing service.
469 ///
470 /// # Parameters
471 /// - `chain` The chain for which to retrieve supported protocol systems.
472 /// - `pagination_params` Optional pagination parameters to control the number of results.
473 ///
474 /// # Return
475 /// A paginated list of supported protocol systems, along with the total count.
476 async fn get_protocol_systems(
477 &self,
478 chain: &Chain,
479 pagination_params: Option<&PaginationParams>,
480 ) -> Result<WithTotal<Vec<String>>, StorageError>;
481
482 /// Retrieve the components total value locked (TVL).
483 ///
484 /// # Parameters
485 /// - `chain` The chain for which to retrieve the total value locked
486 /// - `system` The protocol system for which to retrieve the total value locked
487 /// - `ids` The ids of the components to retrieve the total value locked for
488 /// - `pagination_params` Optional pagination parameters to control the number of results.
489 ///
490 /// # Return
491 /// A result with a map of component ids to their TVL. Err if storage access failed.
492 async fn get_component_tvls(
493 &self,
494 chain: &Chain,
495 system: Option<String>,
496 ids: Option<&[&str]>,
497 pagination_params: Option<&PaginationParams>,
498 ) -> Result<WithTotal<HashMap<String, f64>>, StorageError>;
499}
500
501/// Manage contracts and their state in storage.
502///
503/// Specifies how to retrieve, add and update contracts in storage.
504#[async_trait]
505pub trait ContractStateGateway {
506 /// Get a contracts state from storage
507 ///
508 /// This method retrieves a single contract from the database.
509 ///
510 /// # Parameters
511 /// - `id` The identifier for the contract.
512 /// - `version` Version at which to retrieve state for. None retrieves the latest state.
513 /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
514 /// includes storage slot.
515 /// - `db`: Database session reference.
516 async fn get_contract(
517 &self,
518 id: &ContractId,
519 version: Option<&Version>,
520 include_slots: bool,
521 ) -> Result<Account, StorageError>;
522
523 /// Get multiple contracts' states from storage.
524 ///
525 /// This method retrieves balance and code, and optionally storage, of
526 /// multiple contracts in a chain. It can optionally filter by given
527 /// addresses and retrieve state for specific versions.
528 ///
529 /// # Parameters:
530 /// - `chain`: The blockchain where the contracts reside.
531 /// - `addresses`: Filter for specific addresses. If set to `None`, it retrieves all indexed
532 /// contracts in the chain.
533 /// - `version`: Version at which to retrieve state for. If set to `None`, it retrieves the
534 /// latest state.
535 /// - `include_slots`: Flag to determine whether to include slot changes. If set to `true`, it
536 /// includes storage slot.
537 /// - `db`: Database session reference.
538 ///
539 /// # Returns:
540 /// A `Result` with a list of contract states if the operation is
541 /// successful, or a `StorageError` if the operation fails.
542 async fn get_contracts(
543 &self,
544 chain: &Chain,
545 addresses: Option<&[Address]>,
546 version: Option<&Version>,
547 include_slots: bool,
548 pagination_params: Option<&PaginationParams>,
549 ) -> Result<WithTotal<Vec<Account>>, StorageError>;
550
551 /// Inserts a new contract into the database.
552 ///
553 /// If it the creation transaction is known, the contract will have slots, balance and code
554 /// inserted alongside with the new account else it won't.
555 ///
556 /// # Arguments
557 /// - `new`: A reference to the new contract state to be inserted.
558 /// - `db`: Database session reference.
559 ///
560 /// # Returns
561 /// - A Result with Ok if the operation was successful, and an Err containing `StorageError` if
562 /// there was an issue inserting the contract into the database. E.g. if the contract already
563 /// existed.
564 async fn upsert_contract(&self, new: &Account) -> Result<(), StorageError>;
565
566 /// Update multiple contracts
567 ///
568 /// Given contract deltas, this method will batch all updates to contracts across a single
569 /// chain.
570 ///
571 /// As changes are versioned by transaction, each changeset needs to be associated with a
572 /// transaction hash. All references transaction are assumed to be already persisted.
573 ///
574 /// # Arguments
575 ///
576 /// - `chain`: The blockchain which the contracts belong to.
577 /// - `new`: A reference to a slice of tuples where each tuple has a transaction hash (`TxHash`)
578 /// and a reference to the state delta (`&Self::Delta`) for that transaction.
579 /// - `db`: A mutable reference to the connected database where the updated contracts will be
580 /// stored.
581 ///
582 /// # Returns
583 ///
584 /// A Result with `Ok` if the operation was successful, and an `Err` containing
585 /// `StorageError` if there was an issue updating the contracts in the database. E.g. if a
586 /// transaction can't be located by it's reference or accounts refer to a different chain then
587 /// the one specified.
588 async fn update_contracts(&self, new: &[(TxHash, AccountDelta)]) -> Result<(), StorageError>;
589
590 /// Mark a contract as deleted
591 ///
592 /// Issues a soft delete of the contract.
593 ///
594 /// # Parameters
595 /// - `id` The identifier for the contract.
596 /// - `at_tx` The transaction hash which deleted the contract. This transaction is assumed to be
597 /// in storage already. None retrieves the latest state.
598 /// - `db` The database handle or connection.
599 ///
600 /// # Returns
601 /// Ok if the deletion was successful, might Err if:
602 /// - Contract is not present in storage.
603 /// - Deletion transaction is not present in storage.
604 /// - Contract was already deleted.
605 async fn delete_contract(&self, id: &ContractId, at_tx: &TxHash) -> Result<(), StorageError>;
606
607 /// Retrieve a account delta between two versions.
608 ///
609 /// Given start version V1 and end version V2, this method will return the
610 /// changes necessary to move from V1 to V2. So if V1 < V2, it will contain
611 /// the changes of all accounts that changed between the two versions with the
612 /// values corresponding to V2. If V2 < V1 then it will contain all the
613 /// slots that changed between the two versions with the values corresponding to V1.
614 ///
615 /// This method is mainly meant to handle reverts, but can also be used to create delta changes
616 /// between two historical version thus providing the basis for creating a backtestable stream
617 /// of messages.
618 ///
619 /// # Parameters
620 ///
621 /// - `chain` The chain for which to generate the delta changes.
622 /// - `start_version` The deltas start version, given a block uses VersionKind::Last behaviour.
623 /// If None the latest version is assumed.
624 /// - `end_version` The deltas end version, given a block uses VersionKind::Last behaviour.
625 ///
626 /// # Note
627 ///
628 /// A choice to utilize `BlockOrTimestamp` has been made intentionally in
629 /// this scenario as passing a `Version` by user isn't quite logical.
630 /// Support for deltas is limited to the states at the start or end of
631 /// blocks because blockchain reorganization at the transaction level is not
632 /// common.
633 ///
634 /// The decision to use either the beginning or end state of a block is
635 /// automatically determined by the underlying logic. For example, if we are
636 /// tracing back, `VersionKind::First` retrieval mode will be used.
637 /// Conversely, if we're progressing forward, we would apply the
638 /// `VersionKind::Last` semantics.
639 ///
640 /// # Returns
641 /// A map containing the necessary changes to update a state from start_version to end_version.
642 /// Errors if:
643 /// - The versions can't be located in storage.
644 /// - There was an error with the database
645 async fn get_accounts_delta(
646 &self,
647 chain: &Chain,
648 start_version: Option<&BlockOrTimestamp>,
649 end_version: &BlockOrTimestamp,
650 ) -> Result<Vec<AccountDelta>, StorageError>;
651
652 /// Saves multiple account balances to storage.
653 ///
654 /// # Parameters
655 /// - `account_balances` The account balances to insert.
656 /// - `chain` The chain of the account balances to be inserted.
657 /// - `block_ts` The timestamp of the block that the balances are associated with.
658 ///
659 /// # Return
660 /// Ok if all account balances could be inserted, Err if at least one token failed to insert.
661 async fn add_account_balances(
662 &self,
663 account_balances: &[AccountBalance],
664 ) -> Result<(), StorageError>;
665
666 /// Retrieve account balances
667 ///
668 /// # Parameters
669 /// - `chain` The chain of the account balances
670 /// - `accounts` The accounts to query for. If set to `None`, it retrieves balances for all
671 /// indexed
672 /// accounts in the chain.
673 /// - `version` Version at which to retrieve balances for. If set to `None`, it retrieves the
674 /// latest balances.
675 async fn get_account_balances(
676 &self,
677 chain: &Chain,
678 accounts: Option<&[Address]>,
679 version: Option<&Version>,
680 ) -> Result<HashMap<Address, HashMap<Address, AccountBalance>>, StorageError>;
681}
682
683pub trait Gateway:
684 ChainGateway
685 + ContractStateGateway
686 + ExtractionStateGateway
687 + ProtocolGateway
688 + ContractStateGateway
689 + Send
690 + Sync
691{
692}