miden_protocol/asset/vault/
vault_key.rs1use alloc::boxed::Box;
2use core::fmt;
3
4use miden_core::LexicographicWord;
5use miden_crypto::merkle::smt::LeafIndex;
6
7use crate::account::AccountId;
8use crate::account::AccountType::{self};
9use crate::asset::vault::AssetId;
10use crate::asset::{Asset, FungibleAsset, NonFungibleAsset};
11use crate::crypto::merkle::smt::SMT_DEPTH;
12use crate::errors::AssetError;
13use crate::{Felt, Word};
14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub struct AssetVaultKey {
30 asset_id: AssetId,
32
33 faucet_id: AccountId,
35}
36
37impl AssetVaultKey {
38 pub fn new(asset_id: AssetId, faucet_id: AccountId) -> Result<Self, AssetError> {
49 if !faucet_id.is_faucet() {
50 return Err(AssetError::InvalidFaucetAccountId(Box::from(format!(
51 "expected account ID of type faucet, found account type {}",
52 faucet_id.account_type()
53 ))));
54 }
55
56 if matches!(faucet_id.account_type(), AccountType::FungibleFaucet) && !asset_id.is_empty() {
57 return Err(AssetError::FungibleAssetIdMustBeZero(asset_id));
58 }
59
60 Ok(Self { asset_id, faucet_id })
61 }
62
63 pub fn to_word(self) -> Word {
67 vault_key_to_word(self.asset_id, self.faucet_id)
68 }
69
70 pub fn asset_id(&self) -> AssetId {
73 self.asset_id
74 }
75
76 pub fn faucet_id(&self) -> AccountId {
78 self.faucet_id
79 }
80
81 pub fn new_fungible(faucet_id: AccountId) -> Option<Self> {
86 if matches!(faucet_id.account_type(), AccountType::FungibleFaucet) {
87 let asset_id = AssetId::new(Felt::ZERO, Felt::ZERO);
88 Some(
89 Self::new(asset_id, faucet_id)
90 .expect("we should have account type fungible faucet"),
91 )
92 } else {
93 None
94 }
95 }
96
97 pub fn to_leaf_index(&self) -> LeafIndex<SMT_DEPTH> {
99 LeafIndex::<SMT_DEPTH>::from(self.to_word())
100 }
101}
102
103impl From<AssetVaultKey> for Word {
107 fn from(vault_key: AssetVaultKey) -> Self {
108 vault_key.to_word()
109 }
110}
111
112impl Ord for AssetVaultKey {
113 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
115 LexicographicWord::new(self.to_word()).cmp(&LexicographicWord::new(other.to_word()))
116 }
117}
118
119impl PartialOrd for AssetVaultKey {
120 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
121 Some(self.cmp(other))
122 }
123}
124
125impl TryFrom<Word> for AssetVaultKey {
126 type Error = AssetError;
127
128 fn try_from(key: Word) -> Result<Self, Self::Error> {
137 let asset_id_suffix = key[0];
138 let asset_id_prefix = key[1];
139 let faucet_id_suffix = key[2];
140 let faucet_id_prefix = key[3];
141
142 let asset_id = AssetId::new(asset_id_suffix, asset_id_prefix);
143 let faucet_id = AccountId::try_from_elements(faucet_id_suffix, faucet_id_prefix)
144 .map_err(|err| AssetError::InvalidFaucetAccountId(Box::new(err)))?;
145
146 Self::new(asset_id, faucet_id)
147 }
148}
149
150impl fmt::Display for AssetVaultKey {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 f.write_str(&self.to_word().to_hex())
153 }
154}
155
156impl From<Asset> for AssetVaultKey {
157 fn from(asset: Asset) -> Self {
158 asset.vault_key()
159 }
160}
161
162impl From<FungibleAsset> for AssetVaultKey {
163 fn from(fungible_asset: FungibleAsset) -> Self {
164 fungible_asset.vault_key()
165 }
166}
167
168impl From<NonFungibleAsset> for AssetVaultKey {
169 fn from(non_fungible_asset: NonFungibleAsset) -> Self {
170 non_fungible_asset.vault_key()
171 }
172}
173
174fn vault_key_to_word(asset_id: AssetId, faucet_id: AccountId) -> Word {
175 Word::new([
176 asset_id.suffix(),
177 asset_id.prefix(),
178 faucet_id.suffix(),
179 faucet_id.prefix().as_felt(),
180 ])
181}