use alloc::string::String;
use miden_objects::account::{
Account,
AccountBuilder,
AccountComponent,
AccountStorageMode,
AccountType,
};
use miden_objects::{AccountError, Word};
use thiserror::Error;
use super::AuthScheme;
use crate::account::auth::{
AuthEcdsaK256Keccak,
AuthEcdsaK256KeccakMultisig,
AuthEcdsaK256KeccakMultisigConfig,
AuthRpoFalcon512,
AuthRpoFalcon512Multisig,
AuthRpoFalcon512MultisigConfig,
};
use crate::account::components::basic_wallet_library;
use crate::procedure_digest;
procedure_digest!(
BASIC_WALLET_RECEIVE_ASSET,
BasicWallet::RECEIVE_ASSET_PROC_NAME,
basic_wallet_library
);
procedure_digest!(
BASIC_WALLET_MOVE_ASSET_TO_NOTE,
BasicWallet::MOVE_ASSET_TO_NOTE_PROC_NAME,
basic_wallet_library
);
pub struct BasicWallet;
impl BasicWallet {
const RECEIVE_ASSET_PROC_NAME: &str = "receive_asset";
const MOVE_ASSET_TO_NOTE_PROC_NAME: &str = "move_asset_to_note";
pub fn receive_asset_digest() -> Word {
*BASIC_WALLET_RECEIVE_ASSET
}
pub fn move_asset_to_note_digest() -> Word {
*BASIC_WALLET_MOVE_ASSET_TO_NOTE
}
}
impl From<BasicWallet> for AccountComponent {
fn from(_: BasicWallet) -> Self {
AccountComponent::new(basic_wallet_library(), vec![])
.expect("basic wallet component should satisfy the requirements of a valid account component")
.with_supports_all_types()
}
}
#[derive(Debug, Error)]
pub enum BasicWalletError {
#[error("unsupported authentication scheme: {0}")]
UnsupportedAuthScheme(String),
#[error("account creation failed")]
AccountError(#[source] AccountError),
}
pub fn create_basic_wallet(
init_seed: [u8; 32],
auth_scheme: AuthScheme,
account_type: AccountType,
account_storage_mode: AccountStorageMode,
) -> Result<Account, BasicWalletError> {
if matches!(account_type, AccountType::FungibleFaucet | AccountType::NonFungibleFaucet) {
return Err(BasicWalletError::AccountError(AccountError::other(
"basic wallet accounts cannot have a faucet account type",
)));
}
let auth_component: AccountComponent = match auth_scheme {
AuthScheme::EcdsaK256Keccak { pub_key } => AuthEcdsaK256Keccak::new(pub_key).into(),
AuthScheme::EcdsaK256KeccakMultisig { threshold, pub_keys } => {
let config = AuthEcdsaK256KeccakMultisigConfig::new(pub_keys, threshold)
.and_then(|cfg| {
cfg.with_proc_thresholds(vec![(BasicWallet::receive_asset_digest(), 1)])
})
.map_err(BasicWalletError::AccountError)?;
AuthEcdsaK256KeccakMultisig::new(config)
.map_err(BasicWalletError::AccountError)?
.into()
},
AuthScheme::RpoFalcon512 { pub_key } => AuthRpoFalcon512::new(pub_key).into(),
AuthScheme::RpoFalcon512Multisig { threshold, pub_keys } => {
let config = AuthRpoFalcon512MultisigConfig::new(pub_keys, threshold)
.and_then(|cfg| {
cfg.with_proc_thresholds(vec![(BasicWallet::receive_asset_digest(), 1)])
})
.map_err(BasicWalletError::AccountError)?;
AuthRpoFalcon512Multisig::new(config)
.map_err(BasicWalletError::AccountError)?
.into()
},
AuthScheme::NoAuth => {
return Err(BasicWalletError::UnsupportedAuthScheme(
"basic wallets cannot be created with NoAuth authentication scheme".into(),
));
},
AuthScheme::Unknown => {
return Err(BasicWalletError::UnsupportedAuthScheme(
"basic wallets cannot be created with Unknown authentication scheme".into(),
));
},
};
let account = AccountBuilder::new(init_seed)
.account_type(account_type)
.storage_mode(account_storage_mode)
.with_auth_component(auth_component)
.with_component(BasicWallet)
.build()
.map_err(BasicWalletError::AccountError)?;
Ok(account)
}
#[cfg(test)]
mod tests {
use miden_objects::account::auth::PublicKeyCommitment;
use miden_objects::{ONE, Word};
use miden_processor::utils::{Deserializable, Serializable};
use super::{Account, AccountStorageMode, AccountType, AuthScheme, create_basic_wallet};
use crate::account::wallets::BasicWallet;
#[test]
fn test_create_basic_wallet() {
let pub_key = PublicKeyCommitment::from(Word::from([ONE; 4]));
let wallet = create_basic_wallet(
[1; 32],
AuthScheme::RpoFalcon512 { pub_key },
AccountType::RegularAccountImmutableCode,
AccountStorageMode::Public,
);
wallet.unwrap_or_else(|err| {
panic!("{}", err);
});
}
#[test]
fn test_serialize_basic_wallet() {
let pub_key = PublicKeyCommitment::from(Word::from([ONE; 4]));
let wallet = create_basic_wallet(
[1; 32],
AuthScheme::RpoFalcon512 { pub_key },
AccountType::RegularAccountImmutableCode,
AccountStorageMode::Public,
)
.unwrap();
let bytes = wallet.to_bytes();
let deserialized_wallet = Account::read_from_bytes(&bytes).unwrap();
assert_eq!(wallet, deserialized_wallet);
}
#[test]
fn get_faucet_procedures() {
let _receive_asset_digest = BasicWallet::receive_asset_digest();
let _move_asset_to_note_digest = BasicWallet::move_asset_to_note_digest();
}
}