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