Skip to main content

miden_client/rpc/domain/
account_vault.rs

1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use miden_protocol::Word;
5use miden_protocol::asset::{Asset, AssetVaultKey};
6use miden_protocol::block::BlockNumber;
7
8use crate::rpc::domain::MissingFieldHelper;
9use crate::rpc::{RpcConversionError, RpcError, generated as proto};
10
11// ASSET CONVERSION
12// ================================================================================================
13
14impl TryFrom<proto::primitives::Asset> for Asset {
15    type Error = RpcConversionError;
16
17    fn try_from(value: proto::primitives::Asset) -> Result<Self, Self::Error> {
18        let key_word: Word = value
19            .key
20            .ok_or(proto::primitives::Asset::missing_field(stringify!(key)))?
21            .try_into()?;
22        let value_word: Word = value
23            .value
24            .ok_or(proto::primitives::Asset::missing_field(stringify!(value)))?
25            .try_into()?;
26        Asset::from_key_value_words(key_word, value_word)
27            .map_err(|e| RpcConversionError::InvalidField(e.to_string()))
28    }
29}
30
31// ACCOUNT VAULT INFO
32// ================================================================================================
33
34/// Represents a `proto::rpc::SyncAccountVaultResponse` with fields converted into domain
35/// types. Contains information of asset updates in a given range of blocks specified on request.
36/// Also provides the current chain tip while processing the request.
37pub struct AccountVaultInfo {
38    /// Current chain tip
39    pub chain_tip: BlockNumber,
40    /// The block number of the last check included in this response.
41    pub block_number: BlockNumber,
42    /// List of asset updates for the account.
43    pub updates: Vec<AccountVaultUpdate>,
44}
45
46// ACCOUNT VAULT CONVERSION
47// ================================================================================================
48
49impl TryFrom<proto::rpc::SyncAccountVaultResponse> for AccountVaultInfo {
50    type Error = RpcError;
51
52    fn try_from(value: proto::rpc::SyncAccountVaultResponse) -> Result<Self, Self::Error> {
53        let pagination_info =
54            value
55                .pagination_info
56                .ok_or(proto::rpc::SyncAccountVaultResponse::missing_field(stringify!(
57                    pagination_info
58                )))?;
59        let chain_tip = pagination_info.chain_tip;
60        let block_number = pagination_info.block_num;
61
62        let updates = value
63            .updates
64            .iter()
65            .map(|update| (*update).try_into())
66            .collect::<Result<Vec<_>, _>>()?;
67
68        Ok(Self {
69            chain_tip: chain_tip.into(),
70            block_number: block_number.into(),
71            updates,
72        })
73    }
74}
75
76// ACCOUNT VAULT UPDATE
77// ================================================================================================
78
79/// Represents an update to an account vault, including the vault key and asset value involved.
80pub struct AccountVaultUpdate {
81    /// Block number in which the slot was updated.
82    pub block_num: BlockNumber,
83    /// Asset value related to the vault key. If not present, the asset was removed from the vault.
84    pub asset: Option<Asset>,
85    /// Vault key associated with the asset.
86    pub vault_key: AssetVaultKey,
87}
88
89// ACCOUNT VAULT UPDATE CONVERSION
90// ================================================================================================
91
92impl TryFrom<proto::rpc::AccountVaultUpdate> for AccountVaultUpdate {
93    type Error = RpcError;
94
95    fn try_from(value: proto::rpc::AccountVaultUpdate) -> Result<Self, Self::Error> {
96        let block_num = value.block_num;
97
98        let vault_key_inner: Word = value
99            .vault_key
100            .ok_or(proto::rpc::SyncAccountVaultResponse::missing_field(stringify!(vault_key)))?
101            .try_into()?;
102        let vault_key = AssetVaultKey::try_from(vault_key_inner)
103            .map_err(|e| RpcError::InvalidResponse(e.to_string()))?;
104
105        let asset = value.asset.map(Asset::try_from).transpose()?;
106
107        if let Some(ref asset) = asset
108            && asset.vault_key() != vault_key
109        {
110            return Err(RpcError::InvalidResponse(
111                "account vault update returned mismatched asset key".to_string(),
112            ));
113        }
114
115        Ok(Self {
116            block_num: block_num.into(),
117            asset,
118            vault_key,
119        })
120    }
121}