delta_domain_sdk/views/
finalized.rs

1use base_sdk::{
2    core::Shard,
3    vaults::{
4        fungible,
5        Address,
6        ReadableShardedVault,
7        TokenId,
8        Vault,
9    },
10};
11use domain_runtime::{
12    ports::{
13        DbQueriesPort,
14        FetchVaultsInboundPort,
15    },
16    storage::FinalizedVaultColumnFamily,
17};
18use snafu::{
19    OptionExt,
20    ResultExt,
21    Snafu,
22};
23use std::num::NonZero;
24use storage::{
25    column_family::StorageQuery,
26    database::StorageError,
27};
28
29/// Errors occurring in the [FinalizedState]
30#[derive(Debug, Snafu)]
31pub enum Error {
32    /// Base layer client initialization or communication failed
33    #[snafu(display("Base layer error: {source}"))]
34    BaseLayer {
35        /// The underlying error from the base layer client
36        source: Box<dyn std::error::Error + Send + Sync>,
37    },
38
39    /// Error when reading from storage
40    #[snafu(display("Error while reading from storage: {source}"))]
41    Storage {
42        /// The underlying storage error
43        source: StorageError,
44    },
45
46    /// Local vault not found in storage
47    #[snafu(display("Local vault not found in storage"))]
48    LocalVaultNotFound,
49}
50
51/// Helper to access the finalized state
52#[derive(Debug, Clone)]
53pub struct FinalizedState<Db, F> {
54    shard: NonZero<Shard>,
55    db: Db,
56    fetcher: F,
57}
58
59impl<Db, F> FinalizedState<Db, F> {
60    pub(crate) const fn new(shard: NonZero<Shard>, db: Db, fetcher: F) -> Self {
61        Self { shard, fetcher, db }
62    }
63}
64
65impl<Db, F> FinalizedState<Db, F>
66where
67    Db: DbQueriesPort,
68    F: FetchVaultsInboundPort,
69{
70    /// Get the finalized state of the [Vault] with the given `address`.
71    ///
72    /// The finalized state is the state as it is on the base layer,
73    /// irreversible.
74    ///
75    /// Vaults of this shard are retrieved from local storage while
76    /// shard-external vaults are requested from the base layer.
77    pub async fn get_vault(&self, address: &Address) -> Result<Vault, Error> {
78        if address.shard() == self.shard.get() {
79            StorageQuery::<FinalizedVaultColumnFamily>::get_value(&self.db, &address.owner())
80                .context(StorageSnafu)?
81                .context(LocalVaultNotFoundSnafu)
82        } else {
83            self.fetcher
84                .request_vault(*address)
85                .await
86                .boxed()
87                .context(BaseLayerSnafu)
88        }
89    }
90
91    /// Get the finalized state of the [fungible::Mint] for a given token.
92    ///
93    /// # Parameters
94    /// * `token` - ID of the token
95    ///
96    /// # Returns
97    ///
98    /// * `Ok(Some(mint))` - If the token exists
99    /// * `Ok(None)` - If the token doesn't exist, i.e. there is a non-mint vault at that address
100    /// * `Err(error)` - If an error occurred
101    pub async fn get_mint(&self, token: &TokenId) -> Result<Option<fungible::Mint>, Error> {
102        let vault = self.get_vault(token).await?;
103        Ok(vault.data().and_then(|d| d.token_mint().cloned()))
104    }
105}