miden_lib/account/wallets/
mod.rs1use alloc::string::String;
2
3use miden_objects::account::{
4 Account,
5 AccountBuilder,
6 AccountComponent,
7 AccountStorageMode,
8 AccountType,
9};
10use miden_objects::assembly::{ProcedureName, QualifiedProcedureName};
11use miden_objects::utils::sync::LazyLock;
12use miden_objects::{AccountError, Word};
13use thiserror::Error;
14
15use super::AuthScheme;
16use crate::account::auth::{AuthRpoFalcon512, AuthRpoFalcon512Multisig};
17use crate::account::components::basic_wallet_library;
18
19static BASIC_WALLET_RECEIVE_ASSET: LazyLock<Word> = LazyLock::new(|| {
24 let receive_asset_proc_name = QualifiedProcedureName::new(
25 Default::default(),
26 ProcedureName::new(BasicWallet::RECEIVE_ASSET_PROC_NAME)
27 .expect("failed to create name for 'receive_asset' procedure"),
28 );
29 basic_wallet_library()
30 .get_procedure_root_by_name(receive_asset_proc_name)
31 .expect("Basic Wallet should contain 'receive_asset' procedure")
32});
33
34static BASIC_WALLET_MOVE_ASSET_TO_NOTE: LazyLock<Word> = LazyLock::new(|| {
36 let move_asset_to_note_proc_name = QualifiedProcedureName::new(
37 Default::default(),
38 ProcedureName::new(BasicWallet::MOVE_ASSET_TO_NOTE_PROC_NAME)
39 .expect("failed to create name for 'move_asset_to_note' procedure"),
40 );
41 basic_wallet_library()
42 .get_procedure_root_by_name(move_asset_to_note_proc_name)
43 .expect("Basic Wallet should contain 'move_asset_to_note' procedure")
44});
45
46pub struct BasicWallet;
63
64impl BasicWallet {
65 const RECEIVE_ASSET_PROC_NAME: &str = "receive_asset";
68 const MOVE_ASSET_TO_NOTE_PROC_NAME: &str = "move_asset_to_note";
69
70 pub fn receive_asset_digest() -> Word {
75 *BASIC_WALLET_RECEIVE_ASSET
76 }
77
78 pub fn move_asset_to_note_digest() -> Word {
80 *BASIC_WALLET_MOVE_ASSET_TO_NOTE
81 }
82}
83
84impl From<BasicWallet> for AccountComponent {
85 fn from(_: BasicWallet) -> Self {
86 AccountComponent::new(basic_wallet_library(), vec![])
87 .expect("basic wallet component should satisfy the requirements of a valid account component")
88 .with_supports_all_types()
89 }
90}
91
92#[derive(Debug, Error)]
97pub enum BasicWalletError {
98 #[error("unsupported authentication scheme: {0}")]
99 UnsupportedAuthScheme(String),
100 #[error("account creation failed")]
101 AccountError(#[source] AccountError),
102}
103
104pub fn create_basic_wallet(
115 init_seed: [u8; 32],
116 auth_scheme: AuthScheme,
117 account_type: AccountType,
118 account_storage_mode: AccountStorageMode,
119) -> Result<(Account, Word), BasicWalletError> {
120 if matches!(account_type, AccountType::FungibleFaucet | AccountType::NonFungibleFaucet) {
121 return Err(BasicWalletError::AccountError(AccountError::other(
122 "basic wallet accounts cannot have a faucet account type",
123 )));
124 }
125
126 let auth_component: AccountComponent = match auth_scheme {
127 AuthScheme::RpoFalcon512 { pub_key } => AuthRpoFalcon512::new(pub_key).into(),
128 AuthScheme::RpoFalcon512Multisig { threshold, pub_keys } => {
129 AuthRpoFalcon512Multisig::new(threshold, pub_keys)
130 .map_err(BasicWalletError::AccountError)?
131 .into()
132 },
133 AuthScheme::NoAuth => {
134 return Err(BasicWalletError::UnsupportedAuthScheme(
135 "basic wallets cannot be created with NoAuth authentication scheme".into(),
136 ));
137 },
138 AuthScheme::Unknown => {
139 return Err(BasicWalletError::UnsupportedAuthScheme(
140 "basic wallets cannot be created with Unknown authentication scheme".into(),
141 ));
142 },
143 };
144
145 let (account, account_seed) = AccountBuilder::new(init_seed)
146 .account_type(account_type)
147 .storage_mode(account_storage_mode)
148 .with_auth_component(auth_component)
149 .with_component(BasicWallet)
150 .build()
151 .map_err(BasicWalletError::AccountError)?;
152
153 Ok((account, account_seed))
154}
155
156#[cfg(test)]
160mod tests {
161
162 use miden_objects::crypto::dsa::rpo_falcon512;
163 use miden_objects::{ONE, Word};
164 use miden_processor::utils::{Deserializable, Serializable};
165
166 use super::{Account, AccountStorageMode, AccountType, AuthScheme, create_basic_wallet};
167 use crate::account::wallets::BasicWallet;
168
169 #[test]
170 fn test_create_basic_wallet() {
171 let pub_key = rpo_falcon512::PublicKey::new(Word::from([ONE; 4]));
172 let wallet = create_basic_wallet(
173 [1; 32],
174 AuthScheme::RpoFalcon512 { pub_key },
175 AccountType::RegularAccountImmutableCode,
176 AccountStorageMode::Public,
177 );
178
179 wallet.unwrap_or_else(|err| {
180 panic!("{}", err);
181 });
182 }
183
184 #[test]
185 fn test_serialize_basic_wallet() {
186 let pub_key = rpo_falcon512::PublicKey::new(Word::from([ONE; 4]));
187 let wallet = create_basic_wallet(
188 [1; 32],
189 AuthScheme::RpoFalcon512 { pub_key },
190 AccountType::RegularAccountImmutableCode,
191 AccountStorageMode::Public,
192 )
193 .unwrap()
194 .0;
195
196 let bytes = wallet.to_bytes();
197 let deserialized_wallet = Account::read_from_bytes(&bytes).unwrap();
198 assert_eq!(wallet, deserialized_wallet);
199 }
200
201 #[test]
203 fn get_faucet_procedures() {
204 let _receive_asset_digest = BasicWallet::receive_asset_digest();
205 let _move_asset_to_note_digest = BasicWallet::move_asset_to_note_digest();
206 }
207}