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::{AccountError, Word};
11use thiserror::Error;
12
13use super::AuthScheme;
14use crate::account::auth::{
15 AuthEcdsaK256Keccak,
16 AuthEcdsaK256KeccakMultisig,
17 AuthEcdsaK256KeccakMultisigConfig,
18 AuthRpoFalcon512,
19 AuthRpoFalcon512Multisig,
20 AuthRpoFalcon512MultisigConfig,
21};
22use crate::account::components::basic_wallet_library;
23use crate::procedure_digest;
24
25procedure_digest!(
30 BASIC_WALLET_RECEIVE_ASSET,
31 BasicWallet::RECEIVE_ASSET_PROC_NAME,
32 basic_wallet_library
33);
34
35procedure_digest!(
37 BASIC_WALLET_MOVE_ASSET_TO_NOTE,
38 BasicWallet::MOVE_ASSET_TO_NOTE_PROC_NAME,
39 basic_wallet_library
40);
41
42pub struct BasicWallet;
59
60impl BasicWallet {
61 const RECEIVE_ASSET_PROC_NAME: &str = "receive_asset";
64 const MOVE_ASSET_TO_NOTE_PROC_NAME: &str = "move_asset_to_note";
65
66 pub fn receive_asset_digest() -> Word {
71 *BASIC_WALLET_RECEIVE_ASSET
72 }
73
74 pub fn move_asset_to_note_digest() -> Word {
76 *BASIC_WALLET_MOVE_ASSET_TO_NOTE
77 }
78}
79
80impl From<BasicWallet> for AccountComponent {
81 fn from(_: BasicWallet) -> Self {
82 AccountComponent::new(basic_wallet_library(), vec![])
83 .expect("basic wallet component should satisfy the requirements of a valid account component")
84 .with_supports_all_types()
85 }
86}
87
88#[derive(Debug, Error)]
93pub enum BasicWalletError {
94 #[error("unsupported authentication scheme: {0}")]
95 UnsupportedAuthScheme(String),
96 #[error("account creation failed")]
97 AccountError(#[source] AccountError),
98}
99
100pub fn create_basic_wallet(
111 init_seed: [u8; 32],
112 auth_scheme: AuthScheme,
113 account_type: AccountType,
114 account_storage_mode: AccountStorageMode,
115) -> Result<Account, BasicWalletError> {
116 if matches!(account_type, AccountType::FungibleFaucet | AccountType::NonFungibleFaucet) {
117 return Err(BasicWalletError::AccountError(AccountError::other(
118 "basic wallet accounts cannot have a faucet account type",
119 )));
120 }
121
122 let auth_component: AccountComponent = match auth_scheme {
123 AuthScheme::EcdsaK256Keccak { pub_key } => AuthEcdsaK256Keccak::new(pub_key).into(),
124 AuthScheme::EcdsaK256KeccakMultisig { threshold, pub_keys } => {
125 let config = AuthEcdsaK256KeccakMultisigConfig::new(pub_keys, threshold)
126 .and_then(|cfg| {
127 cfg.with_proc_thresholds(vec![(BasicWallet::receive_asset_digest(), 1)])
128 })
129 .map_err(BasicWalletError::AccountError)?;
130 AuthEcdsaK256KeccakMultisig::new(config)
131 .map_err(BasicWalletError::AccountError)?
132 .into()
133 },
134 AuthScheme::RpoFalcon512 { pub_key } => AuthRpoFalcon512::new(pub_key).into(),
135 AuthScheme::RpoFalcon512Multisig { threshold, pub_keys } => {
136 let config = AuthRpoFalcon512MultisigConfig::new(pub_keys, threshold)
137 .and_then(|cfg| {
138 cfg.with_proc_thresholds(vec![(BasicWallet::receive_asset_digest(), 1)])
139 })
140 .map_err(BasicWalletError::AccountError)?;
141 AuthRpoFalcon512Multisig::new(config)
142 .map_err(BasicWalletError::AccountError)?
143 .into()
144 },
145 AuthScheme::NoAuth => {
146 return Err(BasicWalletError::UnsupportedAuthScheme(
147 "basic wallets cannot be created with NoAuth authentication scheme".into(),
148 ));
149 },
150 AuthScheme::Unknown => {
151 return Err(BasicWalletError::UnsupportedAuthScheme(
152 "basic wallets cannot be created with Unknown authentication scheme".into(),
153 ));
154 },
155 };
156
157 let account = AccountBuilder::new(init_seed)
158 .account_type(account_type)
159 .storage_mode(account_storage_mode)
160 .with_auth_component(auth_component)
161 .with_component(BasicWallet)
162 .build()
163 .map_err(BasicWalletError::AccountError)?;
164
165 Ok(account)
166}
167
168#[cfg(test)]
172mod tests {
173 use miden_objects::account::auth::PublicKeyCommitment;
174 use miden_objects::{ONE, Word};
175 use miden_processor::utils::{Deserializable, Serializable};
176
177 use super::{Account, AccountStorageMode, AccountType, AuthScheme, create_basic_wallet};
178 use crate::account::wallets::BasicWallet;
179
180 #[test]
181 fn test_create_basic_wallet() {
182 let pub_key = PublicKeyCommitment::from(Word::from([ONE; 4]));
183 let wallet = create_basic_wallet(
184 [1; 32],
185 AuthScheme::RpoFalcon512 { pub_key },
186 AccountType::RegularAccountImmutableCode,
187 AccountStorageMode::Public,
188 );
189
190 wallet.unwrap_or_else(|err| {
191 panic!("{}", err);
192 });
193 }
194
195 #[test]
196 fn test_serialize_basic_wallet() {
197 let pub_key = PublicKeyCommitment::from(Word::from([ONE; 4]));
198 let wallet = create_basic_wallet(
199 [1; 32],
200 AuthScheme::RpoFalcon512 { pub_key },
201 AccountType::RegularAccountImmutableCode,
202 AccountStorageMode::Public,
203 )
204 .unwrap();
205
206 let bytes = wallet.to_bytes();
207 let deserialized_wallet = Account::read_from_bytes(&bytes).unwrap();
208 assert_eq!(wallet, deserialized_wallet);
209 }
210
211 #[test]
213 fn get_faucet_procedures() {
214 let _receive_asset_digest = BasicWallet::receive_asset_digest();
215 let _move_asset_to_note_digest = BasicWallet::move_asset_to_note_digest();
216 }
217}