diff --git a/Cargo.lock b/Cargo.lock index 0c3dc48122..7c7c96abfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,6 +498,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" name = "cli-wallet" version = "1.3.0" dependencies = [ + "async-trait", "chrono", "clap", "colored 2.1.0", diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index d7dc366cfa..2c2dd4e9db 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -11,15 +11,13 @@ mod response; use std::fmt::{Formatter, Result as FmtResult}; -use crypto::keys::bip44::Bip44; use derivative::Derivative; use fern_logger::{logger_init, LoggerConfig, LoggerOutputConfigBuilder}; pub use iota_sdk; use iota_sdk::{ client::secret::{SecretManager, SecretManagerDto}, types::block::address::Bech32Address, - utils::serde::bip44::option_bip44, - wallet::{ClientOptions, Wallet}, + wallet::{core::SecretData, ClientOptions, Wallet, WalletBuilder}, }; use serde::Deserialize; @@ -46,8 +44,10 @@ pub fn init_logger(config: String) -> std::result::Result<(), fern_logger::Error pub struct WalletOptions { pub address: Option, pub alias: Option, - #[serde(with = "option_bip44", default)] - pub bip_path: Option, + #[serde(default)] + pub public_key_options: Option, + #[serde(default)] + pub signing_options: Option, pub client_options: Option, #[derivative(Debug(format_with = "OmittedDebug::omitted_fmt"))] pub secret_manager: Option, @@ -65,8 +65,13 @@ impl WalletOptions { self } - pub fn with_bip_path(mut self, bip_path: impl Into>) -> Self { - self.bip_path = bip_path.into(); + pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { + self.public_key_options = public_key_options.into(); + self + } + + pub fn with_signing_options(mut self, signing_options: impl Into>) -> Self { + self.signing_options = signing_options.into(); self } @@ -86,12 +91,13 @@ impl WalletOptions { self } - pub async fn build(self) -> iota_sdk::wallet::Result { + pub async fn build(self) -> iota_sdk::wallet::Result>> { log::debug!("wallet options: {self:?}"); - let mut builder = Wallet::builder() + let mut builder = WalletBuilder::new() .with_address(self.address) .with_alias(self.alias) - .with_bip_path(self.bip_path) + .with_public_key_options(self.public_key_options) + .with_signing_options(self.signing_options) .with_client_options(self.client_options); #[cfg(feature = "storage")] diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 2a13acbca0..2b80ff869f 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -1,12 +1,10 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::{ - client::api::{GetAddressesOptions, PreparedTransactionDataDto}, - types::block::{protocol::ProtocolParameters, UnsignedBlockDto}, - utils::serde::bip44::Bip44Def, + client::api::PreparedTransactionDataDto, + types::block::{address::Hrp, protocol::ProtocolParameters, UnsignedBlockDto}, }; use serde::{Deserialize, Serialize}; @@ -20,12 +18,15 @@ use crate::OmittedDebug; #[non_exhaustive] pub enum SecretManagerMethod { /// Generate Ed25519 addresses. + #[serde(rename_all = "camelCase")] GenerateEd25519Addresses { + /// The Bech32 human-readable part + bech32_hrp: Hrp, /// Addresses generation options - options: GetAddressesOptions, + options: serde_json::Value, }, /// Generate Evm addresses. - GenerateEvmAddresses { options: GetAddressesOptions }, + GenerateEvmAddresses { options: serde_json::Value }, /// Get the ledger status /// Expected response: [`LedgerNanoStatus`](crate::Response::LedgerNanoStatus) #[cfg(feature = "ledger_nano")] @@ -36,25 +37,27 @@ pub enum SecretManagerMethod { SignatureUnlock { /// Transaction signing hash transaction_signing_hash: String, - /// Chain used to sign the hash - #[serde(with = "Bip44Def")] - chain: Bip44, + /// Options used to sign the hash + #[serde(default)] + signing_options: serde_json::Value, }, /// Signs a message with an Ed25519 private key. + #[serde(rename_all = "camelCase")] SignEd25519 { /// The message to sign, hex encoded String message: String, - /// Chain used to sign the message - #[serde(with = "Bip44Def")] - chain: Bip44, + /// Options used to sign the message + #[serde(default)] + signing_options: serde_json::Value, }, /// Signs a message with an Secp256k1Ecdsa private key. + #[serde(rename_all = "camelCase")] SignSecp256k1Ecdsa { /// The message to sign, hex encoded String message: String, - /// Chain used to sign the message - #[serde(with = "Bip44Def")] - chain: Bip44, + /// Options used to sign the hash + #[serde(default)] + signing_options: serde_json::Value, }, /// Sign a transaction #[serde(rename_all = "camelCase")] @@ -62,14 +65,17 @@ pub enum SecretManagerMethod { /// Prepared transaction data prepared_transaction_data: PreparedTransactionDataDto, protocol_parameters: Box, + /// Options used to sign the transaction + #[serde(default)] + signing_options: serde_json::Value, }, // Sign a block. #[serde(rename_all = "camelCase")] SignBlock { unsigned_block: UnsignedBlockDto, - /// Chain used to sign the block - #[serde(with = "Bip44Def")] - chain: Bip44, + /// Options used to sign the block + #[serde(default)] + signing_options: serde_json::Value, }, /// Store a mnemonic in the Stronghold vault #[cfg(feature = "stronghold")] @@ -104,14 +110,16 @@ pub enum SecretManagerMethod { #[cfg(test)] mod test { + use crypto::keys::bip44::Bip44; + use iota_sdk::client::constants::{ETHER_COIN_TYPE, IOTA_COIN_TYPE}; use pretty_assertions::assert_eq; #[test] fn bip44_deserialization() { - let signature_unlock_method: super::SecretManagerMethod = serde_json::from_str( - r#"{"name": "signatureUnlock", "data": {"transactionSigningHash": "txhash", "chain": {"addressIndex": 1}}}"#, - ) - .unwrap(); + let signature_unlock_method = super::SecretManagerMethod::SignatureUnlock { + transaction_signing_hash: "txhash".to_owned(), + signing_options: serde_json::to_value(Bip44::new(IOTA_COIN_TYPE).with_address_index(1)).unwrap(), + }; assert_eq!( serde_json::to_value(&signature_unlock_method).unwrap(), @@ -119,20 +127,20 @@ mod test { "name": "signatureUnlock", "data": { "transactionSigningHash": "txhash", - "chain": { - "coinType": 4218, + "signingOptions": { + "coin_type": 4218, "account": 0, "change": 0, - "addressIndex": 1 + "address_index": 1 } } }) ); - let sign_ed25519_method: super::SecretManagerMethod = serde_json::from_str( - r#"{"name": "signEd25519", "data": {"message": "0xFFFFFFFF", "chain": {"coinType": 60, "change": 1}}}"#, - ) - .unwrap(); + let sign_ed25519_method = super::SecretManagerMethod::SignEd25519 { + message: "0xFFFFFFFF".to_owned(), + signing_options: serde_json::to_value(Bip44::new(ETHER_COIN_TYPE).with_change(1)).unwrap(), + }; assert_eq!( serde_json::to_value(&sign_ed25519_method).unwrap(), @@ -140,20 +148,21 @@ mod test { "name": "signEd25519", "data": { "message": "0xFFFFFFFF", - "chain": { - "coinType": 60, + "signingOptions": { + "coin_type": 60, "account": 0, "change": 1, - "addressIndex": 0 + "address_index": 0 } } }) ); - let sign_secp256k1_ecdsa_method: super::SecretManagerMethod = serde_json::from_str( - r#"{"name": "signSecp256k1Ecdsa", "data": {"message": "0xFFFFFFFF", "chain": {"account": 2, "addressIndex": 1}}}"#, - ) - .unwrap(); + let sign_secp256k1_ecdsa_method = super::SecretManagerMethod::SignSecp256k1Ecdsa { + message: "0xFFFFFFFF".to_owned(), + signing_options: serde_json::to_value(Bip44::new(IOTA_COIN_TYPE).with_account(2).with_address_index(1)) + .unwrap(), + }; assert_eq!( serde_json::to_value(&sign_secp256k1_ecdsa_method).unwrap(), @@ -161,11 +170,11 @@ mod test { "name": "signSecp256k1Ecdsa", "data": { "message": "0xFFFFFFFF", - "chain": { - "coinType": 4218, + "signingOptions": { + "coin_type": 4218, "account": 2, "change": 0, - "addressIndex": 1 + "address_index": 1 } } }) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index c1b6b86367..8fc905764a 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -4,7 +4,6 @@ #[cfg(feature = "stronghold")] use std::path::PathBuf; -use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::utils::serde::string; #[cfg(feature = "events")] @@ -19,7 +18,6 @@ use iota_sdk::{ client::{ api::{input_selection::Burn, PreparedTransactionDataDto, SignedTransactionDataDto}, node_manager::node::NodeAuth, - secret::GenerateAddressOptions, }, types::block::{ address::{Bech32Address, Hrp}, @@ -201,7 +199,7 @@ pub enum WalletMethod { #[serde(default)] public_key: Option, #[serde(default)] - bip_path: Option, + public_key_options: Option, }, /// Returns the implicit accounts of the wallet. /// Expected response: [`OutputsData`](crate::Response::OutputsData) @@ -479,19 +477,6 @@ pub enum WalletMethod { EmitTestEvent { event: WalletEvent }, // TODO: reconsider whether to have the following methods on the wallet - /// Generate an address without storing it - /// Expected response: [`Bech32Address`](crate::Response::Bech32Address) - #[serde(rename_all = "camelCase")] - GenerateEd25519Address { - /// Account index - account_index: u32, - /// Account index - address_index: u32, - /// Options - options: Option, - /// Bech32 HRP - bech32_hrp: Option, - }, /// Get the ledger nano status /// Expected response: [`LedgerNanoStatus`](crate::Response::LedgerNanoStatus) #[cfg(feature = "ledger_nano")] diff --git a/bindings/core/src/method_handler/call_method.rs b/bindings/core/src/method_handler/call_method.rs index 44e3574d40..134ba9da75 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -5,11 +5,8 @@ use std::pin::Pin; use futures::Future; use iota_sdk::{ - client::{ - secret::{DowncastSecretManager, SecretManage}, - Client, - }, - wallet::Wallet, + client::{secret::SecretManager, Client}, + wallet::{core::SecretData, Wallet}, }; use crate::{ @@ -38,7 +35,7 @@ impl CallMethod for Client { } } -impl CallMethod for Wallet { +impl CallMethod for Wallet> { type Method = WalletMethod; fn call_method<'a>(&'a self, method: Self::Method) -> Pin + 'a>> { @@ -58,7 +55,7 @@ pub async fn call_client_method(client: &Client, method: ClientMethod) -> Respon } /// Call a wallet method. -pub async fn call_wallet_method(wallet: &Wallet, method: WalletMethod) -> Response { +pub async fn call_wallet_method(wallet: &Wallet>, method: WalletMethod) -> Response { log::debug!("Wallet method: {method:?}"); let result = convert_async_panics(|| async { call_wallet_method_internal(wallet, method).await }).await; @@ -80,13 +77,7 @@ pub fn call_utils_method(method: UtilsMethod) -> Response { } /// Call a secret manager method. -pub async fn call_secret_manager_method( - secret_manager: &S, - method: SecretManagerMethod, -) -> Response -where - iota_sdk::client::Error: From, -{ +pub async fn call_secret_manager_method(secret_manager: &SecretManager, method: SecretManagerMethod) -> Response { log::debug!("Secret manager method: {method:?}"); let result = convert_async_panics(|| async { call_secret_manager_method_internal(secret_manager, method).await }).await; diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 15fb53f1cc..1a5bc2595a 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -1,17 +1,20 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "ledger_nano")] -use iota_sdk::client::secret::ledger_nano::LedgerSecretManager; -#[cfg(feature = "stronghold")] -use iota_sdk::client::secret::{stronghold::StrongholdSecretManager, SecretManager}; +use crypto::signatures::secp256k1_ecdsa::EvmAddress; use iota_sdk::{ client::{ - api::{GetAddressesOptions, PreparedTransactionData}, - secret::{DowncastSecretManager, SecretManage, SignBlock}, + api::PreparedTransactionData, + secret::{ + types::EvmSignature, BlockSignExt, DowncastSecretManager, Generate, SecretManager, Sign, SignTransaction, + }, }, types::{ - block::{address::ToBech32Ext, core::UnsignedBlock, unlock::Unlock, BlockDto}, + block::{ + address::{Ed25519Address, ToBech32Ext}, + core::UnsignedBlock, + BlockDto, + }, TryFromDto, }, }; @@ -19,26 +22,14 @@ use iota_sdk::{ use crate::{method::SecretManagerMethod, response::Response, Result}; /// Call a secret manager method. -pub(crate) async fn call_secret_manager_method_internal( - secret_manager: &S, +pub(crate) async fn call_secret_manager_method_internal( + secret_manager: &SecretManager, method: SecretManagerMethod, -) -> Result -where - iota_sdk::client::Error: From, -{ +) -> Result { let response = match method { - SecretManagerMethod::GenerateEd25519Addresses { - options: - GetAddressesOptions { - coin_type, - account_index, - range, - bech32_hrp, - options, - }, - } => { - let addresses = secret_manager - .generate_ed25519_addresses(coin_type, account_index, range, options) + SecretManagerMethod::GenerateEd25519Addresses { bech32_hrp, options } => { + let options = serde_json::from_value(options)?; + let addresses = Generate::>::generate(secret_manager, &options) .await .map_err(iota_sdk::client::Error::from)? .into_iter() @@ -46,18 +37,9 @@ where .collect(); Response::GeneratedEd25519Addresses(addresses) } - SecretManagerMethod::GenerateEvmAddresses { - options: - GetAddressesOptions { - coin_type, - account_index, - range, - bech32_hrp: _, - options, - }, - } => { - let addresses = secret_manager - .generate_evm_addresses(coin_type, account_index, range, options) + SecretManagerMethod::GenerateEvmAddresses { options } => { + let options = serde_json::from_value(options)?; + let addresses = Generate::>::generate(secret_manager, &options) .await .map_err(iota_sdk::client::Error::from)? .into_iter() @@ -67,57 +49,61 @@ where } #[cfg(feature = "ledger_nano")] SecretManagerMethod::GetLedgerNanoStatus => { - let secret_manager = if let Some(secret_manager) = secret_manager.downcast::() { - secret_manager - } else if let Some(SecretManager::LedgerNano(secret_manager)) = secret_manager.downcast::() { - secret_manager - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - }; - Response::LedgerNanoStatus(secret_manager.get_ledger_nano_status().await) + Response::LedgerNanoStatus(secret_manager.as_ledger_nano()?.get_ledger_nano_status().await) } SecretManagerMethod::SignTransaction { prepared_transaction_data, protocol_parameters, + signing_options, } => { let transaction = &secret_manager .sign_transaction( PreparedTransactionData::try_from_dto(prepared_transaction_data)?, &protocol_parameters, + &signing_options, ) .await .map_err(iota_sdk::client::Error::from)?; Response::SignedTransaction(transaction.into()) } - SecretManagerMethod::SignBlock { unsigned_block, chain } => Response::Block(BlockDto::from( + SecretManagerMethod::SignBlock { + unsigned_block, + signing_options, + } => Response::Block(BlockDto::from( &UnsignedBlock::try_from_dto(unsigned_block)? - .sign_ed25519(secret_manager, chain) + .sign_ed25519(secret_manager, &signing_options) .await?, )), SecretManagerMethod::SignatureUnlock { transaction_signing_hash, - chain, + signing_options, } => { let transaction_signing_hash: [u8; 32] = prefix_hex::decode(transaction_signing_hash)?; - let unlock: Unlock = secret_manager - .signature_unlock(&transaction_signing_hash, chain) + let unlock = secret_manager + .signature_unlock(&transaction_signing_hash, &signing_options) .await .map_err(iota_sdk::client::Error::from)?; - Response::SignatureUnlock(unlock) + Response::SignatureUnlock(unlock.into()) } - SecretManagerMethod::SignEd25519 { message, chain } => { + SecretManagerMethod::SignEd25519 { + message, + signing_options, + } => { let msg: Vec = prefix_hex::decode(message)?; let signature = secret_manager - .sign_ed25519(&msg, chain) + .sign(&msg, &signing_options) .await .map_err(iota_sdk::client::Error::from)?; Response::Ed25519Signature(signature) } - SecretManagerMethod::SignSecp256k1Ecdsa { message, chain } => { + SecretManagerMethod::SignSecp256k1Ecdsa { + message, + signing_options, + } => { let msg: Vec = prefix_hex::decode(message)?; - let (public_key, signature) = secret_manager - .sign_secp256k1_ecdsa(&msg, chain) + let EvmSignature { public_key, signature } = secret_manager + .sign(&msg, &signing_options) .await .map_err(iota_sdk::client::Error::from)?; Response::Secp256k1EcdsaSignature { @@ -128,50 +114,22 @@ where #[cfg(feature = "stronghold")] SecretManagerMethod::StoreMnemonic { mnemonic } => { let mnemonic = crypto::keys::bip39::Mnemonic::from(mnemonic); - if let Some(secret_manager) = secret_manager.downcast::() { - secret_manager.store_mnemonic(mnemonic).await?; - Response::Ok - } else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::() { - secret_manager.store_mnemonic(mnemonic).await?; - Response::Ok - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - } + secret_manager.as_stronghold()?.store_mnemonic(mnemonic).await?; + Response::Ok } #[cfg(feature = "stronghold")] SecretManagerMethod::SetStrongholdPassword { password } => { - let stronghold = if let Some(secret_manager) = secret_manager.downcast::() { - secret_manager - } else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::() { - secret_manager - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - }; - stronghold.set_password(password).await?; + secret_manager.as_stronghold()?.set_password(password).await?; Response::Ok } #[cfg(feature = "stronghold")] SecretManagerMethod::ChangeStrongholdPassword { password } => { - let stronghold = if let Some(secret_manager) = secret_manager.downcast::() { - secret_manager - } else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::() { - secret_manager - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - }; - stronghold.change_password(password).await?; + secret_manager.as_stronghold()?.change_password(password).await?; Response::Ok } #[cfg(feature = "stronghold")] SecretManagerMethod::ClearStrongholdPassword => { - let stronghold = if let Some(secret_manager) = secret_manager.downcast::() { - secret_manager - } else if let Some(SecretManager::Stronghold(secret_manager)) = secret_manager.downcast::() { - secret_manager - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - }; - stronghold.clear_key().await; + secret_manager.as_stronghold()?.clear_key().await; Response::Ok } }; diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index 2cb6657cc4..0ba5a0d0be 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -5,18 +5,21 @@ use std::time::Duration; use crypto::signatures::ed25519::PublicKey; use iota_sdk::{ - client::api::{PreparedTransactionData, SignedTransactionData, SignedTransactionDataDto}, - types::{ - block::{address::ToBech32Ext, output::feature::BlockIssuerKeySource}, - TryFromDto, + client::{ + api::{PreparedTransactionData, SignedTransactionData, SignedTransactionDataDto}, + secret::{DowncastSecretManager, SecretManager}, }, - wallet::{types::TransactionWithMetadataDto, Wallet}, + types::{block::output::feature::BlockIssuerKeySource, TryFromDto}, + wallet::{core::SecretData, types::TransactionWithMetadataDto, Wallet}, }; use crate::{method::WalletMethod, response::Response}; /// Call a wallet method. -pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletMethod) -> crate::Result { +pub(crate) async fn call_wallet_method_internal( + wallet: &Wallet>, + method: WalletMethod, +) -> crate::Result { let response = match method { WalletMethod::Accounts => Response::OutputsData(wallet.data().await.accounts().cloned().collect()), #[cfg(feature = "stronghold")] @@ -67,26 +70,12 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM } #[cfg(feature = "ledger_nano")] WalletMethod::GetLedgerNanoStatus => { - let ledger_nano_status = wallet.get_ledger_nano_status().await?; + let ledger_nano_status = (&*wallet.secret_manager().read().await) + .as_ledger_nano()? + .get_ledger_nano_status() + .await; Response::LedgerNanoStatus(ledger_nano_status) } - WalletMethod::GenerateEd25519Address { - account_index, - address_index, - options, - bech32_hrp, - } => { - let address = wallet - .generate_ed25519_address(account_index, address_index, options) - .await?; - - let bech32_hrp = match bech32_hrp { - Some(bech32_hrp) => bech32_hrp, - None => *wallet.address().await.hrp(), - }; - - Response::Bech32Address(address.to_bech32(bech32_hrp)) - } #[cfg(feature = "stronghold")] WalletMethod::SetStrongholdPassword { password } => { wallet.set_stronghold_password(password).await?; @@ -209,22 +198,19 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM WalletMethod::PrepareImplicitAccountTransition { output_id, public_key, - bip_path, + public_key_options, } => { - let data = if let Some(public_key_str) = public_key { - let public_key = PublicKey::try_from_bytes(prefix_hex::decode(public_key_str)?) - .map_err(iota_sdk::wallet::Error::from)?; - wallet - .prepare_implicit_account_transition(&output_id, public_key) - .await? - } else if let Some(bip_path) = bip_path { - wallet.prepare_implicit_account_transition(&output_id, bip_path).await? - } else { - wallet - .prepare_implicit_account_transition(&output_id, BlockIssuerKeySource::ImplicitAccountAddress) - .await? - }; - Response::PreparedTransaction(data) + let source = public_key + .map(|s| { + crate::Result::Ok(BlockIssuerKeySource::PublicKey( + PublicKey::try_from_bytes(prefix_hex::decode(s)?).map_err(iota_sdk::wallet::Error::from)?, + )) + }) + .transpose()? + .or(public_key_options.map(BlockIssuerKeySource::Options)) + .unwrap_or(BlockIssuerKeySource::ImplicitAccountAddress); + + Response::PreparedTransaction(wallet.prepare_implicit_account_transition(&output_id, source).await?) } WalletMethod::ImplicitAccounts => { Response::OutputsData(wallet.data().await.implicit_accounts().cloned().collect()) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 6c2e89254a..47cfaba754 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -5,7 +5,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE}, - secret::{mnemonic::MnemonicSecretManager, SecretManagerDto}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManagerDto}, ClientBuilder, }, types::{ @@ -42,7 +42,8 @@ async fn create_wallet() -> Result<()> { let wallet = WalletOptions::default() .with_storage_path(storage_path.to_string()) .with_client_options(ClientBuilder::new().from_json(client_options).unwrap()) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(serde_json::to_value(PublicKeyOptions::new(SHIMMER_COIN_TYPE)).unwrap()) + .with_signing_options(serde_json::to_value(Bip44::new(SHIMMER_COIN_TYPE)).unwrap()) .with_secret_manager(serde_json::from_str::(secret_manager).unwrap()) .build() .await?; @@ -80,7 +81,8 @@ async fn client_from_wallet() -> Result<()> { let wallet = WalletOptions::default() .with_storage_path(storage_path.to_string()) .with_client_options(ClientBuilder::new().from_json(client_options).unwrap()) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(serde_json::to_value(PublicKeyOptions::new(SHIMMER_COIN_TYPE)).unwrap()) + .with_signing_options(serde_json::to_value(Bip44::new(SHIMMER_COIN_TYPE)).unwrap()) .with_secret_manager(serde_json::from_str::(secret_manager).unwrap()) .build() .await?; diff --git a/bindings/core/tests/secrets_debug.rs b/bindings/core/tests/secrets_debug.rs index 6f57d1eba5..68a7f307ba 100644 --- a/bindings/core/tests/secrets_debug.rs +++ b/bindings/core/tests/secrets_debug.rs @@ -26,6 +26,6 @@ fn method_interface_secrets_debug() { let wallet_options = WalletOptions::default().with_secret_manager(SecretManagerDto::Placeholder); assert_eq!( format!("{:?}", wallet_options), - "WalletOptions { address: None, alias: None, bip_path: None, client_options: None, secret_manager: Some(), storage_path: None }" + "WalletOptions { address: None, alias: None, public_key_options: None, signing_options: None, client_options: None, secret_manager: Some(), storage_path: None }" ); } diff --git a/bindings/core/tests/secrets_manager.rs b/bindings/core/tests/secrets_manager.rs index 2192cbae09..0915337486 100644 --- a/bindings/core/tests/secrets_manager.rs +++ b/bindings/core/tests/secrets_manager.rs @@ -1,7 +1,10 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_sdk::client::{api::GetAddressesOptions, constants::ETHER_COIN_TYPE, secret::SecretManager}; +use iota_sdk::client::{ + constants::{ETHER_COIN_TYPE, IOTA_COIN_TYPE, IOTA_TESTNET_BECH32_HRP}, + secret::{PublicKeyOptions, SecretManager}, +}; use iota_sdk_bindings_core::{call_secret_manager_method, Response, Result, SecretManagerMethod}; use pretty_assertions::assert_eq; @@ -12,7 +15,8 @@ async fn generate_ed25519_addresses() -> Result<()> { )?; let method = SecretManagerMethod::GenerateEd25519Addresses { - options: GetAddressesOptions::default().with_range(0..1), + bech32_hrp: IOTA_TESTNET_BECH32_HRP, + options: serde_json::to_value(PublicKeyOptions::new(IOTA_COIN_TYPE)).unwrap(), }; let response = call_secret_manager_method(&secret_manager, method).await; @@ -34,9 +38,7 @@ async fn generate_evm_addresses() -> Result<()> { )?; let method = SecretManagerMethod::GenerateEvmAddresses { - options: GetAddressesOptions::default() - .with_range(0..1) - .with_coin_type(ETHER_COIN_TYPE), + options: serde_json::to_value(PublicKeyOptions::new(ETHER_COIN_TYPE)).unwrap(), }; let response = call_secret_manager_method(&secret_manager, method).await; diff --git a/bindings/core/tests/serialize_error.rs b/bindings/core/tests/serialize_error.rs index b34229c024..e63ff33425 100644 --- a/bindings/core/tests/serialize_error.rs +++ b/bindings/core/tests/serialize_error.rs @@ -1,9 +1,12 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::{constants::SHIMMER_COIN_TYPE, Error as ClientError}, + client::{ + constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE}, + secret::PublicKeyOptions, + Error as ClientError, + }, wallet::Error as WalletError, }; use iota_sdk_bindings_core::Error; @@ -38,9 +41,9 @@ fn custom_error_serialization() { ); // testing a struct-like error - let error = Error::Wallet(WalletError::BipPathMismatch { - old_bip_path: None, - new_bip_path: Some(Bip44::new(SHIMMER_COIN_TYPE)), + let error = Error::Wallet(WalletError::PublicKeyOptionsMismatch { + old: serde_json::to_value(PublicKeyOptions::new(SHIMMER_COIN_TYPE)).unwrap(), + new: serde_json::to_value(PublicKeyOptions::new(IOTA_COIN_TYPE)).unwrap(), }); assert_eq!( serde_json::to_value(&error).unwrap(), diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 4d26911d2c..3574b4e352 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/src/wallet.rs @@ -8,7 +8,10 @@ use std::{ use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, - iota_sdk::wallet::{events::WalletEventType, Wallet}, + iota_sdk::{ + client::secret::SecretManager, + wallet::{core::SecretData, events::WalletEventType, Wallet}, + }, Response, WalletMethod, WalletOptions, }; use napi::{bindgen_prelude::External, threadsafe_function::ThreadsafeFunction, Error, Result}; @@ -19,7 +22,7 @@ use crate::{ build_js_error, client::ClientMethodHandler, destroyed_err, secret_manager::SecretManagerMethodHandler, NodejsError, }; -pub struct WalletMethodHandlerInner(Option); +pub struct WalletMethodHandlerInner(Option>>); impl Drop for WalletMethodHandlerInner { fn drop(&mut self) { @@ -32,7 +35,7 @@ impl Drop for WalletMethodHandlerInner { } impl Deref for WalletMethodHandlerInner { - type Target = Option; + type Target = Option>>; fn deref(&self) -> &Self::Target { &self.0 @@ -121,7 +124,7 @@ pub async fn get_client(wallet: External) -> Result) -> Result> { if let Some(wallet) = &**wallet.as_ref().read().await { - Ok(External::new(wallet.get_secret_manager().clone())) + Ok(External::new(wallet.secret_manager().clone())) } else { Err(destroyed_err("Wallet")) } diff --git a/bindings/python/src/wallet.rs b/bindings/python/src/wallet.rs index 2dd2f39733..a9f5d41701 100644 --- a/bindings/python/src/wallet.rs +++ b/bindings/python/src/wallet.rs @@ -5,7 +5,10 @@ use std::sync::Arc; use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, - iota_sdk::wallet::{events::types::WalletEventType, Wallet as RustWallet}, + iota_sdk::{ + client::secret::SecretManager as RustSecretManager, + wallet::{core::SecretData, events::types::WalletEventType, Wallet as RustWallet}, + }, Response, WalletMethod, WalletOptions, }; use pyo3::{prelude::*, types::PyTuple}; @@ -19,7 +22,7 @@ use crate::{ #[pyclass] pub struct Wallet { - pub wallet: Arc>>, + pub wallet: Arc>>>>, } /// Destroys the wallet instance. @@ -120,7 +123,7 @@ pub fn get_secret_manager_from_wallet(wallet: &Wallet) -> Result .read() .await .as_ref() - .map(|w| w.get_secret_manager().clone()) + .map(|w| w.secret_manager().clone()) .ok_or_else(|| { Error::from( serde_json::to_string(&Response::Panic("wallet was destroyed".into())) diff --git a/bindings/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index 4643dd07c9..127f2ec924 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -5,9 +5,13 @@ use std::sync::Arc; use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, - iota_sdk::wallet::{ - events::types::{WalletEvent, WalletEventType}, - Wallet, + iota_sdk::{ + client::secret::SecretManager, + wallet::{ + core::SecretData, + events::types::{WalletEvent, WalletEventType}, + Wallet, + }, }, Response, WalletOptions, }; @@ -21,7 +25,7 @@ use crate::{client::ClientMethodHandler, destroyed_err, map_err, secret_manager: /// The Wallet method handler. #[wasm_bindgen(js_name = WalletMethodHandler)] -pub struct WalletMethodHandler(Arc>>); +pub struct WalletMethodHandler(Arc>>>>); /// Creates a method handler with the given options. #[wasm_bindgen(js_name = createWallet)] @@ -52,7 +56,7 @@ pub async fn get_client(method_handler: &WalletMethodHandler) -> Result Result { if let Some(wallet) = &*method_handler.0.read().await { - Ok(SecretManagerMethodHandler::new(wallet.get_secret_manager().clone())) + Ok(SecretManagerMethodHandler::new(wallet.secret_manager().clone())) } else { // Notify that the wallet was destroyed Err(destroyed_err("Wallet")) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9714463c52..ad9595d9c8 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -25,6 +25,7 @@ iota-sdk = { path = "../sdk", default-features = false, features = [ "ledger_nano", ] } +async-trait = { version = "0.1.77", default-features = false } chrono = { version = "0.4.33", default-features = false, features = ["std"] } clap = { version = "4.4.18", default-features = false, features = [ "std", diff --git a/cli/src/cli.rs b/cli/src/cli.rs index c4a5f6c8c2..588c7892bc 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -7,13 +7,17 @@ use clap::{builder::BoolishValueParser, Args, CommandFactory, Parser, Subcommand use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{ledger_nano::LedgerSecretManager, stronghold::StrongholdSecretManager, SecretManager}, + secret::{ + ledger_nano::{LedgerOptions, LedgerSecretManager}, + stronghold::StrongholdSecretManager, + DowncastSecretManager, PublicKeyOptions, + }, stronghold::StrongholdAdapter, utils::Password, }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::{ClientOptions, Wallet}, + wallet::{ClientOptions, WalletBuilder}, }; use log::LevelFilter; @@ -24,6 +28,8 @@ use crate::{ import_mnemonic, select_secret_manager, SecretManagerChoice, }, println_log_error, println_log_info, + secret::SecretManager, + Wallet, }; const DEFAULT_LOG_LEVEL: &str = "debug"; @@ -167,9 +173,14 @@ pub async fn new_wallet(cli: Cli) -> Result, Error> { let wallet_and_secret_manager = { if storage_path.is_dir() { - match Wallet::builder().with_storage_path(storage_path).finish().await { + match Wallet::builder() + .with_secret_type::() + .with_storage_path(storage_path) + .finish() + .await + { Ok(wallet) => { - let linked_secret_manager = match &mut *wallet.get_secret_manager().write().await { + let linked_secret_manager = match &mut *wallet.secret_manager().write().await { SecretManager::Stronghold(stronghold) => { let snapshot_path = stronghold.snapshot_path().to_path_buf(); let snapshot_exists = snapshot_path.exists(); @@ -179,7 +190,6 @@ pub async fn new_wallet(cli: Cli) -> Result, Error> { } } SecretManager::LedgerNano(_) => LinkedSecretManager::LedgerNano, - _ => panic!("only Stronghold and LedgerNano supported at the moment."), }; Some((wallet, linked_secret_manager)) } @@ -259,7 +269,7 @@ pub async fn new_wallet(cli: Cli) -> Result, Error> { ))); } let secret_manager = create_secret_manager(&init_parameters).await?; - let secret_manager_variant = secret_manager.to_string(); + let secret_manager_variant = secret_manager.as_ref().to_owned(); let wallet = init_command(storage_path, secret_manager, init_parameters).await?; println_log_info!("Created new wallet with '{}' secret manager.", secret_manager_variant); @@ -362,7 +372,7 @@ pub async fn new_wallet(cli: Cli) -> Result, Error> { if !snapshot_path.exists() { if get_decision("Create a new wallet with default parameters?")? { let secret_manager = create_secret_manager(&init_params).await?; - let secret_manager_variant = secret_manager.to_string(); + let secret_manager_variant = secret_manager.as_ref().to_owned(); let wallet = init_command(storage_path, secret_manager, init_params).await?; println_log_info!("Created new wallet with '{}' secret manager.", secret_manager_variant); Some(wallet) @@ -392,9 +402,10 @@ pub async fn backup_command_stronghold(wallet: &Wallet, password: &Password, bac pub async fn change_password_command(wallet: &Wallet, current_password: Password) -> Result<(), Error> { let new_password = get_password("New Stronghold password", true)?; - wallet - .change_stronghold_password(current_password, new_password) - .await?; + if let Ok(stronghold) = (&*wallet.secret_manager().read().await).as_stronghold() { + stronghold.set_password(current_password).await?; + stronghold.change_password(new_password).await?; + } println_log_info!("The password has been changed"); @@ -416,11 +427,22 @@ pub async fn init_command( .map(|addr| Bech32Address::from_str(&addr)) .transpose()?; - Ok(Wallet::builder() + let public_key_options = init_params.bip_path.map(|bip| { + LedgerOptions::new( + PublicKeyOptions::new(bip.coin_type) + .with_account_index(bip.account) + .with_internal(bip.change != 0) + .with_address_index(bip.address_index), + ) + .with_ledger_nano_prompt(true) + }); + + Ok(WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(ClientOptions::new().with_node(init_params.node_url.as_str())?) .with_storage_path(storage_path.to_str().expect("invalid unicode")) - .with_bip_path(init_params.bip_path) + .with_public_key_options(public_key_options) + .with_signing_options(init_params.bip_path) .with_address(address) .with_alias(alias) .finish() @@ -459,27 +481,18 @@ pub async fn restore_command_stronghold( ) -> Result { check_file_exists(backup_path).await?; - let mut builder = Wallet::builder(); - - let password = if snapshot_path.exists() { - Some(get_password("Stronghold password", false)?) - } else { - None - }; + let mut builder = WalletBuilder::new().with_secret_type(); - if let Some(password) = password { + if let Some(password) = snapshot_path + .exists() + .then_some(get_password("Stronghold password", false)) + .transpose()? + { println!("Detected a stronghold file at {}.", snapshot_path.to_str().unwrap()); - let secret_manager = SecretManager::Stronghold( - StrongholdSecretManager::builder() - .password(password) - .build(snapshot_path)?, - ); - builder = builder.with_secret_manager(secret_manager); - } else { - // If there is no db, set the placeholder so the wallet builder doesn't fail. - if check_file_exists(storage_path).await.is_err() { - builder = builder.with_secret_manager(SecretManager::Placeholder); - } + let secret_manager = StrongholdSecretManager::builder() + .password(password) + .build(snapshot_path)?; + builder = builder.with_secret_manager(SecretManager::Stronghold(secret_manager)); } // If the restore fails we do not want to remove an already existing wallet @@ -489,7 +502,10 @@ pub async fn restore_command_stronghold( .with_client_options(ClientOptions::new().with_node(DEFAULT_NODE_URL)?) .with_storage_path(storage_path.to_str().expect("invalid unicode")) // Will be overwritten by the backup's value. - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options( + LedgerOptions::new(PublicKeyOptions::new(SHIMMER_COIN_TYPE)).with_ledger_nano_prompt(true), + ) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/cli/src/main.rs b/cli/src/main.rs index 5c7c29449c..23c9a15470 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -4,16 +4,21 @@ mod cli; mod error; mod helper; +mod secret; mod wallet_cli; use clap::Parser; use fern_logger::{LoggerConfigBuilder, LoggerOutputConfigBuilder}; +use iota_sdk::wallet::core::SecretData; use log::LevelFilter; use self::{ cli::{new_wallet, Cli}, error::Error, }; +use crate::secret::SecretManager; + +pub type Wallet = iota_sdk::wallet::Wallet>; #[macro_export] macro_rules! println_log_info { diff --git a/cli/src/secret.rs b/cli/src/secret.rs new file mode 100644 index 0000000000..84fcca6023 --- /dev/null +++ b/cli/src/secret.rs @@ -0,0 +1,74 @@ +// Copyright 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use iota_sdk::{ + client::secret::{ + ledger_nano::{LedgerOptions, LedgerSecretManager}, + stronghold::StrongholdSecretManager, + Generate, PublicKeyOptions, SecretManagerConfig, SecretManagerDto, Sign, SignTransaction, + }, + crypto::{keys::bip44::Bip44, signatures::ed25519}, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, +}; + +#[derive(Debug, strum::AsRefStr)] +pub enum SecretManager { + Stronghold(StrongholdSecretManager), + LedgerNano(LedgerSecretManager), +} + +#[async_trait] +impl Generate for SecretManager { + type Options = LedgerOptions; + + async fn generate(&self, options: &Self::Options) -> iota_sdk::client::Result { + match self { + SecretManager::Stronghold(s) => Ok(s.generate(&options.options).await?), + SecretManager::LedgerNano(l) => Ok(l.generate(options).await?), + } + } +} + +#[async_trait] +impl Generate for SecretManager { + type Options = LedgerOptions; + + async fn generate(&self, options: &Self::Options) -> iota_sdk::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) + } +} + +#[async_trait] +impl Sign for SecretManager { + type Options = Bip44; + + async fn sign(&self, msg: &[u8], options: &Self::Options) -> iota_sdk::client::Result { + match self { + SecretManager::Stronghold(s) => Ok(s.sign(msg, options).await?), + SecretManager::LedgerNano(l) => Ok(l.sign(msg, options).await?), + } + } +} + +impl SignTransaction for SecretManager {} + +impl SecretManagerConfig for SecretManager { + type Config = SecretManagerDto; + + fn to_config(&self) -> Option { + match self { + Self::Stronghold(s) => s.to_config().map(Self::Config::Stronghold), + Self::LedgerNano(s) => s.to_config().map(Self::Config::LedgerNano), + } + } + + fn from_config(config: &Self::Config) -> iota_sdk::client::Result { + Ok(match config { + SecretManagerDto::Stronghold(config) => Self::Stronghold(StrongholdSecretManager::from_config(config)?), + SecretManagerDto::LedgerNano(config) => Self::LedgerNano(LedgerSecretManager::from_config(config)?), + _ => panic!("unsupported secret manager"), + }) + } +} diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 3b9819ea0f..2f507d517e 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -8,7 +8,7 @@ use std::str::FromStr; use clap::{CommandFactory, Parser, Subcommand}; use colored::Colorize; use iota_sdk::{ - client::{request_funds_from_faucet, secret::SecretManager}, + client::{request_funds_from_faucet, secret::DowncastSecretManager}, types::block::{ address::{AccountAddress, Bech32Address, ToBech32Ext}, mana::ManaAllotment, @@ -25,7 +25,7 @@ use iota_sdk::{ wallet::{ types::OutputData, BeginStakingParams, ConsolidationParams, CreateDelegationParams, CreateNativeTokenParams, Error as WalletError, MintNftParams, OutputsToClaim, SendNativeTokenParams, SendNftParams, SendParams, - SyncOptions, TransactionOptions, Wallet, + SyncOptions, TransactionOptions, }, U256, }; @@ -35,7 +35,7 @@ use self::completer::WalletCommandHelper; use crate::{ error::Error, helper::{bytes_from_hex_or_file, get_password, to_utc_date_time}, - println_log_error, println_log_info, + println_log_error, println_log_info, Wallet, }; #[derive(Debug, Parser)] @@ -1290,7 +1290,7 @@ async fn print_wallet_address(wallet: &Wallet) -> Result<(), Error> { } } - let bip_path = wallet.bip_path().await; + let bip_path = wallet.signing_options().clone(); log = format!("{log}\nBIP path: {bip_path:?}"); log = format!( @@ -1343,11 +1343,11 @@ pub enum PromptResponse { } async fn ensure_password(wallet: &Wallet) -> Result<(), Error> { - if matches!(*wallet.get_secret_manager().read().await, SecretManager::Stronghold(_)) - && !wallet.is_stronghold_password_available().await? - { - let password = get_password("Stronghold password", false)?; - wallet.set_stronghold_password(password).await?; + if let Ok(stronghold) = (&*wallet.secret_manager().read().await).as_stronghold() { + if stronghold.is_key_available().await { + let password = get_password("Stronghold password", false)?; + stronghold.set_password(password).await?; + } } Ok(()) diff --git a/sdk/examples/client/01_generate_addresses.rs b/sdk/examples/client/01_generate_addresses.rs index c3f10a3e7d..e6cd84da30 100644 --- a/sdk/examples/client/01_generate_addresses.rs +++ b/sdk/examples/client/01_generate_addresses.rs @@ -8,10 +8,13 @@ //! cargo run --release --example 01_generate_addresses //! ``` -use iota_sdk::client::{ - api::GetAddressesOptions, - secret::{GenerateAddressOptions, SecretManager}, - Client, Result, +use iota_sdk::{ + client::{ + constants::IOTA_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, MultiKeyOptions, SecretManageExt}, + Client, Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; #[tokio::main] @@ -29,39 +32,48 @@ async fn main() -> Result<()> { .finish() .await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + + let hrp = client.get_bech32_hrp().await?; // Generate addresses with default account index and range let addresses = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?) - .await?; + .generate::>(&MultiKeyOptions::new(IOTA_COIN_TYPE)) + .await? + .into_iter() + .map(|a| a.to_bech32(hrp)) + .collect::>(); println!("List of generated public addresses (default):"); println!("{addresses:#?}\n"); // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? + .generate::>( + &MultiKeyOptions::new(IOTA_COIN_TYPE) .with_account_index(0) - .with_range(0..4), + .with_address_range(0..4), ) - .await?; + .await? + .into_iter() + .map(|a| a.to_bech32(hrp)) + .collect::>(); println!("List of generated public addresses (0..4):\n"); println!("{addresses:#?}\n"); // Generate internal addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? + .generate::>( + &MultiKeyOptions::new(IOTA_COIN_TYPE) .with_account_index(0) - .with_range(0..4) - .with_options(GenerateAddressOptions::internal()), + .with_address_range(0..4) + .with_internal(true), ) - .await?; + .await? + .into_iter() + .map(|a| a.to_bech32(hrp)) + .collect::>(); println!("List of generated internal addresses:\n"); println!("{addresses:#?}\n"); diff --git a/sdk/examples/client/02_address_balance.rs b/sdk/examples/client/02_address_balance.rs index ac54630929..fd8a98943d 100644 --- a/sdk/examples/client/02_address_balance.rs +++ b/sdk/examples/client/02_address_balance.rs @@ -11,10 +11,15 @@ use iota_sdk::{ client::{ - api::GetAddressesOptions, node_api::indexer::query_parameters::BasicOutputQueryParameters, - secret::SecretManager, Client, Result, + constants::IOTA_COIN_TYPE, + node_api::indexer::query_parameters::BasicOutputQueryParameters, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, + Client, Result, + }, + types::block::{ + address::{Ed25519Address, ToBech32Ext}, + output::NativeTokensBuilder, }, - types::block::output::NativeTokensBuilder, }; #[tokio::main] @@ -32,18 +37,15 @@ async fn main() -> Result<()> { .finish() .await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + + let hrp = client.get_bech32_hrp().await?; // Generate the first address let first_address = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? - .with_account_index(0) - .with_range(0..1), - ) - .await?[0] - .clone(); + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await? + .to_bech32(hrp); // Get output ids of outputs that can be controlled by this address without further unlock constraints let output_ids_response = client diff --git a/sdk/examples/client/block/00_block_no_payload.rs b/sdk/examples/client/block/00_block_no_payload.rs index 5696e1eaf6..de12194365 100644 --- a/sdk/examples/client/block/00_block_no_payload.rs +++ b/sdk/examples/client/block/00_block_no_payload.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::output::AccountId, @@ -33,13 +33,13 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create and send the block. let block = client .build_basic_block(issuer_id, None) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/01_block_confirmation_time.rs b/sdk/examples/client/block/01_block_confirmation_time.rs index a6d1c3e66d..abe55a2053 100644 --- a/sdk/examples/client/block/01_block_confirmation_time.rs +++ b/sdk/examples/client/block/01_block_confirmation_time.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::{api::core::BlockState, block::output::AccountId}, @@ -33,13 +33,13 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create and send a block. let block = client .build_basic_block(issuer_id, None) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; let block_id = client.block_id(&block).await?; diff --git a/sdk/examples/client/block/02_block_custom_parents.rs b/sdk/examples/client/block/02_block_custom_parents.rs index a39e30afee..555269743b 100644 --- a/sdk/examples/client/block/02_block_custom_parents.rs +++ b/sdk/examples/client/block/02_block_custom_parents.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::output::AccountId, @@ -33,7 +33,7 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Use issuance as custom parents. let issuance = client.get_issuance().await?; @@ -44,7 +44,7 @@ async fn main() -> Result<()> { let block = client .build_basic_block(issuer_id, None) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/03_block_custom_payload.rs b/sdk/examples/client/block/03_block_custom_payload.rs index 23d08efe1e..a7a4841a92 100644 --- a/sdk/examples/client/block/03_block_custom_payload.rs +++ b/sdk/examples/client/block/03_block_custom_payload.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::{ @@ -36,7 +36,7 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create a custom payload. let tagged_data_payload = TaggedDataPayload::new(*b"Your tag", *b"Your data")?; @@ -45,7 +45,7 @@ async fn main() -> Result<()> { let block = client .build_basic_block(issuer_id, Some(Payload::from(tagged_data_payload))) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}"); diff --git a/sdk/examples/client/block/04_block_tagged_data.rs b/sdk/examples/client/block/04_block_tagged_data.rs index ce1a70320d..33516695e1 100644 --- a/sdk/examples/client/block/04_block_tagged_data.rs +++ b/sdk/examples/client/block/04_block_tagged_data.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::{ @@ -36,7 +36,7 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create and send the block with tag and data. let block = client @@ -57,7 +57,7 @@ async fn main() -> Result<()> { ))), ) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; println!("{block:#?}\n"); diff --git a/sdk/examples/client/ledger_nano.rs b/sdk/examples/client/ledger_nano.rs index cd0d2ea713..d7abb2c668 100644 --- a/sdk/examples/client/ledger_nano.rs +++ b/sdk/examples/client/ledger_nano.rs @@ -16,11 +16,16 @@ //! cargo run --release --all-features --example ledger_nano //! ``` -use iota_sdk::client::{ - api::GetAddressesOptions, - constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, - secret::{ledger_nano::LedgerSecretManager, SecretManager}, - Result, +use iota_sdk::{ + client::{ + constants::{IOTA_COIN_TYPE, IOTA_TESTNET_BECH32_HRP}, + secret::{ + ledger_nano::{LedgerOptions, LedgerSecretManager}, + MultiKeyOptions, SecretManageExt, + }, + Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; #[tokio::main] @@ -28,22 +33,19 @@ async fn main() -> Result<()> { // This example uses secrets in environment variables for simplicity which should not be done in production. dotenvy::dotenv().ok(); - let ledger_nano = LedgerSecretManager::new(true); + let secret_manager = LedgerSecretManager::new(true); - println!("{:?}", ledger_nano.get_ledger_nano_status().await); - - let secret_manager = SecretManager::LedgerNano(ledger_nano); + println!("{:?}", secret_manager.get_ledger_nano_status().await); // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_account_index(0) - .with_range(0..2), - ) - .await?; + .generate::>(&LedgerOptions::new( + MultiKeyOptions::new(IOTA_COIN_TYPE).with_address_range(0..2), + )) + .await? + .into_iter() + .map(|a| a.to_bech32(IOTA_TESTNET_BECH32_HRP)) + .collect::>(); println!("List of generated public addresses:\n{addresses:?}\n"); diff --git a/sdk/examples/client/ledger_nano_transaction.rs b/sdk/examples/client/ledger_nano_transaction.rs index 8dcdf75a54..df6486e288 100644 --- a/sdk/examples/client/ledger_nano_transaction.rs +++ b/sdk/examples/client/ledger_nano_transaction.rs @@ -17,10 +17,16 @@ //! cargo run --release --all-features --example ledger_nano_transaction //! ``` -use iota_sdk::client::{ - api::GetAddressesOptions, - secret::{ledger_nano::LedgerSecretManager, SecretManager}, - Client, Result, +use iota_sdk::{ + client::{ + constants::IOTA_COIN_TYPE, + secret::{ + ledger_nano::{LedgerOptions, LedgerSecretManager}, + MultiKeyOptions, SecretManageExt, + }, + Client, Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; // const AMOUNT: u64 = 1_000_000; @@ -40,17 +46,19 @@ async fn main() -> Result<()> { .finish() .await?; - let secret_manager = SecretManager::LedgerNano(LedgerSecretManager::new(true)); + let secret_manager = LedgerSecretManager::new(true); + + let hrp = client.get_bech32_hrp().await?; // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? - .with_account_index(0) - .with_range(0..2), - ) - .await?; + .generate::>(&LedgerOptions::new( + MultiKeyOptions::new(IOTA_COIN_TYPE).with_address_range(0..2), + )) + .await? + .into_iter() + .map(|a| a.to_bech32(hrp)) + .collect::>(); println!("List of generated public addresses:\n{addresses:#?}\n"); diff --git a/sdk/examples/client/node_api_core/04_post_block.rs b/sdk/examples/client/node_api_core/04_post_block.rs index e6f9ef34d8..b8fc4b3ac4 100644 --- a/sdk/examples/client/node_api_core/04_post_block.rs +++ b/sdk/examples/client/node_api_core/04_post_block.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::output::AccountId, @@ -36,13 +36,13 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create the block. let block = client .build_basic_block(issuer_id, None) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block. let block_id = client.post_block(&block).await?; diff --git a/sdk/examples/client/node_api_core/05_post_block_raw.rs b/sdk/examples/client/node_api_core/05_post_block_raw.rs index f4c8265253..22b25411b6 100644 --- a/sdk/examples/client/node_api_core/05_post_block_raw.rs +++ b/sdk/examples/client/node_api_core/05_post_block_raw.rs @@ -12,7 +12,7 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::output::AccountId, @@ -36,13 +36,13 @@ async fn main() -> Result<()> { // Create a node client. let client = Client::builder().with_node(&node_url)?.finish().await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; // Create the block. let block = client .build_basic_block(issuer_id, None) .await? - .sign_ed25519(&secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(&secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await?; // Post the block as raw bytes. let block_id = client.post_block_raw(&block).await?; diff --git a/sdk/examples/client/quorum.rs b/sdk/examples/client/quorum.rs index c02b9856e7..8d8dc2c980 100644 --- a/sdk/examples/client/quorum.rs +++ b/sdk/examples/client/quorum.rs @@ -13,9 +13,14 @@ //! cargo run --release --example quorum //! ``` -use iota_sdk::client::{ - api::GetAddressesOptions, node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManager, - Client, Result, +use iota_sdk::{ + client::{ + constants::IOTA_COIN_TYPE, + node_api::indexer::query_parameters::BasicOutputQueryParameters, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, + Client, Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; #[tokio::main] @@ -42,23 +47,19 @@ async fn main() -> Result<()> { .finish() .await?; - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + + let hrp = client.get_bech32_hrp().await?; // Generate the first address - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? - .with_account_index(0) - .with_range(0..1), - ) - .await?; + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await? + .to_bech32(hrp); // Get output ids of outputs that can be controlled by this address without further unlock constraints let output_ids_response = client - .basic_output_ids(BasicOutputQueryParameters::only_address_unlock_condition( - addresses[0].clone(), - )) + .basic_output_ids(BasicOutputQueryParameters::only_address_unlock_condition(address)) .await?; println!("Address outputs: {output_ids_response:?}"); diff --git a/sdk/examples/client/stronghold.rs b/sdk/examples/client/stronghold.rs index d57cfb6d9c..88674d490a 100644 --- a/sdk/examples/client/stronghold.rs +++ b/sdk/examples/client/stronghold.rs @@ -10,12 +10,12 @@ use iota_sdk::{ client::{ - api::GetAddressesOptions, - constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + constants::{IOTA_COIN_TYPE, IOTA_TESTNET_BECH32_HRP}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManageExt}, Result, }, crypto::keys::bip39::Mnemonic, + types::block::address::{Ed25519Address, ToBech32Ext}, }; #[tokio::main] @@ -27,27 +27,22 @@ async fn main() -> Result<()> { std::env::var(var).expect(&format!(".env variable '{var}' is undefined, see .env.example")); } - let stronghold_secret_manager = StrongholdSecretManager::builder() + let secret_manager = StrongholdSecretManager::builder() .password("some_hopefully_secure_password".to_owned()) .build("test.stronghold")?; let mnemonic = Mnemonic::from(std::env::var("MNEMONIC").unwrap()); // The mnemonic only needs to be stored the first time - stronghold_secret_manager.store_mnemonic(mnemonic).await?; - - // Generate addresses with custom account index and range - let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_account_index(0) - .with_range(0..1), - ) - .await?; - - println!("First public address: {}", addresses[0]); + secret_manager.store_mnemonic(mnemonic).await?; + + // Generate address + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await? + .to_bech32(IOTA_TESTNET_BECH32_HRP); + + println!("First public address: {address}"); Ok(()) } diff --git a/sdk/examples/how_tos/account_output/create.rs b/sdk/examples/how_tos/account_output/create.rs index 8eb107aa5b..fb7bf07add 100644 --- a/sdk/examples/how_tos/account_output/create.rs +++ b/sdk/examples/how_tos/account_output/create.rs @@ -12,7 +12,7 @@ //! cargo run --release --all-features --example create_account_output //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -24,6 +24,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account_output/destroy.rs b/sdk/examples/how_tos/account_output/destroy.rs index a77e62d370..c69366bfa1 100644 --- a/sdk/examples/how_tos/account_output/destroy.rs +++ b/sdk/examples/how_tos/account_output/destroy.rs @@ -11,7 +11,7 @@ //! cargo run --release --all-features --example destroy_account_output //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -19,6 +19,7 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account_output/implicit_account_creation.rs b/sdk/examples/how_tos/account_output/implicit_account_creation.rs index 9f565da0b8..af93e9a229 100644 --- a/sdk/examples/how_tos/account_output/implicit_account_creation.rs +++ b/sdk/examples/how_tos/account_output/implicit_account_creation.rs @@ -9,9 +9,12 @@ //! ``` use iota_sdk::{ - client::{constants::SHIMMER_COIN_TYPE, secret::SecretManager}, + client::{ + constants::SHIMMER_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, + }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, WalletBuilder}, }; #[tokio::main] @@ -19,14 +22,15 @@ async fn main() -> Result<()> { //  This example uses secrets in environment variables for simplicity which should not be done in production. dotenvy::dotenv().ok(); - let secret_manager = SecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; let client_options = ClientOptions::new().with_node("https://api.testnet.shimmer.network")?; - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_storage_path("implicit_account_creation") - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/how_tos/account_output/request_funds.rs b/sdk/examples/how_tos/account_output/request_funds.rs index 37adabba64..47bf854655 100644 --- a/sdk/examples/how_tos/account_output/request_funds.rs +++ b/sdk/examples/how_tos/account_output/request_funds.rs @@ -8,7 +8,7 @@ //! `cargo run --release --all-features --example account_output_request_funds` use iota_sdk::{ - client::request_funds_from_faucet, + client::{request_funds_from_faucet, secret::SecretManager}, types::block::address::{AccountAddress, ToBech32Ext}, wallet::{AccountSyncOptions, Result, SyncOptions}, Wallet, @@ -27,6 +27,7 @@ async fn main() -> Result<()> { // Create the wallet let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/account_output/send_amount.rs b/sdk/examples/how_tos/account_output/send_amount.rs index 1deafa7434..3504a517c6 100644 --- a/sdk/examples/how_tos/account_output/send_amount.rs +++ b/sdk/examples/how_tos/account_output/send_amount.rs @@ -7,7 +7,7 @@ //! `cargo run --release --all-features --example account_output_send_amount` use iota_sdk::{ - client::node_api::indexer::query_parameters::BasicOutputQueryParameters, + client::{node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManager}, types::block::address::{AccountAddress, ToBech32Ext}, wallet::{AccountSyncOptions, Result, SyncOptions, TransactionOptions}, Wallet, @@ -32,6 +32,7 @@ async fn main() -> Result<()> { // Create the wallet let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs b/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs index 55cc67f593..0d568cd61a 100644 --- a/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs @@ -8,6 +8,7 @@ //! `cargo run --release --all-features --example advanced_transaction` use iota_sdk::{ + client::secret::SecretManager, types::block::{ address::Bech32Address, output::{ @@ -31,6 +32,7 @@ async fn main() -> Result<()> { // Get the wallet we generated with `create_wallet`. let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs b/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs index 628cd91504..45dabfd80c 100644 --- a/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/claim_transaction.rs @@ -7,6 +7,7 @@ //! `cargo run --release --all-features --example claim_transaction` use iota_sdk::{ + client::secret::SecretManager, wallet::{OutputsToClaim, Result}, Wallet, }; @@ -22,6 +23,7 @@ async fn main() -> Result<()> { // Get the wallet we generated with `create_wallet`. let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs b/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs index 52b9263977..ef4925d17a 100644 --- a/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs +++ b/sdk/examples/how_tos/advanced_transactions/send_micro_transaction.rs @@ -12,6 +12,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, wallet::{Result, TransactionOptions}, Wallet, }; @@ -32,6 +33,7 @@ async fn main() -> Result<()> { // Get the wallet we generated with `create_wallet`. let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/burn.rs b/sdk/examples/how_tos/native_tokens/burn.rs index ac0dc734ec..2dd1e8345b 100644 --- a/sdk/examples/how_tos/native_tokens/burn.rs +++ b/sdk/examples/how_tos/native_tokens/burn.rs @@ -17,6 +17,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{NativeToken, TokenId}, wallet::Result, Wallet, U256, @@ -37,6 +38,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/create.rs b/sdk/examples/how_tos/native_tokens/create.rs index e67fcde805..9b6801c6a6 100644 --- a/sdk/examples/how_tos/native_tokens/create.rs +++ b/sdk/examples/how_tos/native_tokens/create.rs @@ -12,6 +12,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::feature::Irc30Metadata, wallet::{CreateNativeTokenParams, Result}, Wallet, U256, @@ -32,6 +33,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/destroy_foundry.rs b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs index e79d5b905e..b36275ce5d 100644 --- a/sdk/examples/how_tos/native_tokens/destroy_foundry.rs +++ b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs @@ -12,7 +12,7 @@ //! cargo run --release --all-features --example destroy_foundry //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, types::block::output::TokenId, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -24,6 +24,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/melt.rs b/sdk/examples/how_tos/native_tokens/melt.rs index c4d8b86c9f..cfdddae6ec 100644 --- a/sdk/examples/how_tos/native_tokens/melt.rs +++ b/sdk/examples/how_tos/native_tokens/melt.rs @@ -16,7 +16,7 @@ //! cargo run --release --all-features --example melt_native_token [TOKEN_ID] //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, types::block::output::TokenId, wallet::Result, Wallet}; // The amount of native tokens to melt const MELT_AMOUNT: u64 = 10; @@ -31,6 +31,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/mint.rs b/sdk/examples/how_tos/native_tokens/mint.rs index a19cefd48f..55dfd99925 100644 --- a/sdk/examples/how_tos/native_tokens/mint.rs +++ b/sdk/examples/how_tos/native_tokens/mint.rs @@ -16,7 +16,7 @@ //! cargo run --release --all-features --example mint_native_token [TOKEN_ID] //! ``` -use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, types::block::output::TokenId, wallet::Result, Wallet}; // The amount of native tokens to mint const MINT_AMOUNT: u64 = 10; @@ -31,6 +31,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/native_tokens/send.rs b/sdk/examples/how_tos/native_tokens/send.rs index c004a106d2..87ea80accb 100644 --- a/sdk/examples/how_tos/native_tokens/send.rs +++ b/sdk/examples/how_tos/native_tokens/send.rs @@ -12,6 +12,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::address::Bech32Address, wallet::{Result, SendNativeTokenParams}, Wallet, @@ -33,6 +34,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs b/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs index f1475e8a62..c1e1395da4 100644 --- a/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs +++ b/sdk/examples/how_tos/nft_collection/00_mint_issuer_nft.rs @@ -15,6 +15,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::{ output::{feature::MetadataFeature, NftId, Output, OutputId}, payload::signed_transaction::TransactionId, @@ -33,6 +34,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs b/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs index efa828fb6c..3e8e2725e5 100644 --- a/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs +++ b/sdk/examples/how_tos/nft_collection/01_mint_collection_nft.rs @@ -15,6 +15,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::{ address::{Bech32Address, NftAddress}, output::{ @@ -47,6 +48,7 @@ async fn main() -> Result<()> { .parse::()?; let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/burn_nft.rs b/sdk/examples/how_tos/nfts/burn_nft.rs index 5385778a3c..92e86574c9 100644 --- a/sdk/examples/how_tos/nfts/burn_nft.rs +++ b/sdk/examples/how_tos/nfts/burn_nft.rs @@ -11,7 +11,7 @@ //! cargo run --release --all-features --example burn_nft //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -24,6 +24,7 @@ async fn main() -> Result<()> { // Create the wallet let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/mint_nft.rs b/sdk/examples/how_tos/nfts/mint_nft.rs index 1112cab852..0de84006b7 100644 --- a/sdk/examples/how_tos/nfts/mint_nft.rs +++ b/sdk/examples/how_tos/nfts/mint_nft.rs @@ -12,6 +12,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{ feature::{Irc27Metadata, IssuerFeature, MetadataFeature, SenderFeature}, unlock_condition::AddressUnlockCondition, @@ -41,6 +42,7 @@ async fn main() -> Result<()> { // Get the wallet we generated with `create_wallet`. let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/nfts/send_nft.rs b/sdk/examples/how_tos/nfts/send_nft.rs index 603b0e7b7b..7ee8d2a918 100644 --- a/sdk/examples/how_tos/nfts/send_nft.rs +++ b/sdk/examples/how_tos/nfts/send_nft.rs @@ -12,6 +12,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, wallet::{Result, SendNftParams}, Wallet, }; @@ -30,6 +31,7 @@ async fn main() -> Result<()> { // Create the wallet let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/sign_and_verify_ed25519/sign_ed25519.rs b/sdk/examples/how_tos/sign_and_verify_ed25519/sign_ed25519.rs index 3a9b80bff6..ddd672fef0 100644 --- a/sdk/examples/how_tos/sign_and_verify_ed25519/sign_ed25519.rs +++ b/sdk/examples/how_tos/sign_and_verify_ed25519/sign_ed25519.rs @@ -13,9 +13,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, hex_public_key_to_bech32_address, - secret::{stronghold::StrongholdSecretManager, SecretManage, SecretManager}, + secret::{stronghold::StrongholdSecretManager, SecretManageExt}, }, crypto::keys::bip39::Mnemonic, + types::block::signature::Ed25519Signature, wallet::Result, }; @@ -48,9 +49,7 @@ async fn main() -> Result<()> { .with_address_index(ADDRESS_INDEX); let message = FOUNDRY_METADATA.as_bytes(); - let signature = SecretManager::Stronghold(stronghold) - .sign_ed25519(message, bip44_chain) - .await?; + let signature = stronghold.sign::(message, &bip44_chain).await?; println!( "Public key: {}\nSignature: {}", prefix_hex::encode(signature.public_key_bytes().as_ref()), diff --git a/sdk/examples/how_tos/simple_transaction/request_funds.rs b/sdk/examples/how_tos/simple_transaction/request_funds.rs index d14c2820f3..1c987cbc71 100644 --- a/sdk/examples/how_tos/simple_transaction/request_funds.rs +++ b/sdk/examples/how_tos/simple_transaction/request_funds.rs @@ -11,7 +11,11 @@ //! cargo run --release --all-features --example request_funds //! ``` -use iota_sdk::{client::request_funds_from_faucet, wallet::Result, Wallet}; +use iota_sdk::{ + client::{request_funds_from_faucet, secret::SecretManager}, + wallet::Result, + Wallet, +}; #[tokio::main] async fn main() -> Result<()> { @@ -23,6 +27,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/simple_transaction/simple_transaction.rs b/sdk/examples/how_tos/simple_transaction/simple_transaction.rs index 6d98120daa..512bc91191 100644 --- a/sdk/examples/how_tos/simple_transaction/simple_transaction.rs +++ b/sdk/examples/how_tos/simple_transaction/simple_transaction.rs @@ -11,7 +11,7 @@ //! cargo run --release --all-features --example simple_transaction //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; // The base coin amount to send const SEND_AMOUNT: u64 = 1_000_000; @@ -28,6 +28,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/wallet/check_balance.rs b/sdk/examples/how_tos/wallet/check_balance.rs index 419dfcf07e..a4e1ba9a3a 100644 --- a/sdk/examples/how_tos/wallet/check_balance.rs +++ b/sdk/examples/how_tos/wallet/check_balance.rs @@ -11,7 +11,7 @@ //! cargo run --release --all-features --example check_balance //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -23,6 +23,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/wallet/consolidate_outputs.rs b/sdk/examples/how_tos/wallet/consolidate_outputs.rs index 69e4526dfd..959fe4670b 100644 --- a/sdk/examples/how_tos/wallet/consolidate_outputs.rs +++ b/sdk/examples/how_tos/wallet/consolidate_outputs.rs @@ -13,6 +13,8 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, + types::block::address::ToBech32Ext, wallet::{ConsolidationParams, Result}, Wallet, }; @@ -29,6 +31,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/wallet/create_wallet.rs b/sdk/examples/how_tos/wallet/create_wallet.rs index 8d9acb5a92..6ed2bdedd9 100644 --- a/sdk/examples/how_tos/wallet/create_wallet.rs +++ b/sdk/examples/how_tos/wallet/create_wallet.rs @@ -13,10 +13,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, WalletBuilder}, }; #[tokio::main] @@ -48,11 +48,12 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; // Create the wallet - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/how_tos/wallet/list_outputs.rs b/sdk/examples/how_tos/wallet/list_outputs.rs index fc5a77bde9..96074f1309 100644 --- a/sdk/examples/how_tos/wallet/list_outputs.rs +++ b/sdk/examples/how_tos/wallet/list_outputs.rs @@ -8,7 +8,7 @@ //! cargo run --release --all-features --example list_outputs //! ``` -use iota_sdk::{wallet::Result, Wallet}; +use iota_sdk::{client::secret::SecretManager, wallet::Result, Wallet}; #[tokio::main] async fn main() -> Result<()> { @@ -20,6 +20,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/how_tos/wallet/list_transactions.rs b/sdk/examples/how_tos/wallet/list_transactions.rs index fea3b5685c..398095edc9 100644 --- a/sdk/examples/how_tos/wallet/list_transactions.rs +++ b/sdk/examples/how_tos/wallet/list_transactions.rs @@ -9,6 +9,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, wallet::{Result, SyncOptions}, Wallet, }; @@ -23,6 +24,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/17_check_unlock_conditions.rs b/sdk/examples/wallet/17_check_unlock_conditions.rs index acaf1fe265..6fd6ebae75 100644 --- a/sdk/examples/wallet/17_check_unlock_conditions.rs +++ b/sdk/examples/wallet/17_check_unlock_conditions.rs @@ -11,6 +11,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, UnlockCondition}, wallet::Result, Wallet, @@ -29,6 +30,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/background_syncing.rs b/sdk/examples/wallet/background_syncing.rs index ea2505a758..d993adc40c 100644 --- a/sdk/examples/wallet/background_syncing.rs +++ b/sdk/examples/wallet/background_syncing.rs @@ -10,12 +10,12 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, + constants::IOTA_COIN_TYPE, request_funds_from_faucet, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -30,11 +30,12 @@ async fn main() -> Result<()> { // Create a wallet let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/events.rs b/sdk/examples/wallet/events.rs index 1d9b02a9bb..f374f95ae9 100644 --- a/sdk/examples/wallet/events.rs +++ b/sdk/examples/wallet/events.rs @@ -11,15 +11,15 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, types::block::{ address::Address, output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder}, }, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; // The amount of base coins we'll send @@ -40,11 +40,12 @@ async fn main() -> Result<()> { let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/getting_started.rs b/sdk/examples/wallet/getting_started.rs index 72d7aa4250..1d06aa0a5d 100644 --- a/sdk/examples/wallet/getting_started.rs +++ b/sdk/examples/wallet/getting_started.rs @@ -10,11 +10,11 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -35,11 +35,12 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; // Set up and store the wallet. - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) .with_storage_path("getting-started-db") - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .with_alias("Alice".to_string()) .finish() .await?; diff --git a/sdk/examples/wallet/ledger_nano.rs b/sdk/examples/wallet/ledger_nano.rs index d693503442..4848b44047 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -16,11 +16,15 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{ledger_nano::LedgerSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{ + ledger_nano::{LedgerOptions, LedgerSecretManager}, + PublicKeyOptions, SecretManageExt, + }, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + types::block::address::{Ed25519Address, ToBech32Ext}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; // The address to send coins to @@ -38,23 +42,28 @@ async fn main() -> Result<()> { } let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let secret_manager = LedgerSecretManager::new(true); - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + let secret_manager = std::sync::Arc::new(LedgerSecretManager::new(true)); + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager.clone()) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await?; - println!("{:?}", wallet.get_ledger_nano_status().await?); + println!("{:?}", secret_manager.get_ledger_nano_status().await); + + let hrp = wallet.client().get_bech32_hrp().await?; println!("Generating address..."); let now = tokio::time::Instant::now(); - let address = wallet.generate_ed25519_address(0, 0, None).await?; + let address = secret_manager + .generate::(&LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) + .await?; println!("took: {:.2?}", now.elapsed()); - println!("ADDRESS:\n{address:#?}"); + println!("ADDRESS:\n{:#?}", address.to_bech32(hrp)); let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index bb944a5808..751115ab6d 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -10,11 +10,12 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + types::block::address::Ed25519Address, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -38,17 +39,22 @@ async fn main() -> Result<()> { // Restore a wallet let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let secret_manager = std::sync::Arc::new(MnemonicSecretManager::try_from_mnemonic( + std::env::var("MNEMONIC").unwrap(), + )?); + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager.clone()) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await?; println!("Generating address..."); - let _ = wallet.generate_ed25519_address(0, 0, None).await?; + secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await?; println!("Syncing wallet"); wallet.sync(None).await?; diff --git a/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs b/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs index 536f12dca7..5336da90e9 100644 --- a/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -7,12 +7,14 @@ //! cargo run --release --all-features --example migrate_stronghold_snapshot_v2_to_v3 //! ``` -use iota_sdk::client::{ - api::GetAddressesOptions, - constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, - secret::{stronghold::StrongholdSecretManager, SecretManager}, - stronghold::StrongholdAdapter, - Result, +use iota_sdk::{ + client::{ + constants::{IOTA_COIN_TYPE, IOTA_TESTNET_BECH32_HRP}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManageExt}, + stronghold::StrongholdAdapter, + Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; const V2_PATH: &str = "./tests/wallet/fixtures/v2.stronghold"; @@ -48,18 +50,13 @@ async fn main() -> Result<()> { .build(V3_PATH)?; // Generate addresses with custom account index and range - let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_account_index(0) - .with_range(0..1), - ) + let address = stronghold_secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) .await - .unwrap(); + .unwrap() + .to_bech32(IOTA_TESTNET_BECH32_HRP); - println!("First public address: {}", addresses[0]); + println!("First public address: {address}"); Ok(()) } diff --git a/sdk/examples/wallet/offline_signing/0_generate_address.rs b/sdk/examples/wallet/offline_signing/0_generate_address.rs index 1c4b65e3fb..15b41d3dda 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -11,10 +11,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManage}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; const OFFLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-offline-walletdb"; @@ -43,11 +43,12 @@ async fn main() -> Result<()> { secret_manager.store_mnemonic(mnemonic).await?; // Create the wallet with the secret_manager and client options - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(OFFLINE_WALLET_DB_PATH) .with_client_options(offline_client) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; @@ -56,7 +57,7 @@ async fn main() -> Result<()> { write_wallet_address_to_file(&wallet).await } -async fn write_wallet_address_to_file(wallet: &Wallet) -> Result<()> { +async fn write_wallet_address_to_file(wallet: &Wallet) -> Result<()> { use tokio::io::AsyncWriteExt; let wallet_address = wallet.address().await; diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index 67738e46eb..4e4c1df263 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -9,9 +9,8 @@ //! ``` use iota_sdk::{ - client::{api::PreparedTransactionDataDto, constants::SHIMMER_COIN_TYPE, secret::SecretManager}, - crypto::keys::bip44::Bip44, - wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet}, + client::api::PreparedTransactionDataDto, + wallet::{types::Bip44Address, ClientOptions, Result, SendParams, WalletBuilder}, }; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; @@ -39,12 +38,10 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - // Create the wallet with the secret_manager and client options - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Placeholder) + // Create the wallet with the client options and address + let wallet = WalletBuilder::new() .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) .with_address(address) .finish() .await?; diff --git a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs index 7a5c8d244d..d4a30b24c5 100644 --- a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs +++ b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs @@ -8,15 +8,20 @@ //! cargo run --release --all-features --example 2_sign_transaction //! ``` +use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ api::{ transaction::validate_signed_transaction_payload_length, PreparedTransactionData, SignedTransactionData, SignedTransactionDataDto, }, - secret::{stronghold::StrongholdSecretManager, SecretManage, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{stronghold::StrongholdSecretManager, SignTransaction}, + }, + types::{ + block::{payload::SignedTransactionPayload, protocol::protocol_parameters}, + TryFromDto, }, - types::{block::payload::SignedTransactionPayload, TryFromDto}, wallet::Result, }; @@ -39,6 +44,8 @@ async fn main() -> Result<()> { .password(std::env::var("STRONGHOLD_PASSWORD").unwrap()) .build(STRONGHOLD_SNAPSHOT_PATH)?; + let signing_options = Bip44::new(IOTA_COIN_TYPE); + let prepared_transaction_data = PreparedTransactionData::try_from_dto(serde_json::from_str( &read_data_from_file(PREPARED_TRANSACTION_FILE_PATH).await?, )?)?; @@ -46,8 +53,8 @@ async fn main() -> Result<()> { let protocol_parameters = serde_json::from_str(&read_data_from_file(PROTOCOL_PARAMETERS_FILE_PATH).await?)?; // Signs prepared transaction offline. - let unlocks = SecretManager::Stronghold(secret_manager) - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; let signed_transaction = SignedTransactionPayload::new(prepared_transaction_data.transaction.clone(), unlocks)?; diff --git a/sdk/examples/wallet/participation.rs b/sdk/examples/wallet/participation.rs index d3108c30b6..b0851fb9ba 100644 --- a/sdk/examples/wallet/participation.rs +++ b/sdk/examples/wallet/participation.rs @@ -17,7 +17,7 @@ //! ``` use iota_sdk::{ - client::node_manager::node::Node, + client::{node_manager::node::Node, secret::SecretManager}, wallet::{types::participation::ParticipationEventRegistrationOptions, Result}, Wallet, }; @@ -47,6 +47,7 @@ async fn main() -> Result<()> { } let wallet = Wallet::builder() + .with_secret_type::() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .finish() .await?; diff --git a/sdk/examples/wallet/spammer.rs b/sdk/examples/wallet/spammer.rs index df138b94a7..237a8f64f0 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -10,17 +10,17 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, + constants::IOTA_COIN_TYPE, request_funds_from_faucet, - secret::{mnemonic::MnemonicSecretManager, SecretManage, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage, SecretManageExt}, }, crypto::keys::bip44::Bip44, types::block::{ - address::{Address, Bech32Address, Hrp}, + address::{Bech32Address, Ed25519Address, ToBech32Ext}, output::BasicOutput, payload::signed_transaction::TransactionId, }, - wallet::{ClientOptions, FilterOptions, Result, SendParams, Wallet}, + wallet::{core::SecretData, ClientOptions, FilterOptions, Result, SendParams, Wallet, WalletBuilder}, }; // The number of spamming rounds. @@ -47,20 +47,16 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let bip_path = Bip44::new(SHIMMER_COIN_TYPE); - let address = Bech32Address::new( - Hrp::from_str_unchecked("smr"), - Address::from( - secret_manager - .generate_ed25519_addresses(bip_path.coin_type, bip_path.account, 0..1, None) - .await?[0], - ), - ); + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await? + .to_bech32_unchecked("smr"); - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(bip_path) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .with_address(address) .finish() .await?; @@ -91,7 +87,7 @@ async fn main() -> Result<()> { let transaction = wallet .send_with_params(vec![SendParams::new(SEND_AMOUNT, recv_address.clone())?; 127], None) .await?; - wait_for_inclusion(&transaction.transaction_id, &wallet).await?; + wait_for_inclusion(&wallet, &transaction.transaction_id).await?; wallet.sync(None).await?; } @@ -160,7 +156,10 @@ async fn main() -> Result<()> { Ok(()) } -async fn ensure_enough_funds(wallet: &Wallet, bech32_address: &Bech32Address) -> Result<()> { +async fn ensure_enough_funds( + wallet: &Wallet, + bech32_address: &Bech32Address, +) -> Result<()> { let balance = wallet.sync(None).await?; let available_funds = balance.base_coin().available(); println!("Available funds: {available_funds}"); @@ -201,7 +200,10 @@ async fn ensure_enough_funds(wallet: &Wallet, bech32_address: &Bech32Address) -> } } -async fn wait_for_inclusion(transaction_id: &TransactionId, wallet: &Wallet) -> Result<()> { +async fn wait_for_inclusion( + wallet: &Wallet>, + transaction_id: &TransactionId, +) -> Result<()> { println!( "Transaction sent: {}/transaction/{}", std::env::var("EXPLORER_URL").unwrap(), diff --git a/sdk/examples/wallet/storage.rs b/sdk/examples/wallet/storage.rs index c901a155e3..a3be298e2e 100644 --- a/sdk/examples/wallet/storage.rs +++ b/sdk/examples/wallet/storage.rs @@ -10,11 +10,11 @@ use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -30,11 +30,12 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let wallet = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await?; @@ -48,7 +49,7 @@ async fn main() -> Result<()> { Ok(()) } -async fn sync_print_balance(wallet: &Wallet) -> Result<()> { +async fn sync_print_balance(wallet: &Wallet) -> Result<()> { let alias = wallet.alias().await; let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; diff --git a/sdk/examples/wallet/wallet.rs b/sdk/examples/wallet/wallet.rs index 86db26f320..378a217bbf 100644 --- a/sdk/examples/wallet/wallet.rs +++ b/sdk/examples/wallet/wallet.rs @@ -17,11 +17,11 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + constants::IOTA_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, }, types::block::payload::signed_transaction::TransactionId, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::SecretData, ClientOptions, Result, Wallet, WalletBuilder}, }; // The amount of coins to send @@ -45,7 +45,7 @@ async fn main() -> Result<()> { println!("Sending '{}' coins to '{}'...", SEND_AMOUNT, RECV_ADDRESS); let transaction = wallet.send(SEND_AMOUNT, RECV_ADDRESS, None).await?; - wait_for_inclusion(&transaction.transaction_id, &wallet).await?; + wait_for_inclusion(&wallet, &transaction.transaction_id).await?; sync_print_balance(&wallet, false).await?; @@ -53,24 +53,20 @@ async fn main() -> Result<()> { Ok(()) } -async fn create_wallet() -> Result { +async fn create_wallet() -> Result>> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + WalletBuilder::new() + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await } -async fn print_address(wallet: &Wallet) -> Result<()> { - println!("Wallet address: {}", wallet.address().await); - Ok(()) -} - -async fn sync_print_balance(wallet: &Wallet, full_report: bool) -> Result<()> { +async fn sync_print_balance(wallet: &Wallet, full_report: bool) -> Result<()> { let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; println!("Wallet synced in: {:.2?}", now.elapsed()); @@ -82,7 +78,10 @@ async fn sync_print_balance(wallet: &Wallet, full_report: bool) -> Result<()> { Ok(()) } -async fn wait_for_inclusion(transaction_id: &TransactionId, wallet: &Wallet) -> Result<()> { +async fn wait_for_inclusion( + wallet: &Wallet>, + transaction_id: &TransactionId, +) -> Result<()> { println!( "Transaction sent: {}/transaction/{}", std::env::var("EXPLORER_URL").unwrap(), diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs deleted file mode 100644 index 6d5501d4d7..0000000000 --- a/sdk/src/client/api/address.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2021 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use std::ops::Range; - -use serde::{Deserialize, Serialize}; - -use super::ADDRESS_GAP_RANGE; -use crate::{ - client::{ - constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, - secret::{GenerateAddressOptions, SecretManage, SecretManager}, - Client, Result, - }, - types::block::address::{Address, Bech32Address, Hrp, ToBech32Ext}, - utils::ConvertTo, -}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(default)] -pub struct GetAddressesOptions { - /// Coin type - pub coin_type: u32, - /// Account index - pub account_index: u32, - /// Range - pub range: Range, - /// Bech32 human readable part - pub bech32_hrp: Hrp, - /// Options - pub options: Option, -} - -impl GetAddressesOptions { - pub async fn from_client(client: &Client) -> Result { - Ok(Self::default().with_bech32_hrp(client.get_bech32_hrp().await?)) - } - - /// Set the coin type - pub fn with_coin_type(mut self, coin_type: u32) -> Self { - self.coin_type = coin_type; - self - } - - /// Set the account index - pub fn with_account_index(mut self, account_index: u32) -> Self { - self.account_index = account_index; - self - } - - /// Set range to the builder - pub fn with_range(mut self, range: Range) -> Self { - self.range = range; - self - } - - /// Set bech32 human readable part (hrp) - pub fn with_bech32_hrp(mut self, bech32_hrp: Hrp) -> Self { - self.bech32_hrp = bech32_hrp; - self - } - - /// Set bech32 human readable part (hrp) from something that might be valid - pub fn try_with_bech32_hrp(mut self, bech32_hrp: impl ConvertTo) -> Result { - self.bech32_hrp = bech32_hrp.convert()?; - Ok(self) - } - - pub fn internal(mut self) -> Self { - match &mut self.options { - Some(o) => { - o.internal = true; - self - } - None => self.with_options(GenerateAddressOptions::internal()), - } - } - - /// Set the metadata for the address generation (used for ledger to display addresses or not) - pub fn with_options(mut self, options: impl Into>) -> Self { - self.options = options.into(); - self - } -} - -impl Default for GetAddressesOptions { - fn default() -> Self { - Self { - coin_type: SHIMMER_COIN_TYPE, - account_index: 0, - range: 0..ADDRESS_GAP_RANGE, - bech32_hrp: SHIMMER_TESTNET_BECH32_HRP, - options: Default::default(), - } - } -} - -impl SecretManager { - /// Get a vector of public bech32 addresses - pub async fn generate_ed25519_addresses( - &self, - GetAddressesOptions { - coin_type, - account_index, - range, - bech32_hrp, - options, - }: GetAddressesOptions, - ) -> Result> { - Ok( - SecretManage::generate_ed25519_addresses(self, coin_type, account_index, range, options) - .await? - .into_iter() - .map(|a| a.to_bech32(bech32_hrp)) - .collect(), - ) - } - - /// Get a vector of EVM address strings - pub async fn generate_evm_addresses( - &self, - GetAddressesOptions { - coin_type, - account_index, - range, - options, - .. - }: GetAddressesOptions, - ) -> Result> { - Ok( - SecretManage::generate_evm_addresses(self, coin_type, account_index, range, options) - .await? - .into_iter() - .map(|a| prefix_hex::encode(a.as_ref())) - .collect(), - ) - } -} - -/// Function to find the index and public (false) or internal (true) type of an Bech32 encoded address -pub async fn search_address( - secret_manager: &SecretManager, - bech32_hrp: Hrp, - coin_type: u32, - account_index: u32, - range: Range, - address: &Address, -) -> Result<(u32, bool)> { - let opts = GetAddressesOptions::default() - .with_coin_type(coin_type) - .with_account_index(account_index) - .with_range(range.clone()); - let public = secret_manager.generate_ed25519_addresses(opts.clone()).await?; - let internal = secret_manager.generate_ed25519_addresses(opts.internal()).await?; - for index in 0..public.len() { - if public[index].inner == *address { - return Ok((range.start + index as u32, false)); - } - if internal[index].inner == *address { - return Ok((range.start + index as u32, true)); - } - } - Err(crate::client::Error::InputAddressNotFound { - address: address.clone().to_bech32(bech32_hrp).to_string(), - range: format!("{range:?}"), - }) -} diff --git a/sdk/src/client/api/block_builder/input_selection/remainder.rs b/sdk/src/client/api/block_builder/input_selection/remainder.rs index 119dcd3171..3ae4ad9f0a 100644 --- a/sdk/src/client/api/block_builder/input_selection/remainder.rs +++ b/sdk/src/client/api/block_builder/input_selection/remainder.rs @@ -1,8 +1,6 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; - use super::{ requirement::native_tokens::{get_minted_and_melted_native_tokens, get_native_tokens, get_native_tokens_diff}, Error, InputSelection, @@ -21,7 +19,7 @@ use crate::{ impl InputSelection { // Gets the remainder address from configuration of finds one from the inputs. - fn get_remainder_address(&self) -> Result)>, Error> { + fn get_remainder_address(&self) -> Result, Error> { if let Some(remainder_address) = &self.remainder_address { // Search in inputs for the Bip44 chain for the remainder address, so the ledger can regenerate it for input in self.available_inputs.iter().chain(self.selected_inputs.iter()) { @@ -31,10 +29,10 @@ impl InputSelection { .expect("expiration unlockable outputs already filtered out"); if &required_address == remainder_address { - return Ok(Some((remainder_address.clone(), input.chain))); + return Ok(Some(remainder_address.clone())); } } - return Ok(Some((remainder_address.clone(), None))); + return Ok(Some(remainder_address.clone())); } for input in &self.selected_inputs { @@ -44,7 +42,7 @@ impl InputSelection { .expect("expiration unlockable outputs already filtered out"); if required_address.is_ed25519_backed() { - return Ok(Some((required_address, input.chain))); + return Ok(Some(required_address)); } } @@ -152,7 +150,7 @@ impl InputSelection { } } - let Some((remainder_address, chain)) = self.get_remainder_address()? else { + let Some(remainder_address) = self.get_remainder_address()? else { return Err(Error::MissingInputWithEd25519Address); }; @@ -161,7 +159,6 @@ impl InputSelection { mana_diff, native_tokens_diff, remainder_address, - chain, self.protocol_parameters.storage_score_parameters(), )?; @@ -201,7 +198,6 @@ fn create_remainder_outputs( mana_diff: u64, native_tokens_diff: Option, remainder_address: Address, - remainder_address_chain: Option, storage_score_parameters: StorageScoreParameters, ) -> Result, Error> { let mut remainder_outputs = Vec::new(); @@ -249,7 +245,6 @@ fn create_remainder_outputs( .into_iter() .map(|o| RemainderData { output: o, - chain: remainder_address_chain, address: remainder_address.clone(), }) .collect()) diff --git a/sdk/src/client/api/mod.rs b/sdk/src/client/api/mod.rs index 45d2073fea..f9d939db8b 100644 --- a/sdk/src/client/api/mod.rs +++ b/sdk/src/client/api/mod.rs @@ -3,11 +3,8 @@ //! High level APIs -mod address; mod block_builder; mod high_level; mod types; -pub use self::{address::*, block_builder::*, types::*}; - -const ADDRESS_GAP_RANGE: u32 = 20; +pub use self::{block_builder::*, types::*}; diff --git a/sdk/src/client/api/types.rs b/sdk/src/client/api/types.rs index 08598b0a44..943b6ba5df 100644 --- a/sdk/src/client/api/types.rs +++ b/sdk/src/client/api/types.rs @@ -3,7 +3,6 @@ use alloc::collections::BTreeMap; -use crypto::keys::bip44::Bip44; use serde::{Deserialize, Serialize}; use crate::{ @@ -24,7 +23,7 @@ use crate::{ }, TryFromDto, }, - utils::serde::{bip44::option_bip44, mana_rewards}, + utils::serde::mana_rewards, }; /// Helper struct for offline signing @@ -148,9 +147,6 @@ impl TryFromDto for SignedTransactionData { pub struct RemainderData { /// The remainder output pub output: Output, - /// The chain derived from seed, for the remainder addresses - #[serde(with = "option_bip44", default)] - pub chain: Option, /// The remainder address pub address: Address, } diff --git a/sdk/src/client/error.rs b/sdk/src/client/error.rs index 07826b4c78..dc2f0a2957 100644 --- a/sdk/src/client/error.rs +++ b/sdk/src/client/error.rs @@ -146,9 +146,9 @@ pub enum Error { /// Input selection error. #[error("{0}")] InputSelection(#[from] InputSelectionError), - /// Missing BIP32 chain to sign with. - #[error("missing BIP32 chain to sign with")] - MissingBip32Chain, + /// Missing options for signing. + #[error("missing options for signing")] + MissingSigningOptions, /// Unexpected block body kind. #[error("unexpected block body kind: expected {expected}, found {actual}")] UnexpectedBlockBodyKind { expected: u8, actual: u8 }, diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index 07f9f6a754..ff9649ddc2 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -5,33 +5,30 @@ //! //! Ledger status codes: . -use std::{collections::HashMap, ops::Range}; +use std::collections::HashMap; use async_trait::async_trait; use crypto::{ keys::{bip44::Bip44, slip10::Segment}, - signatures::{ - ed25519, - secp256k1_ecdsa::{self, EvmAddress}, - }, + signatures::ed25519, }; use iota_ledger_nano::{ api::errors::APIError, get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index, Packable as LedgerNanoPackable, TransportTypes, }; use packable::{error::UnexpectedEOF, unpacker::SliceUnpacker, Packable, PackableExt}; +use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; -use super::{GenerateAddressOptions, SecretManage, SecretManagerConfig}; use crate::{ client::secret::{ types::{LedgerApp, LedgerDeviceType}, - LedgerNanoStatus, PreparedTransactionData, + Generate, LedgerNanoStatus, MultiKeyOptions, PreparedTransactionData, PublicKeyOptions, SecretManagerConfig, + Sign, SignTransaction, }, types::block::{ - address::{AccountAddress, Address, NftAddress}, + address::{AccountAddress, Address, Ed25519Address, NftAddress}, output::Output, - payload::signed_transaction::SignedTransactionPayload, protocol::ProtocolParameters, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, @@ -39,6 +36,29 @@ use crate::{ }, }; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct LedgerOptions { + pub options: O, + ledger_nano_prompt: bool, +} + +impl LedgerOptions { + /// Create a new ledger options + pub fn new(options: O) -> Self { + Self { + options, + ledger_nano_prompt: false, + } + } + + /// Set ledger_nano_prompt flag. + pub fn with_ledger_nano_prompt(mut self, ledger_nano_prompt: bool) -> Self { + self.ledger_nano_prompt = ledger_nano_prompt; + self + } +} + /// Ledger nano errors. #[derive(Debug, thiserror::Error)] #[non_exhaustive] @@ -135,23 +155,18 @@ impl TryFrom for LedgerDeviceType { } #[async_trait] -impl SecretManage for LedgerSecretManager { - type Error = crate::client::Error; +impl Generate for LedgerSecretManager { + type Options = LedgerOptions; - async fn generate_ed25519_public_keys( - &self, - // https://github.com/satoshilabs/slips/blob/master/slip-0044.md - // current ledger app only supports IOTA_COIN_TYPE, SHIMMER_COIN_TYPE and TESTNET_COIN_TYPE - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - let options = options.into().unwrap_or_default(); - let bip32_account = account_index.harden().into(); + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let LedgerOptions { + options, + ledger_nano_prompt, + } = options; + let bip32_account = options.account_index.harden().into(); let bip32 = LedgerBIP32Index { - bip32_index: address_indexes.start.harden().into(), + bip32_index: options.address_index.harden().into(), bip32_change: u32::from(options.internal).harden().into(), }; @@ -159,7 +174,56 @@ impl SecretManage for LedgerSecretManager { let lock = self.mutex.lock().await; // get ledger - let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; + let ledger = get_ledger(options.coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; + if ledger.is_debug_app() { + ledger + .set_non_interactive_mode(self.non_interactive) + .map_err(Error::from)?; + } + + let public_key = ed25519::PublicKey::try_from_bytes( + ledger + .get_public_keys(*ledger_nano_prompt, bip32, 0) + .map_err(Error::from)?[0], + )?; + + drop(lock); + + Ok(public_key) + } +} + +#[async_trait] +impl Generate for LedgerSecretManager { + type Options = LedgerOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) + } +} + +#[async_trait] +impl Generate> for LedgerSecretManager { + type Options = LedgerOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let LedgerOptions { + options, + ledger_nano_prompt, + } = options; + let bip32_account = options.account_index.harden().into(); + + let bip32 = LedgerBIP32Index { + bip32_index: options.address_range.start.harden().into(), + bip32_change: u32::from(options.internal).harden().into(), + }; + + // lock the mutex to prevent multiple simultaneous requests to a ledger + let lock = self.mutex.lock().await; + + // get ledger + let ledger = get_ledger(options.coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; if ledger.is_debug_app() { ledger .set_non_interactive_mode(self.non_interactive) @@ -167,40 +231,47 @@ impl SecretManage for LedgerSecretManager { } let public_keys = ledger - .get_public_keys(options.ledger_nano_prompt, bip32, address_indexes.len()) - .map_err(Error::from)?; + .get_addresses(*ledger_nano_prompt, bip32, options.address_range.len()) + .map_err(Error::from)? + .into_iter() + .map(|b| ed25519::PublicKey::try_from_bytes(b)) + .collect::, _>>()?; drop(lock); + Ok(public_keys) + } +} + +#[async_trait] +impl Generate> for LedgerSecretManager { + type Options = LedgerOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; Ok(public_keys .into_iter() - .map(ed25519::PublicKey::try_from_bytes) - .collect::, _>>()?) + .map(|k| Ed25519Address::from_public_key_bytes(k.to_bytes())) + .collect()) } +} - async fn generate_evm_addresses( - &self, - _coin_type: u32, - _account_index: u32, - _address_indexes: Range, - _options: impl Into> + Send, - ) -> Result, Self::Error> { - Err(Error::UnsupportedOperation.into()) - } +#[async_trait] +impl Sign for LedgerSecretManager { + type Options = Bip44; - /// Ledger only allows signing messages of 32 bytes, anything else is unsupported and will result in an error. - async fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> Result { + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result { if msg.len() != 32 { return Err(Error::UnsupportedOperation.into()); } let msg = msg.to_vec(); - let coin_type = chain.coin_type; - let account_index = chain.account.harden().into(); + let coin_type = options.coin_type; + let account_index = options.account.harden().into(); let bip32_index = LedgerBIP32Index { - bip32_change: chain.change.harden().into(), - bip32_index: chain.address_index.harden().into(), + bip32_change: options.change.harden().into(), + bip32_index: options.address_index.harden().into(), }; // Lock the mutex to prevent multiple simultaneous requests to a ledger. @@ -239,29 +310,23 @@ impl SecretManage for LedgerSecretManager { _ => Err(Error::UnsupportedOperation.into()), }; } +} - async fn sign_secp256k1_ecdsa( - &self, - _msg: &[u8], - _chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> { - Err(Error::UnsupportedOperation.into()) - } - +#[async_trait] +impl SignTransaction for LedgerSecretManager { async fn transaction_unlocks( &self, prepared_transaction: &PreparedTransactionData, protocol_parameters: &ProtocolParameters, - ) -> Result::Error> { + chain: &Self::Options, + ) -> crate::client::Result { let mut input_bip32_indices = Vec::new(); let mut coin_type = None; let mut account_index = None; let input_len = prepared_transaction.inputs_data.len(); - for input in &prepared_transaction.inputs_data { - let chain = input.chain.ok_or(Error::MissingBip32Chain)?; - + for _input in &prepared_transaction.inputs_data { // coin_type and account_index should be the same in each output if (coin_type.is_some() && coin_type != Some(chain.coin_type)) || (account_index.is_some() && account_index != Some(chain.account)) @@ -310,19 +375,13 @@ impl SecretManage for LedgerSecretManager { let (remainder_output, remainder_bip32) = match &prepared_transaction.remainders.as_slice() { // Multiple remainder outputs would require blind signing since at least one would contain a native // token, that's why matching a single one is enough. - [remainder] => { - if let Some(chain) = remainder.chain { - ( - Some(&remainder.output), - LedgerBIP32Index { - bip32_change: chain.change.harden().into(), - bip32_index: chain.address_index.harden().into(), - }, - ) - } else { - (None, LedgerBIP32Index::default()) - } - } + [remainder] => ( + Some(&remainder.output), + LedgerBIP32Index { + bip32_change: chain.change.harden().into(), + bip32_index: chain.address_index.harden().into(), + }, + ), _ => (None, LedgerBIP32Index::default()), }; @@ -413,14 +472,6 @@ impl SecretManage for LedgerSecretManager { Ok(Unlocks::new(unlocks)?) } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data, protocol_parameters).await - } } impl SecretManagerConfig for LedgerSecretManager { @@ -430,7 +481,7 @@ impl SecretManagerConfig for LedgerSecretManager { Some(self.is_simulator) } - fn from_config(config: &Self::Config) -> Result { + fn from_config(config: &Self::Config) -> crate::client::Result { Ok(Self::new(*config)) } } @@ -614,10 +665,7 @@ mod tests { use pretty_assertions::assert_eq; use super::*; - use crate::{ - client::{api::GetAddressesOptions, constants::IOTA_COIN_TYPE, secret::SecretManager}, - types::block::address::ToBech32Ext, - }; + use crate::{client::constants::IOTA_COIN_TYPE, types::block::address::ToBech32Ext}; #[tokio::test] #[ignore = "requires ledger nano instance"] @@ -625,18 +673,15 @@ mod tests { let mut secret_manager = LedgerSecretManager::new(true); secret_manager.non_interactive = true; - let addresses = SecretManager::LedgerNano(secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(IOTA_COIN_TYPE) - .with_account_index(0) - .with_range(0..1), - ) - .await - .unwrap(); + let address = Generate::::generate( + &secret_manager, + &LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE)), + ) + .await + .unwrap(); assert_eq!( - addresses[0].clone().to_bech32_unchecked("atoi").to_string(), + address.to_bech32_unchecked("atoi").to_string(), "atoi1qqdnv60ryxynaeyu8paq3lp9rkll7d7d92vpumz88fdj4l0pn5mru50gvd8" ); } diff --git a/sdk/src/client/secret/manager.rs b/sdk/src/client/secret/manager.rs new file mode 100644 index 0000000000..01caf6ce73 --- /dev/null +++ b/sdk/src/client/secret/manager.rs @@ -0,0 +1,469 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use core::str::FromStr; + +use async_trait::async_trait; +use crypto::{ + keys::bip39::Mnemonic, + signatures::{ + ed25519, + secp256k1_ecdsa::{self, EvmAddress}, + }, +}; +use serde::{Deserialize, Serialize}; +use zeroize::Zeroizing; + +#[cfg(feature = "ledger_nano")] +use crate::client::secret::ledger_nano::{self, LedgerSecretManager}; +#[cfg(feature = "private_key_secret_manager")] +use crate::client::secret::private_key::PrivateKeySecretManager; +#[cfg(feature = "stronghold")] +use crate::client::secret::{stronghold::StrongholdSecretManager, types::StrongholdDto}; +use crate::{ + client::{ + secret::{ + mnemonic::MnemonicSecretManager, types::EvmSignature, Generate, SecretManagerConfig, Sign, SignTransaction, + }, + Error, + }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, +}; + +/// Supported secret managers +#[non_exhaustive] +pub enum SecretManager { + /// Secret manager that uses [`iota_stronghold`] as the backing storage. + #[cfg(feature = "stronghold")] + #[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))] + Stronghold(StrongholdSecretManager), + + /// Secret manager that uses a Ledger Nano hardware wallet or Speculos simulator. + #[cfg(feature = "ledger_nano")] + #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] + LedgerNano(LedgerSecretManager), + + /// Secret manager that uses a mnemonic in plain memory. It's not recommended for production use. Use + /// LedgerNano or Stronghold instead. + Mnemonic(MnemonicSecretManager), + + /// Secret manager that uses a single private key. + #[cfg(feature = "private_key_secret_manager")] + #[cfg_attr(docsrs, doc(cfg(feature = "private_key_secret_manager")))] + PrivateKey(Box), + + /// Secret manager that's just a placeholder, so it can be provided to an online wallet, but can't be used for + /// signing. + Placeholder, +} + +#[async_trait] +impl Generate for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = >::Options::deserialize(options)?; + Ok(s.generate(&options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(l) => { + let options = >::Options::deserialize(options)?; + Ok(l.generate(&options).await?) + } + SecretManager::Mnemonic(m) => { + let options = >::Options::deserialize(options)?; + Ok(m.generate(&options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(p) => Ok(p.generate(&()).await?), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +#[async_trait] +impl Generate for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) + } +} + +#[async_trait] +impl Generate> for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = + >>::Options::deserialize(options)?; + Ok(s.generate(&options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(l) => { + let options = + >>::Options::deserialize(options)?; + Ok(l.generate(&options).await?) + } + SecretManager::Mnemonic(m) => { + let options = + >>::Options::deserialize(options)?; + Ok(m.generate(&options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(_) => todo!(), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +#[async_trait] +impl Generate> for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys + .into_iter() + .map(|k| Ed25519Address::from_public_key_bytes(k.to_bytes())) + .collect()) + } +} + +#[async_trait] +impl Generate for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = + >::Options::deserialize(options)?; + Ok(s.generate(&options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(_) => Err(ledger_nano::Error::UnsupportedOperation.into()), + SecretManager::Mnemonic(m) => { + let options = + >::Options::deserialize(options)?; + Ok(m.generate(&options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(_) => todo!(), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +#[async_trait] +impl Generate for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: secp256k1_ecdsa::PublicKey = self.generate(options).await?; + Ok(public_key.evm_address()) + } +} + +#[async_trait] +impl Generate> for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = + >>::Options::deserialize( + options, + )?; + Ok(s.generate(&options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(_) => Err(ledger_nano::Error::UnsupportedOperation.into()), + SecretManager::Mnemonic(m) => { + let options = + >>::Options::deserialize( + options, + )?; + Ok(m.generate(&options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(_) => todo!(), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +#[async_trait] +impl Generate> for SecretManager { + type Options = serde_json::Value; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys.into_iter().map(|k| k.evm_address()).collect()) + } +} + +#[async_trait] +impl Sign for SecretManager { + type Options = serde_json::Value; + + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = >::Options::deserialize(options)?; + Ok(s.sign(msg, &options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(l) => { + let options = >::Options::deserialize(options)?; + Ok(l.sign(msg, &options).await?) + } + SecretManager::Mnemonic(m) => { + let options = >::Options::deserialize(options)?; + Ok(m.sign(msg, &options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(p) => Ok(p.sign(msg, &()).await?), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +#[async_trait] +impl Sign for SecretManager { + type Options = serde_json::Value; + + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result { + match self { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(s) => { + let options = >::Options::deserialize(options)?; + Ok(s.sign(msg, &options).await?) + } + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(_) => Err(ledger_nano::Error::UnsupportedOperation.into()), + SecretManager::Mnemonic(m) => { + let options = >::Options::deserialize(options)?; + Ok(m.sign(msg, &options).await?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(_) => todo!(), + SecretManager::Placeholder => Err(Error::PlaceholderSecretManager), + } + } +} + +impl SignTransaction for SecretManager {} + +#[cfg(feature = "stronghold")] +impl From for SecretManager { + fn from(secret_manager: StrongholdSecretManager) -> Self { + Self::Stronghold(secret_manager) + } +} + +#[cfg(feature = "ledger_nano")] +impl From for SecretManager { + fn from(secret_manager: LedgerSecretManager) -> Self { + Self::LedgerNano(secret_manager) + } +} + +impl From for SecretManager { + fn from(secret_manager: MnemonicSecretManager) -> Self { + Self::Mnemonic(secret_manager) + } +} + +#[cfg(feature = "private_key_secret_manager")] +impl From for SecretManager { + fn from(secret_manager: PrivateKeySecretManager) -> Self { + Self::PrivateKey(Box::new(secret_manager)) + } +} + +impl core::fmt::Debug for SecretManager { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(feature = "stronghold")] + Self::Stronghold(_) => f.debug_tuple("Stronghold").field(&"...").finish(), + #[cfg(feature = "ledger_nano")] + Self::LedgerNano(_) => f.debug_tuple("LedgerNano").field(&"...").finish(), + Self::Mnemonic(_) => f.debug_tuple("Mnemonic").field(&"...").finish(), + #[cfg(feature = "private_key_secret_manager")] + Self::PrivateKey(_) => f.debug_tuple("PrivateKey").field(&"...").finish(), + Self::Placeholder => f.debug_struct("Placeholder").finish(), + } + } +} + +impl FromStr for SecretManager { + type Err = Error; + + fn from_str(s: &str) -> crate::client::Result { + Self::try_from(serde_json::from_str::(s)?) + } +} + +/// DTO for secret manager types with required data. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum SecretManagerDto { + /// Stronghold + #[cfg(feature = "stronghold")] + #[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))] + #[serde(alias = "stronghold")] + Stronghold(StrongholdDto), + /// Ledger Device, bool specifies if it's a simulator or not + #[cfg(feature = "ledger_nano")] + #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] + #[serde(alias = "ledgerNano")] + LedgerNano(bool), + /// Mnemonic + #[serde(alias = "mnemonic")] + Mnemonic(Zeroizing), + /// Private Key + #[cfg(feature = "private_key_secret_manager")] + #[cfg_attr(docsrs, doc(cfg(feature = "private_key_secret_manager")))] + #[serde(alias = "privateKey")] + PrivateKey(Zeroizing), + /// Hex seed + #[serde(alias = "hexSeed")] + HexSeed(Zeroizing), + /// Placeholder + #[serde(alias = "placeholder")] + Placeholder, +} + +impl TryFrom for SecretManager { + type Error = Error; + + fn try_from(value: SecretManagerDto) -> crate::client::Result { + Ok(match value { + #[cfg(feature = "stronghold")] + SecretManagerDto::Stronghold(stronghold_dto) => { + let mut builder = StrongholdSecretManager::builder(); + + if let Some(password) = stronghold_dto.password { + builder = builder.password(password); + } + + if let Some(timeout) = stronghold_dto.timeout { + builder = builder.timeout(core::time::Duration::from_secs(timeout)); + } + + Self::Stronghold(builder.build(&stronghold_dto.snapshot_path)?) + } + + #[cfg(feature = "ledger_nano")] + SecretManagerDto::LedgerNano(is_simulator) => Self::LedgerNano(LedgerSecretManager::new(is_simulator)), + + SecretManagerDto::Mnemonic(mnemonic) => { + Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.as_str().to_owned())?) + } + + #[cfg(feature = "private_key_secret_manager")] + SecretManagerDto::PrivateKey(private_key) => { + Self::PrivateKey(Box::new(PrivateKeySecretManager::try_from_hex(private_key)?)) + } + + SecretManagerDto::HexSeed(hex_seed) => { + // `SecretManagerDto` is `ZeroizeOnDrop` so it will take care of zeroizing the original. + Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(hex_seed)?) + } + + SecretManagerDto::Placeholder => Self::Placeholder, + }) + } +} + +impl From<&SecretManager> for SecretManagerDto { + fn from(value: &SecretManager) -> Self { + match value { + #[cfg(feature = "stronghold")] + SecretManager::Stronghold(stronghold_adapter) => Self::Stronghold(StrongholdDto { + password: None, + timeout: stronghold_adapter.get_timeout().map(|duration| duration.as_secs()), + snapshot_path: stronghold_adapter + .snapshot_path + .clone() + .into_os_string() + .to_string_lossy() + .into(), + }), + + #[cfg(feature = "ledger_nano")] + SecretManager::LedgerNano(ledger_nano) => Self::LedgerNano(ledger_nano.is_simulator), + + // `MnemonicSecretManager(Seed)` doesn't have Debug or Display implemented and in the current use cases of + // the client/wallet we also don't need to convert it in this direction with the mnemonic/seed, we only need + // to know the type + SecretManager::Mnemonic(_mnemonic) => Self::Mnemonic("...".to_string().into()), + + #[cfg(feature = "private_key_secret_manager")] + SecretManager::PrivateKey(_private_key) => Self::PrivateKey("...".to_string().into()), + + SecretManager::Placeholder => Self::Placeholder, + } + } +} + +impl SecretManagerConfig for SecretManager { + type Config = SecretManagerDto; + + fn to_config(&self) -> Option { + match self { + #[cfg(feature = "stronghold")] + Self::Stronghold(s) => s.to_config().map(Self::Config::Stronghold), + #[cfg(feature = "ledger_nano")] + Self::LedgerNano(s) => s.to_config().map(Self::Config::LedgerNano), + Self::Mnemonic(_) => None, + #[cfg(feature = "private_key_secret_manager")] + Self::PrivateKey(_) => None, + Self::Placeholder => None, + } + } + + fn from_config(config: &Self::Config) -> crate::client::Result { + Ok(match config { + #[cfg(feature = "stronghold")] + SecretManagerDto::Stronghold(config) => Self::Stronghold(StrongholdSecretManager::from_config(config)?), + #[cfg(feature = "ledger_nano")] + SecretManagerDto::LedgerNano(config) => Self::LedgerNano(LedgerSecretManager::from_config(config)?), + SecretManagerDto::HexSeed(hex_seed) => { + Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(hex_seed.clone())?) + } + SecretManagerDto::Mnemonic(mnemonic) => { + Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.as_str().to_owned())?) + } + #[cfg(feature = "private_key_secret_manager")] + SecretManagerDto::PrivateKey(private_key) => { + Self::PrivateKey(Box::new(PrivateKeySecretManager::try_from_hex(private_key.to_owned())?)) + } + SecretManagerDto::Placeholder => Self::Placeholder, + }) + } +} + +impl SecretManager { + /// Tries to create a [`SecretManager`] from a mnemonic string. + pub fn try_from_mnemonic(mnemonic: impl Into) -> crate::client::Result { + Ok(Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic)?)) + } + + /// Tries to create a [`SecretManager`] from a seed hex string. + pub fn try_from_hex_seed(seed: impl Into>) -> crate::client::Result { + Ok(Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(seed)?)) + } +} diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index 0c460ec640..9bae4ac36c 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -3,8 +3,6 @@ //! Implementation of [`MnemonicSecretManager`]. -use std::ops::Range; - use async_trait::async_trait; use crypto::{ keys::{bip39::Mnemonic, bip44::Bip44, slip10::Seed}, @@ -15,13 +13,15 @@ use crypto::{ }; use zeroize::Zeroizing; -use super::{GenerateAddressOptions, SecretManage}; use crate::{ - client::{api::PreparedTransactionData, Client, Error}, - types::block::{ - payload::signed_transaction::SignedTransactionPayload, protocol::ProtocolParameters, - signature::Ed25519Signature, unlock::Unlocks, + client::{ + secret::{ + types::EvmSignature, Generate, MultiKeyOptions, PublicKeyOptions, SecretManagerConfig, Sign, + SignTransaction, + }, + Client, Error, }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, }; /// Secret manager that uses only a mnemonic. @@ -36,62 +36,134 @@ impl std::fmt::Debug for MnemonicSecretManager { } #[async_trait] -impl SecretManage for MnemonicSecretManager { - type Error = Error; - - async fn generate_ed25519_public_keys( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - let internal = options.into().map(|o| o.internal).unwrap_or_default(); - - Ok(address_indexes - .map(|address_index| { - let chain = Bip44::new(coin_type) - .with_account(account_index) - .with_change(internal as _) - .with_address_index(address_index); - - let public_key = chain - .derive(&self.0.to_master_key::()) - .secret_key() - .public_key(); - - crate::client::Result::Ok(public_key) - }) - .collect::>()?) - } - - async fn generate_evm_addresses( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - let internal = options.into().map(|o| o.internal).unwrap_or_default(); - - Ok(address_indexes - .map(|address_index| { - let chain = Bip44::new(coin_type) - .with_account(account_index) - .with_change(internal as _) - .with_address_index(address_index); - - let public_key = chain - .derive(&self.0.to_master_key::()) - .secret_key() - .public_key(); - - crate::client::Result::Ok(public_key.evm_address()) - }) - .collect::>()?) - } - - async fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> Result { +impl Generate for MnemonicSecretManager { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_address_index(options.address_index) + .with_change(options.internal as _); + + let public_key = chain + .derive(&self.0.to_master_key::()) + .secret_key() + .public_key(); + + Ok(public_key) + } +} + +#[async_trait] +impl Generate for MnemonicSecretManager { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) + } +} + +#[async_trait] +impl Generate> for MnemonicSecretManager { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let mut res = Vec::with_capacity(options.address_range.len()); + for address_index in options.address_range.clone() { + let public_key: ed25519::PublicKey = self + .generate( + &PublicKeyOptions::new(options.coin_type) + .with_account_index(options.account_index) + .with_internal(options.internal) + .with_address_index(address_index), + ) + .await?; + res.push(public_key); + } + Ok(res) + } +} + +#[async_trait] +impl Generate> for MnemonicSecretManager { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys + .into_iter() + .map(|k| Ed25519Address::from_public_key_bytes(k.to_bytes())) + .collect()) + } +} + +#[async_trait] +impl Generate for MnemonicSecretManager { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_address_index(options.address_index) + .with_change(options.internal as _); + + let public_key = chain + .derive(&self.0.to_master_key::()) + .secret_key() + .public_key(); + + Ok(public_key) + } +} + +#[async_trait] +impl Generate for MnemonicSecretManager { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: secp256k1_ecdsa::PublicKey = self.generate(options).await?; + Ok(public_key.evm_address()) + } +} + +#[async_trait] +impl Generate> for MnemonicSecretManager { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let mut res = Vec::with_capacity(options.address_range.len()); + for address_index in options.address_range.clone() { + res.push( + Generate::::generate( + self, + &PublicKeyOptions::new(options.coin_type) + .with_account_index(options.account_index) + .with_internal(options.internal) + .with_address_index(address_index), + ) + .await?, + ); + } + Ok(res) + } +} + +#[async_trait] +impl Generate> for MnemonicSecretManager { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys.into_iter().map(|k| k.evm_address()).collect()) + } +} + +#[async_trait] +impl Sign for MnemonicSecretManager { + type Options = Bip44; + + async fn sign(&self, msg: &[u8], chain: &Self::Options) -> crate::client::Result { // Get the private and public key for this Ed25519 address let private_key = chain.derive(&self.0.to_master_key::()).secret_key(); let public_key = private_key.public_key(); @@ -99,12 +171,13 @@ impl SecretManage for MnemonicSecretManager { Ok(Ed25519Signature::new(public_key, signature)) } +} - async fn sign_secp256k1_ecdsa( - &self, - msg: &[u8], - chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> { +#[async_trait] +impl Sign for MnemonicSecretManager { + type Options = Bip44; + + async fn sign(&self, msg: &[u8], chain: &Self::Options) -> crate::client::Result { // Get the private and public key for this secp256k1_ecdsa key let private_key = chain .derive(&self.0.to_master_key::()) @@ -112,26 +185,12 @@ impl SecretManage for MnemonicSecretManager { let public_key = private_key.public_key(); let signature = private_key.try_sign_keccak256(msg)?; - Ok((public_key, signature)) - } - - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - super::default_transaction_unlocks(self, prepared_transaction_data, protocol_parameters).await - } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data, protocol_parameters).await + Ok(EvmSignature { public_key, signature }) } } +impl SignTransaction for MnemonicSecretManager {} + impl MnemonicSecretManager { /// Create a new [`MnemonicSecretManager`] from a BIP-39 mnemonic in English. /// @@ -149,6 +208,21 @@ impl MnemonicSecretManager { } } +impl SecretManagerConfig for MnemonicSecretManager { + type Config = String; + + fn to_config(&self) -> Option { + None + } + + fn from_config(config: &Self::Config) -> crate::client::Result + where + Self: Sized, + { + Self::try_from_mnemonic(config.as_str()) + } +} + #[cfg(test)] mod tests { use pretty_assertions::assert_eq; @@ -163,13 +237,12 @@ mod tests { let mnemonic = "giant dynamic museum toddler six deny defense ostrich bomb access mercy blood explain muscle shoot shallow glad autumn author calm heavy hawk abuse rally"; let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic.to_owned()).unwrap(); - let addresses = secret_manager - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None) - .await - .unwrap(); + let options = PublicKeyOptions::new(IOTA_COIN_TYPE); + + let address: Ed25519Address = secret_manager.generate(&options).await.unwrap(); assert_eq!( - addresses[0].to_bech32_unchecked("atoi"), + address.to_bech32_unchecked("atoi"), "atoi1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluehe53e" ); } @@ -181,13 +254,12 @@ mod tests { let seed = "0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2".to_owned(); let secret_manager = MnemonicSecretManager::try_from_hex_seed(seed).unwrap(); - let addresses = secret_manager - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None) - .await - .unwrap(); + let options = PublicKeyOptions::new(IOTA_COIN_TYPE); + + let address: Ed25519Address = secret_manager.generate(&options).await.unwrap(); assert_eq!( - addresses[0].to_bech32_unchecked("atoi"), + address.to_bech32_unchecked("atoi"), "atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r" ); } diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 9194402f1f..0d44bfe131 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -7,6 +7,7 @@ #[cfg(feature = "ledger_nano")] #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] pub mod ledger_nano; +mod manager; /// Module for mnemonic based secret management. pub mod mnemonic; /// Module for single private key based secret management. @@ -20,32 +21,22 @@ pub mod stronghold; /// Signing related types pub mod types; -#[cfg(feature = "stronghold")] -use std::time::Duration; -use std::{collections::HashMap, fmt, ops::Range, str::FromStr}; +use std::{collections::HashMap, fmt::Debug, ops::Range, sync::Arc}; use async_trait::async_trait; -use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, - keys::{bip39::Mnemonic, bip44::Bip44}, - signatures::{ - ed25519, - secp256k1_ecdsa::{self, EvmAddress}, - }, -}; +use crypto::{keys::bip44::Bip44, signatures::ed25519}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use zeroize::Zeroizing; #[cfg(feature = "ledger_nano")] use self::ledger_nano::LedgerSecretManager; +pub use self::manager::{SecretManager, SecretManagerDto}; use self::mnemonic::MnemonicSecretManager; #[cfg(feature = "private_key_secret_manager")] use self::private_key::PrivateKeySecretManager; +#[cfg(feature = "ledger_nano")] +pub use self::types::LedgerNanoStatus; #[cfg(feature = "stronghold")] -use self::stronghold::StrongholdSecretManager; -pub use self::types::{GenerateAddressOptions, LedgerNanoStatus}; -#[cfg(feature = "stronghold")] -use crate::client::secret::types::StrongholdDto; +use super::stronghold::StrongholdAdapter; use crate::{ client::{ api::{ @@ -55,7 +46,7 @@ use crate::{ Error, }, types::block::{ - address::{Address, Ed25519Address}, + address::Address, core::UnsignedBlock, output::Output, payload::SignedTransactionPayload, @@ -66,635 +57,525 @@ use crate::{ }, }; -/// The secret manager interface. -#[async_trait] -pub trait SecretManage: Send + Sync { - type Error: std::error::Error + Send + Sync; - - /// Generates public keys. - /// - /// For `coin_type`, see also . - async fn generate_ed25519_public_keys( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error>; - - /// Generates addresses. - /// - /// For `coin_type`, see also . - async fn generate_ed25519_addresses( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - Ok(self - .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) - .await? - .iter() - .map(|public_key| Ed25519Address::new(Blake2b256::digest(public_key.to_bytes()).into())) - .collect()) - } - - async fn generate_evm_addresses( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error>; - - /// Signs msg using the given [`Bip44`] using Ed25519. - async fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> Result; - - /// Signs msg using the given [`Bip44`] using Secp256k1. - async fn sign_secp256k1_ecdsa( - &self, - msg: &[u8], - chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error>; - - /// Signs `transaction_signing_hash` using the given `chain`, returning an [`Unlock`]. - async fn signature_unlock(&self, transaction_signing_hash: &[u8; 32], chain: Bip44) -> Result { - Ok(Unlock::from(SignatureUnlock::new(Signature::from( - self.sign_ed25519(transaction_signing_hash, chain).await?, - )))) - } - - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result; - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result; -} - -pub trait SecretManagerConfig: SecretManage { - type Config: Serialize + DeserializeOwned + fmt::Debug + Send + Sync; - - fn to_config(&self) -> Option; - - fn from_config(config: &Self::Config) -> Result - where - Self: Sized; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct PublicKeyOptions { + pub coin_type: u32, + pub account_index: u32, + pub internal: bool, + pub address_index: u32, } -/// Supported secret managers -#[non_exhaustive] -pub enum SecretManager { - /// Secret manager that uses [`iota_stronghold`] as the backing storage. - #[cfg(feature = "stronghold")] - #[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))] - Stronghold(StrongholdSecretManager), - - /// Secret manager that uses a Ledger Nano hardware wallet or Speculos simulator. - #[cfg(feature = "ledger_nano")] - #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] - LedgerNano(LedgerSecretManager), - - /// Secret manager that uses a mnemonic in plain memory. It's not recommended for production use. Use - /// LedgerNano or Stronghold instead. - Mnemonic(MnemonicSecretManager), - - /// Secret manager that uses a single private key. - #[cfg(feature = "private_key_secret_manager")] - #[cfg_attr(docsrs, doc(cfg(feature = "private_key_secret_manager")))] - PrivateKey(Box), +impl PublicKeyOptions { + /// Create a new public key generation options + pub fn new(coin_type: u32) -> Self { + Self { + coin_type, + account_index: 0, + internal: false, + address_index: 0, + } + } - /// Secret manager that's just a placeholder, so it can be provided to an online wallet, but can't be used for - /// signing. - Placeholder, -} + /// Set the account index + pub fn with_account_index(mut self, account_index: u32) -> Self { + self.account_index = account_index; + self + } -#[cfg(feature = "stronghold")] -impl From for SecretManager { - fn from(secret_manager: StrongholdSecretManager) -> Self { - Self::Stronghold(secret_manager) + /// Set internal flag. + pub fn with_internal(mut self, internal: bool) -> Self { + self.internal = internal; + self } -} -#[cfg(feature = "ledger_nano")] -impl From for SecretManager { - fn from(secret_manager: LedgerSecretManager) -> Self { - Self::LedgerNano(secret_manager) + /// Set the address index. + pub fn with_address_index(mut self, address_index: u32) -> Self { + self.address_index = address_index; + self } } -impl From for SecretManager { - fn from(secret_manager: MnemonicSecretManager) -> Self { - Self::Mnemonic(secret_manager) +impl From for PublicKeyOptions { + fn from(value: Bip44) -> Self { + Self::new(value.coin_type) + .with_account_index(value.account) + .with_internal(value.change != 0) + .with_address_index(value.address_index) } } -#[cfg(feature = "private_key_secret_manager")] -impl From for SecretManager { - fn from(secret_manager: PrivateKeySecretManager) -> Self { - Self::PrivateKey(Box::new(secret_manager)) +impl From for Bip44 { + fn from(value: PublicKeyOptions) -> Self { + Bip44::new(value.coin_type) + .with_account(value.account_index) + .with_change(value.internal as _) + .with_address_index(value.address_index) } } -impl fmt::Debug for SecretManager { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(_) => f.debug_tuple("Stronghold").field(&"...").finish(), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(_) => f.debug_tuple("LedgerNano").field(&"...").finish(), - Self::Mnemonic(_) => f.debug_tuple("Mnemonic").field(&"...").finish(), - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(_) => f.debug_tuple("PrivateKey").field(&"...").finish(), - Self::Placeholder => f.debug_struct("Placeholder").finish(), - } - } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct MultiKeyOptions { + pub coin_type: u32, + pub account_index: u32, + pub internal: bool, + pub address_range: Range, } -impl fmt::Display for SecretManager { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(_) => write!(f, "Stronghold"), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(l) => { - if l.is_simulator { - write!(f, "LedgerNano Simulator") - } else { - write!(f, "LedgerNano") - } - } - Self::Mnemonic(_) => write!(f, "Mnemonic"), - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(_) => write!(f, "PrivateKey"), - Self::Placeholder => write!(f, "Placeholder"), +impl MultiKeyOptions { + /// Create a new multikey generation options + pub fn new(coin_type: u32) -> Self { + Self { + coin_type, + account_index: 0, + internal: false, + address_range: 0..1, } } -} -impl FromStr for SecretManager { - type Err = Error; + /// Set the account index + pub fn with_account_index(mut self, account_index: u32) -> Self { + self.account_index = account_index; + self + } - fn from_str(s: &str) -> crate::client::Result { - Self::try_from(serde_json::from_str::(s)?) + /// Set internal flag. + pub fn with_internal(mut self, internal: bool) -> Self { + self.internal = internal; + self } -} -/// DTO for secret manager types with required data. -#[derive(Clone, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum SecretManagerDto { - /// Stronghold - #[cfg(feature = "stronghold")] - #[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))] - #[serde(alias = "stronghold")] - Stronghold(StrongholdDto), - /// Ledger Device, bool specifies if it's a simulator or not - #[cfg(feature = "ledger_nano")] - #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] - #[serde(alias = "ledgerNano")] - LedgerNano(bool), - /// Mnemonic - #[serde(alias = "mnemonic")] - Mnemonic(Zeroizing), - /// Private Key - #[cfg(feature = "private_key_secret_manager")] - #[cfg_attr(docsrs, doc(cfg(feature = "private_key_secret_manager")))] - #[serde(alias = "privateKey")] - PrivateKey(Zeroizing), - /// Hex seed - #[serde(alias = "hexSeed")] - HexSeed(Zeroizing), - /// Placeholder - #[serde(alias = "placeholder")] - Placeholder, + /// Set the address index range + pub fn with_address_range(mut self, range: Range) -> Self { + self.address_range = range; + self + } } -impl TryFrom for SecretManager { - type Error = Error; - - fn try_from(value: SecretManagerDto) -> crate::client::Result { - Ok(match value { - #[cfg(feature = "stronghold")] - SecretManagerDto::Stronghold(stronghold_dto) => { - let mut builder = StrongholdSecretManager::builder(); - - if let Some(password) = stronghold_dto.password { - builder = builder.password(password); - } - - if let Some(timeout) = stronghold_dto.timeout { - builder = builder.timeout(Duration::from_secs(timeout)); - } - - Self::Stronghold(builder.build(&stronghold_dto.snapshot_path)?) - } - - #[cfg(feature = "ledger_nano")] - SecretManagerDto::LedgerNano(is_simulator) => Self::LedgerNano(LedgerSecretManager::new(is_simulator)), - - SecretManagerDto::Mnemonic(mnemonic) => { - Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.as_str().to_owned())?) - } +#[async_trait] +pub trait Generate: Send + Sync { + type Options: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; - #[cfg(feature = "private_key_secret_manager")] - SecretManagerDto::PrivateKey(private_key) => { - Self::PrivateKey(Box::new(PrivateKeySecretManager::try_from_hex(private_key)?)) - } + async fn generate(&self, options: &Self::Options) -> crate::client::Result; +} - SecretManagerDto::HexSeed(hex_seed) => { - // `SecretManagerDto` is `ZeroizeOnDrop` so it will take care of zeroizing the original. - Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(hex_seed)?) - } +#[async_trait] +impl, K> Generate for Arc { + type Options = T::Options; - SecretManagerDto::Placeholder => Self::Placeholder, - }) + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + self.as_ref().generate(options).await } } -impl From<&SecretManager> for SecretManagerDto { - fn from(value: &SecretManager) -> Self { - match value { - #[cfg(feature = "stronghold")] - SecretManager::Stronghold(stronghold_adapter) => Self::Stronghold(StrongholdDto { - password: None, - timeout: stronghold_adapter.get_timeout().map(|duration| duration.as_secs()), - snapshot_path: stronghold_adapter - .snapshot_path - .clone() - .into_os_string() - .to_string_lossy() - .into(), - }), - - #[cfg(feature = "ledger_nano")] - SecretManager::LedgerNano(ledger_nano) => Self::LedgerNano(ledger_nano.is_simulator), - - // `MnemonicSecretManager(Seed)` doesn't have Debug or Display implemented and in the current use cases of - // the client/wallet we also don't need to convert it in this direction with the mnemonic/seed, we only need - // to know the type - SecretManager::Mnemonic(_mnemonic) => Self::Mnemonic("...".to_string().into()), - - #[cfg(feature = "private_key_secret_manager")] - SecretManager::PrivateKey(_private_key) => Self::PrivateKey("...".to_string().into()), - - SecretManager::Placeholder => Self::Placeholder, - } - } +#[async_trait] +pub trait Sign: Send + Sync { + type Options: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; + + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result; } #[async_trait] -impl SecretManage for SecretManager { - type Error = Error; - - async fn generate_ed25519_public_keys( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager - .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) - .await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager - .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) - .await?), - Self::Mnemonic(secret_manager) => { - secret_manager - .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) - .await - } - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => { - secret_manager - .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) - .await - } - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } - } +impl, S> Sign for Arc { + type Options = T::Options; - async fn generate_evm_addresses( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager - .generate_evm_addresses(coin_type, account_index, address_indexes, options) - .await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager - .generate_evm_addresses(coin_type, account_index, address_indexes, options) - .await?), - Self::Mnemonic(secret_manager) => { - secret_manager - .generate_evm_addresses(coin_type, account_index, address_indexes, options) - .await - } - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => { - secret_manager - .generate_evm_addresses(coin_type, account_index, address_indexes, options) - .await - } - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result { + self.as_ref().sign(msg, options).await } +} - async fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> crate::client::Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager.sign_ed25519(msg, chain).await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager.sign_ed25519(msg, chain).await?), - Self::Mnemonic(secret_manager) => secret_manager.sign_ed25519(msg, chain).await, - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => secret_manager.sign_ed25519(msg, chain).await, - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } +#[async_trait] +pub trait SignBlock: Sign { + async fn sign_block(&self, unsigned_block: UnsignedBlock, options: &Self::Options) -> crate::client::Result { + let msg = unsigned_block.signing_input(); + Ok(unsigned_block.finish(self.sign(&msg, options).await?)?) } +} +impl> SignBlock for T {} - async fn sign_secp256k1_ecdsa( +#[async_trait] +pub trait SignTransaction: Sign { + /// Signs `transaction_signing_hash` using the given `options`, returning a [`SignatureUnlock`]. + async fn signature_unlock( &self, - msg: &[u8], - chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager.sign_secp256k1_ecdsa(msg, chain).await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager.sign_secp256k1_ecdsa(msg, chain).await?), - Self::Mnemonic(secret_manager) => secret_manager.sign_secp256k1_ecdsa(msg, chain).await, - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => secret_manager.sign_secp256k1_ecdsa(msg, chain).await, - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } + transaction_signing_hash: &[u8; 32], + options: &Self::Options, + ) -> crate::client::Result { + Ok(SignatureUnlock::new(Signature::from( + self.sign(transaction_signing_hash, options).await?, + ))) } async fn transaction_unlocks( &self, prepared_transaction_data: &PreparedTransactionData, protocol_parameters: &ProtocolParameters, - ) -> Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager - .transaction_unlocks(prepared_transaction_data, protocol_parameters) - .await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager - .transaction_unlocks(prepared_transaction_data, protocol_parameters) - .await?), - Self::Mnemonic(secret_manager) => { - secret_manager - .transaction_unlocks(prepared_transaction_data, protocol_parameters) - .await - } - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => { - secret_manager - .transaction_unlocks(prepared_transaction_data, protocol_parameters) - .await + options: &Self::Options, + ) -> crate::client::Result { + let transaction_signing_hash = prepared_transaction_data.transaction.signing_hash(); + let mut blocks = Vec::new(); + let mut block_indexes = HashMap::::new(); + let slot_index = prepared_transaction_data + .transaction + .context_inputs() + .commitment() + .map(|c| c.slot_index()); + + // Assuming inputs_data is ordered by address type + for (current_block_index, input) in prepared_transaction_data.inputs_data.iter().enumerate() { + // Get the address that is required to unlock the input + let required_address = input + .output + .required_address(slot_index, protocol_parameters.committable_age_range())? + .ok_or(crate::client::Error::ExpirationDeadzone)?; + + // Convert restricted and implicit addresses to Ed25519 address, so they're the same entry in + // `block_indexes`. + let required_address = match required_address { + Address::ImplicitAccountCreation(implicit) => Address::Ed25519(*implicit.ed25519_address()), + Address::Restricted(restricted) => restricted.address().clone(), + _ => required_address, + }; + + // Check if we already added an [Unlock] for this address + match block_indexes.get(&required_address) { + // If we already have an [Unlock] for this address, add a [Unlock] based on the address type + Some(block_index) => match required_address { + Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => { + blocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?)); + } + Address::Account(_) => blocks.push(Unlock::Account(AccountUnlock::new(*block_index as u16)?)), + Address::Nft(_) => blocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)), + _ => Err(BlockError::UnsupportedAddressKind(required_address.kind()))?, + }, + None => { + // We can only sign ed25519 addresses and block_indexes needs to contain the account or nft + // address already at this point, because the reference index needs to be lower + // than the current block index + match &required_address { + Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => {} + _ => Err(InputSelectionError::MissingInputWithEd25519Address)?, + } + + let block = self.signature_unlock(&transaction_signing_hash, options).await?; + blocks.push(block.into()); + + // Add the ed25519 address to the block_indexes, so it gets referenced if further inputs have + // the same address in their unlock condition + block_indexes.insert(required_address.clone(), current_block_index); + } } - Self::Placeholder => Err(Error::PlaceholderSecretManager), + + // When we have an account or Nft output, we will add their account or nft address to block_indexes, + // because they can be used to unlock outputs via [Unlock::Account] or [Unlock::Nft], + // that have the corresponding account or nft address in their unlock condition + match &input.output { + Output::Account(account_output) => block_indexes.insert( + Address::Account(account_output.account_address(input.output_id())), + current_block_index, + ), + Output::Nft(nft_output) => block_indexes.insert( + Address::Nft(nft_output.nft_address(input.output_id())), + current_block_index, + ), + _ => None, + }; } + + Ok(Unlocks::new(blocks)?) } async fn sign_transaction( &self, prepared_transaction_data: PreparedTransactionData, protocol_parameters: &ProtocolParameters, - ) -> Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager - .sign_transaction(prepared_transaction_data, protocol_parameters) - .await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager - .sign_transaction(prepared_transaction_data, protocol_parameters) - .await?), - Self::Mnemonic(secret_manager) => { - secret_manager - .sign_transaction(prepared_transaction_data, protocol_parameters) - .await - } - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => { - secret_manager - .sign_transaction(prepared_transaction_data, protocol_parameters) - .await - } - Self::Placeholder => Err(Error::PlaceholderSecretManager), + options: &Self::Options, + ) -> crate::client::Result { + log::debug!("[sign_transaction] {:?}", prepared_transaction_data); + + let unlocks = self + .transaction_unlocks(&prepared_transaction_data, protocol_parameters, options) + .await?; + + let PreparedTransactionData { + transaction, + inputs_data, + mana_rewards, + .. + } = prepared_transaction_data; + let tx_payload = SignedTransactionPayload::new(transaction, unlocks)?; + + validate_signed_transaction_payload_length(&tx_payload)?; + + let conflict = verify_semantic(&inputs_data, &tx_payload, mana_rewards, protocol_parameters.clone())?; + + if let Some(conflict) = conflict { + log::debug!("[sign_transaction] conflict: {conflict:?} for {:#?}", tx_payload); + return Err(Error::TransactionSemantic(conflict)); } + + Ok(tx_payload) } } +impl SignTransaction for Arc {} + +/// Unifying trait for secret managers. This type must be able to, at minimum, generate +/// an address and sign transactions and blocks. +#[async_trait] +pub trait SecretManage: + Generate + + SignTransaction + + SignBlock +{ + type GenerationOptions: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; + type SigningOptions: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; +} -pub trait DowncastSecretManager: SecretManage { - fn downcast(&self) -> Option<&T>; +#[async_trait] +impl + SignTransaction + SignBlock> SecretManage for T { + type GenerationOptions = >::Options; + type SigningOptions = >::Options; } -impl DowncastSecretManager for S { - fn downcast(&self) -> Option<&T> { - (self as &(dyn std::any::Any + Send + Sync)).downcast_ref::() +#[async_trait] +pub trait SecretManageExt { + async fn generate(&self, options: &Self::Options) -> crate::client::Result + where + Self: Generate, + { + Generate::::generate(self, options).await + } + + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result + where + Self: Sign, + { + Sign::::sign(self, msg, options).await } } +impl SecretManageExt for T {} + +pub trait SecretManagerConfig: SecretManage { + type Config: Serialize + DeserializeOwned + core::fmt::Debug + Send + Sync; + + fn to_config(&self) -> Option; + + fn from_config(config: &Self::Config) -> crate::client::Result + where + Self: Sized; +} -impl SecretManagerConfig for SecretManager { - type Config = SecretManagerDto; +impl SecretManagerConfig for Arc { + type Config = T::Config; fn to_config(&self) -> Option { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(s) => s.to_config().map(Self::Config::Stronghold), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(s) => s.to_config().map(Self::Config::LedgerNano), - Self::Mnemonic(_) => None, - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(_) => None, - Self::Placeholder => None, - } + self.as_ref().to_config() } - fn from_config(config: &Self::Config) -> Result { - Ok(match config { - #[cfg(feature = "stronghold")] - SecretManagerDto::Stronghold(config) => Self::Stronghold(StrongholdSecretManager::from_config(config)?), - #[cfg(feature = "ledger_nano")] - SecretManagerDto::LedgerNano(config) => Self::LedgerNano(LedgerSecretManager::from_config(config)?), - SecretManagerDto::HexSeed(hex_seed) => { - Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(hex_seed.clone())?) - } - SecretManagerDto::Mnemonic(mnemonic) => { - Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.as_str().to_owned())?) - } - #[cfg(feature = "private_key_secret_manager")] - SecretManagerDto::PrivateKey(private_key) => { - Self::PrivateKey(Box::new(PrivateKeySecretManager::try_from_hex(private_key.to_owned())?)) - } - SecretManagerDto::Placeholder => Self::Placeholder, - }) + fn from_config(config: &Self::Config) -> crate::client::Result { + Ok(Arc::new(T::from_config(config)?)) } } -impl SecretManager { - /// Tries to create a [`SecretManager`] from a mnemonic string. - pub fn try_from_mnemonic(mnemonic: impl Into) -> crate::client::Result { - Ok(Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic)?)) +pub trait DowncastSecretManager { + fn is(&self) -> bool; + + fn downcast_ref(&self) -> Option<&T>; + + fn downcast_mut(&mut self) -> Option<&mut T>; + + fn downcast(self) -> Option; + + #[cfg(feature = "stronghold")] + fn as_stronghold(&self) -> crate::client::Result<&StrongholdAdapter> { + self.downcast_ref::() + .or_else(|| { + self.downcast_ref::().and_then(|s| { + if let SecretManager::Stronghold(a) = s { + Some(a) + } else { + None + } + }) + }) + .ok_or(crate::client::Error::SecretManagerMismatch) } - /// Tries to create a [`SecretManager`] from a seed hex string. - pub fn try_from_hex_seed(seed: impl Into>) -> crate::client::Result { - Ok(Self::Mnemonic(MnemonicSecretManager::try_from_hex_seed(seed)?)) + #[cfg(feature = "stronghold")] + fn as_stronghold_mut(&mut self) -> crate::client::Result<&mut StrongholdAdapter> { + // Have to do this because of https://docs.rs/polonius-the-crab/latest/polonius_the_crab/#rationale-limitations-of-the-nll-borrow-checker + if self.is::() { + Ok(self.downcast_mut::().unwrap()) + } else { + self.downcast_mut::() + .and_then(|s| { + if let SecretManager::Stronghold(a) = s { + Some(a) + } else { + None + } + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } } -} -pub(crate) async fn default_transaction_unlocks( - secret_manager: &M, - prepared_transaction_data: &PreparedTransactionData, - protocol_parameters: &ProtocolParameters, -) -> crate::client::Result -where - crate::client::Error: From, -{ - let transaction_signing_hash = prepared_transaction_data.transaction.signing_hash(); - let mut blocks = Vec::new(); - let mut block_indexes = HashMap::::new(); - let slot_index = prepared_transaction_data - .transaction - .context_inputs() - .commitment() - .map(|c| c.slot_index()); - - // Assuming inputs_data is ordered by address type - for (current_block_index, input) in prepared_transaction_data.inputs_data.iter().enumerate() { - // Get the address that is required to unlock the input - let required_address = input - .output - .required_address(slot_index, protocol_parameters.committable_age_range())? - .ok_or(crate::client::Error::ExpirationDeadzone)?; - - // Convert restricted and implicit addresses to Ed25519 address, so they're the same entry in `block_indexes`. - let required_address = match required_address { - Address::ImplicitAccountCreation(implicit) => Address::Ed25519(*implicit.ed25519_address()), - Address::Restricted(restricted) => restricted.address().clone(), - _ => required_address, - }; - - // Check if we already added an [Unlock] for this address - match block_indexes.get(&required_address) { - // If we already have an [Unlock] for this address, add a [Unlock] based on the address type - Some(block_index) => match required_address { - Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => { - blocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?)); - } - Address::Account(_) => blocks.push(Unlock::Account(AccountUnlock::new(*block_index as u16)?)), - Address::Nft(_) => blocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)), - _ => Err(BlockError::UnsupportedAddressKind(required_address.kind()))?, - }, - None => { - // We can only sign ed25519 addresses and block_indexes needs to contain the account or nft - // address already at this point, because the reference index needs to be lower - // than the current block index - match &required_address { - Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => {} - _ => Err(InputSelectionError::MissingInputWithEd25519Address)?, - } + fn as_mnemonic(&self) -> crate::client::Result<&MnemonicSecretManager> { + self.downcast_ref::() + .or_else(|| { + self.downcast_ref::().and_then(|s| { + if let SecretManager::Mnemonic(a) = s { + Some(a) + } else { + None + } + }) + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } - let chain = input.chain.ok_or(Error::MissingBip32Chain)?; + fn as_mnemonic_mut(&mut self) -> crate::client::Result<&mut MnemonicSecretManager> { + // Have to do this because of https://docs.rs/polonius-the-crab/latest/polonius_the_crab/#rationale-limitations-of-the-nll-borrow-checker + if self.is::() { + Ok(self.downcast_mut::().unwrap()) + } else { + self.downcast_mut::() + .and_then(|s| { + if let SecretManager::Mnemonic(a) = s { + Some(a) + } else { + None + } + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } + } - let block = secret_manager - .signature_unlock(&transaction_signing_hash, chain) - .await?; - blocks.push(block); + #[cfg(feature = "ledger_nano")] + fn as_ledger_nano(&self) -> crate::client::Result<&LedgerSecretManager> { + self.downcast_ref::() + .or_else(|| { + self.downcast_ref::().and_then(|s| { + if let SecretManager::LedgerNano(a) = s { + Some(a) + } else { + None + } + }) + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } - // Add the ed25519 address to the block_indexes, so it gets referenced if further inputs have - // the same address in their unlock condition - block_indexes.insert(required_address.clone(), current_block_index); - } + #[cfg(feature = "ledger_nano")] + fn as_ledger_nano_mut(&mut self) -> crate::client::Result<&mut LedgerSecretManager> { + // Have to do this because of https://docs.rs/polonius-the-crab/latest/polonius_the_crab/#rationale-limitations-of-the-nll-borrow-checker + if self.is::() { + Ok(self.downcast_mut::().unwrap()) + } else { + self.downcast_mut::() + .and_then(|s| { + if let SecretManager::LedgerNano(a) = s { + Some(a) + } else { + None + } + }) + .ok_or(crate::client::Error::SecretManagerMismatch) } + } + + #[cfg(feature = "private_key_secret_manager")] + fn as_private_key(&self) -> crate::client::Result<&PrivateKeySecretManager> { + self.downcast_ref::() + .or_else(|| { + self.downcast_ref::().and_then(|s| { + if let SecretManager::PrivateKey(a) = s { + Some(a.as_ref()) + } else { + None + } + }) + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } - // When we have an account or Nft output, we will add their account or nft address to block_indexes, - // because they can be used to unlock outputs via [Unlock::Account] or [Unlock::Nft], - // that have the corresponding account or nft address in their unlock condition - match &input.output { - Output::Account(account_output) => block_indexes.insert( - Address::Account(account_output.account_address(input.output_id())), - current_block_index, - ), - Output::Nft(nft_output) => block_indexes.insert( - Address::Nft(nft_output.nft_address(input.output_id())), - current_block_index, - ), - _ => None, - }; - } - - Ok(Unlocks::new(blocks)?) + #[cfg(feature = "private_key_secret_manager")] + fn as_private_key_mut(&mut self) -> crate::client::Result<&mut PrivateKeySecretManager> { + // Have to do this because of https://docs.rs/polonius-the-crab/latest/polonius_the_crab/#rationale-limitations-of-the-nll-borrow-checker + if self.is::() { + Ok(self.downcast_mut::().unwrap()) + } else { + self.downcast_mut::() + .and_then(|s| { + if let SecretManager::PrivateKey(a) = s { + Some(a.as_mut()) + } else { + None + } + }) + .ok_or(crate::client::Error::SecretManagerMismatch) + } + } } -pub(crate) async fn default_sign_transaction( - secret_manager: &M, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, -) -> crate::client::Result -where - crate::client::Error: From, -{ - log::debug!("[sign_transaction] {:?}", prepared_transaction_data); +impl DowncastSecretManager for S { + fn is(&self) -> bool { + self.as_any().is::() + } - let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, protocol_parameters) - .await?; + fn downcast_ref(&self) -> Option<&T> { + self.as_any().downcast_ref::() + } - let PreparedTransactionData { - transaction, - inputs_data, - mana_rewards, - .. - } = prepared_transaction_data; - let tx_payload = SignedTransactionPayload::new(transaction, unlocks)?; + fn downcast_mut(&mut self) -> Option<&mut T> { + self.as_any_mut().downcast_mut::() + } - validate_signed_transaction_payload_length(&tx_payload)?; + fn downcast(self) -> Option { + self.as_any_boxed().downcast::().ok().map(|b| *b) + } +} - let conflict = verify_semantic(&inputs_data, &tx_payload, mana_rewards, protocol_parameters.clone())?; +pub trait AsAny: Send + Sync { + fn as_any(&self) -> &(dyn std::any::Any + Send + Sync); + fn as_any_mut(&mut self) -> &mut (dyn std::any::Any + Send + Sync); + fn as_any_boxed(self) -> Box; +} - if let Some(conflict) = conflict { - log::debug!("[sign_transaction] conflict: {conflict:?} for {:#?}", tx_payload); - return Err(Error::TransactionSemantic(conflict)); +impl AsAny for T { + fn as_any(&self) -> &(dyn std::any::Any + Send + Sync) { + self + } + fn as_any_mut(&mut self) -> &mut (dyn std::any::Any + Send + Sync) { + self } - Ok(tx_payload) + fn as_any_boxed(self) -> Box { + Box::new(self) as Box + } } #[async_trait] -pub trait SignBlock { - async fn sign_ed25519(self, secret_manager: &S, chain: Bip44) -> crate::client::Result +pub trait BlockSignExt { + async fn sign_ed25519( + self, + secret_manager: &S, + options: &S::Options, + ) -> crate::client::Result where - crate::client::Error: From; + Self: Sized; } #[async_trait] -impl SignBlock for UnsignedBlock { - async fn sign_ed25519(self, secret_manager: &S, chain: Bip44) -> crate::client::Result +impl BlockSignExt for UnsignedBlock { + async fn sign_ed25519( + self, + secret_manager: &S, + options: &S::Options, + ) -> crate::client::Result where - crate::client::Error: From, + Self: Sized, { - let msg = self.signing_input(); - Ok(self.finish(secret_manager.sign_ed25519(&msg, chain).await?)?) + Ok(secret_manager.sign_block(self, options).await?) } } diff --git a/sdk/src/client/secret/private_key.rs b/sdk/src/client/secret/private_key.rs index 4a07392e14..75bed66a31 100644 --- a/sdk/src/client/secret/private_key.rs +++ b/sdk/src/client/secret/private_key.rs @@ -3,25 +3,16 @@ //! Implementation of [`PrivateKeySecretManager`]. -use std::ops::Range; - use async_trait::async_trait; -use crypto::{ - keys::bip44::Bip44, - signatures::{ - ed25519, - secp256k1_ecdsa::{self, EvmAddress}, - }, -}; +use crypto::signatures::ed25519; use zeroize::{Zeroize, Zeroizing}; -use super::{GenerateAddressOptions, SecretManage}; use crate::{ - client::{api::PreparedTransactionData, Error}, - types::block::{ - payload::signed_transaction::SignedTransactionPayload, protocol::ProtocolParameters, - signature::Ed25519Signature, unlock::Unlocks, + client::{ + secret::{Generate, Sign, SignTransaction}, + Error, }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, }; /// Secret manager based on a single private key. @@ -34,63 +25,38 @@ impl std::fmt::Debug for PrivateKeySecretManager { } #[async_trait] -impl SecretManage for PrivateKeySecretManager { - type Error = Error; - - async fn generate_ed25519_public_keys( - &self, - _coin_type: u32, - _account_index: u32, - _address_indexes: Range, - _options: impl Into> + Send, - ) -> Result, Self::Error> { - crate::client::Result::Ok(vec![self.0.public_key()]) - } +impl Generate for PrivateKeySecretManager { + type Options = (); - async fn generate_evm_addresses( - &self, - _coin_type: u32, - _account_index: u32, - _address_indexes: Range, - _options: impl Into> + Send, - ) -> Result, Self::Error> { - // TODO replace with a more fitting variant. - Err(Error::SecretManagerMismatch) + async fn generate(&self, _options: &Self::Options) -> crate::client::Result { + crate::client::Result::Ok(self.0.public_key()) } +} - async fn sign_ed25519(&self, msg: &[u8], _chain: Bip44) -> Result { - let public_key = self.0.public_key(); - let signature = self.0.sign(msg); +#[async_trait] +impl Generate for PrivateKeySecretManager { + type Options = (); - Ok(Ed25519Signature::new(public_key, signature)) + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) } +} - async fn sign_secp256k1_ecdsa( - &self, - _msg: &[u8], - _chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> { - // TODO replace with a more fitting variant. - Err(Error::SecretManagerMismatch) - } +#[async_trait] +impl Sign for PrivateKeySecretManager { + type Options = (); - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - super::default_transaction_unlocks(self, prepared_transaction_data, protocol_parameters).await - } + async fn sign(&self, msg: &[u8], _options: &Self::Options) -> crate::client::Result { + let public_key = self.0.public_key(); + let signature = self.0.sign(msg); - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data, protocol_parameters).await + Ok(Ed25519Signature::new(public_key, signature)) } } +impl SignTransaction for PrivateKeySecretManager {} + impl PrivateKeySecretManager { /// Create a new [`PrivateKeySecretManager`] from a base 58 encoded private key. pub fn try_from_b58>(b58: T) -> Result { diff --git a/sdk/src/client/secret/types.rs b/sdk/src/client/secret/types.rs index 7bf5366017..8aa4047bb5 100644 --- a/sdk/src/client/secret/types.rs +++ b/sdk/src/client/secret/types.rs @@ -3,13 +3,10 @@ //! Miscellaneous types for secret managers. -use crypto::keys::bip44::Bip44; +use crypto::signatures::secp256k1_ecdsa; use serde::{Deserialize, Serialize}; -use crate::{ - types::block::output::{Output, OutputId, OutputMetadata}, - utils::serde::bip44::option_bip44, -}; +use crate::types::block::output::{Output, OutputId, OutputMetadata}; /// Stronghold DTO to allow the creation of a Stronghold secret manager from bindings #[cfg(feature = "stronghold")] @@ -35,24 +32,6 @@ impl core::fmt::Debug for StrongholdDto { } } -/// Options provided to generate addresses. -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", default)] -pub struct GenerateAddressOptions { - pub internal: bool, - /// Display the address on ledger devices. - pub ledger_nano_prompt: bool, -} - -impl GenerateAddressOptions { - pub const fn internal() -> Self { - Self { - internal: true, - ledger_nano_prompt: false, - } - } -} - /// The Ledger device status. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct LedgerApp { @@ -141,9 +120,6 @@ pub struct InputSigningData { pub output: Output, /// The output metadata pub output_metadata: OutputMetadata, - /// The chain derived from seed, only for ed25519 addresses - #[serde(with = "option_bip44", default)] - pub chain: Option, } impl InputSigningData { @@ -152,3 +128,8 @@ impl InputSigningData { self.output_metadata.output_id() } } + +pub struct EvmSignature { + pub public_key: secp256k1_ecdsa::PublicKey, + pub signature: secp256k1_ecdsa::RecoverableSignature, +} diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index 8878069aa9..edde0b9add 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -1,10 +1,9 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//! The [SecretManage] implementation for [StrongholdAdapter]. +//! The secret implementations for [StrongholdAdapter]. -use core::borrow::Borrow; -use std::ops::Range; +use core::{borrow::Borrow, time::Duration}; use async_trait::async_trait; use crypto::{ @@ -18,7 +17,6 @@ use crypto::{ secp256k1_ecdsa::{self, EvmAddress}, }, }; -use instant::Duration; use iota_stronghold::{ procedures::{self, Curve, KeyType, Slip10DeriveInput}, Location, @@ -30,27 +28,86 @@ use super::{ }; use crate::{ client::{ - api::PreparedTransactionData, - secret::{types::StrongholdDto, GenerateAddressOptions, SecretManage, SecretManagerConfig}, + secret::{ + types::{EvmSignature, StrongholdDto}, + Generate, MultiKeyOptions, PublicKeyOptions, SecretManagerConfig, Sign, SignTransaction, + }, stronghold::Error, }, - types::block::{ - payload::signed_transaction::SignedTransactionPayload, protocol::ProtocolParameters, - signature::Ed25519Signature, unlock::Unlocks, - }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, }; #[async_trait] -impl SecretManage for StrongholdAdapter { - type Error = crate::client::Error; +impl Generate for StrongholdAdapter { + type Options = PublicKeyOptions; - async fn generate_ed25519_public_keys( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold + // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but + // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). + // Thus, we put an extra guard here to prevent this methods from being invoked when our cached key has + // been cleared. + if !self.is_key_available().await { + return Err(Error::KeyCleared.into()); + } + + // Stronghold arguments. + let seed_location = Slip10DeriveInput::Seed(Location::generic(SECRET_VAULT_PATH, SEED_RECORD_PATH)); + + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_address_index(options.address_index) + .with_change(options.internal as _); + + let derive_location = Location::generic( + SECRET_VAULT_PATH, + [ + DERIVE_OUTPUT_RECORD_PATH, + &chain + .to_chain::() + .into_iter() + .flat_map(|seg| seg.ser32()) + .collect::>(), + ] + .concat(), + ); + + // Derive a SLIP-10 private key in the vault. + self.slip10_derive(Curve::Ed25519, chain, seed_location.clone(), derive_location.clone()) + .await?; + + // Get the Ed25519 public key from the derived SLIP-10 private key in the vault. + let public_key = self.ed25519_public_key(derive_location.clone()).await?; + + // Cleanup location afterwards + self.stronghold + .lock() + .await + .get_client(PRIVATE_DATA_CLIENT_PATH) + .map_err(Error::from)? + .vault(SECRET_VAULT_PATH) + .delete_secret(derive_location.record_path()) + .map_err(Error::from)?; + + Ok(public_key) + } +} + +#[async_trait] +impl Generate for StrongholdAdapter { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: ed25519::PublicKey = self.generate(options).await?; + Ok(Ed25519Address::from_public_key_bytes(public_key.to_bytes())) + } +} + +#[async_trait] +impl Generate> for StrongholdAdapter { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -65,12 +122,11 @@ impl SecretManage for StrongholdAdapter { // Public keys to return. let mut public_keys = Vec::new(); - let internal = options.into().map(|o| o.internal).unwrap_or_default(); - for address_index in address_indexes { - let chain = Bip44::new(coin_type) - .with_account(account_index) - .with_change(internal as _) + for address_index in options.address_range.clone() { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_change(options.internal as _) .with_address_index(address_index); let derive_location = Location::generic( @@ -109,14 +165,92 @@ impl SecretManage for StrongholdAdapter { Ok(public_keys) } +} - async fn generate_evm_addresses( - &self, - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { +#[async_trait] +impl Generate> for StrongholdAdapter { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys + .into_iter() + .map(|k| Ed25519Address::from_public_key_bytes(k.to_bytes())) + .collect()) + } +} + +#[async_trait] +impl Generate for StrongholdAdapter { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold + // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but + // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). + // Thus, we put an extra guard here to prevent this methods from being invoked when our cached key has + // been cleared. + if !self.is_key_available().await { + return Err(Error::KeyCleared.into()); + } + + // Stronghold arguments. + let seed_location = Slip10DeriveInput::Seed(Location::generic(SECRET_VAULT_PATH, SEED_RECORD_PATH)); + + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_address_index(options.address_index) + .with_change(options.internal as _); + + let derive_location = Location::generic( + SECRET_VAULT_PATH, + [ + DERIVE_OUTPUT_RECORD_PATH, + &chain + .to_chain::() + .into_iter() + .flat_map(|seg| seg.ser32()) + .collect::>(), + ] + .concat(), + ); + + // Derive a SLIP-10 private key in the vault. + self.slip10_derive(Curve::Secp256k1, chain, seed_location.clone(), derive_location.clone()) + .await?; + + // Get the Secp256k1 public key from the derived SLIP-10 private key in the vault. + let public_key = self.secp256k1_ecdsa_public_key(derive_location.clone()).await?; + + // Cleanup location afterwards + self.stronghold + .lock() + .await + .get_client(PRIVATE_DATA_CLIENT_PATH) + .map_err(Error::from)? + .vault(SECRET_VAULT_PATH) + .delete_secret(derive_location.record_path()) + .map_err(Error::from)?; + + Ok(public_key) + } +} + +#[async_trait] +impl Generate for StrongholdAdapter { + type Options = PublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let public_key: secp256k1_ecdsa::PublicKey = self.generate(options).await?; + Ok(public_key.evm_address()) + } +} + +#[async_trait] +impl Generate> for StrongholdAdapter { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -131,12 +265,11 @@ impl SecretManage for StrongholdAdapter { // Addresses to return. let mut addresses = Vec::new(); - let internal = options.into().map(|o| o.internal).unwrap_or_default(); - for address_index in address_indexes { - let chain = Bip44::new(coin_type) - .with_account(account_index) - .with_change(internal as _) + for address_index in options.address_range.clone() { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_index) + .with_change(options.internal as _) .with_address_index(address_index); let derive_location = Location::generic( @@ -170,13 +303,28 @@ impl SecretManage for StrongholdAdapter { .map_err(Error::from)?; // Collect it. - addresses.push(public_key.evm_address()); + addresses.push(public_key); } Ok(addresses) } +} - async fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> Result { +#[async_trait] +impl Generate> for StrongholdAdapter { + type Options = MultiKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result> { + let public_keys: Vec = self.generate(options).await?; + Ok(public_keys.into_iter().map(|k| k.evm_address()).collect()) + } +} + +#[async_trait] +impl Sign for StrongholdAdapter { + type Options = Bip44; + + async fn sign(&self, msg: &[u8], chain: &Self::Options) -> crate::client::Result { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -203,7 +351,7 @@ impl SecretManage for StrongholdAdapter { ); // Derive a SLIP-10 private key in the vault. - self.slip10_derive(Curve::Ed25519, chain, seed_location, derive_location.clone()) + self.slip10_derive(Curve::Ed25519, *chain, seed_location, derive_location.clone()) .await?; // Get the Ed25519 public key from the derived SLIP-10 private key in the vault. @@ -222,12 +370,13 @@ impl SecretManage for StrongholdAdapter { Ok(Ed25519Signature::new(public_key, signature)) } +} - async fn sign_secp256k1_ecdsa( - &self, - msg: &[u8], - chain: Bip44, - ) -> Result<(secp256k1_ecdsa::PublicKey, secp256k1_ecdsa::RecoverableSignature), Self::Error> { +#[async_trait] +impl Sign for StrongholdAdapter { + type Options = Bip44; + + async fn sign(&self, msg: &[u8], chain: &Self::Options) -> crate::client::Result { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -254,7 +403,7 @@ impl SecretManage for StrongholdAdapter { ); // Derive a SLIP-10 private key in the vault. - self.slip10_derive(Curve::Secp256k1, chain, seed_location, derive_location.clone()) + self.slip10_derive(Curve::Secp256k1, *chain, seed_location, derive_location.clone()) .await?; // Get the public key from the derived SLIP-10 private key in the vault. @@ -271,26 +420,12 @@ impl SecretManage for StrongholdAdapter { .delete_secret(derive_location.record_path()) .map_err(Error::from)?; - Ok((public_key, signature)) - } - - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - crate::client::secret::default_transaction_unlocks(self, prepared_transaction_data, protocol_parameters).await - } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - protocol_parameters: &ProtocolParameters, - ) -> Result { - crate::client::secret::default_sign_transaction(self, prepared_transaction_data, protocol_parameters).await + Ok(EvmSignature { public_key, signature }) } } +impl SignTransaction for StrongholdAdapter {} + impl SecretManagerConfig for StrongholdAdapter { type Config = StrongholdDto; @@ -302,7 +437,7 @@ impl SecretManagerConfig for StrongholdAdapter { }) } - fn from_config(config: &Self::Config) -> Result { + fn from_config(config: &Self::Config) -> crate::client::Result { let mut builder = Self::builder(); if let Some(password) = &config.password { @@ -520,13 +655,12 @@ mod tests { // The snapshot should have been on the disk now. assert!(Path::new(stronghold_path).exists()); - let addresses = stronghold_adapter - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None) + let address = Generate::::generate(&stronghold_adapter, &PublicKeyOptions::new(IOTA_COIN_TYPE)) .await .unwrap(); assert_eq!( - addresses[0].to_bech32_unchecked("atoi"), + address.to_bech32_unchecked("atoi"), "atoi1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluehe53e" ); @@ -552,13 +686,12 @@ mod tests { // The snapshot should have been on the disk now. assert!(Path::new(stronghold_path).exists()); - let addresses = stronghold_adapter - .generate_evm_addresses(ETHER_COIN_TYPE, 0, 0..1, None) + let address = Generate::::generate(&stronghold_adapter, &PublicKeyOptions::new(ETHER_COIN_TYPE)) .await .unwrap(); assert_eq!( - prefix_hex::encode(addresses[0].as_ref()), + prefix_hex::encode(address.as_ref()), "0xcaefde2b487ded55688765964320ff390cd87828" ); @@ -588,8 +721,7 @@ mod tests { // Address generation returns an error when the key is cleared. assert!( - stronghold_adapter - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None) + Generate::::generate(&stronghold_adapter, &PublicKeyOptions::new(IOTA_COIN_TYPE)) .await .is_err() ); @@ -597,13 +729,12 @@ mod tests { stronghold_adapter.set_password("drowssap".to_owned()).await.unwrap(); // After setting the correct password it works again. - let addresses = stronghold_adapter - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None) + let address = Generate::::generate(&stronghold_adapter, &PublicKeyOptions::new(IOTA_COIN_TYPE)) .await .unwrap(); assert_eq!( - addresses[0].to_bech32_unchecked("atoi"), + address.to_bech32_unchecked("atoi"), "atoi1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluehe53e" ); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 9d8f5780cf..3bfd41bd72 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -31,4 +31,4 @@ pub use packable; pub use primitive_types::U256; #[cfg(feature = "wallet")] -pub type Wallet = self::wallet::Wallet; +pub type Wallet = self::wallet::Wallet>; diff --git a/sdk/src/types/block/output/feature/block_issuer.rs b/sdk/src/types/block/output/feature/block_issuer.rs index 5334d301c4..ad7c6128c5 100644 --- a/sdk/src/types/block/output/feature/block_issuer.rs +++ b/sdk/src/types/block/output/feature/block_issuer.rs @@ -6,7 +6,6 @@ use core::ops::RangeInclusive; use crypto::{ hashes::{blake2b::Blake2b256, Digest}, - keys::bip44::Bip44, signatures::{ed25519, ed25519::PublicKey}, }; use derive_more::{AsRef, Deref, From}; @@ -255,11 +254,10 @@ impl WorkScore for BlockIssuerFeature { } } -#[derive(From)] -pub enum BlockIssuerKeySource { +pub enum BlockIssuerKeySource { ImplicitAccountAddress, PublicKey(PublicKey), - Bip44Path(Bip44), + Options(O), } #[cfg(feature = "serde")] diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index ae8df31326..24117a4ba7 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -8,7 +8,6 @@ use std::sync::Arc; use serde::Serialize; use tokio::sync::{Mutex, RwLock}; -use super::operations::storage::SaveLoadWallet; #[cfg(feature = "events")] use crate::wallet::events::EventEmitter; #[cfg(all(feature = "storage", not(feature = "rocksdb")))] @@ -16,61 +15,48 @@ use crate::wallet::storage::adapter::memory::Memory; #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::secret::{GenerateAddressOptions, SecretManage, SecretManager}, - types::block::address::{Address, Bech32Address}, + client::secret::{SecretManage, SecretManagerConfig}, + types::block::address::{Bech32Address, Ed25519Address, ToBech32Ext}, wallet::{ - core::{operations::background_syncing::BackgroundSyncStatus, Bip44, WalletData, WalletInner}, + core::{operations::background_syncing::BackgroundSyncStatus, SecretData, WalletData, WalletInner}, operations::syncing::SyncOptions, ClientOptions, Wallet, }, }; /// Builder for the wallet. -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Default)] #[serde(rename_all = "camelCase")] -pub struct WalletBuilder { - pub(crate) bip_path: Option, +pub struct WalletBuilder { + #[serde(flatten)] + pub(crate) secret_data: T, pub(crate) address: Option, pub(crate) alias: Option, pub(crate) client_options: Option, #[cfg(feature = "storage")] pub(crate) storage_options: Option, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SecretDataBuilder { + pub(crate) public_key_options: Option, + pub(crate) signing_options: Option, #[serde(skip)] pub(crate) secret_manager: Option>>, } -impl Default for WalletBuilder { +impl Default for SecretDataBuilder { fn default() -> Self { Self { - bip_path: Default::default(), - address: Default::default(), - alias: Default::default(), - client_options: Default::default(), - #[cfg(feature = "storage")] - storage_options: Default::default(), + public_key_options: Default::default(), + signing_options: Default::default(), secret_manager: Default::default(), } } } -impl WalletBuilder -where - crate::wallet::Error: From, -{ - /// Initialises a new instance of the wallet builder with the default storage adapter. - pub fn new() -> Self { - Self { - secret_manager: None, - ..Default::default() - } - } - - /// Set the BIP44 path of the wallet. - pub fn with_bip_path(mut self, bip_path: impl Into>) -> Self { - self.bip_path = bip_path.into(); - self - } - +impl WalletBuilder { /// Set the wallet address. pub fn with_address(mut self, address: impl Into>) -> Self { self.address = address.into(); @@ -97,39 +83,223 @@ where self } + /// Set the storage path to be used. + #[cfg(feature = "storage")] + #[cfg_attr(docsrs, doc(cfg(feature = "storage")))] + pub fn with_storage_path(mut self, path: impl Into) -> Self { + self.storage_options = Some(StorageOptions { + path: path.into(), + ..Default::default() + }); + self + } +} + +impl WalletBuilder { + /// Initialises a new instance of the wallet builder with the default storage adapter. + pub fn new() -> Self { + Self::default() + } + + pub fn with_secret_type(self) -> WalletBuilder> { + WalletBuilder { + secret_data: Default::default(), + address: self.address, + alias: self.alias, + client_options: self.client_options, + #[cfg(feature = "storage")] + storage_options: self.storage_options, + } + } + + /// Set the public key options. + pub fn with_public_key_options( + self, + public_key_options: impl Into>, + ) -> WalletBuilder> { + self.with_secret_type::().with_public_key_options(public_key_options) + } + + /// Set the signing options. + pub fn with_signing_options( + self, + signing_options: impl Into>, + ) -> WalletBuilder> { + self.with_secret_type::().with_signing_options(signing_options) + } + + /// Set the secret_manager to be used. + pub fn with_secret_manager( + self, + secret_manager: impl Into>, + ) -> WalletBuilder> { + self.with_secret_type::().with_secret_manager(secret_manager) + } + + /// Set the secret_manager to be used wrapped in an Arc> so it can be cloned and mutated also outside of + /// the Wallet. + pub fn with_secret_manager_arc( + self, + secret_manager: impl Into>>>, + ) -> WalletBuilder> { + self.with_secret_type::().with_secret_manager_arc(secret_manager) + } +} + +impl WalletBuilder> { + /// Set the public key options. + pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { + self.secret_data.public_key_options = public_key_options.into(); + self + } + + /// Set the signing options. + pub fn with_signing_options(mut self, signing_options: impl Into>) -> Self { + self.secret_data.signing_options = signing_options.into(); + self + } + /// Set the secret_manager to be used. pub fn with_secret_manager(mut self, secret_manager: impl Into>) -> Self { - self.secret_manager = secret_manager.into().map(|sm| Arc::new(RwLock::new(sm))); + self.secret_data.secret_manager = secret_manager.into().map(|sm| Arc::new(RwLock::new(sm))); self } /// Set the secret_manager to be used wrapped in an Arc> so it can be cloned and mutated also outside of /// the Wallet. pub fn with_secret_manager_arc(mut self, secret_manager: impl Into>>>) -> Self { - self.secret_manager = secret_manager.into(); + self.secret_data.secret_manager = secret_manager.into(); self } +} - /// Set the storage path to be used. - #[cfg(feature = "storage")] - #[cfg_attr(docsrs, doc(cfg(feature = "storage")))] - pub fn with_storage_path(mut self, path: impl Into) -> Self { - self.storage_options = Some(StorageOptions { - path: path.into(), - ..Default::default() - }); - self +impl WalletBuilder { + /// Builds the wallet. + pub async fn finish(mut self) -> crate::wallet::Result { + log::debug!("[WalletBuilder]"); + + #[cfg(feature = "storage")] + let storage_options = self.storage_options.clone().unwrap_or_default(); + // Check if the db exists and if not, return an error if one parameter is missing, because otherwise the db + // would be created with an empty parameter which just leads to errors later + #[cfg(feature = "storage")] + if !storage_options.path.is_dir() && self.client_options.is_none() { + return Err(crate::wallet::Error::MissingParameter("client_options")); + } + + #[cfg(all(feature = "rocksdb", feature = "storage"))] + let storage = + crate::wallet::storage::adapter::rocksdb::RocksdbStorageAdapter::new(storage_options.path.clone())?; + #[cfg(all(not(feature = "rocksdb"), feature = "storage"))] + let storage = Memory::default(); + + #[cfg(feature = "storage")] + let storage_manager = StorageManager::new(storage, storage_options.encryption_key.clone()).await?; + + #[cfg(feature = "storage")] + let loaded_wallet_builder = Self::load::<()>(&storage_manager).await?; + #[cfg(not(feature = "storage"))] + let loaded_wallet_builder: Option = None; + + // May use a previously stored client options if those weren't provided + let provided_client_options = if self.client_options.is_none() { + let loaded_client_options = loaded_wallet_builder + .as_ref() + .and_then(|data| data.client_options.clone()) + .ok_or(crate::wallet::Error::MissingParameter("client_options"))?; + + // Update self so it gets used and stored again + self.client_options = Some(loaded_client_options); + false + } else { + true + }; + + // May use a previously stored wallet alias if it wasn't provided + if self.alias.is_none() { + self.alias = loaded_wallet_builder.as_ref().and_then(|builder| builder.alias.clone()); + } + + // May use a previously stored wallet address if it wasn't provided + if self.address.is_none() { + self.address = loaded_wallet_builder + .as_ref() + .and_then(|builder| builder.address.clone()); + } + + let address = self + .address + .as_ref() + .ok_or(crate::wallet::Error::MissingParameter("address"))? + .clone(); + + #[cfg(feature = "storage")] + let mut wallet_data = storage_manager.load_wallet_data().await?; + + // Store the wallet builder (for convenience reasons) + #[cfg(feature = "storage")] + self.save(&storage_manager).await?; + + // It happened that inputs got locked, the transaction failed, but they weren't unlocked again, so we do this + // here + #[cfg(feature = "storage")] + if let Some(wallet_data) = &mut wallet_data { + unlock_unused_inputs(wallet_data)?; + } + + // Create the node client. + let client = self + .client_options + .clone() + .ok_or(crate::wallet::Error::MissingParameter("client_options"))? + .finish() + .await?; + + let background_syncing_status = tokio::sync::watch::channel(BackgroundSyncStatus::Stopped); + let background_syncing_status = (Arc::new(background_syncing_status.0), background_syncing_status.1); + + // Build the wallet. + let wallet_inner = WalletInner { + default_sync_options: Mutex::new(SyncOptions::default()), + last_synced: Mutex::new(0), + background_syncing_status, + client, + #[cfg(feature = "events")] + event_emitter: tokio::sync::RwLock::new(EventEmitter::new()), + #[cfg(feature = "storage")] + storage_options, + #[cfg(feature = "storage")] + storage_manager, + }; + #[cfg(feature = "storage")] + let wallet_data = match wallet_data { + Some(d) => d, + None => WalletData::new(address, self.alias.clone()), + }; + #[cfg(not(feature = "storage"))] + let wallet_data = WalletData::new(address, self.alias.clone()); + let wallet = Wallet { + inner: Arc::new(wallet_inner), + data: Arc::new(RwLock::new(wallet_data)), + secret_data: (), + }; + + // If the wallet builder is not set, it means the user provided it and we need to update the addresses. + // In the other case it was loaded from the database and addresses are up to date. + if provided_client_options { + wallet.update_bech32_hrp().await?; + } + + Ok(wallet) } } -impl WalletBuilder +impl WalletBuilder> where - crate::wallet::Error: From, - crate::client::Error: From, - Self: SaveLoadWallet, + for<'a> &'a S::GenerationOptions: PartialEq, { /// Builds the wallet. - pub async fn finish(mut self) -> crate::wallet::Result> { + pub async fn finish(mut self) -> crate::wallet::Result>> { log::debug!("[WalletBuilder]"); #[cfg(feature = "storage")] @@ -151,7 +321,7 @@ where let storage_manager = StorageManager::new(storage, storage_options.encryption_key.clone()).await?; #[cfg(feature = "storage")] - let loaded_wallet_builder = Self::load(&storage_manager).await?; + let loaded_wallet_builder = Self::load::>(&storage_manager).await?; #[cfg(not(feature = "storage"))] let loaded_wallet_builder: Option = None; @@ -169,18 +339,35 @@ where true }; - // May use a previously stored secret manager if it wasn't provided - if self.secret_manager.is_none() { - let secret_manager = loaded_wallet_builder + // May use previously stored options if they weren't provided + if self.secret_data.public_key_options.is_none() { + self.secret_data.public_key_options = loaded_wallet_builder .as_ref() - .and_then(|builder| builder.secret_manager.clone()); + .and_then(|builder| builder.secret_data.public_key_options.clone()); + } - self.secret_manager = secret_manager; + // The public key options must not change. + #[cfg(feature = "storage")] + if let Some(secret_data) = loaded_wallet_builder.as_ref().map(|b| &b.secret_data) { + if self.secret_data.public_key_options.is_some() { + if self.secret_data.public_key_options != secret_data.public_key_options { + return Err(crate::wallet::Error::PublicKeyOptionsMismatch { + new: serde_json::to_value(&self.secret_data.public_key_options)?, + old: serde_json::to_value(&secret_data.public_key_options)?, + }); + } + } else { + self.secret_data.public_key_options = secret_data.public_key_options.clone(); + } } - // May use a previously stored BIP path if it wasn't provided - if self.bip_path.is_none() { - self.bip_path = loaded_wallet_builder.as_ref().and_then(|builder| builder.bip_path); + // May use a previously stored secret manager if it wasn't provided + if self.secret_data.secret_manager.is_none() { + let secret_manager = loaded_wallet_builder + .as_ref() + .and_then(|builder| builder.secret_data.secret_manager.clone()); + + self.secret_data.secret_manager = secret_manager; } // May use a previously stored wallet alias if it wasn't provided @@ -197,7 +384,7 @@ where // May create a default Ed25519 wallet address if there's a secret manager. if self.address.is_none() { - if self.secret_manager.is_some() { + if self.secret_data.secret_manager.is_some() { let address = self.create_default_wallet_address().await?; self.address = Some(address); } else { @@ -210,23 +397,13 @@ where #[cfg(feature = "storage")] let mut wallet_data = storage_manager.load_wallet_data().await?; - // The bip path must not change. - #[cfg(feature = "storage")] - if let Some(wallet_data) = &wallet_data { - let new_bip_path = self.bip_path; - let old_bip_path = wallet_data.bip_path; - if new_bip_path != old_bip_path { - return Err(crate::wallet::Error::BipPathMismatch { - new_bip_path, - old_bip_path, - }); - } - } - // Store the wallet builder (for convenience reasons) #[cfg(feature = "storage")] self.save(&storage_manager).await?; + #[cfg(feature = "events")] + let event_emitter = tokio::sync::RwLock::new(EventEmitter::new()); + // It happened that inputs got locked, the transaction failed, but they weren't unlocked again, so we do this // here #[cfg(feature = "storage")] @@ -251,21 +428,38 @@ where last_synced: Mutex::new(0), background_syncing_status, client, - secret_manager: self.secret_manager.expect("make WalletInner::secret_manager optional?"), #[cfg(feature = "events")] - event_emitter: tokio::sync::RwLock::new(EventEmitter::new()), + event_emitter, #[cfg(feature = "storage")] storage_options, #[cfg(feature = "storage")] storage_manager, }; #[cfg(feature = "storage")] - let wallet_data = wallet_data.unwrap_or_else(|| WalletData::new(self.bip_path, address, self.alias.clone())); + let wallet_data = match wallet_data { + Some(d) => d, + None => WalletData::new(address, self.alias.clone()), + }; #[cfg(not(feature = "storage"))] - let wallet_data = WalletData::new(self.bip_path, address, self.alias.clone()); + let wallet_data = WalletData::new(address, self.alias.clone()); let wallet = Wallet { inner: Arc::new(wallet_inner), data: Arc::new(RwLock::new(wallet_data)), + secret_data: SecretData { + public_key_options: Arc::new(RwLock::new( + self.secret_data + .public_key_options + .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, + )), + signing_options: self + .secret_data + .signing_options + .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, + secret_manager: self + .secret_data + .secret_manager + .ok_or(crate::wallet::Error::MissingParameter("secret_manager"))?, + }, }; // If the wallet builder is not set, it means the user provided it and we need to update the addresses. @@ -286,39 +480,87 @@ where .network_info .protocol_parameters .bech32_hrp; - let bip_path = self.bip_path.as_ref().unwrap(); - - Ok(Bech32Address::new( - bech32_hrp, - Address::Ed25519( - self.secret_manager - .as_ref() - .unwrap() - .read() - .await - .generate_ed25519_addresses( - bip_path.coin_type, - bip_path.account, - bip_path.address_index..bip_path.address_index + 1, - GenerateAddressOptions { - internal: bip_path.change != 0, - ledger_nano_prompt: false, - }, - ) - .await?[0], - ), - )) + let options = self.secret_data.public_key_options.as_ref().unwrap(); + + Ok(Ed25519Address::from_public_key_bytes( + self.secret_data + .secret_manager + .as_ref() + .unwrap() + .read() + .await + .generate(options) + .await? + .to_bytes(), + ) + .to_bech32(bech32_hrp)) } +} +impl WalletBuilder { #[cfg(feature = "storage")] - pub(crate) async fn from_wallet(wallet: &Wallet) -> Self { - Self { - bip_path: wallet.bip_path().await, - address: Some(wallet.address().await), - alias: wallet.alias().await, - client_options: Some(wallet.client_options().await), - storage_options: Some(wallet.storage_options.clone()), - secret_manager: Some(wallet.secret_manager.clone()), + pub(crate) async fn from_wallet(wallet: &Wallet) -> Self + where + Wallet: BuilderFrom, + { + BuilderFrom::from(wallet).await + } +} + +#[async_trait::async_trait] +pub trait BuilderFrom { + type Builder; + + async fn from(&self) -> Self::Builder; +} + +mod builder_from { + use async_trait::async_trait; + + use super::BuilderFrom; + use crate::{ + client::secret::SecretManage, + wallet::{ + core::{builder::SecretDataBuilder, SecretData}, + Wallet, WalletBuilder, + }, + }; + + #[async_trait] + impl BuilderFrom for SecretData { + type Builder = SecretDataBuilder; + + async fn from(&self) -> Self::Builder { + Self::Builder { + public_key_options: Some(self.public_key_options.read().await.clone()), + signing_options: Some(self.signing_options.clone()), + secret_manager: Some(self.secret_manager.clone()), + } + } + } + + #[async_trait] + impl BuilderFrom for () { + type Builder = (); + + async fn from(&self) -> Self::Builder { + () + } + } + + #[async_trait] + impl BuilderFrom for Wallet { + type Builder = WalletBuilder; + + async fn from(&self) -> Self::Builder { + Self::Builder { + address: Some(self.address().await), + alias: self.alias().await, + client_options: Some(self.client_options().await), + #[cfg(feature = "storage")] + storage_options: Some(self.storage_options.clone()), + secret_data: BuilderFrom::from(&self.secret_data).await, + } } } } @@ -356,9 +598,9 @@ pub(crate) mod dto { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] - pub struct WalletBuilderDto { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub(crate) bip_path: Option, + pub struct WalletBuilderDto { + #[serde(flatten)] + secret_data: T, #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) address: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -370,26 +612,57 @@ pub(crate) mod dto { pub(crate) storage_options: Option, } - impl From for WalletBuilder { - fn from(value: WalletBuilderDto) -> Self { + #[derive(Debug, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct SecretDataDto { + #[serde(default = "Option::default", skip_serializing_if = "Option::is_none")] + pub(crate) public_key_options: Option, + #[serde(default = "Option::default", skip_serializing_if = "Option::is_none")] + pub(crate) signing_options: Option, + } + + impl From> for SecretDataBuilder { + fn from(value: SecretDataDto) -> Self { Self { - bip_path: value.bip_path, + public_key_options: value.public_key_options, + signing_options: value.signing_options, + secret_manager: None, + } + } + } + + impl, T2> From> for WalletBuilder { + fn from(value: WalletBuilderDto) -> Self { + Self { + secret_data: value.secret_data.into(), address: value.address, alias: value.alias, client_options: value.client_options, #[cfg(feature = "storage")] storage_options: value.storage_options, - secret_manager: None, } } } - impl<'de, S: SecretManage> Deserialize<'de> for WalletBuilder { + impl<'de, S: SecretManage> Deserialize<'de> for SecretDataBuilder + where + S::GenerationOptions: Deserialize<'de>, + S::SigningOptions: Deserialize<'de>, + { + fn deserialize(d: D) -> Result + where + D: serde::Deserializer<'de>, + { + SecretDataDto::::deserialize(d).map(Into::into) + } + } + + impl<'de, T: Deserialize<'de>> Deserialize<'de> for WalletBuilder { fn deserialize(d: D) -> Result where D: serde::Deserializer<'de>, { - WalletBuilderDto::deserialize(d).map(Into::into) + WalletBuilderDto::::deserialize(d).map(Into::into) } } } diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 59f5b92e1d..87338dfd6b 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -9,10 +9,7 @@ use std::{ sync::Arc, }; -use crypto::keys::{ - bip39::{Mnemonic, MnemonicRef}, - bip44::Bip44, -}; +use crypto::keys::bip39::{Mnemonic, MnemonicRef}; use serde::{Deserialize, Serialize}; use tokio::sync::{Mutex, RwLock}; @@ -27,10 +24,7 @@ use crate::wallet::events::{ #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::{ - secret::{SecretManage, SecretManager}, - verify_mnemonic, Client, - }, + client::{secret::SecretManage, verify_mnemonic, Client}, types::{ block::{ address::{Address, Bech32Address, Hrp, ImplicitAccountCreationAddress}, @@ -44,42 +38,50 @@ use crate::{ }; /// The stateful wallet used to interact with an IOTA network. -#[derive(Debug)] -pub struct Wallet { - pub(crate) inner: Arc>, +#[derive(Debug, Clone)] +pub struct Wallet { + pub(crate) inner: Arc, pub(crate) data: Arc>, + pub(crate) secret_data: T, +} + +#[derive(Debug)] +pub struct SecretData { + /// The public key generation options. + pub(crate) public_key_options: Arc>, + /// The signing options for transactions and blocks. + pub(crate) signing_options: S::SigningOptions, + pub(crate) secret_manager: Arc>, } -impl Clone for Wallet { +impl Clone for SecretData { fn clone(&self) -> Self { Self { - inner: self.inner.clone(), - data: self.data.clone(), + public_key_options: self.public_key_options.clone(), + signing_options: self.signing_options.clone(), + secret_manager: self.secret_manager.clone(), } } } -impl core::ops::Deref for Wallet { - type Target = WalletInner; +impl core::ops::Deref for Wallet { + type Target = WalletInner; fn deref(&self) -> &Self::Target { &self.inner } } -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Initialises the wallet builder. - pub fn builder() -> WalletBuilder { - WalletBuilder::::new() + pub fn builder() -> WalletBuilder { + WalletBuilder::new() } } /// Wallet inner. #[derive(Debug)] -pub struct WalletInner { +pub struct WalletInner { // mutex to prevent multiple sync calls at the same or almost the same time, the u128 is a timestamp // if the last synced time was < `MIN_SYNC_INTERVAL` second ago, we don't sync, but only calculate the balance // again, because sending transactions can change that @@ -90,8 +92,6 @@ pub struct WalletInner { tokio::sync::watch::Receiver, ), pub(crate) client: Client, - // TODO: make this optional? - pub(crate) secret_manager: Arc>, #[cfg(feature = "events")] pub(crate) event_emitter: tokio::sync::RwLock, #[cfg(feature = "storage")] @@ -101,10 +101,8 @@ pub struct WalletInner { } /// Wallet data. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct WalletData { - /// The wallet BIP44 path. - pub(crate) bip_path: Option, /// The wallet address. pub(crate) address: Bech32Address, /// The wallet alias. @@ -138,9 +136,8 @@ pub struct WalletData { } impl WalletData { - pub(crate) fn new(bip_path: Option, address: Bech32Address, alias: Option) -> Self { + pub(crate) fn new(address: Bech32Address, alias: Option) -> Self { Self { - bip_path, address, alias, outputs: HashMap::new(), @@ -355,13 +352,9 @@ impl WalletData { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Create a new wallet. - pub(crate) async fn new(inner: Arc>, data: WalletData) -> Result { + pub(crate) async fn new(inner: Arc, data: WalletData, secret_data: T) -> Result { #[cfg(feature = "storage")] let default_sync_options = inner .storage_manager @@ -382,6 +375,7 @@ where Ok(Self { inner, data: Arc::new(RwLock::new(data)), + secret_data, }) } @@ -451,19 +445,24 @@ where pub async fn bech32_hrp(&self) -> Hrp { self.data().await.address.hrp } +} - /// Get the wallet's configured bip path. - pub async fn bip_path(&self) -> Option { - self.data().await.bip_path +impl Wallet> { + /// Gets the secret manager. + pub fn secret_manager(&self) -> &Arc> { + &self.secret_data.secret_manager } -} -impl WalletInner { - /// Get the [SecretManager] - pub fn get_secret_manager(&self) -> &Arc> { - &self.secret_manager + pub async fn public_key_options(&self) -> S::GenerationOptions { + self.secret_data.public_key_options.read().await.clone() } + pub fn signing_options(&self) -> &S::SigningOptions { + &self.secret_data.signing_options + } +} + +impl WalletInner { /// Listen to wallet events, empty vec will listen to all events #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] @@ -511,23 +510,10 @@ impl WalletInner { } } -impl Drop for Wallet { - fn drop(&mut self) { - log::debug!("drop Wallet"); - } -} - -impl Drop for WalletInner { - fn drop(&mut self) { - log::debug!("drop WalletInner"); - } -} - /// Dto for the wallet data. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WalletDataDto { - pub bip_path: Option, pub address: Bech32Address, pub alias: Option, pub outputs: HashMap, @@ -548,7 +534,6 @@ impl TryFromDto for WalletData { params: Option<&ProtocolParameters>, ) -> core::result::Result { Ok(Self { - bip_path: dto.bip_path, address: dto.address, alias: dto.alias, outputs: dto.outputs, @@ -574,7 +559,6 @@ impl TryFromDto for WalletData { impl From<&WalletData> for WalletDataDto { fn from(value: &WalletData) -> Self { Self { - bip_path: value.bip_path, address: value.address.clone(), alias: value.alias.clone(), outputs: value.outputs.clone(), @@ -596,6 +580,22 @@ impl From<&WalletData> for WalletDataDto { } } +pub trait OptionalSecretManager { + fn secret_manager_opt(&self) -> Option<&Arc>>; +} + +impl OptionalSecretManager for Wallet<()> { + fn secret_manager_opt(&self) -> Option<&Arc>> { + None + } +} + +impl OptionalSecretManager for Wallet> { + fn secret_manager_opt(&self) -> Option<&Arc>> { + Some(self.secret_manager()) + } +} + #[cfg(test)] mod test { use core::str::FromStr; @@ -687,7 +687,6 @@ mod test { ); let wallet_data = WalletData { - bip_path: Some(Bip44::new(4218)), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", ) @@ -720,7 +719,6 @@ mod test { #[cfg(feature = "storage")] pub(crate) fn mock() -> Self { Self { - bip_path: Some(Bip44::new(4218)), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", ) diff --git a/sdk/src/wallet/core/operations/address_generation.rs b/sdk/src/wallet/core/operations/address_generation.rs index 50427dd324..633c01192d 100644 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ b/sdk/src/wallet/core/operations/address_generation.rs @@ -1,92 +1,91 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crate::{ - client::secret::{GenerateAddressOptions, SecretManage, SecretManager}, - types::block::address::Ed25519Address, - wallet::{Error, Wallet}, -}; -#[cfg(all(feature = "events", feature = "ledger_nano"))] -use crate::{ - types::block::address::ToBech32Ext, - wallet::events::types::{AddressData, WalletEvent}, -}; +// use crate::{ +// client::secret::{Generate, SecretManage, SecretManager}, +// types::block::address::Ed25519Address, +// wallet::{Error, Wallet}, +// }; +// #[cfg(all(feature = "events", feature = "ledger_nano"))] +// use crate::{ +// types::block::address::ToBech32Ext, +// wallet::events::types::{AddressData, WalletEvent}, +// }; -impl Wallet { - /// Generate an address without storing it - /// ```ignore - /// let public_addresses = wallet - /// .generate_ed25519_address(None) - /// .await?; - /// ``` - pub async fn generate_ed25519_address( - &self, - account_index: u32, - address_index: u32, - options: impl Into> + Send, - ) -> crate::wallet::Result { - // TODO #1279: not sure yet whether we also should allow this method to generate addresses for different bip - // paths. - let coin_type = self.bip_path().await.ok_or(Error::MissingBipPath)?.coin_type; +// impl Wallet { +// /// Generate an address without storing it +// /// ```ignore +// /// let public_addresses = wallet +// /// .generate_ed25519_address(None) +// /// .await?; +// /// ``` +// pub async fn generate_ed25519_address( +// &self, +// account_index: u32, +// address_index: u32, +// options: &S::GenerationOptions, +// ) -> crate::wallet::Result { // TODO #1279: not sure yet whether we also should allow this method +// to generate addresses for different bip // paths. let coin_type = +// self.bip_path().await.ok_or(Error::MissingBipPath)?.coin_type; - let address = match &*self.secret_manager.read().await { - #[cfg(feature = "ledger_nano")] - SecretManager::LedgerNano(ledger_nano) => { - // If we don't sync, then we want to display the prompt on the ledger with the address. But the user - // needs to have it visible on the computer first, so we need to generate it without the - // prompt first - let options = options.into(); - #[cfg(feature = "events")] - if options.as_ref().map_or(false, |o| o.ledger_nano_prompt) { - let changed_options = options.map(|mut options| { - // Change options so ledger will not show the prompt the first time - options.ledger_nano_prompt = false; - options - }); - // Generate without prompt to be able to display it - let address = ledger_nano - .generate_ed25519_addresses( - coin_type, - account_index, - address_index..address_index + 1, - changed_options, - ) - .await?; +// let address = match &*self.secret_manager.read().await { +// #[cfg(feature = "ledger_nano")] +// SecretManager::LedgerNano(ledger_nano) => { +// // If we don't sync, then we want to display the prompt on the ledger with the address. But the user +// // needs to have it visible on the computer first, so we need to generate it without the +// // prompt first +// let options = options.into(); +// #[cfg(feature = "events")] +// if options.as_ref().map_or(false, |o| o.ledger_nano_prompt) { +// let changed_options = options.map(|mut options| { +// // Change options so ledger will not show the prompt the first time +// options.ledger_nano_prompt = false; +// options +// }); +// // Generate without prompt to be able to display it +// let address = ledger_nano +// .generate_ed25519_addresses( +// coin_type, +// account_index, +// address_index..address_index + 1, +// changed_options, +// ) +// .await?; - let bech32_hrp = self.bech32_hrp().await; +// let bech32_hrp = self.bech32_hrp().await; - self.emit(WalletEvent::LedgerAddressGeneration(AddressData { - address: address[0].to_bech32(bech32_hrp), - })) - .await; - } - // Generate with prompt so the user can verify - ledger_nano - .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) - .await? - } - #[cfg(feature = "stronghold")] - SecretManager::Stronghold(stronghold) => { - stronghold - .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) - .await? - } - SecretManager::Mnemonic(mnemonic) => { - mnemonic - .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) - .await? - } - #[cfg(feature = "private_key_secret_manager")] - SecretManager::PrivateKey(private_key) => { - private_key - .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) - .await? - } - SecretManager::Placeholder => return Err(crate::client::Error::PlaceholderSecretManager.into()), - }; +// self.emit(WalletEvent::LedgerAddressGeneration(AddressData { +// address: address[0].to_bech32(bech32_hrp), +// })) +// .await; +// } +// // Generate with prompt so the user can verify +// ledger_nano +// .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) +// .await? +// } +// #[cfg(feature = "stronghold")] +// SecretManager::Stronghold(stronghold) => { +// stronghold +// .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) +// .await? +// } +// SecretManager::Mnemonic(mnemonic) => { +// mnemonic +// .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) +// .await? +// } +// #[cfg(feature = "private_key_secret_manager")] +// SecretManager::PrivateKey(private_key) => { +// private_key +// .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) +// .await? +// } +// SecretManager::Placeholder => return Err(crate::client::Error::PlaceholderSecretManager.into()), +// }; - Ok(*address - .first() - .ok_or(crate::wallet::Error::MissingParameter("address"))?) - } -} +// Ok(*address +// .first() +// .ok_or(crate::wallet::Error::MissingParameter("address"))?) +// } +// } diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index 7328441fef..db835d9f10 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -5,10 +5,7 @@ use std::time::Duration; use tokio::time::timeout; -use crate::{ - client::secret::SecretManage, - wallet::{operations::syncing::SyncOptions, task, Wallet}, -}; +use crate::wallet::{operations::syncing::SyncOptions, task, Wallet}; /// The default interval for background syncing pub(crate) const DEFAULT_BACKGROUNDSYNCING_INTERVAL: Duration = Duration::from_secs(7); @@ -20,11 +17,7 @@ pub(crate) enum BackgroundSyncStatus { Stopping, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Start the background syncing process for the wallet, default interval is 7 seconds pub async fn start_background_syncing( &self, diff --git a/sdk/src/wallet/core/operations/client.rs b/sdk/src/wallet/core/operations/client.rs index bece74f09a..b594c51769 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -3,22 +3,21 @@ use std::collections::{HashMap, HashSet}; +use serde::Serialize; use url::Url; -use super::storage::SaveLoadWallet; use crate::{ client::{ node_manager::{ builder::NodeManagerBuilder, node::{Node, NodeAuth, NodeDto}, }, - secret::SecretManage, Client, ClientBuilder, }, - wallet::{Wallet, WalletBuilder}, + wallet::{core::builder::BuilderFrom, Wallet, WalletBuilder}, }; -impl Wallet { +impl Wallet { pub fn client(&self) -> &Client { &self.client } @@ -28,11 +27,9 @@ impl Wallet { } } -impl Wallet +impl Wallet where - crate::client::Error: From, - crate::wallet::Error: From, - WalletBuilder: SaveLoadWallet, + T::Builder: Send + Sync + Serialize, { pub async fn set_client_options(&self, client_options: ClientBuilder) -> crate::wallet::Result<()> { let ClientBuilder { diff --git a/sdk/src/wallet/core/operations/ledger_nano.rs b/sdk/src/wallet/core/operations/ledger_nano.rs deleted file mode 100644 index 8d1beeb028..0000000000 --- a/sdk/src/wallet/core/operations/ledger_nano.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2022 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use crate::{ - client::secret::{ledger_nano::LedgerSecretManager, LedgerNanoStatus, SecretManager}, - wallet::Wallet, -}; - -impl Wallet { - /// Get the ledger nano status - pub async fn get_ledger_nano_status(&self) -> crate::wallet::Result { - Ok(self.secret_manager.read().await.get_ledger_nano_status().await) - } -} - -impl Wallet { - /// Get the ledger nano status - pub async fn get_ledger_nano_status(&self) -> crate::wallet::Result { - if let SecretManager::LedgerNano(ledger) = &*self.secret_manager.read().await { - Ok(ledger.get_ledger_nano_status().await) - } else { - Err(crate::client::Error::SecretManagerMismatch.into()) - } - } -} diff --git a/sdk/src/wallet/core/operations/mod.rs b/sdk/src/wallet/core/operations/mod.rs index e01ca173a6..4de64e5317 100644 --- a/sdk/src/wallet/core/operations/mod.rs +++ b/sdk/src/wallet/core/operations/mod.rs @@ -4,8 +4,7 @@ pub(crate) mod address_generation; pub(crate) mod background_syncing; pub(crate) mod client; -#[cfg(feature = "ledger_nano")] -pub(crate) mod ledger_nano; +#[cfg(feature = "storage")] pub(crate) mod storage; #[cfg(feature = "stronghold")] pub(crate) mod stronghold; diff --git a/sdk/src/wallet/core/operations/storage.rs b/sdk/src/wallet/core/operations/storage.rs index 7ccbc935de..b0036ce8e8 100644 --- a/sdk/src/wallet/core/operations/storage.rs +++ b/sdk/src/wallet/core/operations/storage.rs @@ -1,92 +1,36 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "storage")] -mod storage_stub { - use async_trait::async_trait; - - use crate::{ - client::{ - secret::{mnemonic::MnemonicSecretManager, SecretManagerConfig}, - storage::StorageAdapter, - }, - wallet::{ - core::builder::dto::WalletBuilderDto, - storage::constants::{SECRET_MANAGER_KEY, WALLET_BUILDER_KEY}, - WalletBuilder, - }, - }; - - #[async_trait] - pub trait SaveLoadWallet { - async fn save(&self, storage: &impl StorageAdapter) -> crate::wallet::Result<()>; - - async fn load( - storage: &impl StorageAdapter, - ) -> crate::wallet::Result> - where - Self: Sized; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::{ + client::storage::StorageAdapter, + wallet::{core::builder::dto::WalletBuilderDto, storage::constants::WALLET_BUILDER_KEY, WalletBuilder}, +}; + +impl WalletBuilder { + pub(crate) async fn save( + &self, + storage: &impl StorageAdapter, + ) -> crate::wallet::Result<()> { + log::debug!("[save] wallet builder"); + storage.set(WALLET_BUILDER_KEY, self).await?; + Ok(()) } - #[async_trait] - impl SaveLoadWallet for WalletBuilder + pub(crate) async fn load( + storage: &impl StorageAdapter, + ) -> crate::wallet::Result> where - crate::wallet::Error: From, + T: From, { - async fn save(&self, storage: &impl StorageAdapter) -> crate::wallet::Result<()> { - log::debug!("[save] wallet builder"); - storage.set(WALLET_BUILDER_KEY, self).await?; - - if let Some(secret_manager) = &self.secret_manager { - let secret_manager = secret_manager.read().await; - if let Some(config) = secret_manager.to_config() { - log::debug!("[save] secret manager: {config:?}"); - storage.set(SECRET_MANAGER_KEY, &config).await?; - } - } - Ok(()) - } - - async fn load( - storage: &impl StorageAdapter, - ) -> crate::wallet::Result> { - log::debug!("[load] wallet builder"); - if let Some(wallet_builder_dto) = storage.get::(WALLET_BUILDER_KEY).await? { - log::debug!("[load] wallet builder dto: {wallet_builder_dto:?}"); - - let secret_manager_dto = storage.get(SECRET_MANAGER_KEY).await?; - log::debug!("[load] secret manager dto: {secret_manager_dto:?}"); + log::debug!("[load] wallet builder"); + if let Some(wallet_builder_dto) = storage.get::>(WALLET_BUILDER_KEY).await? { + log::debug!("[load] wallet builder dto: {wallet_builder_dto:?}"); - Ok(Some(Self::from(wallet_builder_dto).with_secret_manager( - secret_manager_dto.map(|dto| S::from_config(&dto)).transpose()?, - ))) - } else { - Ok(None) - } + Ok(Some(Self::from(wallet_builder_dto))) + } else { + Ok(None) } } - - #[async_trait] - impl SaveLoadWallet for WalletBuilder { - async fn save(&self, storage: &impl StorageAdapter) -> crate::wallet::Result<()> { - log::debug!("[save] wallet builder"); - storage.set(WALLET_BUILDER_KEY, self).await?; - Ok(()) - } - - async fn load( - storage: &impl StorageAdapter, - ) -> crate::wallet::Result> { - log::debug!("[load] wallet builder"); - let res = storage.get::(WALLET_BUILDER_KEY).await?; - log::debug!("[load] wallet builder: {res:?}"); - Ok(res.map(Into::into)) - } - } -} -#[cfg(not(feature = "storage"))] -mod storage_stub { - pub trait SaveLoadWallet {} - impl SaveLoadWallet for T {} } -pub(crate) use storage_stub::*; diff --git a/sdk/src/wallet/core/operations/stronghold.rs b/sdk/src/wallet/core/operations/stronghold.rs index d3c72db45c..1b634f5ed3 100644 --- a/sdk/src/wallet/core/operations/stronghold.rs +++ b/sdk/src/wallet/core/operations/stronghold.rs @@ -7,15 +7,16 @@ use crypto::keys::bip39::Mnemonic; use crate::{ client::{secret::SecretManager, stronghold::StrongholdAdapter, utils::Password}, - wallet::Wallet, + wallet::{core::SecretData, Wallet}, }; -impl Wallet { +// TODO: Remove these and just use the secret manager directly +impl Wallet> { /// Sets the Stronghold password pub async fn set_stronghold_password(&self, password: impl Into + Send) -> crate::wallet::Result<()> { let password = password.into(); - if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager().write().await { stronghold.set_password(password).await?; Ok(()) } else { @@ -32,7 +33,7 @@ impl Wallet { let current_password = current_password.into(); let new_password = new_password.into(); - if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager().write().await { stronghold.set_password(current_password).await?; stronghold.change_password(new_password).await?; Ok(()) @@ -43,7 +44,7 @@ impl Wallet { /// Sets the Stronghold password clear interval pub async fn set_stronghold_password_clear_interval(&self, timeout: Option) -> crate::wallet::Result<()> { - if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager().write().await { stronghold.set_timeout(timeout).await; Ok(()) } else { @@ -53,7 +54,7 @@ impl Wallet { /// Stores a mnemonic into the Stronghold vault pub async fn store_mnemonic(&self, mnemonic: Mnemonic) -> crate::wallet::Result<()> { - if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager().write().await { stronghold.store_mnemonic(mnemonic).await?; Ok(()) } else { @@ -64,7 +65,7 @@ impl Wallet { /// Clears the Stronghold password from memory. pub async fn clear_stronghold_password(&self) -> crate::wallet::Result<()> { log::debug!("[clear_stronghold_password]"); - if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &mut *self.secret_manager().write().await { stronghold.clear_key().await; Ok(()) } else { @@ -75,7 +76,7 @@ impl Wallet { /// Checks if the Stronghold password is available. pub async fn is_stronghold_password_available(&self) -> crate::wallet::Result { log::debug!("[is_stronghold_password_available]"); - if let SecretManager::Stronghold(stronghold) = &*self.secret_manager.write().await { + if let SecretManager::Stronghold(stronghold) = &*self.secret_manager().write().await { Ok(stronghold.is_key_available().await) } else { Err(crate::client::Error::SecretManagerMismatch.into()) @@ -83,10 +84,10 @@ impl Wallet { } } -impl Wallet { +impl Wallet> { /// Sets the Stronghold password pub async fn set_stronghold_password(&self, password: impl Into + Send) -> crate::wallet::Result<()> { - Ok(self.secret_manager.write().await.set_password(password).await?) + Ok(self.secret_manager().write().await.set_password(password).await?) } /// Change the Stronghold password to another one and also re-encrypt the values in the loaded snapshot with it. @@ -95,7 +96,7 @@ impl Wallet { current_password: impl Into + Send, new_password: impl Into + Send, ) -> crate::wallet::Result<()> { - let stronghold = &mut *self.secret_manager.write().await; + let stronghold = &mut *self.secret_manager().write().await; stronghold.set_password(current_password).await?; stronghold.change_password(new_password).await?; Ok(()) @@ -103,25 +104,25 @@ impl Wallet { /// Sets the Stronghold password clear interval pub async fn set_stronghold_password_clear_interval(&self, timeout: Option) -> crate::wallet::Result<()> { - self.secret_manager.write().await.set_timeout(timeout).await; + self.secret_manager().write().await.set_timeout(timeout).await; Ok(()) } /// Stores a mnemonic into the Stronghold vault pub async fn store_mnemonic(&self, mnemonic: Mnemonic) -> crate::wallet::Result<()> { - Ok(self.secret_manager.write().await.store_mnemonic(mnemonic).await?) + Ok(self.secret_manager().write().await.store_mnemonic(mnemonic).await?) } /// Clears the Stronghold password from memory. pub async fn clear_stronghold_password(&self) -> crate::wallet::Result<()> { log::debug!("[clear_stronghold_password]"); - self.secret_manager.write().await.clear_key().await; + self.secret_manager().write().await.clear_key().await; Ok(()) } /// Checks if the Stronghold password is available. pub async fn is_stronghold_password_available(&self) -> crate::wallet::Result { log::debug!("[is_stronghold_password_available]"); - Ok(self.secret_manager.write().await.is_key_available().await) + Ok(self.secret_manager().write().await.is_key_available().await) } } diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index 3435397b5e..a82cd1befa 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -10,14 +10,14 @@ use self::stronghold_snapshot::read_wallet_data_from_stronghold_snapshot; use crate::wallet::WalletBuilder; use crate::{ client::{ - secret::{stronghold::StrongholdSecretManager, SecretManager, SecretManagerConfig, SecretManagerDto}, + secret::{stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManagerConfig}, utils::Password, }, types::block::address::Hrp, - wallet::Wallet, + wallet::{core::SecretData, Wallet}, }; -impl Wallet { +impl Wallet> { /// Backup the wallet data in a Stronghold file. /// `stronghold_password` must be the current one when Stronghold is used as SecretManager. pub async fn backup( @@ -28,11 +28,11 @@ impl Wallet { let stronghold_password = stronghold_password.into(); log::debug!("[backup] creating a stronghold backup"); - let secret_manager = self.secret_manager.read().await; + let secret_manager = self.secret_manager().read().await; - match &*secret_manager { + match (&*secret_manager).as_stronghold() { // Backup with existing stronghold - SecretManager::Stronghold(stronghold) => { + Ok(stronghold) => { stronghold.set_password(stronghold_password).await?; self.store_data_to_stronghold(stronghold).await?; // Write snapshot to backup path @@ -88,8 +88,6 @@ impl Wallet { )); } - let curr_bip_path = wallet_data.bip_path; - // Explicitly drop the data to avoid contention drop(wallet_data); @@ -98,49 +96,56 @@ impl Wallet { .password(stronghold_password.clone()) .build(backup_path.clone())?; - let (read_client_options, read_secret_manager, read_wallet_data) = - read_wallet_data_from_stronghold_snapshot::(&new_stronghold).await?; + let (loaded_client_options, loaded_secret_manager_config, loaded_wallet_data, loaded_secret_data) = + read_wallet_data_from_stronghold_snapshot::(&new_stronghold).await?; - let read_bip_path = read_wallet_data.as_ref().and_then(|data| data.bip_path); + let loaded_pub_key_opts = loaded_secret_data.map(|data| { + std::sync::Arc::into_inner(data.public_key_options) + .unwrap() + .into_inner() + }); // If the bip path is not matching the current one, we may ignore the backup - let ignore_backup_values = ignore_if_bip_path_mismatch.map_or(false, |ignore| { - if ignore { - // TODO: #1279 okay that if both are none we always load the backup values? - curr_bip_path != read_bip_path + let ignore_backup_values = if matches!(ignore_if_bip_path_mismatch, Some(ignore) if ignore) { + // TODO: #1279 okay that if both are none we always load the backup values? + if let Some(opts) = &loaded_pub_key_opts { + &self.public_key_options().await != opts } else { false } - }); + } else { + false + }; if !ignore_backup_values { - self.data_mut().await.bip_path = read_bip_path; + if let Some(opts) = loaded_pub_key_opts { + *self.secret_data.public_key_options.write().await = opts; + } } // Get the current snapshot path if set - let new_snapshot_path = if let SecretManager::Stronghold(stronghold) = &*self.secret_manager.read().await { + let new_snapshot_path = if let Ok(stronghold) = (&*self.secret_manager().read().await).as_stronghold() { stronghold.snapshot_path.clone() } else { PathBuf::from("wallet.stronghold") }; - if let Some(mut read_secret_manager) = read_secret_manager { + if let Some(config) = loaded_secret_manager_config { + let mut restored_secret_manager = + S::from_config(&config).map_err(|_| crate::wallet::Error::Backup("invalid secret_manager"))?; // We have to replace the snapshot path with the current one, when building stronghold - if let SecretManagerDto::Stronghold(stronghold_dto) = &mut read_secret_manager { - stronghold_dto.snapshot_path = new_snapshot_path.display().to_string(); + if let Ok(stronghold_dto) = restored_secret_manager.as_stronghold_mut() { + stronghold_dto.snapshot_path = new_snapshot_path.clone(); } - let restored_secret_manager = SecretManager::from_config(&read_secret_manager) - .map_err(|_| crate::wallet::Error::Backup("invalid secret_manager"))?; - // Copy Stronghold file so the seed is available in the new location fs::copy(backup_path, new_snapshot_path)?; - if let SecretManager::Stronghold(stronghold) = &restored_secret_manager { + if let Ok(stronghold) = restored_secret_manager.as_stronghold() { // Set password to restored secret manager stronghold.set_password(stronghold_password).await?; } - *self.secret_manager.write().await = restored_secret_manager; + *self.secret_manager().write().await = restored_secret_manager; } else { // If no secret manager data was in the backup, just copy the Stronghold file so the seed is available in // the new location. @@ -148,162 +153,13 @@ impl Wallet { } if ignore_if_bip_path_mismatch.is_none() { - if let Some(read_client_options) = read_client_options { - self.set_client_options(read_client_options).await?; - } - } - - if !ignore_backup_values { - if let Some(read_wallet_data) = read_wallet_data { - let restore_wallet = ignore_if_bech32_hrp_mismatch.map_or(true, |expected_bech32_hrp| { - // Only restore if bech32 hrps match - read_wallet_data.address.hrp() == &expected_bech32_hrp - }); - - if restore_wallet { - *self.data_mut().await = read_wallet_data; - } - } - } - - // store new data - #[cfg(feature = "storage")] - { - use crate::wallet::core::operations::storage::SaveLoadWallet; - let wallet_builder = WalletBuilder::new() - .with_secret_manager_arc(self.secret_manager.clone()) - .with_storage_path( - &self - .storage_options - .path - .clone() - .into_os_string() - .into_string() - .expect("can't convert os string"), - ) - .with_client_options(self.client_options().await) - .with_bip_path(self.data().await.bip_path); - - wallet_builder.save(self.storage_manager()).await?; - - // also save wallet data to db - self.storage_manager().save_wallet_data(&*self.data().await).await?; - } - - Ok(()) - } -} - -impl Wallet { - /// Backup the wallet data in a Stronghold file - /// stronghold_password must be the current one when Stronghold is used as SecretManager. - pub async fn backup( - &self, - backup_path: PathBuf, - stronghold_password: impl Into + Send, - ) -> crate::wallet::Result<()> { - log::debug!("[backup] creating a stronghold backup"); - let secret_manager = self.secret_manager.read().await; - - secret_manager.set_password(stronghold_password).await?; - - self.store_data_to_stronghold(&secret_manager).await?; - - // Write snapshot to backup path - secret_manager.write_stronghold_snapshot(Some(&backup_path)).await?; - - Ok(()) - } - - /// Restore a backup from a Stronghold file - /// Replaces client_options, bip path, secret_manager and wallet. Returns an error if the wallet was already - /// created If Stronghold is used as secret_manager, the existing Stronghold file will be overwritten. If a - /// mnemonic was stored, it will be gone. - /// if ignore_if_bip_path_mismatch.is_some(), client options will not be restored - /// if ignore_if_bip_path_mismatch == Some(true), client options bip path and wallet will not be restored if the - /// bip path doesn't match - /// If a bech32 hrp is provided to ignore_if_bech32_hrp_mismatch, that doesn't match the one of the current address, - /// the wallet will not be restored. - pub async fn restore_backup( - &self, - backup_path: PathBuf, - stronghold_password: impl Into + Send, - ignore_if_bip_path_mismatch: Option, - ignore_if_bech32_hrp_mismatch: Option, - ) -> crate::wallet::Result<()> { - let stronghold_password = stronghold_password.into(); - - log::debug!("[restore_backup] loading stronghold backup"); - - if !backup_path.is_file() { - return Err(crate::wallet::Error::Backup("backup path doesn't exist")); - } - - let wallet_data = self.data().await; - - // We don't want to overwrite a possible existing wallet - if !wallet_data.outputs.is_empty() { - return Err(crate::wallet::Error::Backup( - "can't restore backup when there is already a wallet", - )); - } - - let curr_bip_path = wallet_data.bip_path; - - // Explicitly drop the data to avoid contention - drop(wallet_data); - - // We'll create a new stronghold to load the backup - let new_stronghold = StrongholdSecretManager::builder() - .password(stronghold_password.clone()) - .build(backup_path.clone())?; - - let (read_client_options, read_secret_manager, read_wallet_data) = - read_wallet_data_from_stronghold_snapshot::(&new_stronghold).await?; - - let read_bip_path = read_wallet_data.as_ref().and_then(|data| data.bip_path); - - // If the bip path is not matching the current one, we may ignore the backup - let ignore_backup_values = ignore_if_bip_path_mismatch.map_or(false, |ignore| { - if ignore { - // TODO: #1279 okay that if both are none we always load the backup values? - curr_bip_path != read_bip_path - } else { - false - } - }); - - if !ignore_backup_values { - self.data_mut().await.bip_path = read_bip_path; - } - - if let Some(mut read_secret_manager) = read_secret_manager { - // Get the current snapshot path if set - let new_snapshot_path = self.secret_manager.read().await.snapshot_path.clone(); - - read_secret_manager.snapshot_path = new_snapshot_path.to_string_lossy().into_owned(); - - let restored_secret_manager = StrongholdSecretManager::from_config(&read_secret_manager) - .map_err(|_| crate::wallet::Error::Backup("invalid secret_manager"))?; - - // Copy Stronghold file so the seed is available in the new location - fs::copy(backup_path, new_snapshot_path)?; - - // Set password to restored secret manager - restored_secret_manager.set_password(stronghold_password).await?; - *self.secret_manager.write().await = restored_secret_manager; - } - - // Update Wallet with read data - if ignore_if_bip_path_mismatch.is_none() { - if let Some(read_client_options) = read_client_options { - // If the nodes are from the same network as the current client options, then extend it + if let Some(read_client_options) = loaded_client_options { self.set_client_options(read_client_options).await?; } } if !ignore_backup_values { - if let Some(read_wallet_data) = read_wallet_data { + if let Some(read_wallet_data) = loaded_wallet_data { let restore_wallet = ignore_if_bech32_hrp_mismatch.map_or(true, |expected_bech32_hrp| { // Only restore if bech32 hrps match read_wallet_data.address.hrp() == &expected_bech32_hrp @@ -318,9 +174,8 @@ impl Wallet { // store new data #[cfg(feature = "storage")] { - use crate::wallet::core::operations::storage::SaveLoadWallet; let wallet_builder = WalletBuilder::new() - .with_secret_manager_arc(self.secret_manager.clone()) + .with_secret_manager_arc(self.secret_manager().clone()) .with_storage_path( &self .storage_options @@ -331,7 +186,8 @@ impl Wallet { .expect("can't convert os string"), ) .with_client_options(self.client_options().await) - .with_bip_path(self.data().await.bip_path); + .with_public_key_options(self.public_key_options().await.clone()) + .with_signing_options(self.signing_options().clone()); wallet_builder.save(self.storage_manager()).await?; diff --git a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs index 83632aaca1..6140553c6a 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs @@ -5,7 +5,7 @@ use crate::{ client::{secret::SecretManagerConfig, storage::StorageAdapter, stronghold::StrongholdAdapter}, types::TryFromDto, wallet::{ - core::{WalletData, WalletDataDto}, + core::{SecretData, WalletData, WalletDataDto}, migration::{latest_backup_migration_version, migrate, MIGRATION_VERSION_KEY}, ClientOptions, Wallet, }, @@ -15,7 +15,7 @@ pub(crate) const CLIENT_OPTIONS_KEY: &str = "client_options"; pub(crate) const SECRET_MANAGER_KEY: &str = "secret_manager"; pub(crate) const WALLET_DATA_KEY: &str = "wallet_data"; -impl Wallet { +impl Wallet> { pub(crate) async fn store_data_to_stronghold(&self, stronghold: &StrongholdAdapter) -> crate::wallet::Result<()> { // Set migration version stronghold @@ -25,7 +25,7 @@ impl Wallet { let client_options = self.client_options().await; stronghold.set(CLIENT_OPTIONS_KEY, &client_options).await?; - if let Some(secret_manager_dto) = self.secret_manager.read().await.to_config() { + if let Some(secret_manager_dto) = self.secret_manager().read().await.to_config() { stronghold.set(SECRET_MANAGER_KEY, &secret_manager_dto).await?; } @@ -38,7 +38,12 @@ impl Wallet { pub(crate) async fn read_wallet_data_from_stronghold_snapshot( stronghold: &StrongholdAdapter, -) -> crate::wallet::Result<(Option, Option, Option)> { +) -> crate::wallet::Result<( + Option, + Option, + Option, + Option>, +)> { migrate(stronghold).await?; // Get client_options @@ -69,5 +74,12 @@ pub(crate) async fn read_wallet_data_from_stronghold_snapshot), /// BIP44 coin type mismatch - #[error("BIP44 mismatch: {new_bip_path:?}, existing bip path is: {old_bip_path:?}")] - BipPathMismatch { - new_bip_path: Option, - old_bip_path: Option, + #[error("public key options mismatch, new: {new:?}, previous: {old:?}")] + PublicKeyOptionsMismatch { + new: serde_json::Value, + old: serde_json::Value, }, /// Crypto.rs error #[error("{0}")] diff --git a/sdk/src/wallet/events/types.rs b/sdk/src/wallet/events/types.rs index 475fd5ab2e..7bb1e592d0 100644 --- a/sdk/src/wallet/events/types.rs +++ b/sdk/src/wallet/events/types.rs @@ -13,10 +13,7 @@ use crate::{ payload::signed_transaction::{dto::SignedTransactionPayloadDto, TransactionId}, }, }, - wallet::{ - types::{InclusionState, OutputData}, - Error, - }, + wallet::{types::InclusionState, Error, OutputData}, }; #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/sdk/src/wallet/operations/announce_candidacy.rs b/sdk/src/wallet/operations/announce_candidacy.rs index b00593c537..43030de583 100644 --- a/sdk/src/wallet/operations/announce_candidacy.rs +++ b/sdk/src/wallet/operations/announce_candidacy.rs @@ -8,14 +8,10 @@ use crate::{ payload::{CandidacyAnnouncementPayload, Payload}, BlockId, }, - wallet::Wallet, + wallet::{core::SecretData, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Announce a staking account's candidacy for the staking period. pub async fn announce_candidacy(&self, account_id: AccountId) -> crate::wallet::Result { self.submit_basic_block( diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index e9efdbfd80..560e34e449 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -4,7 +4,6 @@ use primitive_types::U256; use crate::{ - client::secret::SecretManage, types::block::output::{ unlock_condition::UnlockCondition, DecayedMana, FoundryId, MinimumOutputAmount, NativeTokensBuilder, Output, }, @@ -15,11 +14,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Get the balance of the wallet. pub async fn balance(&self) -> Result { log::debug!("[BALANCE] balance"); diff --git a/sdk/src/wallet/operations/block.rs b/sdk/src/wallet/operations/block.rs index 491bd78ae6..5676f62a45 100644 --- a/sdk/src/wallet/operations/block.rs +++ b/sdk/src/wallet/operations/block.rs @@ -2,16 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::secret::{SecretManage, SignBlock}, + client::secret::{BlockSignExt, SecretManage}, types::block::{output::AccountId, payload::Payload, BlockId}, - wallet::{Error, Result, Wallet}, + wallet::{core::SecretData, Error, Result, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { pub(crate) async fn submit_basic_block( &self, payload: impl Into> + Send, @@ -40,10 +36,7 @@ where } let block = unsigned_block - .sign_ed25519( - &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, - ) + .sign_ed25519(&*self.secret_manager().read().await, &self.signing_options()) .await?; let block_id = self.client().post_block(&block).await?; diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index 14e1c6c999..7cfd463963 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -16,7 +16,7 @@ use crate::{ slot::SlotIndex, }, wallet::{ - core::WalletData, + core::{SecretData, WalletData}, operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, Wallet, @@ -130,11 +130,7 @@ impl WalletData { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) or @@ -187,7 +183,9 @@ where log::debug!("[OUTPUT_CLAIMING] available basic outputs: {}", basic_outputs.len()); Ok(basic_outputs) } +} +impl Wallet> { /// Try to claim basic or nft outputs that have additional unlock conditions to their [AddressUnlockCondition] /// from [`Wallet::claimable_outputs()`]. pub async fn claim_outputs + Send>( @@ -226,7 +224,9 @@ where ); Ok(claim_tx) } +} +impl Wallet { /// Try to claim basic outputs that have additional unlock conditions to their [AddressUnlockCondition]. pub async fn prepare_claim_outputs + Send>( &self, diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index f30904437c..ae8ea4a440 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; #[cfg(feature = "ledger_nano")] -use crate::client::secret::{ledger_nano::LedgerSecretManager, DowncastSecretManager}; +use crate::client::secret::DowncastSecretManager; use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, types::block::{ @@ -17,6 +17,7 @@ use crate::{ }, wallet::{ constants::DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD, + core::{OptionalSecretManager, SecretData}, operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, RemainderValueStrategy, Result, Wallet, @@ -67,11 +68,7 @@ impl ConsolidationParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Consolidates basic outputs from an account by sending them to a provided address or to an own address again if /// the output amount is >= the output_threshold. When `force` is set to `true`, the threshold is ignored. Only /// consolidates the amount of outputs that fit into a single transaction. @@ -89,9 +86,15 @@ where Ok(consolidation_tx) } +} +impl Wallet { /// Prepares the transaction for [Wallet::consolidate_outputs()]. - pub async fn prepare_consolidate_outputs(&self, params: ConsolidationParams) -> Result { + pub async fn prepare_consolidate_outputs(&self, params: ConsolidationParams) -> Result + where + Self: OptionalSecretManager, + S: 'static + Send + Sync, + { log::debug!("[OUTPUT_CONSOLIDATION] prepare consolidating outputs if needed"); let wallet_address = self.data().await.address.clone(); @@ -156,7 +159,11 @@ where } /// Returns all outputs that should be consolidated. - async fn get_outputs_to_consolidate(&self, params: &ConsolidationParams) -> Result> { + async fn get_outputs_to_consolidate(&self, params: &ConsolidationParams) -> Result> + where + Self: OptionalSecretManager, + S: 'static + Send + Sync, + { // #[cfg(feature = "participation")] // let voting_output = self.get_voting_output().await?; let slot_index = self.client().get_slot_index().await?; @@ -241,35 +248,34 @@ where /// Returns the max amount of inputs that can be used in a consolidation transaction. For Ledger Nano it's more /// limited. - async fn get_max_inputs(&self) -> Result { + async fn get_max_inputs(&self) -> Result + where + Self: OptionalSecretManager, + S: 'static + Send + Sync, + { #[cfg(feature = "ledger_nano")] let max_inputs = { - use crate::client::secret::SecretManager; - let secret_manager = self.secret_manager.read().await; - if let Some(ledger) = secret_manager.downcast::().or_else(|| { - secret_manager.downcast::().and_then(|s| { - if let SecretManager::LedgerNano(n) = s { - Some(n) + if let Some(secret_manager) = self.secret_manager_opt() { + let secret_manager = secret_manager.read().await; + if let Ok(ledger) = (&*secret_manager).as_ledger_nano() { + let ledger_nano_status = ledger.get_ledger_nano_status().await; + // With blind signing we are only limited by the protocol + if ledger_nano_status.blind_signing_enabled() { + INPUT_COUNT_MAX } else { - None + ledger_nano_status + .buffer_size() + .map(|buffer_size| { + // Calculate how many inputs we can have with this ledger, buffer size is different for + // different ledger types + let available_buffer_size_for_inputs = + buffer_size - ESSENCE_SIZE_WITHOUT_IN_AND_OUTPUTS - MIN_OUTPUT_SIZE_IN_ESSENCE; + (available_buffer_size_for_inputs / INPUT_SIZE) as u16 + }) + .unwrap_or(INPUT_COUNT_MAX) } - }) - }) { - let ledger_nano_status = ledger.get_ledger_nano_status().await; - // With blind signing we are only limited by the protocol - if ledger_nano_status.blind_signing_enabled() { - INPUT_COUNT_MAX } else { - ledger_nano_status - .buffer_size() - .map(|buffer_size| { - // Calculate how many inputs we can have with this ledger, buffer size is different for - // different ledger types - let available_buffer_size_for_inputs = - buffer_size - ESSENCE_SIZE_WITHOUT_IN_AND_OUTPUTS - MIN_OUTPUT_SIZE_IN_ESSENCE; - (available_buffer_size_for_inputs / INPUT_SIZE) as u16 - }) - .unwrap_or(INPUT_COUNT_MAX) + INPUT_COUNT_MAX } } else { INPUT_COUNT_MAX @@ -282,29 +288,24 @@ where /// Returns the threshold value above which outputs should be consolidated. Lower for ledger nano secret manager, as /// their memory size is limited. - async fn get_output_consolidation_threshold(&self, params: &ConsolidationParams) -> Result { + async fn get_output_consolidation_threshold(&self, params: &ConsolidationParams) -> Result + where + Self: OptionalSecretManager, + S: 'static + Send + Sync, + { #[allow(clippy::option_if_let_else)] let output_threshold = match params.output_threshold { Some(t) => t, None => { #[cfg(feature = "ledger_nano")] { - use crate::client::secret::SecretManager; - let secret_manager = self.secret_manager.read().await; - if secret_manager - .downcast::() - .or_else(|| { - secret_manager.downcast::().and_then(|s| { - if let SecretManager::LedgerNano(n) = s { - Some(n) - } else { - None - } - }) - }) - .is_some() - { - DEFAULT_LEDGER_OUTPUT_CONSOLIDATION_THRESHOLD + if let Some(secret_manager) = self.secret_manager_opt() { + let secret_manager = secret_manager.read().await; + if (&*secret_manager).as_ledger_nano().is_ok() { + DEFAULT_LEDGER_OUTPUT_CONSOLIDATION_THRESHOLD + } else { + DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD + } } else { DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD } diff --git a/sdk/src/wallet/operations/participation/event.rs b/sdk/src/wallet/operations/participation/event.rs index 73e76c5cc8..4232568706 100644 --- a/sdk/src/wallet/operations/participation/event.rs +++ b/sdk/src/wallet/operations/participation/event.rs @@ -14,11 +14,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Stores participation information for the given events locally and returns them all. /// /// This will NOT store the node url and auth inside the client options. diff --git a/sdk/src/wallet/operations/participation/mod.rs b/sdk/src/wallet/operations/participation/mod.rs index 4b83fa1b69..abf71fae01 100644 --- a/sdk/src/wallet/operations/participation/mod.rs +++ b/sdk/src/wallet/operations/participation/mod.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use crate::{ - client::{node_manager::node::Node, secret::SecretManage}, + client::node_manager::node::Node, types::{ api::plugins::participation::{ responses::TrackedParticipation, @@ -46,19 +46,15 @@ pub struct ParticipationEventWithNodes { pub nodes: Vec, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ - // /// Calculates the voting overview of a wallet. If event_ids are provided, only return outputs and tracked - // /// participations for them. - // pub async fn get_participation_overview( - // &self, - // event_ids: Option>, - // ) -> Result { - // log::debug!("[get_participation_overview]"); - // // TODO: Could use the address endpoint in the future when https://github.com/iotaledger/inx-participation/issues/50 is done. +impl Wallet { + // /// Calculates the voting overview of a wallet. If event_ids are provided, only return outputs and tracked + // /// participations for them. + // pub async fn get_participation_overview( + // &self, + // event_ids: Option>, + // ) -> Result { + // log::debug!("[get_participation_overview]"); + // // TODO: Could use the address endpoint in the future when https://github.com/iotaledger/inx-participation/issues/50 is done. // let mut spent_cached_outputs = self.storage_manager().get_cached_participation_output_status().await?; // let restored_spent_cached_outputs_len = spent_cached_outputs.len(); diff --git a/sdk/src/wallet/operations/participation/voting.rs b/sdk/src/wallet/operations/participation/voting.rs index b8642af3c6..65e86f8e36 100644 --- a/sdk/src/wallet/operations/participation/voting.rs +++ b/sdk/src/wallet/operations/participation/voting.rs @@ -13,14 +13,12 @@ use crate::{ payload::TaggedDataPayload, }, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Result, Wallet}, + wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Result, Wallet, + }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Casts a given number of votes for a given (voting) event. /// /// If voting for other events, continues voting for them. @@ -43,7 +41,23 @@ where self.sign_and_submit_transaction(prepared, None, None).await } +} + +impl Wallet> { + /// Removes metadata corresponding to a given (voting) event ID from the voting output if it contains it. + /// + /// If voting for other events, continues voting for them. + /// Removes metadata for any event that has expired (use event IDs to get cached event information, checks event + /// milestones in there against latest network milestone). + /// If NOT already voting for this event, throws an error. + pub async fn stop_participating(&self, event_id: ParticipationEventId) -> Result { + let prepared = self.prepare_stop_participating(event_id).await?; + self.sign_and_submit_transaction(prepared, None, None).await + } +} + +impl Wallet { /// Prepares the transaction for [Wallet::vote()]. pub async fn prepare_vote( &self, @@ -122,18 +136,6 @@ where .await } - /// Removes metadata corresponding to a given (voting) event ID from the voting output if it contains it. - /// - /// If voting for other events, continues voting for them. - /// Removes metadata for any event that has expired (use event IDs to get cached event information, checks event - /// milestones in there against latest network milestone). - /// If NOT already voting for this event, throws an error. - pub async fn stop_participating(&self, event_id: ParticipationEventId) -> Result { - let prepared = self.prepare_stop_participating(event_id).await?; - - self.sign_and_submit_transaction(prepared, None, None).await - } - /// Prepares the transaction for [Wallet::stop_participating()]. pub async fn prepare_stop_participating(&self, event_id: ParticipationEventId) -> Result { let voting_output = self diff --git a/sdk/src/wallet/operations/participation/voting_power.rs b/sdk/src/wallet/operations/participation/voting_power.rs index 550ffe64d9..722b5a1c40 100644 --- a/sdk/src/wallet/operations/participation/voting_power.rs +++ b/sdk/src/wallet/operations/participation/voting_power.rs @@ -14,14 +14,13 @@ use crate::{ payload::TaggedDataPayload, }, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Result, Wallet}, + wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Result, + Wallet, + }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Returns an account's total voting power (voting or NOT voting). pub async fn get_voting_power(&self) -> Result { Ok(self @@ -47,6 +46,23 @@ where self.sign_and_submit_transaction(prepared, None, None).await } + /// Reduces an account's "voting power" by a given amount. + /// This will stop voting, but the voting data isn't lost and calling `Vote` without parameters will revote. + /// + /// If amount is higher than actual voting power, throws an error. + /// If voting and amount is equal to voting power, removes tagged data payload and output metadata. + /// Removes metadata for any events that have expired (uses event IDs to get cached event information, checks event + /// milestones in there against latest network milestone). + /// Prioritizes consuming outputs that are designated for voting but don't have any metadata (only possible if user + /// increases voting power then decreases immediately after). + pub async fn decrease_voting_power(&self, amount: u64) -> Result { + let prepared = self.prepare_decrease_voting_power(amount).await?; + + self.sign_and_submit_transaction(prepared, None, None).await + } +} + +impl Wallet { /// Prepares the transaction for [Wallet::increase_voting_power()]. pub async fn prepare_increase_voting_power(&self, amount: u64) -> Result { let (new_output, tx_options) = match self.get_voting_output().await? { @@ -80,21 +96,6 @@ where self.prepare_transaction([new_output], tx_options).await } - /// Reduces an account's "voting power" by a given amount. - /// This will stop voting, but the voting data isn't lost and calling `Vote` without parameters will revote. - /// - /// If amount is higher than actual voting power, throws an error. - /// If voting and amount is equal to voting power, removes tagged data payload and output metadata. - /// Removes metadata for any events that have expired (uses event IDs to get cached event information, checks event - /// milestones in there against latest network milestone). - /// Prioritizes consuming outputs that are designated for voting but don't have any metadata (only possible if user - /// increases voting power then decreases immediately after). - pub async fn decrease_voting_power(&self, amount: u64) -> Result { - let prepared = self.prepare_decrease_voting_power(amount).await?; - - self.sign_and_submit_transaction(prepared, None, None).await - } - /// Prepares the transaction for [Wallet::decrease_voting_power()]. pub async fn prepare_decrease_voting_power(&self, amount: u64) -> Result { let current_output_data = self diff --git a/sdk/src/wallet/operations/reissue.rs b/sdk/src/wallet/operations/reissue.rs index 7bad812224..7eec5af561 100644 --- a/sdk/src/wallet/operations/reissue.rs +++ b/sdk/src/wallet/operations/reissue.rs @@ -3,7 +3,7 @@ use crate::{ client::{ - secret::{SecretManage, SignBlock}, + secret::{BlockSignExt, SecretManage}, Error as ClientError, }, types::{ @@ -13,17 +13,13 @@ use crate::{ BlockId, }, }, - wallet::{types::InclusionState, Error, Wallet}, + wallet::{core::SecretData, types::InclusionState, Error, Wallet}, }; const DEFAULT_REISSUE_UNTIL_INCLUDED_INTERVAL: u64 = 1; const DEFAULT_REISSUE_UNTIL_INCLUDED_MAX_AMOUNT: u64 = 40; -impl Wallet -where - Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Reissues a transaction sent from the account for a provided transaction id until it's /// included (referenced by a milestone). Returns the included block id. pub async fn reissue_transaction_until_included( @@ -61,10 +57,7 @@ where Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? - .sign_ed25519( - &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, - ) + .sign_ed25519(&*self.secret_manager().read().await, self.signing_options()) .await? .id(&protocol_parameters), }; @@ -109,10 +102,7 @@ where Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? - .sign_ed25519( - &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, - ) + .sign_ed25519(&*self.secret_manager().read().await, self.signing_options()) .await?; block_ids.push(reissued_block.id(&protocol_parameters)); } diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs index ff4d7995cd..7018b53924 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/account_foundry.rs @@ -4,10 +4,7 @@ use std::collections::HashSet; use crate::{ - client::{ - node_api::indexer::query_parameters::{AccountOutputQueryParameters, FoundryOutputQueryParameters}, - secret::SecretManage, - }, + client::node_api::indexer::query_parameters::{AccountOutputQueryParameters, FoundryOutputQueryParameters}, types::{ api::plugins::indexer::OutputIdsResponse, block::{ @@ -19,11 +16,7 @@ use crate::{ wallet::{operations::syncing::SyncOptions, task, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Returns output ids of account outputs pub(crate) async fn get_account_and_foundry_output_ids( &self, diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs index 4374d0c859..f3a886999d 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs @@ -2,16 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::{node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManage}, + client::node_api::indexer::query_parameters::BasicOutputQueryParameters, types::block::{address::Bech32Address, output::OutputId}, utils::ConvertTo, wallet::Wallet, }; -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Returns output ids of basic outputs that have only the address unlock condition pub(crate) async fn get_basic_output_ids_with_address_unlock_condition_only( &self, diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs index 994b036752..6d3f159e2e 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs @@ -12,10 +12,7 @@ use futures::FutureExt; use instant::Instant; use crate::{ - client::{ - node_api::indexer::query_parameters::{FoundryOutputQueryParameters, OutputQueryParameters}, - secret::SecretManage, - }, + client::node_api::indexer::query_parameters::{FoundryOutputQueryParameters, OutputQueryParameters}, types::block::{address::Bech32Address, output::OutputId}, wallet::{ constants::PARALLEL_REQUESTS_AMOUNT, operations::syncing::SyncOptions, @@ -23,11 +20,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Returns output ids for outputs that are directly (Ed25519 address in AddressUnlockCondition) or indirectly /// (account/nft address in AddressUnlockCondition and the account/nft output is controlled with the Ed25519 /// address) connected to diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs index 5430bcb009..61981b0d94 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs @@ -2,16 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::{node_api::indexer::query_parameters::NftOutputQueryParameters, secret::SecretManage}, + client::node_api::indexer::query_parameters::NftOutputQueryParameters, types::block::{address::Bech32Address, output::OutputId}, utils::ConvertTo, wallet::Wallet, }; -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Returns output ids of NFT outputs that have the address in the `AddressUnlockCondition` or /// `ExpirationUnlockCondition` pub(crate) async fn get_nft_output_ids_with_any_unlock_condition( diff --git a/sdk/src/wallet/operations/syncing/addresses/outputs.rs b/sdk/src/wallet/operations/syncing/addresses/outputs.rs index ca45fc9438..e0c73540e4 100644 --- a/sdk/src/wallet/operations/syncing/addresses/outputs.rs +++ b/sdk/src/wallet/operations/syncing/addresses/outputs.rs @@ -3,21 +3,14 @@ use instant::Instant; -use crate::{ - client::secret::SecretManage, - wallet::{ - constants::PARALLEL_REQUESTS_AMOUNT, - task, - types::{address::AddressWithUnspentOutputs, OutputData}, - Wallet, - }, +use crate::wallet::{ + constants::PARALLEL_REQUESTS_AMOUNT, + task, + types::{address::AddressWithUnspentOutputs, OutputData}, + Wallet, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Get outputs from addresses pub(crate) async fn get_outputs_from_address_output_ids( &self, diff --git a/sdk/src/wallet/operations/syncing/foundries.rs b/sdk/src/wallet/operations/syncing/foundries.rs index 278ceca9a9..2730d2e88f 100644 --- a/sdk/src/wallet/operations/syncing/foundries.rs +++ b/sdk/src/wallet/operations/syncing/foundries.rs @@ -4,16 +4,11 @@ use std::collections::HashSet; use crate::{ - client::secret::SecretManage, types::block::output::{FoundryId, Output}, wallet::{task, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { pub(crate) async fn request_and_store_foundry_outputs( &self, foundry_ids: HashSet, diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index 4dde220f37..5f54e365e0 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -11,7 +11,6 @@ use std::collections::{HashMap, HashSet}; pub use self::options::SyncOptions; use crate::{ - client::secret::SecretManage, types::block::{ address::{AccountAddress, Address, Bech32Address, NftAddress}, output::{FoundryId, Output, OutputId, OutputMetadata}, @@ -23,11 +22,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Set the fallback SyncOptions for account syncing. /// If storage is enabled, will persist during restarts. pub async fn set_default_sync_options(&self, options: SyncOptions) -> crate::wallet::Result<()> { @@ -44,7 +39,9 @@ where pub async fn default_sync_options(&self) -> SyncOptions { self.default_sync_options.lock().await.clone() } +} +impl Wallet { /// Sync the wallet by fetching new information from the nodes. Will also reissue pending transactions /// if necessary. A custom default can be set using set_default_sync_options. pub async fn sync(&self, options: Option) -> crate::wallet::Result { diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index c317953024..b113d23e94 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -4,7 +4,7 @@ use instant::Instant; use crate::{ - client::{secret::SecretManage, Client, Error as ClientError}, + client::{Client, Error as ClientError}, types::{ api::core::OutputWithMetadataResponse, block::{ @@ -17,11 +17,7 @@ use crate::{ wallet::{build_transaction_from_payload_and_inputs, task, types::OutputData, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Convert OutputWithMetadataResponse to OutputData with the network_id added pub(crate) async fn output_response_to_output_data( &self, diff --git a/sdk/src/wallet/operations/syncing/transactions.rs b/sdk/src/wallet/operations/syncing/transactions.rs index b5ab3a80ee..29ecfbc064 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::secret::SecretManage, types::{ api::core::TransactionState, block::{input::Input, output::OutputId, BlockId}, @@ -19,15 +18,11 @@ use crate::{ // also revalidate that the locked outputs needs to be there, maybe there was a conflict or the transaction got // confirmed, then they should get removed -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Sync transactions. Returns the transaction with updated metadata and spent - /// output ids that don't need to be locked anymore + /// output ids that don't need to be locked anymore. /// Return true if a transaction got confirmed for which we don't have an output already, based on this outputs will - /// be synced again + /// be synced again. pub(crate) async fn sync_pending_transactions(&self) -> crate::wallet::Result { log::debug!("[SYNC] sync pending transactions"); let wallet_data = self.data().await; @@ -50,7 +45,7 @@ where for transaction_id in &wallet_data.pending_transactions { log::debug!("[SYNC] sync pending transaction {transaction_id}"); - let mut transaction = wallet_data + let transaction = wallet_data .transactions .get(transaction_id) // panic during development to easier detect if something is wrong, should be handled different later @@ -178,14 +173,6 @@ where &mut updated_transactions, &mut output_ids_to_unlock, )?; - } else { - // Reissue if there was no block id yet, because then we also didn't burn any mana - log::debug!("[SYNC] reissue transaction {}", transaction.transaction_id); - let reissued_block = self - .submit_signed_transaction(transaction.payload.clone(), None) - .await?; - transaction.block_id.replace(reissued_block); - updated_transactions.push(transaction); } } drop(wallet_data); diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index c915f3631b..63c88f3e86 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -16,21 +16,18 @@ use crate::{ }, }, wallet::{ + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Result, Wallet, }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Transitions an implicit account to an account. pub async fn implicit_account_transition( &self, output_id: &OutputId, - key_source: impl Into + Send, + key_source: impl Into> + Send, ) -> Result { let issuer_id = AccountId::from(output_id); @@ -46,11 +43,8 @@ where pub async fn prepare_implicit_account_transition( &self, output_id: &OutputId, - key_source: impl Into + Send, - ) -> Result - where - crate::wallet::Error: From, - { + key_source: impl Into> + Send, + ) -> Result { let wallet_data = self.data().await; let implicit_account_data = wallet_data .unspent_outputs @@ -71,17 +65,8 @@ where BlockIssuerKeySource::PublicKey(public_key) => { Ed25519PublicKeyHashBlockIssuerKey::from_public_key(public_key) } - BlockIssuerKeySource::Bip44Path(bip_path) => Ed25519PublicKeyHashBlockIssuerKey::from_public_key( - self.secret_manager - .read() - .await - .generate_ed25519_public_keys( - bip_path.coin_type, - bip_path.account, - bip_path.address_index..bip_path.address_index + 1, - None, - ) - .await?[0], + BlockIssuerKeySource::Options(options) => Ed25519PublicKeyHashBlockIssuerKey::from_public_key( + self.secret_manager().read().await.generate(&options).await?, ), }); diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 63ec5b6177..0715dc4b1a 100644 --- a/sdk/src/wallet/operations/transaction/build_transaction.rs +++ b/sdk/src/wallet/operations/transaction/build_transaction.rs @@ -6,10 +6,7 @@ use std::collections::HashSet; use instant::Instant; use crate::{ - client::{ - api::{input_selection::Selected, transaction::validate_transaction_length, PreparedTransactionData}, - secret::SecretManage, - }, + client::api::{input_selection::Selected, transaction::validate_transaction_length, PreparedTransactionData}, types::block::{ context_input::{BlockIssuanceCreditContextInput, CommitmentContextInput, ContextInput, RewardContextInput}, input::{Input, UtxoInput}, @@ -19,10 +16,7 @@ use crate::{ wallet::{operations::transaction::TransactionOptions, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Builds the transaction from the selected inputs and outputs. pub(crate) async fn build_transaction( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs b/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs index f1ac22f624..2ac6053c94 100644 --- a/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs +++ b/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs @@ -5,16 +5,13 @@ use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, types::block::mana::ManaAllotment, wallet::{ + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Wallet, }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { pub async fn allot_mana( &self, allotments: impl IntoIterator> + Send, @@ -26,7 +23,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { pub async fn prepare_allot_mana( &self, allotments: impl IntoIterator> + Send, diff --git a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs index 70cde54392..2d939a76ef 100644 --- a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs @@ -10,17 +10,14 @@ use crate::{ TokenScheme, }, wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Error, Wallet, }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Melts native tokens. /// /// This happens with the foundry output which minted them, by increasing it's @@ -40,7 +37,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::melt_native_token()]. pub async fn prepare_melt_native_token( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs b/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs index 12e0341087..fc04485b6e 100644 --- a/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs +++ b/sdk/src/wallet/operations/transaction/high_level/burning_melting/mod.rs @@ -2,13 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::api::{input_selection::Burn, PreparedTransactionData}, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, + client::{ + api::{input_selection::Burn, PreparedTransactionData}, + secret::SecretManage, + }, + wallet::{core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, }; pub(crate) mod melt_native_token; -impl Wallet { +impl Wallet> { /// A generic function that can be used to burn native tokens, nfts, delegations, foundries and accounts. /// /// Note that burning **native tokens** doesn't require the foundry output which minted them, but will not increase @@ -24,7 +27,9 @@ impl Wallet { self.sign_and_submit_transaction(prepared, None, options).await } +} +impl Wallet { /// A generic `prepare_burn()` function that can be used to prepare the burn of native tokens, nfts, delegations, /// foundries and accounts. /// diff --git a/sdk/src/wallet/operations/transaction/high_level/create_account.rs b/sdk/src/wallet/operations/transaction/high_level/create_account.rs index 063e310f6d..a275e38979 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -12,6 +12,7 @@ use crate::{ }, }, wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Wallet, @@ -31,11 +32,7 @@ pub struct CreateAccountParams { pub metadata: Option, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Creates an account output. /// ```ignore /// let params = CreateAccountParams { @@ -62,7 +59,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::create_account_output()]. pub async fn prepare_create_account_output( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/delegation/create.rs b/sdk/src/wallet/operations/transaction/high_level/delegation/create.rs index 64a10cc25a..6858ec77bd 100644 --- a/sdk/src/wallet/operations/transaction/high_level/delegation/create.rs +++ b/sdk/src/wallet/operations/transaction/high_level/delegation/create.rs @@ -9,7 +9,7 @@ use crate::{ address::{AccountAddress, Bech32Address}, output::{unlock_condition::AddressUnlockCondition, DelegationId, DelegationOutputBuilder}, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, + wallet::{core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, }; /// Params for `create_delegation_output()` @@ -42,11 +42,7 @@ pub struct PreparedCreateDelegationTransaction { pub transaction: PreparedTransactionData, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Creates a delegation output. /// ```ignore /// let params = CreateDelegationParams { @@ -77,7 +73,9 @@ where transaction, }) } +} +impl Wallet { /// Prepares the transaction for [Wallet::create_delegation_output()]. pub async fn prepare_create_delegation_output( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/delegation/delay.rs b/sdk/src/wallet/operations/transaction/high_level/delegation/delay.rs index 8e7c70d9aa..a286aaf4f8 100644 --- a/sdk/src/wallet/operations/transaction/high_level/delegation/delay.rs +++ b/sdk/src/wallet/operations/transaction/high_level/delegation/delay.rs @@ -4,14 +4,10 @@ use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, types::block::output::{AddressUnlockCondition, DelegationId, DelegationOutputBuilder, MinimumOutputAmount}, - wallet::{types::TransactionWithMetadata, Wallet}, + wallet::{core::SecretData, types::TransactionWithMetadata, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Delay a delegation's claiming. The `reclaim_excess` flag indicates whether excess value over the minimum storage /// requirements will be moved to a basic output that is unlockable by the same address which controls the /// delegation. Otherwise it will be added to a new delegation. In this manner, one can delegate for one epoch @@ -27,7 +23,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, None).await } +} +impl Wallet { /// Prepare to delay a delegation's claiming. The `reclaim_excess` flag indicates whether excess value /// over the minimum storage requirements will be moved to a basic output that is unlockable by the same address /// which controls the delegation. diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs index 16a9faa2c6..b758d979ac 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs @@ -13,7 +13,7 @@ use crate::{ AccountOutputBuilder, FoundryId, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, }, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, + wallet::{core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, }; /// Address and foundry data for `create_native_token()` @@ -47,11 +47,7 @@ pub struct PreparedCreateNativeTokenTransaction { pub transaction: PreparedTransactionData, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Creates a new foundry output with minted native tokens. /// /// Calls [Wallet::prepare_transaction()](crate::wallet::Wallet::prepare_transaction) internally, the options may @@ -85,7 +81,9 @@ where transaction, }) } +} +impl Wallet { /// Prepares the transaction for [Wallet::create_native_token()]. pub async fn prepare_create_native_token( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs index 4342e48b97..3761bdf681 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs @@ -8,14 +8,12 @@ use crate::{ types::block::output::{ AccountOutputBuilder, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Wallet}, + wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Wallet, + }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Mints additional native tokens. /// /// The max supply must not be reached yet. The foundry needs to be @@ -45,7 +43,9 @@ where Ok(transaction) } +} +impl Wallet { /// Prepares the transaction for [Wallet::mint_native_token()]. pub async fn prepare_mint_native_token( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs b/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs index c4b7de591a..c62dc2c92f 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/mint_nfts.rs @@ -16,6 +16,7 @@ use crate::{ }, utils::ConvertTo, wallet::{ + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Wallet, }, @@ -107,11 +108,7 @@ impl MintNftParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Mints NFTs. /// /// Calls [Wallet::prepare_transaction()](crate::wallet::Wallet::prepare_transaction) internally. The options may @@ -148,7 +145,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::mint_nfts()]. pub async fn prepare_mint_nfts + Send>( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/send.rs b/sdk/src/wallet/operations/transaction/high_level/send.rs index f51d01afaf..f388a10a59 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send.rs @@ -17,6 +17,7 @@ use crate::{ utils::{serde::string, ConvertTo}, wallet::{ constants::DEFAULT_EXPIRATION_SLOTS, + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Wallet, }, @@ -73,11 +74,7 @@ impl SendParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Sends a certain amount of base coins to a single address. /// /// Calls [Wallet::send_with_params()] internally. @@ -124,7 +121,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::send()]. pub async fn prepare_send + Send>( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs index 255931a5f3..1e76ba4a7c 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs @@ -18,6 +18,7 @@ use crate::{ utils::ConvertTo, wallet::{ constants::DEFAULT_EXPIRATION_SLOTS, + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Result, Wallet, }, @@ -73,11 +74,7 @@ impl SendNativeTokenParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) /// and an [`ExpirationUnlockCondition`], so that the storage deposit is returned to the sender and the sender @@ -114,7 +111,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::send_native_tokens()]. pub async fn prepare_send_native_tokens + Send>( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs index ff47666b93..57b624c792 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs @@ -12,6 +12,7 @@ use crate::{ }, utils::ConvertTo, wallet::{ + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Wallet, }, @@ -42,11 +43,7 @@ impl SendNftParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Sends an NFT to the provided address. /// Calls [Wallet::prepare_transaction()](crate::wallet::Wallet::prepare_transaction) internally. The /// options may define the remainder value strategy. Note that custom inputs will be replaced with the required @@ -79,7 +76,9 @@ where self.sign_and_submit_transaction(prepared_transaction, None, options) .await } +} +impl Wallet { /// Prepares the transaction for [Wallet::send_nft()]. pub async fn prepare_send_nft + Send>( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs index 9129046698..2a6d2113ca 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs @@ -9,7 +9,7 @@ use crate::{ output::{feature::StakingFeature, AccountId, AccountOutputBuilder}, slot::EpochIndex, }, - wallet::{types::TransactionWithMetadata, TransactionOptions, Wallet}, + wallet::{operations::transaction::SecretData, types::TransactionWithMetadata, TransactionOptions, Wallet}, }; /// Parameters for beginning a staking period. @@ -26,11 +26,7 @@ pub struct BeginStakingParams { pub staking_period: Option, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { pub async fn begin_staking( &self, params: BeginStakingParams, @@ -41,7 +37,9 @@ where self.sign_and_submit_transaction(prepared, None, options).await } +} +impl Wallet { /// Prepares the transaction for [Wallet::begin_staking()]. pub async fn prepare_begin_staking( &self, diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs index d6524b40bb..cb14f76080 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs @@ -7,20 +7,18 @@ use crate::{ context_input::{ContextInput, RewardContextInput}, output::{AccountId, AccountOutputBuilder}, }, - wallet::{types::TransactionWithMetadata, TransactionOptions, Wallet}, + wallet::{operations::transaction::SecretData, types::TransactionWithMetadata, TransactionOptions, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { pub async fn end_staking(&self, account_id: AccountId) -> crate::wallet::Result { let prepared = self.prepare_end_staking(account_id).await?; self.sign_and_submit_transaction(prepared, None, None).await } +} +impl Wallet { /// Prepares the transaction for [Wallet::end_staking()]. pub async fn prepare_end_staking(&self, account_id: AccountId) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_end_staking"); diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs index 06d0b35b2d..8d675d7bad 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs @@ -7,14 +7,10 @@ use crate::{ context_input::{ContextInput, RewardContextInput}, output::{feature::StakingFeature, AccountId, AccountOutputBuilder}, }, - wallet::{types::TransactionWithMetadata, TransactionOptions, Wallet}, + wallet::{operations::transaction::SecretData, types::TransactionWithMetadata, TransactionOptions, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { pub async fn extend_staking( &self, account_id: AccountId, @@ -24,7 +20,9 @@ where self.sign_and_submit_transaction(prepared, None, None).await } +} +impl Wallet { /// Prepares the transaction for [Wallet::extend_staking()]. pub async fn prepare_extend_staking( &self, diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 5be57db361..c2d0f7a289 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -8,7 +8,7 @@ use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ client::{ api::input_selection::{Burn, InputSelection, Selected}, - secret::{types::InputSigningData, SecretManage}, + secret::types::InputSigningData, }, types::block::{ address::Address, @@ -23,11 +23,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Selects inputs for a transaction and locks them in the wallet, so they don't get used again pub(crate) async fn select_inputs( &self, diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 0db7cf7de3..6d52d61599 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -26,16 +26,13 @@ use crate::{ }, }, wallet::{ + core::SecretData, types::{InclusionState, TransactionWithMetadata}, Wallet, }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Sends a transaction by specifying its outputs. /// /// Note that, if sending a block fails, the method will return `None` for the block id, but the wallet @@ -137,7 +134,6 @@ where return Err(Error::TransactionSemantic(conflict).into()); } - // Ignore errors from sending, we will try to send it again during [`sync_pending_transactions`] let block_id = match self .submit_signed_transaction(signed_transaction_data.payload.clone(), issuer_id) .await @@ -145,6 +141,12 @@ where Ok(block_id) => Some(block_id), Err(err) => { log::error!("Failed to submit_transaction_payload {}", err); + // TODO + // // Reissue if there was no block id yet, because then we also didn't burn any mana + // log::debug!("[SYNC] reissue transaction {}", transaction.transaction_id); + // let reissued_block = self + // .submit_signed_transaction(transaction.payload.clone(), None) + // .await?; None } }; @@ -189,7 +191,9 @@ where Ok(transaction) } +} +impl Wallet { // unlock outputs async fn unlock_inputs(&self, inputs: &[InputSigningData]) -> crate::wallet::Result<()> { let mut wallet_data = self.data_mut().await; diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 75da29a3a7..141056dd5a 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -4,7 +4,6 @@ use serde::{Deserialize, Serialize}; use crate::{ - client::secret::SecretManage, types::block::{ address::{Address, Bech32Address, Ed25519Address}, output::{ @@ -27,11 +26,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Prepare a basic or NFT output for sending /// If the amount is below the minimum required storage deposit, by default the remaining amount will automatically /// be added with a StorageDepositReturn UnlockCondition, when setting the ReturnStrategy to `gift`, the full diff --git a/sdk/src/wallet/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/operations/transaction/prepare_transaction.rs index 04cc7d1371..2e8bf22e49 100644 --- a/sdk/src/wallet/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/operations/transaction/prepare_transaction.rs @@ -7,7 +7,7 @@ use instant::Instant; use packable::bounded::TryIntoBoundedU16Error; use crate::{ - client::{api::PreparedTransactionData, secret::SecretManage}, + client::api::PreparedTransactionData, types::block::{input::INPUT_COUNT_RANGE, output::Output}, wallet::{ operations::transaction::{RemainderValueStrategy, TransactionOptions}, @@ -15,11 +15,7 @@ use crate::{ }, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Get inputs and build the transaction pub async fn prepare_transaction( &self, diff --git a/sdk/src/wallet/operations/transaction/sign_transaction.rs b/sdk/src/wallet/operations/transaction/sign_transaction.rs index dfdee16c5b..c16e42304c 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -1,15 +1,6 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -#[cfg(all(feature = "events", feature = "ledger_nano"))] -use { - crate::client::api::PreparedTransactionDataDto, - crate::client::secret::{ - ledger_nano::{needs_blind_signing, LedgerSecretManager}, - DowncastSecretManager, - }, -}; - #[cfg(feature = "events")] use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ @@ -17,16 +8,12 @@ use crate::{ api::{ transaction::validate_signed_transaction_payload_length, PreparedTransactionData, SignedTransactionData, }, - secret::SecretManage, + secret::{DowncastSecretManager, SecretManage}, }, - wallet::{operations::transaction::SignedTransactionPayload, Wallet}, + wallet::{core::SecretData, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Signs a transaction. pub async fn sign_transaction( &self, @@ -42,17 +29,9 @@ where #[cfg(all(feature = "events", feature = "ledger_nano"))] { - use crate::client::secret::SecretManager; - let secret_manager = self.secret_manager.read().await; - if let Some(ledger) = secret_manager.downcast::().or_else(|| { - secret_manager.downcast::().and_then(|s| { - if let SecretManager::LedgerNano(n) = s { - Some(n) - } else { - None - } - }) - }) { + use crate::client::{api::PreparedTransactionDataDto, secret::ledger_nano::needs_blind_signing}; + let secret_manager = &*self.secret_manager().read().await; + if let Ok(ledger) = secret_manager.as_ledger_nano() { let ledger_nano_status = ledger.get_ledger_nano_status().await; if let Some(buffer_size) = ledger_nano_status.buffer_size() { if needs_blind_signing(prepared_transaction_data, buffer_size) { @@ -76,10 +55,10 @@ where let protocol_parameters = self.client().get_protocol_parameters().await?; let unlocks = match self - .secret_manager + .secret_manager() .read() .await - .transaction_unlocks(prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(prepared_transaction_data, &protocol_parameters, self.signing_options()) .await { Ok(res) => res, diff --git a/sdk/src/wallet/operations/transaction/submit_transaction.rs b/sdk/src/wallet/operations/transaction/submit_transaction.rs index 0da286d2ee..c421ad5a33 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -6,14 +6,10 @@ use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ client::secret::SecretManage, types::block::{output::AccountId, payload::Payload, BlockId}, - wallet::{operations::transaction::SignedTransactionPayload, Wallet}, + wallet::{core::SecretData, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet> { /// Submits a signed transaction in a block. pub(crate) async fn submit_signed_transaction( &self, diff --git a/sdk/src/wallet/storage/manager.rs b/sdk/src/wallet/storage/manager.rs index ec217e5365..5086dcd461 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -96,8 +96,12 @@ mod tests { use super::*; use crate::{ - client::secret::SecretManager, - wallet::{core::operations::storage::SaveLoadWallet, storage::adapter::memory::Memory, WalletBuilder}, + client::secret::mnemonic::MnemonicSecretManager, + wallet::{ + core::builder::{dto::SecretDataDto, SecretDataBuilder}, + storage::adapter::memory::Memory, + WalletBuilder, + }, }; #[tokio::test] @@ -137,17 +141,17 @@ mod tests { async fn save_load_wallet_builder() { let storage_manager = StorageManager::new(Memory::default(), None).await.unwrap(); assert!( - WalletBuilder::::load(&storage_manager) + WalletBuilder::>::load::>(&storage_manager) .await .unwrap() .is_none() ); - let wallet_builder = WalletBuilder::::new(); + let wallet_builder = WalletBuilder::new().with_secret_type::(); wallet_builder.save(&storage_manager).await.unwrap(); assert!( - WalletBuilder::::load(&storage_manager) + WalletBuilder::>::load::>(&storage_manager) .await .unwrap() .is_some() diff --git a/sdk/src/wallet/types/mod.rs b/sdk/src/wallet/types/mod.rs index 0741bf4fbc..0a5fbda55b 100644 --- a/sdk/src/wallet/types/mod.rs +++ b/sdk/src/wallet/types/mod.rs @@ -64,27 +64,14 @@ impl OutputData { .required_address(slot_index.into(), committable_age_range)? .ok_or(crate::client::Error::ExpirationDeadzone)?; - let chain = if let Some(required_ed25519) = required_address.backing_ed25519() { - if let Some(backing_ed25519) = wallet_data.address.inner().backing_ed25519() { - if required_ed25519 == backing_ed25519 { - wallet_data.bip_path - } else { - // Different ed25519 chain than the wallet one. - None - } - } else { - // Address can't be unlocked, wallet is not ed25519-based. - return Ok(None); - } - } else { - // Non-chain based address. - None - }; + // Address can't be unlocked, wallet is not ed25519-based. + if required_address.is_ed25519_backed() && !wallet_data.address.inner().is_ed25519_backed() { + return Ok(None); + } Ok(Some(InputSigningData { output: self.output.clone(), output_metadata: self.metadata, - chain, })) } } diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 54a2fe8df1..29483f76df 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -3,8 +3,13 @@ use std::collections::HashMap; +#[cfg(feature = "events")] +use crate::{ + types::api::core::OutputWithMetadataResponse, + types::block::payload::signed_transaction::dto::SignedTransactionPayloadDto, + wallet::events::types::{NewOutputEvent, SpentOutputEvent, TransactionInclusionEvent, WalletEvent}, +}; use crate::{ - client::secret::SecretManage, types::block::{ output::{OutputConsumptionMetadata, OutputId, OutputMetadata}, payload::signed_transaction::TransactionId, @@ -14,17 +19,8 @@ use crate::{ Wallet, }, }; -#[cfg(feature = "events")] -use crate::{ - types::block::payload::signed_transaction::dto::SignedTransactionPayloadDto, - wallet::events::types::{NewOutputEvent, SpentOutputEvent, TransactionInclusionEvent, WalletEvent}, -}; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Set the alias for the wallet. pub async fn set_alias(&self, alias: &str) -> crate::wallet::Result<()> { let mut wallet_data = self.data_mut().await; diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index 33515fe33d..32ea7244a7 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -1,19 +1,21 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use core::ops::Range; + #[cfg(feature = "stronghold")] use crypto::keys::bip39::Mnemonic; +use crypto::signatures::secp256k1_ecdsa::EvmAddress; #[cfg(feature = "stronghold")] use iota_sdk::client::secret::stronghold::StrongholdSecretManager; use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::{IOTA_BECH32_HRP, IOTA_COIN_TYPE, IOTA_TESTNET_BECH32_HRP, SHIMMER_BECH32_HRP, SHIMMER_COIN_TYPE}, generate_mnemonic, - secret::{GenerateAddressOptions, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, MultiKeyOptions, PublicKeyOptions, SecretManageExt}, Client, Result, }, - types::block::address::{Address, Hrp}, + types::block::address::{Address, Ed25519Address, Hrp, ToBech32Ext}, }; use pretty_assertions::assert_eq; use serde::{Deserialize, Serialize}; @@ -22,22 +24,23 @@ use serde::{Deserialize, Serialize}; async fn ed25519_addresses() { let secret_manager = crate::client::node_api::setup_secret_manager(); - let opts = GetAddressesOptions::default() - .with_bech32_hrp(IOTA_TESTNET_BECH32_HRP) - .with_coin_type(IOTA_COIN_TYPE) - .with_range(0..1); - let public = secret_manager.generate_ed25519_addresses(opts.clone()).await.unwrap(); + let public = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await + .unwrap() + .to_bech32(IOTA_TESTNET_BECH32_HRP); let internal = secret_manager - .generate_ed25519_addresses(opts.internal()) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_internal(true)) .await - .unwrap(); + .unwrap() + .to_bech32(IOTA_TESTNET_BECH32_HRP); assert_eq!( - public[0], + public, "atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r" ); assert_eq!( - internal[0], + internal, "atoi1qprxpfvaz2peggq6f8k9cj8zfsxuw69e4nszjyv5kuf8yt70t2847shpjak" ); } @@ -46,18 +49,26 @@ async fn ed25519_addresses() { async fn evm_addresses() { let secret_manager = crate::client::node_api::setup_secret_manager(); - let opts = GetAddressesOptions::default() - .with_bech32_hrp(IOTA_TESTNET_BECH32_HRP) - .with_coin_type(IOTA_COIN_TYPE) - .with_range(0..1); - let public = secret_manager.generate_evm_addresses(opts.clone()).await.unwrap(); - let internal = secret_manager.generate_evm_addresses(opts.internal()).await.unwrap(); + let public = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await + .unwrap(); + let internal = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_internal(true)) + .await + .unwrap(); // Address generated with bip32 path: [44, 4218, 0, 0, 0]. // This address was generated with a MnemonicSecretManager and verified with an outside source. // Seed: 0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2. - assert_eq!(public[0], "0xb23e784f0464a30d536c961e414925eab6b3107d"); - assert_eq!(internal[0], "0x98d8833ec4b82587d66207eb9c578fd0134c51b6"); + assert_eq!( + prefix_hex::encode(public.as_ref()), + "0xb23e784f0464a30d536c961e414925eab6b3107d" + ); + assert_eq!( + prefix_hex::encode(internal.as_ref()), + "0x98d8833ec4b82587d66207eb9c578fd0134c51b6" + ); } #[tokio::test] @@ -79,19 +90,16 @@ async fn public_key_to_address() { #[tokio::test] async fn mnemonic_address_generation_iota() { let mnemonic = "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast".to_owned(); - let secret_manager = SecretManager::try_from_mnemonic(mnemonic).unwrap(); + let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic).unwrap(); // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(IOTA_BECH32_HRP) - .with_coin_type(IOTA_COIN_TYPE) - .with_range(0..2) - .with_account_index(0), - ) + .generate::>(&MultiKeyOptions::new(IOTA_COIN_TYPE).with_address_range(0..2)) .await - .unwrap(); + .unwrap() + .into_iter() + .map(|a| a.to_bech32(IOTA_BECH32_HRP)) + .collect::>(); assert_eq!( addresses[0], @@ -103,19 +111,14 @@ async fn mnemonic_address_generation_iota() { ); // account 1 - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(IOTA_BECH32_HRP) - .with_coin_type(IOTA_COIN_TYPE) - .with_range(0..1) - .with_account_index(1), - ) + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_account_index(1)) .await - .unwrap(); + .unwrap() + .to_bech32(IOTA_BECH32_HRP); assert_eq!( - addresses[0], + address, "iota1qr43g007shcd7zx3xe7s4lu2c9fr33w7tfjppyy0swlhrxx247szqhuaeaa" ); } @@ -123,19 +126,16 @@ async fn mnemonic_address_generation_iota() { #[tokio::test] async fn mnemonic_address_generation_shimmer() { let mnemonic = "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast".to_owned(); - let secret_manager = SecretManager::try_from_mnemonic(mnemonic).unwrap(); + let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic).unwrap(); // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..2) - .with_account_index(0), - ) + .generate::>(&MultiKeyOptions::new(SHIMMER_COIN_TYPE).with_address_range(0..2)) .await - .unwrap(); + .unwrap() + .into_iter() + .map(|a| a.to_bech32(SHIMMER_BECH32_HRP)) + .collect::>(); assert_eq!( addresses[0], @@ -147,19 +147,14 @@ async fn mnemonic_address_generation_shimmer() { ); // account 1 - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1) - .with_account_index(1), - ) + let address = secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE).with_account_index(1)) .await - .unwrap(); + .unwrap() + .to_bech32(SHIMMER_BECH32_HRP); assert_eq!( - addresses[0], + address, "smr1qrexl2g0m74v57y4kl6kfwqz7zrlrkvjt8m30av0cxgxlu92kyzc5npslm8" ); } @@ -184,26 +179,22 @@ async fn address_generation() { let addresses_data: Vec = serde_json::from_value(general.get("address_generations").unwrap().clone()).unwrap(); - for address in &addresses_data { - let secret_manager = SecretManager::try_from_mnemonic(address.mnemonic.clone()).unwrap(); - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(address.bech32_hrp) - .with_coin_type(address.coin_type) - .with_range(address.address_index..address.address_index + 1) - .with_account_index(address.account_index) - .with_options(GenerateAddressOptions { - internal: address.internal, - ..Default::default() - }), + for address_data in &addresses_data { + let secret_manager = MnemonicSecretManager::try_from_mnemonic(address_data.mnemonic.clone()).unwrap(); + let address = secret_manager + .generate::( + &PublicKeyOptions::new(address_data.coin_type) + .with_account_index(address_data.account_index) + .with_address_index(address_data.address_index) + .with_internal(address_data.internal), ) .await - .unwrap(); + .unwrap() + .to_bech32(address_data.bech32_hrp); - assert_eq!(addresses[0], address.bech32_address); - if let Address::Ed25519(ed25519_address) = addresses[0].inner() { - assert_eq!(ed25519_address.to_string(), address.ed25519_address); + assert_eq!(address, address_data.bech32_address); + if let Address::Ed25519(ed25519_address) = address.inner() { + assert_eq!(ed25519_address.to_string(), address_data.ed25519_address); } else { panic!("Invalid address type") } @@ -212,36 +203,32 @@ async fn address_generation() { #[cfg(feature = "stronghold")] { iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); - for address in &addresses_data { - let stronghold_filename = format!("{}.stronghold", address.bech32_address); + for address_data in &addresses_data { + let stronghold_filename = format!("{}.stronghold", address_data.bech32_address); let stronghold_secret_manager = StrongholdSecretManager::builder() .password("some_hopefully_secure_password".to_owned()) .build(&stronghold_filename) .unwrap(); stronghold_secret_manager - .store_mnemonic(Mnemonic::from(address.mnemonic.as_str())) + .store_mnemonic(Mnemonic::from(address_data.mnemonic.as_str())) .await .unwrap(); - let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(address.bech32_hrp) - .with_coin_type(address.coin_type) - .with_range(address.address_index..address.address_index + 1) - .with_account_index(address.account_index) - .with_options(GenerateAddressOptions { - internal: address.internal, - ..Default::default() - }), + let address = stronghold_secret_manager + .generate::( + &PublicKeyOptions::new(address_data.coin_type) + .with_account_index(address_data.account_index) + .with_address_index(address_data.address_index) + .with_internal(address_data.internal), ) .await - .unwrap(); + .unwrap() + .to_bech32(address_data.bech32_hrp); - assert_eq!(addresses[0], address.bech32_address); - if let Address::Ed25519(ed25519_address) = addresses[0].inner() { - assert_eq!(ed25519_address.to_string(), address.ed25519_address); + assert_eq!(address, address_data.bech32_address); + if let Address::Ed25519(ed25519_address) = address.inner() { + assert_eq!(ed25519_address.to_string(), address_data.ed25519_address); } else { panic!("Invalid address type") } @@ -251,64 +238,34 @@ async fn address_generation() { } #[tokio::test] -async fn search_address() -> Result<()> { - let client = Client::builder().finish().await.unwrap(); - - let secret_manager = SecretManager::try_from_mnemonic(generate_mnemonic()?)?; +async fn address_search() -> Result<()> { + let secret_manager = MnemonicSecretManager::try_from_mnemonic(generate_mnemonic()?)?; // Public - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? - .with_coin_type(IOTA_COIN_TYPE) - .with_account_index(0) - .with_range(9..10) - .with_bech32_hrp(IOTA_BECH32_HRP), - ) - .await?; + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_address_index(9)) + .await + .unwrap(); - let res = iota_sdk::client::api::search_address( - &secret_manager, - IOTA_BECH32_HRP, - IOTA_COIN_TYPE, - 0, - 0..10, - &addresses[0], - ) - .await?; + let res = search_address(&secret_manager, IOTA_BECH32_HRP, IOTA_COIN_TYPE, 0, 0..10, &address).await?; assert_eq!(res, (9, false)); // Internal - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await? - .internal() - .with_coin_type(IOTA_COIN_TYPE) - .with_account_index(0) - .with_range(9..10) - .with_bech32_hrp(IOTA_BECH32_HRP), + let address = secret_manager + .generate::( + &PublicKeyOptions::new(IOTA_COIN_TYPE) + .with_address_index(9) + .with_internal(true), ) .await?; - let res = iota_sdk::client::api::search_address( - &secret_manager, - IOTA_BECH32_HRP, - IOTA_COIN_TYPE, - 0, - 0..10, - &addresses[0], - ) - .await?; + let res = search_address(&secret_manager, IOTA_BECH32_HRP, IOTA_COIN_TYPE, 0, 0..10, &address).await?; assert_eq!(res, (9, true)); // not in range - let res = - iota_sdk::client::api::search_address(&secret_manager, IOTA_BECH32_HRP, IOTA_COIN_TYPE, 0, 0..9, &addresses[0]) - .await; + let res = search_address(&secret_manager, IOTA_BECH32_HRP, IOTA_COIN_TYPE, 0, 0..9, &address).await; match res { Err(iota_sdk::client::Error::InputAddressNotFound { .. }) => {} @@ -317,3 +274,32 @@ async fn search_address() -> Result<()> { Ok(()) } + +pub async fn search_address, Options = MultiKeyOptions>>( + secret_manager: &S, + bech32_hrp: Hrp, + coin_type: u32, + account_index: u32, + range: Range, + address: &Ed25519Address, +) -> Result<(u32, bool)> { + use iota_sdk::client::secret::Generate; + let mut opts = MultiKeyOptions::new(coin_type) + .with_account_index(account_index) + .with_address_range(range.clone()); + let public = Generate::>::generate(secret_manager, &opts).await?; + opts = opts.with_internal(true); + let internal = Generate::>::generate(secret_manager, &opts).await?; + for index in 0..public.len() { + if &public[index] == address { + return Ok((range.start + index as u32, false)); + } + if &internal[index] == address { + return Ok((range.start + index as u32, true)); + } + } + Err(iota_sdk::client::Error::InputAddressNotFound { + address: address.clone().to_bech32(bech32_hrp).to_string(), + range: format!("{range:?}"), + }) +} diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index d798619e03..937a70f2d3 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -26,24 +26,22 @@ fn input_account_eq_output_account() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -65,25 +63,23 @@ fn transition_account_id_zero() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); let account_id = AccountId::from(inputs[0].output_id()); - let outputs = build_outputs([Account( - 1_000_000, + let outputs = build_outputs([Account { + amount: 1_000_000, account_id, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -239,26 +235,24 @@ fn create_account() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -289,26 +283,24 @@ fn burn_account() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -376,26 +368,24 @@ fn missing_input_for_account_output() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -420,35 +410,32 @@ fn missing_input_for_account_output_2() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -471,26 +458,24 @@ fn missing_input_for_account_output_but_created() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -511,40 +496,37 @@ fn account_in_output_and_sender() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let account_output = AccountOutputBuilder::from(inputs[0].output.as_account()) .finish_output() .unwrap(); - let mut outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let mut outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); outputs.push(account_output); let selected = InputSelection::new( @@ -567,24 +549,22 @@ fn missing_ed25519_sender() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -607,26 +587,24 @@ fn missing_ed25519_issuer_created() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -649,24 +627,22 @@ fn missing_ed25519_issuer_transition() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -686,24 +662,22 @@ fn missing_account_sender() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -726,26 +700,24 @@ fn missing_account_issuer_created() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -768,24 +740,22 @@ fn missing_account_issuer_transition() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -805,24 +775,22 @@ fn missing_nft_sender() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + issuer: None, + }]); let selected = InputSelection::new( inputs, @@ -845,26 +813,24 @@ fn missing_nft_issuer_created() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -887,24 +853,22 @@ fn missing_nft_issuer_transition() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - )], + [Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + }]); let selected = InputSelection::new( inputs, @@ -925,35 +889,32 @@ fn increase_account_amount() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 3_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 3_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -976,35 +937,32 @@ fn decrease_account_amount() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1039,37 +997,34 @@ fn prefer_basic_to_account() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1093,37 +1048,34 @@ fn take_amount_from_account_to_fund_basic() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_200_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_200_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1161,37 +1113,34 @@ fn account_burn_should_validate_account_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1227,37 +1176,34 @@ fn account_burn_should_validate_account_address() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1292,26 +1238,24 @@ fn transitioned_zero_account_id_no_longer_is_zero() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1350,35 +1294,32 @@ fn two_accounts_required() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Account( - 2_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Account { + amount: 2_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1421,26 +1362,24 @@ fn state_controller_sender_required() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1463,35 +1402,32 @@ fn state_controller_sender_required_already_selected() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -1515,24 +1451,22 @@ fn state_transition_and_required() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1555,24 +1489,22 @@ fn remainder_address_in_state_controller() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/basic_outputs.rs b/sdk/tests/client/input_selection/basic_outputs.rs index 5689848353..46035ea8ea 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -25,28 +25,26 @@ fn input_amount_equal_output_amount() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -67,28 +65,26 @@ fn input_amount_lower_than_output_amount() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -114,39 +110,36 @@ fn input_amount_lower_than_output_amount_2() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -171,28 +164,26 @@ fn input_amount_greater_than_output_amount() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -226,28 +217,26 @@ fn input_amount_greater_than_output_amount_with_remainder_address() { let remainder_address = Address::try_from_bech32(BECH32_ADDRESS_REMAINDER).unwrap(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -282,39 +271,36 @@ fn two_same_inputs_one_needed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -349,39 +335,36 @@ fn two_inputs_one_needed() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -403,39 +386,36 @@ fn two_inputs_one_needed_reversed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -457,39 +437,36 @@ fn two_inputs_both_needed() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -511,39 +488,36 @@ fn two_inputs_remainder() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -620,69 +594,63 @@ fn ed25519_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -714,28 +682,26 @@ fn missing_ed25519_sender() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -759,67 +725,61 @@ fn account_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -851,38 +811,35 @@ fn account_sender_zero_id() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); let account_id = AccountId::from(inputs[1].output_id()); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::from(account_id)), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::from(account_id)), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -909,28 +866,26 @@ fn missing_account_sender() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -954,69 +909,63 @@ fn nft_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1048,41 +997,38 @@ fn nft_sender_zero_id() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), + [ + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let nft_id = NftId::from(inputs[1].output_id()); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::from(nft_id)), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::from(nft_id)), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1109,28 +1055,26 @@ fn missing_nft_sender() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -1152,28 +1096,26 @@ fn simple_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1285,28 +1227,26 @@ fn one_provided_one_needed() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1327,28 +1267,26 @@ fn insufficient_amount() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_250_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_250_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -1374,39 +1312,36 @@ fn two_inputs_remainder_2() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1440,39 +1375,36 @@ fn two_inputs_remainder_3() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_750_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_750_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1544,28 +1476,26 @@ fn sender_already_selected() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1590,28 +1520,26 @@ fn single_mandatory_input() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1637,31 +1565,27 @@ fn too_many_inputs() { // 129 inputs that would be required for the amount, but that's above max inputs let inputs = build_inputs( - std::iter::repeat_with(|| { - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ) + std::iter::repeat_with(|| Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, }) .take(129), None, ); - let outputs = build_outputs([Basic( - 129_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 129_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -1684,47 +1608,42 @@ fn more_than_max_inputs_only_one_needed() { // 1000 inputs where 129 would be needed for the required amount which is above the max inputs let mut inputs = build_inputs( - std::iter::repeat_with(|| { - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ) + std::iter::repeat_with(|| Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, }) .take(1000), None, ); // Add the needed input let needed_input = build_inputs( - [Basic( - 129_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 129_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); inputs.push(needed_input[0].clone()); - let outputs = build_outputs([Basic( - 129_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 129_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -1745,30 +1664,26 @@ fn too_many_outputs() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); let outputs = build_outputs( - std::iter::repeat_with(|| { - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ) + std::iter::repeat_with(|| Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, }) .take(129), ); @@ -1793,31 +1708,27 @@ fn too_many_outputs_with_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); let outputs = build_outputs( - std::iter::repeat_with(|| { - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ) + std::iter::repeat_with(|| Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, }) .take(128), ); @@ -1846,60 +1757,63 @@ fn restricted_ed25519() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic(1_000_000, restricted, None, None, None, None, None, None), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: restricted, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1925,30 +1839,36 @@ fn restricted_nft() { let inputs = build_inputs( [ - Basic(2_000_000, restricted, None, None, None, None, None, None), - Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: restricted, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1974,28 +1894,34 @@ fn restricted_account() { let inputs = build_inputs( [ - Basic(3_000_000, restricted, None, None, None, None, None, None), - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 3_000_000, + address: restricted, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -2020,69 +1946,63 @@ fn restricted_ed25519_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(restricted_sender), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(restricted_sender), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -2129,49 +2049,45 @@ fn multi_address_sender_already_fulfilled() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(multi), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(multi), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -2204,41 +2120,46 @@ fn ed25519_backed_available_address() { let inputs = build_inputs( [ - Basic( - 1_000_000, - restricted_address.clone(), - None, - None, - None, - None, - None, - None, - ), - Basic(1_000_000, ed25519.clone(), None, None, None, None, None, None), + Basic { + amount: 1_000_000, + address: restricted_address.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: ed25519.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(restricted_address.clone()), - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(restricted_address.clone()), + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/burn.rs b/sdk/tests/client/input_selection/burn.rs index 1a450bdfa2..f7a8b0ae54 100644 --- a/sdk/tests/client/input_selection/burn.rs +++ b/sdk/tests/client/input_selection/burn.rs @@ -30,37 +30,34 @@ fn burn_account_present() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -85,37 +82,34 @@ fn burn_account_present_and_required() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -141,39 +135,36 @@ fn burn_account_id_zero() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let nft_id = NftId::from(inputs[0].output_id()); let selected = InputSelection::new( @@ -198,28 +189,26 @@ fn burn_account_absent() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -245,45 +234,41 @@ fn burn_accounts_present() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -307,46 +292,42 @@ fn burn_account_in_outputs() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -372,39 +353,36 @@ fn burn_nft_present() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -429,39 +407,36 @@ fn burn_nft_present_and_required() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -487,37 +462,34 @@ fn burn_nft_id_zero() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let account_id = AccountId::from(inputs[0].output_id()); let selected = InputSelection::new( @@ -542,28 +514,26 @@ fn burn_nft_absent() { let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -589,49 +559,45 @@ fn burn_nfts_present() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -655,50 +621,46 @@ fn burn_nft_in_outputs() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -724,44 +686,41 @@ fn burn_foundry_present() { let inputs = build_inputs( [ - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -810,13 +769,13 @@ fn burn_foundry_absent() { let protocol_parameters = protocol_parameters(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id_1 = build_inputs( - [Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - )], + [Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }], Some(SLOT_INDEX), )[0] .output @@ -825,37 +784,34 @@ fn burn_foundry_absent() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -880,41 +836,39 @@ fn burn_foundries_present() { let inputs = build_inputs( [ - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Foundry( - 1_000_000, - account_id_1, - 2, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 2, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -956,44 +910,42 @@ fn burn_foundry_in_outputs() { let inputs = build_inputs( [ - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let foundry_id_1 = inputs[0].output.as_foundry().id(); @@ -1019,26 +971,24 @@ fn burn_native_tokens() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); @@ -1065,12 +1015,12 @@ fn burn_native_tokens() { &selected.outputs[0], nt_remainder_output_amount, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 80)) + Some((TOKEN_ID_1.to_string(), 80)) ) && is_remainder_or_return( &selected.outputs[1], 2_000_000 - nt_remainder_output_amount, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 70)) + Some((TOKEN_ID_2.to_string(), 70)) ) ); } @@ -1082,44 +1032,41 @@ fn burn_foundry_and_its_account() { let inputs = build_inputs( [ - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/delegation_outputs.rs b/sdk/tests/client/input_selection/delegation_outputs.rs index cbece610ef..6eed35ac8d 100644 --- a/sdk/tests/client/input_selection/delegation_outputs.rs +++ b/sdk/tests/client/input_selection/delegation_outputs.rs @@ -55,7 +55,6 @@ fn remainder_needed_for_mana() { InputSigningData { output, output_metadata: rand_output_metadata_with_id(OutputId::new(transaction_id, 0)), - chain: None, } }) .collect::>(); diff --git a/sdk/tests/client/input_selection/expiration.rs b/sdk/tests/client/input_selection/expiration.rs index 82c56051c5..63e2f627be 100644 --- a/sdk/tests/client/input_selection/expiration.rs +++ b/sdk/tests/client/input_selection/expiration.rs @@ -26,28 +26,26 @@ fn one_output_expiration_not_expired() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -66,28 +64,26 @@ fn expiration_equal_timestamp() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), + }], Some(SlotIndex::from(200)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -108,28 +104,26 @@ fn one_output_expiration_expired() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -151,39 +145,36 @@ fn two_outputs_one_expiration_expired() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -206,39 +197,36 @@ fn two_outputs_one_unexpired_one_missing() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -261,49 +249,45 @@ fn two_outputs_two_expired() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 100)), - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 100)), + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SlotIndex::from(200)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -326,39 +310,36 @@ fn two_outputs_two_expired_2() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 100)), - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 100)), + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), + }, ], Some(SlotIndex::from(200)), ); - let outputs = build_outputs([Basic( - 4_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 4_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -382,28 +363,26 @@ fn expiration_expired_with_sdr() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -424,28 +403,26 @@ fn expiration_expired_with_sdr_2() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -466,28 +443,26 @@ fn expiration_expired_with_sdr_and_timelock() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 1_000_000)), - Some(50), - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 1_000_000)), + timelock: Some(50), + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -508,28 +483,26 @@ fn expiration_expired_with_sdr_and_timelock_2() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - Some(50), - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: Some(50), + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -551,69 +524,63 @@ fn sender_in_expiration() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -638,28 +605,26 @@ fn sender_in_expiration_already_selected() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -684,28 +649,26 @@ fn remainder_in_expiration() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -740,28 +703,26 @@ fn expiration_expired_non_ed25519_in_address_unlock_condition() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -784,38 +745,35 @@ fn expiration_expired_only_account_addresses() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), 50)), - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), 50)), + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -837,28 +795,26 @@ fn one_nft_output_expiration_unexpired() { let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( - [Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 150)), - None, - )], + [Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 150)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -880,28 +836,26 @@ fn one_nft_output_expiration_expired() { let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( - [Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, - )], + [Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/foundry_outputs.rs b/sdk/tests/client/input_selection/foundry_outputs.rs index 7ec2d88494..113cc52fcd 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -32,25 +32,24 @@ fn missing_input_account_for_foundry() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs, @@ -112,34 +111,32 @@ fn minted_native_tokens_in_new_remainder() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(10, 0, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 0, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -172,45 +169,42 @@ fn minted_native_tokens_in_provided_output() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(100, 0, 100).unwrap(), - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((&token_id.to_string(), 100)), - None, - None, - None, - None, - None, - ), + Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 100).unwrap(), + native_token: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((token_id.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -237,26 +231,25 @@ fn melt_native_tokens() { let mut inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 0, 10).unwrap(), - Some(( - "0x0811111111111111111111111111111111111111111111111111111111111111110100000000", + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 0, 10).unwrap(), + native_token: Some(( + "0x0811111111111111111111111111111111111111111111111111111111111111110100000000".to_owned(), 10, )), - ), + }, ], Some(SLOT_INDEX), ); @@ -270,16 +263,14 @@ fn melt_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - // Melt 5 native tokens - SimpleTokenScheme::new(10, 5, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 5, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -310,21 +301,20 @@ fn destroy_foundry_with_account_state_transition() { let inputs = build_inputs( [ - Account( - 50_300, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 52_800, - account_id_2, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - ), + Account { + amount: 50_300, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 52_800, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); @@ -358,34 +348,32 @@ fn destroy_foundry_with_account_burn() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -424,44 +412,41 @@ fn prefer_basic_to_foundry() { let inputs = build_inputs( [ - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -485,23 +470,22 @@ fn simple_foundry_transition_basic_not_needed() { let mut inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); @@ -515,16 +499,15 @@ fn simple_foundry_transition_basic_not_needed() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -564,23 +547,22 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { let mut inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Foundry( - 2_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Foundry { + amount: 2_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); @@ -594,15 +576,14 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(10, 10, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(10, 10, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -720,13 +701,13 @@ fn mint_and_burn_at_the_same_time() { let token_id = TokenId::from(foundry_id); let mut inputs = build_inputs( - [Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 200).unwrap(), - Some((&token_id.to_string(), 100)), - )], + [Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 200).unwrap(), + native_token: Some((token_id.to_string(), 100)), + }], Some(SLOT_INDEX), ); let account_output = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) @@ -739,16 +720,15 @@ fn mint_and_burn_at_the_same_time() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(120, 0, 200).unwrap(), - Some((&token_id.to_string(), 110)), - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(120, 0, 200).unwrap(), + native_token: Some((token_id.to_string(), 110)), + }]); let selected = InputSelection::new( inputs.clone(), @@ -775,23 +755,22 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { let mut inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 200).unwrap(), - Some((&token_id.to_string(), 100)), - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 200).unwrap(), + native_token: Some((token_id.to_string(), 100)), + }, ], Some(SLOT_INDEX), ); @@ -805,18 +784,16 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Basic( - 3_200_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_200_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -848,31 +825,30 @@ fn create_native_token_but_burn_account() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(0, 0, 100).unwrap(), - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 100).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 100).unwrap(), - Some((&token_id.to_string(), 100)), - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 100).unwrap(), + native_token: Some((token_id.to_string(), 100)), + }]); let selected = InputSelection::new( inputs.clone(), @@ -910,31 +886,30 @@ fn melted_tokens_not_provided() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 100).unwrap(), - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 100).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 100, 100).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 100, 100).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs, @@ -963,31 +938,30 @@ fn burned_tokens_not_provided() { let inputs = build_inputs( [ - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), - Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 100).unwrap(), - None, - ), + Account { + amount: 2_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, + Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 100).unwrap(), + native_token: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_1, - 1, - SimpleTokenScheme::new(100, 0, 100).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_1, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(100, 0, 100).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs, @@ -1014,13 +988,13 @@ fn foundry_in_outputs_and_required() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let mut inputs = build_inputs( - [Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - )], + [Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }], Some(SLOT_INDEX), ); let account_output = AccountOutputBuilder::new_with_amount(1_251_500, account_id_2) @@ -1033,15 +1007,14 @@ fn foundry_in_outputs_and_required() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, - account_id_2, - 1, - SimpleTokenScheme::new(0, 0, 10).unwrap(), - None, - )]); + let outputs = build_outputs([Foundry { + amount: 1_000_000, + account_id: account_id_2, + serial_number: 1, + token_scheme: SimpleTokenScheme::new(0, 0, 10).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1073,23 +1046,22 @@ fn melt_and_burn_native_tokens() { let mut inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Foundry( - 1_000_000, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Foundry { + amount: 1_000_000, account_id, - 1, - SimpleTokenScheme::new(1000, 0, 1000).unwrap(), - Some((&token_id.to_string(), 1000)), - ), + serial_number: 1, + token_scheme: SimpleTokenScheme::new(1000, 0, 1000).unwrap(), + native_token: Some((token_id.to_string(), 1000)), + }, ], Some(SLOT_INDEX), ); @@ -1103,16 +1075,14 @@ fn melt_and_burn_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }); - let outputs = build_outputs([Foundry( - 1_000_000, + let outputs = build_outputs([Foundry { + amount: 1_000_000, account_id, - 1, - // Melt 123 native tokens - SimpleTokenScheme::new(1000, 123, 1000).unwrap(), - None, - )]); + serial_number: 1, + token_scheme: SimpleTokenScheme::new(1000, 123, 1000).unwrap(), + native_token: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/native_tokens.rs b/sdk/tests/client/input_selection/native_tokens.rs index 688b2f893c..81655582f4 100644 --- a/sdk/tests/client/input_selection/native_tokens.rs +++ b/sdk/tests/client/input_selection/native_tokens.rs @@ -21,39 +21,36 @@ fn two_native_tokens_one_needed() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 150)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 150)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -76,50 +73,46 @@ fn two_native_tokens_both_needed_plus_remainder() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 150)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -141,7 +134,7 @@ fn two_native_tokens_both_needed_plus_remainder() { output, 2_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 50)) + Some((TOKEN_ID_2.to_string(), 50)) )); } }); @@ -153,49 +146,45 @@ fn three_inputs_two_needed_plus_remainder() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 120)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 120)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -216,7 +205,7 @@ fn three_inputs_two_needed_plus_remainder() { output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 80)) + Some((TOKEN_ID_1.to_string(), 80)) )); } }); @@ -228,49 +217,45 @@ fn three_inputs_two_needed_no_remainder() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -291,28 +276,26 @@ fn insufficient_native_tokens_one_input() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 150)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -338,49 +321,45 @@ fn insufficient_native_tokens_three_inputs() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 301)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 301)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -406,39 +385,36 @@ fn burn_and_send_at_the_same_time() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 50)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -464,7 +440,7 @@ fn burn_and_send_at_the_same_time() { output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 40)) + Some((TOKEN_ID_1.to_string(), 40)) )); } }); @@ -475,16 +451,15 @@ fn burn_one_input_no_output() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); @@ -505,7 +480,7 @@ fn burn_one_input_no_output() { &selected.outputs[0], 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)) + Some((TOKEN_ID_1.to_string(), 50)) )); } @@ -515,39 +490,36 @@ fn multiple_native_tokens() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -569,28 +541,26 @@ fn insufficient_native_tokens() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 150)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -615,28 +585,26 @@ fn insufficient_native_tokens_2() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 150)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 150)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -661,28 +629,26 @@ fn insufficient_amount_for_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 50)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -707,28 +673,26 @@ fn single_output_native_token_no_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -749,28 +713,26 @@ fn single_output_native_token_remainder_1() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 50)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -789,7 +751,7 @@ fn single_output_native_token_remainder_1() { &selected.outputs[0], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)) + Some((TOKEN_ID_1.to_string(), 50)) )); } @@ -798,28 +760,26 @@ fn single_output_native_token_remainder_2() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -848,39 +808,36 @@ fn two_basic_outputs_1() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -900,7 +857,7 @@ fn two_basic_outputs_1() { &selected.outputs[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), + Some((TOKEN_ID_1.to_string(), 100)), )); } @@ -910,39 +867,36 @@ fn two_basic_outputs_2() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 50)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -962,7 +916,7 @@ fn two_basic_outputs_2() { &selected.outputs[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), + Some((TOKEN_ID_1.to_string(), 50)), )); } @@ -972,39 +926,36 @@ fn two_basic_outputs_3() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 75)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 75)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1024,7 +975,7 @@ fn two_basic_outputs_3() { &selected.outputs[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 25)), + Some((TOKEN_ID_1.to_string(), 25)), )); } @@ -1034,39 +985,36 @@ fn two_basic_outputs_4() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1096,39 +1044,36 @@ fn two_basic_outputs_5() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1158,39 +1103,36 @@ fn two_basic_outputs_6() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 250)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 250)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1209,7 +1151,7 @@ fn two_basic_outputs_6() { &selected.outputs[1], 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)), + Some((TOKEN_ID_1.to_string(), 50)), )); } @@ -1219,39 +1161,36 @@ fn two_basic_outputs_7() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 300)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 300)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1280,39 +1219,36 @@ fn two_basic_outputs_8() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 200)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 200)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 350)), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 350)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -1338,39 +1274,36 @@ fn two_basic_outputs_native_tokens_not_needed() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 500_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 500_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1400,59 +1333,54 @@ fn multiple_remainders() { let inputs = build_inputs( [ - Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 100)), - None, - None, - None, - None, - None, - ), - Basic( - 5_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)), - None, - None, - None, - None, - None, - ), + Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_1.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 5_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: Some((TOKEN_ID_2.to_string(), 100)), + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 15_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 15_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1475,12 +1403,12 @@ fn multiple_remainders() { output, nt_remainder_min_storage_deposit, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 300)) + Some((TOKEN_ID_1.to_string(), 300)) ) || is_remainder_or_return( output, 5_000_000 - nt_remainder_min_storage_deposit, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)) + Some((TOKEN_ID_2.to_string(), 100)) ) ); } diff --git a/sdk/tests/client/input_selection/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 9c6748a316..46ab76ac70 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -30,28 +30,26 @@ fn input_nft_eq_output_nft() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -73,29 +71,27 @@ fn transition_nft_id_zero() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); let nft_id = NftId::from(inputs[0].output_id()); - let outputs = build_outputs([Nft( - 1_000_000, + let outputs = build_outputs([Nft { + amount: 1_000_000, nft_id, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -205,28 +201,26 @@ fn mint_nft() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -257,28 +251,26 @@ fn burn_nft() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 2_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 2_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -346,28 +338,26 @@ fn missing_input_for_nft_output() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -390,28 +380,26 @@ fn missing_input_for_nft_output_but_created() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -432,50 +420,46 @@ fn nft_in_output_and_sender() { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - None, - ), + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -506,28 +490,26 @@ fn missing_ed25519_sender() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -550,28 +532,26 @@ fn missing_ed25519_issuer_created() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -594,28 +574,26 @@ fn missing_ed25519_issuer_transition() { let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -635,28 +613,26 @@ fn missing_account_sender() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -679,28 +655,26 @@ fn missing_account_issuer_created() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -723,28 +697,26 @@ fn missing_account_issuer_transition() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -764,28 +736,26 @@ fn missing_nft_sender() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -808,28 +778,26 @@ fn missing_nft_issuer_created() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -852,28 +820,26 @@ fn missing_nft_issuer_transition() { let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( - [Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - )], + [Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -894,39 +860,36 @@ fn increase_nft_amount() { let inputs = build_inputs( [ - Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 3_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 3_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -949,39 +912,36 @@ fn decrease_nft_amount() { let inputs = build_inputs( [ - Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1016,39 +976,36 @@ fn prefer_basic_to_nft() { let inputs = build_inputs( [ - Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1072,39 +1029,36 @@ fn take_amount_from_nft_to_fund_basic() { let inputs = build_inputs( [ - Nft( - 2_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Nft { + amount: 2_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_200_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_200_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1140,39 +1094,36 @@ fn nft_burn_should_validate_nft_sender() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1196,39 +1147,36 @@ fn nft_burn_should_validate_nft_address() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 3_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1251,28 +1199,26 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( - [Nft( - 2_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - )], + [Nft { + amount: 2_000_000, + nft_id: nft_id_0, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -1329,7 +1275,6 @@ fn changed_immutable_metadata() { let inputs = [InputSigningData { output: nft_output.clone(), output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, }]; #[cfg(feature = "irc_27")] diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index 4d2a94ba0a..8c05baec25 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -20,16 +20,15 @@ fn no_inputs() { let protocol_parameters = protocol_parameters(); let inputs = Vec::new(); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -48,16 +47,15 @@ fn no_outputs() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); let outputs = Vec::new(); @@ -79,16 +77,15 @@ fn no_outputs_but_required_input() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); let outputs = Vec::new(); @@ -121,14 +118,13 @@ fn no_outputs_but_burn() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( - [Account( - 2_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - )], + [Account { + amount: 2_000_000, + account_id: account_id_2, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }], Some(SLOT_INDEX), ); let outputs = Vec::new(); @@ -159,28 +155,26 @@ fn no_address_provided() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new(inputs, outputs, [], SLOT_INDEX, protocol_parameters).select(); @@ -192,28 +186,26 @@ fn no_matching_address_provided() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )], + [Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], None, ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -233,39 +225,36 @@ fn two_addresses_one_missing() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -291,39 +280,36 @@ fn two_addresses() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/storage_deposit_return.rs b/sdk/tests/client/input_selection/storage_deposit_return.rs index 3b451de41a..800c9e9f14 100644 --- a/sdk/tests/client/input_selection/storage_deposit_return.rs +++ b/sdk/tests/client/input_selection/storage_deposit_return.rs @@ -21,28 +21,26 @@ fn sdruc_output_not_provided_no_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -74,39 +72,36 @@ fn sdruc_output_provided_no_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); let outputs = build_outputs([ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let selected = InputSelection::new( @@ -128,28 +123,26 @@ fn sdruc_output_provided_remainder() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -182,39 +175,36 @@ fn two_sdrucs_to_the_same_address_both_needed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -247,39 +237,36 @@ fn two_sdrucs_to_the_same_address_one_needed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -313,39 +300,36 @@ fn two_sdrucs_to_different_addresses_both_needed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -384,39 +368,36 @@ fn two_sdrucs_to_different_addresses_one_needed() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -449,28 +430,26 @@ fn insufficient_amount_because_of_sdruc() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), - None, - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -496,39 +475,36 @@ fn useless_sdruc_required_for_sender_feature() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -565,37 +541,34 @@ fn sdruc_required_non_ed25519_in_address_unlock() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None, - Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), + native_token: None, + sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -629,47 +602,43 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { let inputs = build_inputs( [ - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - ), + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_1, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }, ], Some(SLOT_INDEX), ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_selection/timelock.rs b/sdk/tests/client/input_selection/timelock.rs index a57655846c..9bcc6dbd4d 100644 --- a/sdk/tests/client/input_selection/timelock.rs +++ b/sdk/tests/client/input_selection/timelock.rs @@ -16,28 +16,26 @@ fn one_output_timelock_not_expired() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(200), - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(200), + expiration: None, + }], None, ); - let outputs = build_outputs([Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs, @@ -56,28 +54,26 @@ fn timelock_equal_timestamp() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(200), - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(200), + expiration: None, + }], Some(SlotIndex::from(200)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -99,39 +95,36 @@ fn two_outputs_one_timelock_expired() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(200), - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(50), - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(200), + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(50), + expiration: None, + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -154,39 +147,36 @@ fn two_outputs_one_timelocked_one_missing() { let inputs = build_inputs( [ - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(200), - None, - None, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - None, - ), + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(200), + expiration: None, + }, + Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -208,28 +198,26 @@ fn one_output_timelock_expired() { let protocol_parameters = protocol_parameters(); let inputs = build_inputs( - [Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(50), - None, - None, - )], + [Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: Some(50), + expiration: None, + }], Some(SlotIndex::from(100)), ); - let outputs = build_outputs([Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - None, - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), diff --git a/sdk/tests/client/input_signing_data.rs b/sdk/tests/client/input_signing_data.rs index 75dfe2658d..b44ffdd5c9 100644 --- a/sdk/tests/client/input_signing_data.rs +++ b/sdk/tests/client/input_signing_data.rs @@ -1,7 +1,6 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{constants::SHIMMER_COIN_TYPE, secret::types::InputSigningData}, types::block::{ @@ -14,8 +13,6 @@ use pretty_assertions::assert_eq; #[test] fn input_signing_data_conversion() { - let bip44_chain = Bip44::new(SHIMMER_COIN_TYPE); - let output = BasicOutput::build_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32("rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy").unwrap(), @@ -26,14 +23,10 @@ fn input_signing_data_conversion() { let input_signing_data = InputSigningData { output, output_metadata: rand_output_metadata(), - chain: Some(bip44_chain), }; - assert_eq!(input_signing_data.chain.as_ref(), Some(&bip44_chain)); - let input_signing_data_json = serde_json::to_value(&input_signing_data).unwrap(); let restored_input_signing_data = serde_json::from_value::(input_signing_data_json).unwrap(); assert!(restored_input_signing_data.output.is_basic()); - assert_eq!(restored_input_signing_data.chain.as_ref(), Some(&bip44_chain)); } diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index ff7e2d1bb7..d4fb769c28 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -17,9 +17,8 @@ mod signing; use std::{collections::HashMap, hash::Hash, str::FromStr}; -use crypto::keys::bip44::Bip44; use iota_sdk::{ - client::secret::types::InputSigningData, + client::secret::{mnemonic::MnemonicSecretManager, types::InputSigningData}, types::block::{ address::{AccountAddress, Address}, output::{ @@ -60,180 +59,176 @@ const _BECH32_ADDRESS_NFT_2: &str = "rms1zq3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3 const SLOT_INDEX: SlotIndex = SlotIndex(10); #[derive(Debug, Clone)] -enum Build<'a> { - Basic( - u64, - Address, - Option<(&'a str, u64)>, - Option
, - Option<(Address, u64)>, - Option, - Option<(Address, u32)>, - Option, - ), - Nft( - u64, - NftId, - Address, - Option
, - Option
, - Option<(Address, u64)>, - Option<(Address, u32)>, - Option, - ), - Account(u64, AccountId, Address, Option
, Option
, Option), - Foundry(u64, AccountId, u32, SimpleTokenScheme, Option<(&'a str, u64)>), -} - -fn build_basic_output( - amount: u64, - address: Address, - native_token: Option<(&str, u64)>, - sender: Option
, - sdruc: Option<(Address, u64)>, - timelock: Option, - expiration: Option<(Address, u32)>, -) -> Output { - let mut builder = - BasicOutputBuilder::new_with_amount(amount).add_unlock_condition(AddressUnlockCondition::new(address.clone())); - - if let Some((id, amount)) = native_token { - builder = builder.with_native_token(NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()); - } - - if let Some(sender) = sender { - builder = builder.add_feature(SenderFeature::new(sender.clone())); - } - - if let Some((address, amount)) = sdruc { - builder = - builder.add_unlock_condition(StorageDepositReturnUnlockCondition::new(address.clone(), amount).unwrap()); - } - - if let Some(timelock) = timelock { - builder = builder.add_unlock_condition(TimelockUnlockCondition::new(timelock).unwrap()); - } - - if let Some((address, timestamp)) = expiration { - builder = builder.add_unlock_condition(ExpirationUnlockCondition::new(address.clone(), timestamp).unwrap()); - } - - builder.finish_output().unwrap() -} - -fn build_nft_output( - amount: u64, - nft_id: NftId, - address: Address, - sender: Option
, - issuer: Option
, - sdruc: Option<(Address, u64)>, - expiration: Option<(Address, u32)>, -) -> Output { - let mut builder = NftOutputBuilder::new_with_amount(amount, nft_id) - .add_unlock_condition(AddressUnlockCondition::new(address.clone())); - - if let Some(sender) = sender { - builder = builder.add_feature(SenderFeature::new(sender.clone())); - } - - if let Some(issuer) = issuer { - builder = builder.add_immutable_feature(IssuerFeature::new(issuer.clone())); - } - - if let Some((address, amount)) = sdruc { - builder = - builder.add_unlock_condition(StorageDepositReturnUnlockCondition::new(address.clone(), amount).unwrap()); - } - - if let Some((address, timestamp)) = expiration { - builder = builder.add_unlock_condition(ExpirationUnlockCondition::new(address.clone(), timestamp).unwrap()); - } - - builder.finish_output().unwrap() -} - -fn build_account_output( - amount: u64, - account_id: AccountId, - address: Address, - sender: Option
, - issuer: Option
, -) -> Output { - let mut builder = AccountOutputBuilder::new_with_amount(amount, account_id) - .add_unlock_condition(AddressUnlockCondition::new(address.clone())); - - if let Some(sender) = sender { - builder = builder.add_feature(SenderFeature::new(sender.clone())); - } - - if let Some(issuer) = issuer { - builder = builder.add_immutable_feature(IssuerFeature::new(issuer.clone())); - } - - builder.finish_output().unwrap() -} - -fn build_foundry_output( - amount: u64, - account_id: AccountId, - serial_number: u32, - token_scheme: SimpleTokenScheme, - native_token: Option<(&str, u64)>, -) -> Output { - let mut builder = FoundryOutputBuilder::new_with_amount(amount, serial_number, TokenScheme::Simple(token_scheme)) - .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(AccountAddress::new( - account_id, - ))); - - if let Some((id, amount)) = native_token { - builder = builder.with_native_token(NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()); - } - - builder.finish_output().unwrap() +enum Build { + Basic { + amount: u64, + address: Address, + native_token: Option<(String, u64)>, + sender: Option
, + sdruc: Option<(Address, u64)>, + timelock: Option, + expiration: Option<(Address, u32)>, + }, + Nft { + amount: u64, + nft_id: NftId, + address: Address, + sender: Option
, + issuer: Option
, + sdruc: Option<(Address, u64)>, + expiration: Option<(Address, u32)>, + }, + Account { + amount: u64, + account_id: AccountId, + address: Address, + sender: Option
, + issuer: Option
, + }, + Foundry { + amount: u64, + account_id: AccountId, + serial_number: u32, + token_scheme: SimpleTokenScheme, + native_token: Option<(String, u64)>, + }, } -fn build_output_inner(build: Build) -> (Output, Option) { - match build { - Build::Basic(amount, address, native_token, sender, sdruc, timelock, expiration, chain) => ( - build_basic_output(amount, address, native_token, sender, sdruc, timelock, expiration), - chain, - ), - Build::Nft(amount, nft_id, address, sender, issuer, sdruc, expiration, chain) => ( - build_nft_output(amount, nft_id, address, sender, issuer, sdruc, expiration), - chain, - ), - Build::Account(amount, account_id, address, sender, issuer, chain) => { - (build_account_output(amount, account_id, address, sender, issuer), chain) +impl Build { + fn build(self) -> Output { + match self { + Build::Basic { + amount, + address, + native_token, + sender, + sdruc, + timelock, + expiration, + } => { + let mut builder = BasicOutputBuilder::new_with_amount(amount) + .add_unlock_condition(AddressUnlockCondition::new(address.clone())); + + if let Some((id, amount)) = native_token { + builder = + builder.with_native_token(NativeToken::new(TokenId::from_str(&id).unwrap(), amount).unwrap()); + } + + if let Some(sender) = sender { + builder = builder.add_feature(SenderFeature::new(sender.clone())); + } + + if let Some((address, amount)) = sdruc { + builder = builder.add_unlock_condition( + StorageDepositReturnUnlockCondition::new(address.clone(), amount).unwrap(), + ); + } + + if let Some(timelock) = timelock { + builder = builder.add_unlock_condition(TimelockUnlockCondition::new(timelock).unwrap()); + } + + if let Some((address, timestamp)) = expiration { + builder = builder + .add_unlock_condition(ExpirationUnlockCondition::new(address.clone(), timestamp).unwrap()); + } + + builder.finish_output().unwrap() + } + Build::Nft { + amount, + nft_id, + address, + sender, + issuer, + sdruc, + expiration, + } => { + let mut builder = NftOutputBuilder::new_with_amount(amount, nft_id) + .add_unlock_condition(AddressUnlockCondition::new(address.clone())); + + if let Some(sender) = sender { + builder = builder.add_feature(SenderFeature::new(sender.clone())); + } + + if let Some(issuer) = issuer { + builder = builder.add_immutable_feature(IssuerFeature::new(issuer.clone())); + } + + if let Some((address, amount)) = sdruc { + builder = builder.add_unlock_condition( + StorageDepositReturnUnlockCondition::new(address.clone(), amount).unwrap(), + ); + } + + if let Some((address, timestamp)) = expiration { + builder = builder + .add_unlock_condition(ExpirationUnlockCondition::new(address.clone(), timestamp).unwrap()); + } + + builder.finish_output().unwrap() + } + Build::Account { + amount, + account_id, + address, + sender, + issuer, + } => { + let mut builder = AccountOutputBuilder::new_with_amount(amount, account_id) + .add_unlock_condition(AddressUnlockCondition::new(address.clone())); + + if let Some(sender) = sender { + builder = builder.add_feature(SenderFeature::new(sender.clone())); + } + + if let Some(issuer) = issuer { + builder = builder.add_immutable_feature(IssuerFeature::new(issuer.clone())); + } + + builder.finish_output().unwrap() + } + Build::Foundry { + amount, + account_id, + serial_number, + token_scheme, + native_token, + } => { + let mut builder = + FoundryOutputBuilder::new_with_amount(amount, serial_number, TokenScheme::Simple(token_scheme)) + .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(AccountAddress::new( + account_id, + ))); + + if let Some((id, amount)) = native_token { + builder = + builder.with_native_token(NativeToken::new(TokenId::from_str(&id).unwrap(), amount).unwrap()); + } + + builder.finish_output().unwrap() + } } - Build::Foundry(amount, account_id, serial_number, token_scheme, native_token) => ( - build_foundry_output(amount, account_id, serial_number, token_scheme, native_token), - None, - ), } } -fn build_inputs<'a>( - outputs: impl IntoIterator>, - slot_index: Option, -) -> Vec { +fn build_inputs(outputs: impl IntoIterator, slot_index: Option) -> Vec { outputs .into_iter() .map(|build| { - let (output, chain) = build_output_inner(build); + let output = build.build(); let transaction_id = slot_index.map_or_else(rand_transaction_id, rand_transaction_id_with_slot_index); InputSigningData { output, output_metadata: rand_output_metadata_with_id(OutputId::new(transaction_id, 0)), - chain, } }) .collect() } -fn build_outputs<'a>(outputs: impl IntoIterator>) -> Vec { - outputs.into_iter().map(|build| build_output_inner(build).0).collect() +fn build_outputs(outputs: impl IntoIterator) -> Vec { + outputs.into_iter().map(Build::build).collect() } fn unsorted_eq(a: &[T], b: &[T]) -> bool @@ -254,7 +249,7 @@ where count(a) == count(b) } -fn is_remainder_or_return(output: &Output, amount: u64, address: Address, native_token: Option<(&str, u64)>) -> bool { +fn is_remainder_or_return(output: &Output, amount: u64, address: Address, native_token: Option<(String, u64)>) -> bool { if let Output::Basic(output) = output { if output.amount() != amount { return false; @@ -274,7 +269,7 @@ fn is_remainder_or_return(output: &Output, amount: u64, address: Address, native } if let Some((token_id, amount)) = native_token { - let native_token = NativeToken::new(TokenId::from_str(token_id).unwrap(), amount).unwrap(); + let native_token = NativeToken::new(TokenId::from_str(&token_id).unwrap(), amount).unwrap(); if output.native_token().unwrap() != &native_token { return false; @@ -288,3 +283,7 @@ fn is_remainder_or_return(output: &Output, amount: u64, address: Address, native false } } + +pub fn random_mnemonic_secret_manager() -> Result { + MnemonicSecretManager::try_from_mnemonic(iota_sdk::client::Client::generate_mnemonic()?) +} diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index e508c91263..c9a46dab29 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -5,12 +5,15 @@ use iota_sdk::{ client::{ - api::GetAddressesOptions, node_api::indexer::query_parameters::BasicOutputQueryParameters, Client, - NodeInfoWrapper, + constants::IOTA_COIN_TYPE, + node_api::indexer::query_parameters::BasicOutputQueryParameters, + secret::{PublicKeyOptions, SecretManageExt}, + Client, NodeInfoWrapper, }, types::{ api::core::TransactionState, block::{ + address::{Ed25519Address, ToBech32Ext}, output::{Output, OutputId}, Block, }, @@ -116,17 +119,10 @@ async fn test_get_address_outputs() { let secret_manager = setup_secret_manager(); let address = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::from_client(&client) - .await - .unwrap() - .with_range(0..1), - ) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) .await .unwrap() - .into_iter() - .next() - .unwrap(); + .to_bech32(client.get_bech32_hrp().await.unwrap()); let output_ids_response = client .basic_output_ids(BasicOutputQueryParameters::new().address(address)) diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index f47af0dae6..1973c656e1 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -9,14 +9,14 @@ mod mqtt; use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::GetAddressesOptions, - constants::IOTA_COIN_TYPE, + constants::{IOTA_BECH32_HRP, IOTA_COIN_TYPE}, node_api::indexer::query_parameters::BasicOutputQueryParameters, request_funds_from_faucet, - secret::{SecretManager, SignBlock}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt, PublicKeyOptions, SecretManage, SecretManageExt}, Client, }, types::block::{ + address::{Ed25519Address, ToBech32Ext}, output::AccountId, payload::{signed_transaction::TransactionId, tagged_data::TaggedDataPayload, Payload}, BlockId, @@ -29,7 +29,7 @@ use crate::client::common::{setup_client_with_node_health_ignored, FAUCET_URL}; const DEFAULT_DEVELOPMENT_SEED: &str = "0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2"; // Sends a tagged data block to the node to test against it. -async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { +async fn setup_tagged_data_block>(secret_manager: &S) -> BlockId { let client = setup_client_with_node_health_ignored().await; let protocol_params = client.get_protocol_parameters().await.unwrap(); @@ -43,28 +43,26 @@ async fn setup_tagged_data_block(secret_manager: &SecretManager) -> BlockId { ) .await .unwrap() - .sign_ed25519(secret_manager, Bip44::new(IOTA_COIN_TYPE)) + .sign_ed25519(secret_manager, &Bip44::new(IOTA_COIN_TYPE)) .await .unwrap() .id(&protocol_params) } -pub fn setup_secret_manager() -> SecretManager { - SecretManager::try_from_hex_seed(DEFAULT_DEVELOPMENT_SEED.to_owned()).unwrap() +pub fn setup_secret_manager() -> MnemonicSecretManager { + MnemonicSecretManager::try_from_hex_seed(DEFAULT_DEVELOPMENT_SEED.to_owned()).unwrap() } // Sends a transaction block to the node to test against it. pub async fn setup_transaction_block(client: &Client) -> (BlockId, TransactionId) { let secret_manager = setup_secret_manager(); - let addresses = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::from_client(client).await.unwrap().with_range(0..2)) + let address = secret_manager + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) .await - .unwrap(); - println!( - "{}", - request_funds_from_faucet(FAUCET_URL, &addresses[0]).await.unwrap() - ); + .unwrap() + .to_bech32(IOTA_BECH32_HRP); + println!("{}", request_funds_from_faucet(FAUCET_URL, &address).await.unwrap()); // Continue only after funds are received let mut round = 0; @@ -76,7 +74,7 @@ pub async fn setup_transaction_block(client: &Client) -> (BlockId, TransactionId tokio::time::sleep(std::time::Duration::from_secs(1)).await; let output_ids_response = client .basic_output_ids(BasicOutputQueryParameters::only_address_unlock_condition( - addresses[0].clone(), + address.clone(), )) .await .unwrap(); diff --git a/sdk/tests/client/secret_manager/mnemonic.rs b/sdk/tests/client/secret_manager/mnemonic.rs index e97e1a962a..e825cd27ae 100644 --- a/sdk/tests/client/secret_manager/mnemonic.rs +++ b/sdk/tests/client/secret_manager/mnemonic.rs @@ -1,28 +1,30 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_sdk::client::{ - api::GetAddressesOptions, constants::SHIMMER_TESTNET_BECH32_HRP, secret::SecretManager, Result, +use iota_sdk::{ + client::{ + constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, + Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; use pretty_assertions::assert_eq; #[tokio::test] async fn mnemonic_secret_manager() -> Result<()> { - let dto = r#"{"mnemonic": "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast"}"#; - let secret_manager: SecretManager = dto.parse()?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic( + "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast", + )?; - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(0) - .with_range(0..1), - ) + let address = secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) .await - .unwrap(); + .unwrap() + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( - addresses[0], + address, "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" ); diff --git a/sdk/tests/client/secret_manager/private_key.rs b/sdk/tests/client/secret_manager/private_key.rs index 934a529d3c..337d1e1577 100644 --- a/sdk/tests/client/secret_manager/private_key.rs +++ b/sdk/tests/client/secret_manager/private_key.rs @@ -1,62 +1,32 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_sdk::client::{ - api::GetAddressesOptions, - constants::SHIMMER_TESTNET_BECH32_HRP, - secret::{private_key::PrivateKeySecretManager, SecretManager}, - Result, +use iota_sdk::{ + client::{ + constants::SHIMMER_TESTNET_BECH32_HRP, + secret::{private_key::PrivateKeySecretManager, SecretManageExt}, + Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; use pretty_assertions::assert_eq; #[tokio::test] async fn private_key_secret_manager_hex() -> Result<()> { - let dto = r#"{"privateKey": "0x9e845b327c44e28bdd206c7c9eff09c40680bc2512add57280baf5b064d7e6f6"}"#; - let secret_manager: SecretManager = dto.parse()?; + let secret_manager = PrivateKeySecretManager::try_from_hex( + "0x9e845b327c44e28bdd206c7c9eff09c40680bc2512add57280baf5b064d7e6f6".to_owned(), + )?; - let address_0 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(0) - .with_range(0..1), - ) - .await - .unwrap()[0] - .clone(); - // Changing range generates the same address. - let address_1 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(0) - .with_range(1..2), - ) - .await - .unwrap()[0] - .clone(); - // Changing account generates the same address. - let address_2 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(1) - .with_range(0..1), - ) + // Private key manager only implements generation from it's key with no options, + // therefore only one address can be created + let address = secret_manager + .generate::(&()) .await - .unwrap()[0] - .clone(); + .unwrap() + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( - address_0, - "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" - ); - assert_eq!( - address_1, - "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" - ); - assert_eq!( - address_2, + address, "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" ); @@ -65,20 +35,13 @@ async fn private_key_secret_manager_hex() -> Result<()> { #[tokio::test] async fn private_key_secret_manager_bs58() -> Result<()> { - let secret_manager = SecretManager::from(PrivateKeySecretManager::try_from_b58( - "BfnURR6WSXJA6RyBr3WqGU99UzrVbWk9GSQgJqKtTRxZ", - )?); + let secret_manager = PrivateKeySecretManager::try_from_b58("BfnURR6WSXJA6RyBr3WqGU99UzrVbWk9GSQgJqKtTRxZ")?; let address = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(0) - .with_range(0..1), - ) + .generate::(&()) .await - .unwrap()[0] - .clone(); + .unwrap() + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( address, diff --git a/sdk/tests/client/secret_manager/stronghold.rs b/sdk/tests/client/secret_manager/stronghold.rs index b915d9364f..dd0905902d 100644 --- a/sdk/tests/client/secret_manager/stronghold.rs +++ b/sdk/tests/client/secret_manager/stronghold.rs @@ -1,50 +1,45 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_sdk::client::{ - api::GetAddressesOptions, constants::SHIMMER_TESTNET_BECH32_HRP, secret::SecretManager, Result, +use crypto::keys::bip39::Mnemonic; +use iota_sdk::{ + client::{ + constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManageExt, SecretManagerConfig}, + Result, + }, + types::block::address::{Ed25519Address, ToBech32Ext}, }; use pretty_assertions::assert_eq; +use serde_json::json; #[tokio::test] async fn stronghold_secret_manager() -> Result<()> { iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); - let dto = r#"{"stronghold": {"password": "some_hopefully_secure_password", "snapshotPath": "snapshot_test_dir/test.stronghold"}}"#; - let mnemonic = crypto::keys::bip39::Mnemonic::from( - "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast".to_owned(), + let secret_manager = StrongholdSecretManager::from_config(&serde_json::from_value(json!({ + "password": "some_hopefully_secure_password", + "snapshotPath": "snapshot_test_dir/test.stronghold" + }))?)?; + let mnemonic = Mnemonic::from( + "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast", ); - let mut secret_manager: SecretManager = dto.parse()?; - // The mnemonic only needs to be stored the first time - if let SecretManager::Stronghold(secret_manager) = &mut secret_manager { - secret_manager.store_mnemonic(mnemonic.clone()).await.unwrap(); - } else { - panic!("expect a Stronghold secret manager, but it's not the case!"); - } + secret_manager.store_mnemonic(mnemonic.clone()).await?; - let addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_account_index(0) - .with_range(0..1), - ) - .await - .unwrap(); + let address = secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await? + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( - addresses[0], + address, "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" ); // Calling store_mnemonic() twice should fail, because we would otherwise overwrite the stored entry - if let SecretManager::Stronghold(secret_manager) = &mut secret_manager { - assert!(secret_manager.store_mnemonic(mnemonic).await.is_err()); - } else { - panic!("expect a Stronghold secret manager, but it's not the case!"); - } + assert!(secret_manager.store_mnemonic(mnemonic).await.is_err()); // Remove garbage after test, but don't care about the result std::fs::remove_dir_all("snapshot_test_dir").ok(); @@ -63,12 +58,8 @@ async fn stronghold_mnemonic_missing() -> Result<()> { .build("stronghold_mnemonic_missing/test.stronghold")?; // Generating addresses will fail because no mnemonic has been stored - let error = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default(), - // .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - // .with_coin_type(iota_sdk::client::constants::SHIMMER_COIN_TYPE) - ) + let error = stronghold_secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) .await .unwrap_err(); diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index ba32f9bfd6..a3be9662da 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -6,16 +6,13 @@ use std::str::FromStr; use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::{ - transaction::validate_signed_transaction_payload_length, verify_semantic, GetAddressesOptions, - PreparedTransactionData, - }, + api::{transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData}, constants::SHIMMER_COIN_TYPE, - secret::{SecretManage, SecretManager}, - Client, Result, + secret::{PublicKeyOptions, SecretManageExt, SignTransaction}, + Result, }, types::block::{ - address::{AccountAddress, Address}, + address::{AccountAddress, Address, Ed25519Address}, input::{Input, UtxoInput}, output::AccountId, payload::{signed_transaction::Transaction, SignedTransactionPayload}, @@ -27,42 +24,45 @@ use iota_sdk::{ use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, + build_inputs, build_outputs, random_mnemonic_secret_manager, Build::{Account, Basic}, ACCOUNT_ID_1, }; #[tokio::test] async fn sign_account_state_transition() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = random_mnemonic_secret_manager()?; - let address = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); + let address = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); let protocol_parameters = protocol_parameters(); let account_id = AccountId::from_str(ACCOUNT_ID_1)?; let slot_index = SlotIndex::from(10); + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let inputs = build_inputs( - [Account( - 1_000_000, - account_id, - address.clone(), - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )], + [Account { + amount: 1_000_000, + account_id: account_id, + address: address.clone(), + sender: None, + issuer: None, + }], Some(slot_index), ); - let outputs = build_outputs([Account(1_000_000, account_id, address.clone(), None, None, None)]); + let outputs = build_outputs([Account { + amount: 1_000_000, + account_id: account_id, + address: address.clone(), + sender: None, + issuer: None, + }]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -83,7 +83,7 @@ async fn sign_account_state_transition() -> Result<()> { }; let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 1); @@ -109,42 +109,69 @@ async fn sign_account_state_transition() -> Result<()> { #[tokio::test] async fn account_reference_unlocks() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = random_mnemonic_secret_manager()?; - let address = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); + let address = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); let protocol_parameters = protocol_parameters(); let account_id = AccountId::from_str(ACCOUNT_ID_1)?; let account_address = Address::Account(AccountAddress::new(account_id)); let slot_index = SlotIndex::from(10); + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let inputs = build_inputs( [ - Account( - 1_000_000, - account_id, - address.clone(), - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic(1_000_000, account_address.clone(), None, None, None, None, None, None), - Basic(1_000_000, account_address.clone(), None, None, None, None, None, None), + Account { + amount: 1_000_000, + account_id: account_id, + address: address.clone(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: account_address.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: account_address.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(slot_index), ); let outputs = build_outputs([ - Account(1_000_000, account_id, address, None, None, None), - Basic(2_000_000, account_address, None, None, None, None, None, None), + Account { + amount: 1_000_000, + account_id: account_id, + address: address, + sender: None, + issuer: None, + }, + Basic { + amount: 2_000_000, + address: account_address, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let transaction = Transaction::builder(protocol_parameters.network_id()) @@ -166,7 +193,7 @@ async fn account_reference_unlocks() -> Result<()> { }; let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 3); diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index 8379d311f7..4ccd040250 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -4,15 +4,13 @@ use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::{ - transaction::validate_signed_transaction_payload_length, verify_semantic, GetAddressesOptions, - PreparedTransactionData, - }, + api::{transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData}, constants::SHIMMER_COIN_TYPE, - secret::{SecretManage, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt, SignTransaction}, Client, Result, }, types::block::{ + address::{Address, Ed25519Address}, input::{Input, UtxoInput}, payload::{signed_transaction::Transaction, SignedTransactionPayload}, protocol::protocol_parameters, @@ -26,45 +24,39 @@ use crate::client::{build_inputs, build_outputs, Build::Basic}; #[tokio::test] async fn single_ed25519_unlock() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; - let address_0 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); + let address_0 = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); let protocol_parameters = protocol_parameters(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( - [Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )], + [Basic { + amount: 1_000_000, + address: address_0.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }], Some(slot_index), ); - let outputs = build_outputs([Basic( - 1_000_000, - address_0, - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); + let outputs = build_outputs([Basic { + amount: 1_000_000, + address: address_0, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -84,8 +76,10 @@ async fn single_ed25519_unlock() -> Result<()> { mana_rewards: Default::default(), }; + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 1); @@ -111,67 +105,59 @@ async fn single_ed25519_unlock() -> Result<()> { #[tokio::test] async fn ed25519_reference_unlocks() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; - let address_0 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); + let address_0 = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); let protocol_parameters = protocol_parameters(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( [ - Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), + Basic { + amount: 1_000_000, + address: address_0.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: address_0.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: address_0.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(slot_index), ); - let outputs = build_outputs([Basic( - 3_000_000, - address_0, - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); + let outputs = build_outputs([Basic { + amount: 3_000_000, + address: address_0, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -191,8 +177,10 @@ async fn ed25519_reference_unlocks() -> Result<()> { mana_rewards: Default::default(), }; + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 3); @@ -230,66 +218,55 @@ async fn ed25519_reference_unlocks() -> Result<()> { #[tokio::test] async fn two_signature_unlocks() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = MnemonicSecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; - let address_0 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); - let address_1 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(1..2), - ) - .await?[0] - .clone() - .into_inner(); + let address_0 = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); + let address_1 = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE).with_address_index(1)) + .await?, + ); let protocol_parameters = protocol_parameters(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( [ - Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic( - 1_000_000, - address_1, - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(1)), - ), + Basic { + amount: 1_000_000, + address: address_0.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: address_1, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(slot_index), ); - let outputs = build_outputs([Basic( - 2_000_000, - address_0, - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); + let outputs = build_outputs([Basic { + amount: 2_000_000, + address: address_0, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -309,8 +286,10 @@ async fn two_signature_unlocks() -> Result<()> { mana_rewards: Default::default(), }; + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 2); diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index 530c1d36e7..97c6c7bf63 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -12,14 +12,14 @@ use iota_sdk::{ client::{ api::{ input_selection::InputSelection, transaction::validate_signed_transaction_payload_length, verify_semantic, - GetAddressesOptions, PreparedTransactionData, + PreparedTransactionData, }, constants::SHIMMER_COIN_TYPE, - secret::{SecretManage, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, MultiKeyOptions, SecretManageExt, SignTransaction}, Result, }, types::block::{ - address::{AccountAddress, Address, NftAddress}, + address::{AccountAddress, Address, Ed25519Address, NftAddress}, context_input::{CommitmentContextInput, ContextInput}, input::{Input, UtxoInput}, output::{AccountId, NftId}, @@ -39,23 +39,19 @@ use crate::client::{ #[tokio::test] async fn all_combined() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic( + let secret_manager = MnemonicSecretManager::try_from_mnemonic( // mnemonic needs to be hardcoded to make the ordering deterministic "mirror add nothing long orphan hat this rough scare gallery fork twelve old shrug voyage job table obscure mimic holiday possible proud giraffe fan".to_owned(), )?; let protocol_parameters = protocol_parameters(); - let ed25519_bech32_addresses = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..3), - ) - .await?; - let ed25519_0 = ed25519_bech32_addresses[0].clone().into_inner(); - let ed25519_1 = ed25519_bech32_addresses[1].clone().into_inner(); - let ed25519_2 = ed25519_bech32_addresses[2].clone().into_inner(); + let [ed25519_0, ed25519_1, ed25519_2] = secret_manager + .generate::>(&MultiKeyOptions::new(SHIMMER_COIN_TYPE).with_address_range(0..3)) + .await?[..] + else { + unreachable!() + }; let account_id_1 = AccountId::from_str(ACCOUNT_ID_1)?; let account_id_2 = AccountId::from_str(ACCOUNT_ID_2)?; @@ -71,145 +67,248 @@ async fn all_combined() -> Result<()> { let nft_3 = Address::Nft(NftAddress::new(nft_id_3)); let nft_4 = Address::Nft(NftAddress::new(nft_id_4)); - let slot_index = SlotIndex::from(90); + let slot_index = SlotIndex::from(100); let inputs = build_inputs( [ - Account(1_000_000, account_id_1, nft_1.clone(), None, None, None), - Account( - 1_000_000, - account_id_2, - ed25519_0.clone(), - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic(1_000_000, account_1.clone(), None, None, None, None, None, None), - Basic(1_000_000, account_2.clone(), None, None, None, None, None, None), - Basic(1_000_000, account_2, None, None, None, None, None, None), - Basic(1_000_000, nft_2.clone(), None, None, None, None, None, None), - Basic(1_000_000, nft_2, None, None, None, None, None, None), - Basic(1_000_000, nft_4.clone(), None, None, None, None, None, None), - Basic( - 1_000_000, - ed25519_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic( - 1_000_000, - ed25519_1.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(1)), - ), - Basic( - 1_000_000, - ed25519_2.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(2)), - ), - Basic( - 1_000_000, - ed25519_2.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(2)), - ), - Nft( - 1_000_000, - nft_id_1, - ed25519_0.clone(), - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Nft(1_000_000, nft_id_2, account_1.clone(), None, None, None, None, None), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: nft_1.clone(), + sender: None, + issuer: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_2, + address: ed25519_0.into(), + sender: None, + issuer: None, + }, + Basic { + amount: 1_000_000, + address: account_1.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: account_2.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: account_2, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: nft_2.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: nft_2, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: nft_4.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: ed25519_0.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: ed25519_1.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: ed25519_2.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: ed25519_2.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: ed25519_0.into(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: account_1.clone(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, // Expirations - Basic( - 2_000_000, - ed25519_0.clone(), - None, - None, - None, - None, - Some((account_1.clone(), 50)), - None, - ), - Basic( - 2_000_000, - ed25519_0.clone(), - None, - None, - None, - None, - Some((nft_3.clone(), 50)), - None, - ), - Basic( - 2_000_000, - ed25519_0.clone(), - None, - None, - None, - None, - Some((nft_3.clone(), 150)), - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Nft( - 1_000_000, - nft_id_3, - account_1.clone(), - None, - None, - None, - Some((nft_4, 50)), - None, - ), - Nft( - 1_000_000, - nft_id_4, - account_1, - None, - None, - None, - Some((nft_3, 150)), - None, - ), + Basic { + amount: 2_000_000, + address: ed25519_0.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((account_1.clone(), 50)), + }, + Basic { + amount: 2_000_000, + address: ed25519_0.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((nft_3.clone(), 50)), + }, + Basic { + amount: 2_000_000, + address: ed25519_0.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: Some((nft_3.clone(), 150)), + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_3, + address: account_1.clone(), + sender: None, + issuer: None, + sdruc: None, + expiration: Some((nft_4, 50)), + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_4, + address: account_1, + sender: None, + issuer: None, + sdruc: None, + expiration: Some((nft_3, 150)), + }, ], Some(slot_index), ); let outputs = build_outputs([ - Account(1_000_000, account_id_1, nft_1, None, None, None), - Account(1_000_000, account_id_2, ed25519_0.clone(), None, None, None), - Basic(10_000_000, ed25519_0.clone(), None, None, None, None, None, None), - Nft(1_000_000, nft_id_1, ed25519_0.clone(), None, None, None, None, None), - Nft(1_000_000, nft_id_2, ed25519_0.clone(), None, None, None, None, None), - Nft(1_000_000, nft_id_3, ed25519_0.clone(), None, None, None, None, None), - Nft(1_000_000, nft_id_4, ed25519_0.clone(), None, None, None, None, None), + Account { + amount: 1_000_000, + account_id: account_id_1, + address: nft_1, + sender: None, + issuer: None, + }, + Account { + amount: 1_000_000, + account_id: account_id_2, + address: ed25519_0.into(), + sender: None, + issuer: None, + }, + Basic { + amount: 10_000_000, + address: ed25519_0.into(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_1, + address: ed25519_0.into(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_2, + address: ed25519_0.into(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_3, + address: ed25519_0.into(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Nft { + amount: 1_000_000, + nft_id: nft_id_4, + address: ed25519_0.into(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, ]); let selected = InputSelection::new( inputs.clone(), outputs.clone(), - [ed25519_0, ed25519_1, ed25519_2], + [ed25519_0.into(), ed25519_1.into(), ed25519_2.into()], slot_index, protocol_parameters.clone(), ) @@ -238,8 +337,10 @@ async fn all_combined() -> Result<()> { mana_rewards: Default::default(), }; + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 15); diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index b797a3e29d..8cb6372a37 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -6,16 +6,13 @@ use std::str::FromStr; use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ - api::{ - transaction::validate_signed_transaction_payload_length, verify_semantic, GetAddressesOptions, - PreparedTransactionData, - }, + api::{transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData}, constants::SHIMMER_COIN_TYPE, - secret::{SecretManage, SecretManager}, - Client, Result, + secret::{PublicKeyOptions, SecretManageExt, SignTransaction}, + Result, }, types::block::{ - address::{Address, NftAddress}, + address::{Address, Ed25519Address, NftAddress}, input::{Input, UtxoInput}, output::NftId, payload::{signed_transaction::Transaction, SignedTransactionPayload}, @@ -27,24 +24,20 @@ use iota_sdk::{ use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, + build_inputs, build_outputs, random_mnemonic_secret_manager, Build::{Basic, Nft}, NFT_ID_1, }; #[tokio::test] async fn nft_reference_unlocks() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = random_mnemonic_secret_manager()?; - let address_0 = secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_coin_type(SHIMMER_COIN_TYPE) - .with_range(0..1), - ) - .await?[0] - .clone() - .into_inner(); + let address_0 = Address::from( + secret_manager + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .await?, + ); let protocol_parameters = protocol_parameters(); let nft_id = NftId::from_str(NFT_ID_1)?; @@ -53,25 +46,56 @@ async fn nft_reference_unlocks() -> Result<()> { let inputs = build_inputs( [ - Nft( - 1_000_000, - nft_id, - address_0.clone(), - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic(1_000_000, nft_address.clone(), None, None, None, None, None, None), - Basic(1_000_000, nft_address.clone(), None, None, None, None, None, None), + Nft { + amount: 1_000_000, + nft_id: nft_id, + address: address_0.clone(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: nft_address.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, + Basic { + amount: 1_000_000, + address: nft_address.clone(), + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ], Some(slot_index), ); let outputs = build_outputs([ - Nft(1_000_000, nft_id, address_0, None, None, None, None, None), - Basic(2_000_000, nft_address, None, None, None, None, None, None), + Nft { + amount: 1_000_000, + nft_id: nft_id, + address: address_0, + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }, + Basic { + amount: 2_000_000, + address: nft_address, + native_token: None, + sender: None, + sdruc: None, + timelock: None, + expiration: None, + }, ]); let transaction = Transaction::builder(protocol_parameters.network_id()) @@ -92,8 +116,10 @@ async fn nft_reference_unlocks() -> Result<()> { mana_rewards: Default::default(), }; + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); + let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; assert_eq!(unlocks.len(), 3); diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index eccd3aa430..9fe1cce9fe 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -4,20 +4,19 @@ #[cfg(feature = "stronghold")] use crypto::keys::bip39::Mnemonic; use crypto::keys::bip44::Bip44; +#[cfg(feature = "ledger_nano")] +use iota_sdk::client::secret::ledger_nano::{LedgerOptions, LedgerSecretManager}; #[cfg(feature = "stronghold")] use iota_sdk::client::secret::stronghold::StrongholdSecretManager; -#[cfg(feature = "ledger_nano")] -use iota_sdk::client::secret::{ledger_nano::LedgerSecretManager, GenerateAddressOptions}; #[cfg(feature = "events")] use iota_sdk::wallet::events::{WalletEvent, WalletEventType}; use iota_sdk::{ client::{ - constants::IOTA_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, - Error as ClientError, + constants::{IOTA_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, }, - types::block::address::ToBech32Ext, - wallet::{ClientOptions, Error, Result, Wallet}, + types::block::address::{Ed25519Address, ToBech32Ext}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; use pretty_assertions::assert_eq; @@ -32,10 +31,11 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { let secret_manager = MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { @@ -43,7 +43,9 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { } let wallet = wallet_builder.finish().await?; - let address = wallet.generate_ed25519_address(0, 0, None).await?; + let address = (*wallet.secret_manager().read().await) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await?; assert_eq!( address.to_bech32_unchecked("smr"), @@ -71,17 +73,20 @@ async fn wallet_address_generation_stronghold() -> Result<()> { let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { wallet_builder = wallet_builder.with_storage_path(storage_path); } let wallet = wallet_builder.finish().await?; - let address = wallet.generate_ed25519_address(0, 0, None).await?; + let address = (*wallet.secret_manager().read().await) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await?; assert_eq!( address.to_bech32_unchecked("smr"), @@ -104,10 +109,11 @@ async fn wallet_address_generation_ledger() -> Result<()> { secret_manager.non_interactive = true; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { @@ -115,7 +121,10 @@ async fn wallet_address_generation_ledger() -> Result<()> { } let wallet = wallet_builder.finish().await?; - let address = wallet.generate_ed25519_address(0, 0, None).await?; + let address = (*wallet.secret_manager().read().await) + .generate::(&LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) + .await? + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( address.to_bech32_unchecked("smr"), @@ -140,16 +149,12 @@ async fn wallet_address_generation_ledger() -> Result<()> { }) .await; - let address = wallet - .generate_ed25519_address( - 0, - 0, - Some(GenerateAddressOptions { - ledger_nano_prompt: true, - ..Default::default() - }), + let address = (*wallet.secret_manager().read().await) + .generate::( + &LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE)).with_ledger_nano_prompt(true), ) - .await?; + .await? + .to_bech32(SHIMMER_TESTNET_BECH32_HRP); assert_eq!( address.to_bech32_unchecked("smr"), @@ -204,3 +209,102 @@ async fn wallet_address_generation_ledger() -> Result<()> { // tear_down(storage_path) // } + +#[tokio::test] +async fn wallet_address_generation_custom_secret_manager() -> Result<()> { + let storage_path = "test-storage/wallet_address_generation_custom_secret_manager"; + setup(storage_path)?; + + #[derive(Debug, serde::Serialize, serde::Deserialize)] + pub struct CustomSecretManager { + pub public_key: String, + // Will obviously be invalid, just to have something + pub signature: String, + } + + #[async_trait::async_trait] + impl iota_sdk::client::secret::Generate for CustomSecretManager { + type Options = (); + + async fn generate( + &self, + _options: &Self::Options, + ) -> iota_sdk::client::Result { + Ok(crypto::signatures::ed25519::PublicKey::try_from_bytes( + prefix_hex::decode(&self.public_key)?, + )?) + } + } + + #[async_trait::async_trait] + impl iota_sdk::client::secret::Sign for CustomSecretManager { + type Options = (); + + async fn sign( + &self, + _msg: &[u8], + _options: &Self::Options, + ) -> iota_sdk::client::Result { + Ok(iota_sdk::types::block::signature::Ed25519Signature::try_from_bytes( + prefix_hex::decode(&self.public_key)?, + prefix_hex::decode(&self.signature)?, + )?) + } + } + impl iota_sdk::client::secret::SignTransaction for CustomSecretManager {} + + impl iota_sdk::client::secret::SecretManagerConfig for CustomSecretManager { + type Config = String; + + fn to_config(&self) -> Option { + Some(serde_json::to_string(self).unwrap()) + } + + fn from_config(config: &Self::Config) -> iota_sdk::client::Result { + Ok(serde_json::from_str(config)?) + } + } + + let custom_secret_manager = CustomSecretManager { + public_key: "0x503b258b32c586e2c66c99d3af45086d1c96fbcd86b3d04f464081589d1a51b2".to_string(), + signature: "0xbb36dc62c92d35175b6ccee15341a776d188a71c50fed86204ca01555cd344303611a836c546c7fcfa983af75fe941ae1533a10d692ccd0008578b351b170f03".to_string(), + }; + + assert_eq!( + Ed25519Address::from_public_key_bytes( + custom_secret_manager + .generate::(&()) + .await? + .to_bytes() + ), + ::from_str( + "0x69da7d3cf43670a6585763eb05d4a9272d424bcc921d550fd726a183501a8539" + ) + .unwrap() + ); + + let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; + + #[allow(unused_mut)] + let mut wallet_builder = Wallet::<()>::builder() + .with_secret_manager(custom_secret_manager) + .with_public_key_options(()) // TODO: Should we have a default bound somewhere? + .with_signing_options(()) + .with_client_options(client_options); + + #[cfg(feature = "storage")] + { + wallet_builder = wallet_builder.with_storage_path(storage_path); + } + let wallet = wallet_builder.finish().await?; + + assert_eq!( + *wallet.address().await.inner().as_ed25519(), + ::from_str( + "0x69da7d3cf43670a6585763eb05d4a9272d424bcc921d550fd726a183501a8539" + ) + .unwrap() + ); + + tear_down(storage_path) +} diff --git a/sdk/tests/wallet/backup_restore.rs b/sdk/tests/wallet/backup_restore.rs index 7fd0ceec97..86e7f51376 100644 --- a/sdk/tests/wallet/backup_restore.rs +++ b/sdk/tests/wallet/backup_restore.rs @@ -103,7 +103,7 @@ // // secret manager is the same // assert_eq!( // wallet -// .get_secret_manager() +// .secret_manager() // .read() // .await // .generate_ed25519_addresses(GetAddressesOptions { @@ -113,7 +113,7 @@ // }) // .await?, // restored_wallet -// .get_secret_manager() +// .secret_manager() // .read() // .await // .generate_ed25519_addresses(GetAddressesOptions { diff --git a/sdk/tests/wallet/burn_outputs.rs b/sdk/tests/wallet/burn_outputs.rs index 33c3367d1d..418d4c8dc9 100644 --- a/sdk/tests/wallet/burn_outputs.rs +++ b/sdk/tests/wallet/burn_outputs.rs @@ -2,13 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::{ - client::api::input_selection::Burn, + client::{api::input_selection::Burn, secret::SecretManage}, types::block::output::{ feature::MetadataFeature, unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, NativeToken, NftId, NftOutputBuilder, OutputId, UnlockCondition, }, - wallet::{CreateNativeTokenParams, MintNftParams, Result, Wallet}, + wallet::{core::SecretData, CreateNativeTokenParams, MintNftParams, Result, Wallet}, U256, }; use pretty_assertions::assert_eq; @@ -178,7 +178,7 @@ async fn create_and_melt_native_token() -> Result<()> { tear_down(storage_path) } -async fn destroy_foundry(wallet: &Wallet) -> Result<()> { +async fn destroy_foundry(wallet: &Wallet>) -> Result<()> { let balance = wallet.sync(None).await?; println!("wallet balance -> {}", serde_json::to_string(&balance).unwrap()); @@ -201,7 +201,7 @@ async fn destroy_foundry(wallet: &Wallet) -> Result<()> { Ok(()) } -async fn destroy_account(wallet: &Wallet) -> Result<()> { +async fn destroy_account(wallet: &Wallet>) -> Result<()> { let balance = wallet.sync(None).await.unwrap(); println!("account balance -> {}", serde_json::to_string(&balance).unwrap()); diff --git a/sdk/tests/wallet/common/mod.rs b/sdk/tests/wallet/common/mod.rs index e73a4b2174..0c8725d34d 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -8,10 +8,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, request_funds_from_faucet, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, Client, }, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::SecretData, ClientOptions, Result, Wallet, WalletBuilder}, }; pub use self::constants::*; @@ -29,16 +29,21 @@ pub use self::constants::*; /// /// A Wallet #[allow(dead_code, unused_variables)] -pub(crate) async fn make_wallet(storage_path: &str, mnemonic: Option, node: Option<&str>) -> Result { +pub(crate) async fn make_wallet( + storage_path: &str, + mnemonic: Option, + node: Option<&str>, +) -> Result>> { let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic.unwrap_or_else(|| Client::generate_mnemonic().unwrap()))?; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)); + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)); #[cfg(feature = "storage")] { @@ -50,16 +55,22 @@ pub(crate) async fn make_wallet(storage_path: &str, mnemonic: Option, #[allow(dead_code, unused_variables)] #[cfg(feature = "ledger_nano")] -pub(crate) async fn make_ledger_nano_wallet(storage_path: &str, node: Option<&str>) -> Result { +pub(crate) async fn make_ledger_nano_wallet( + storage_path: &str, + node: Option<&str>, +) -> Result>> { + use iota_sdk::client::secret::ledger_nano::{LedgerOptions, LedgerSecretManager}; + let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; - let mut secret_manager = iota_sdk::client::secret::ledger_nano::LedgerSecretManager::new(true); + let mut secret_manager = LedgerSecretManager::new(true); secret_manager.non_interactive = true; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)); + .with_public_key_options(LedgerOptions::new(PublicKeyOptions::new(SHIMMER_COIN_TYPE))) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)); #[cfg(feature = "storage")] { wallet_builder = wallet_builder.with_storage_path(storage_path); @@ -70,7 +81,7 @@ pub(crate) async fn make_ledger_nano_wallet(storage_path: &str, node: Option<&st /// Request funds from the faucet and sync the wallet. #[allow(dead_code)] -pub(crate) async fn request_funds(wallet: &Wallet) -> Result<()> { +pub(crate) async fn request_funds(wallet: &Wallet) -> Result<()> { request_funds_from_faucet(FAUCET_URL, &wallet.address().await).await?; // Continue only after funds are received diff --git a/sdk/tests/wallet/core.rs b/sdk/tests/wallet/core.rs index 8723afe641..f26cab0b8d 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -11,11 +11,11 @@ use iota_sdk::{ use iota_sdk::{ client::{ constants::IOTA_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, WalletBuilder}, }; use pretty_assertions::assert_eq; use url::Url; @@ -79,7 +79,7 @@ async fn update_client_options() -> Result<()> { async fn changed_bip_path() -> Result<()> { use iota_sdk::crypto::keys::bip44::Bip44; - let storage_path = "test-storage/changed_coin_type"; + let storage_path = "test-storage/changed_bip_path"; setup(storage_path)?; let mnemonic = Mnemonic::from(DEFAULT_MNEMONIC.to_owned()); @@ -88,34 +88,30 @@ async fn changed_bip_path() -> Result<()> { drop(wallet); - let err = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic( - mnemonic.clone(), - )?)) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)) + let err = WalletBuilder::new() + .with_secret_manager(MnemonicSecretManager::try_from_mnemonic(mnemonic.clone())?) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .with_storage_path(storage_path) .finish() .await; // Building the wallet with another coin type needs to return an error, because a different coin type was used in // the existing account - let mismatch_err: Result = Err(Error::BipPathMismatch { - new_bip_path: Some(Bip44::new(IOTA_COIN_TYPE)), - old_bip_path: Some(Bip44::new(SHIMMER_COIN_TYPE)), - }); - assert!(matches!(err, mismatch_err)); + assert!(matches!(err, Err(Error::PublicKeyOptionsMismatch{new, old}) + if new == serde_json::to_value(PublicKeyOptions::new(IOTA_COIN_TYPE))? && + old == serde_json::to_value(PublicKeyOptions::new(SHIMMER_COIN_TYPE))? + )); // Building the wallet with the same coin type still works - assert!( - Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic( - mnemonic, - )?)) - .with_storage_path(storage_path) - .finish() - .await - .is_ok() - ); + WalletBuilder::new() + .with_secret_manager(MnemonicSecretManager::try_from_mnemonic(mnemonic)?) + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) + .with_storage_path(storage_path) + .finish() + .await + .unwrap(); tear_down(storage_path) } @@ -146,10 +142,11 @@ async fn iota_coin_type() -> Result<()> { let secret_manager = MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let mut wallet_builder = WalletBuilder::new() + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { diff --git a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs index 1bd1747ecb..820bd82a7d 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -5,15 +5,15 @@ use std::path::PathBuf; use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + secret::{stronghold::StrongholdSecretManager, MultiKeyOptions, PublicKeyOptions, SecretManageExt}, storage::StorageAdapter, stronghold::{Error as StrongholdError, StrongholdAdapter}, Error as ClientError, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Error as WalletError, Wallet}, + types::block::address::{Ed25519Address, ToBech32Ext}, + wallet::{ClientOptions, Error as WalletError, Wallet, WalletBuilder}, }; use pretty_assertions::assert_eq; @@ -48,23 +48,18 @@ async fn stronghold_snapshot_v2_v3_migration() { ) .unwrap(); - let stronghold_secret_manager = SecretManager::Stronghold( - StrongholdSecretManager::builder() - .password("new_password".to_owned()) - .build("./tests/wallet/fixtures/v3.stronghold") - .unwrap(), - ); + let stronghold_secret_manager = StrongholdSecretManager::builder() + .password("new_password".to_owned()) + .build("./tests/wallet/fixtures/v3.stronghold") + .unwrap(); let addresses = stronghold_secret_manager - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_account_index(0) - .with_range(0..10), - ) + .generate::>(&MultiKeyOptions::new(SHIMMER_COIN_TYPE).with_address_range(0..10)) .await - .unwrap(); + .unwrap() + .into_iter() + .map(|a| a.to_bech32(SHIMMER_TESTNET_BECH32_HRP)) + .collect::>(); // mnemonic: winter spend artefact viable cigar pink easy charge ranch license coyote cage brass mushroom repair // game attack peanut glad rather cart obey famous chat @@ -84,12 +79,13 @@ async fn stronghold_snapshot_v2_v3_migration() { ] ); - let restore_manager = Wallet::builder() + let restore_manager = WalletBuilder::new() .with_storage_path("test-storage/stronghold_snapshot_v2_v3_migration") .with_secret_manager(stronghold_secret_manager) .with_client_options(ClientOptions::new().with_node(NODE_LOCAL).unwrap()) // Build with a different coin type, to check if it gets replaced by the one from the backup - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) + .with_signing_options(Bip44::new(IOTA_COIN_TYPE)) .finish() .await .unwrap(); @@ -191,16 +187,13 @@ async fn stronghold_snapshot_v2_v3_migration_with_backup() { let coin_type = u32::from_le_bytes(coin_type_bytes.try_into().expect("invalid coin_type")); assert_eq!(coin_type, SHIMMER_COIN_TYPE); - let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( - GetAddressesOptions::default() - .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) - .with_coin_type(SHIMMER_COIN_TYPE) - .with_account_index(0) - .with_range(0..10), - ) + let addresses = stronghold_secret_manager + .generate::>(&MultiKeyOptions::new(SHIMMER_COIN_TYPE).with_address_range(0..10)) .await - .unwrap(); + .unwrap() + .into_iter() + .map(|a| a.to_bech32(SHIMMER_TESTNET_BECH32_HRP)) + .collect::>(); // mnemonic: brisk egg allow van merge process chest type dove bomb proud purity monitor snap load verb utility // hungry cube coast fetch pioneer gadget credit