From 48805bd862e0ca18a13078842d68e551851bd6db Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Tue, 5 Dec 2023 16:03:20 -0500 Subject: [PATCH 01/24] close --- bindings/core/src/lib.rs | 2 +- bindings/core/src/method/secret_manager.rs | 3 +- bindings/core/src/method/utils.rs | 2 +- .../core/src/method_handler/secret_manager.rs | 6 +- bindings/core/tests/serialize_error.rs | 6 +- cli/src/cli.rs | 4 +- cli/src/wallet_cli/mod.rs | 2 +- .../account/implicit_account_creation.rs | 2 +- .../accounts_and_addresses/create_wallet.rs | 2 +- sdk/examples/wallet/background_syncing.rs | 2 +- sdk/examples/wallet/events.rs | 2 +- sdk/examples/wallet/getting_started.rs | 2 +- sdk/examples/wallet/ledger_nano.rs | 2 +- sdk/examples/wallet/logger.rs | 2 +- .../offline_signing/0_generate_address.rs | 2 +- .../offline_signing/1_prepare_transaction.rs | 2 +- sdk/examples/wallet/spammer.rs | 2 +- sdk/examples/wallet/storage.rs | 2 +- sdk/examples/wallet/wallet.rs | 2 +- sdk/src/client/api/address.rs | 168 ---- .../api/block_builder/input_selection/mod.rs | 28 +- .../input_selection/remainder.rs | 14 +- .../input_selection/requirement/account.rs | 4 +- .../input_selection/requirement/amount.rs | 30 +- .../input_selection/requirement/ed25519.rs | 8 +- .../input_selection/requirement/foundry.rs | 4 +- .../input_selection/requirement/issuer.rs | 4 +- .../input_selection/requirement/mod.rs | 4 +- .../requirement/native_tokens.rs | 8 +- .../input_selection/requirement/nft.rs | 4 +- .../input_selection/requirement/sender.rs | 4 +- .../input_selection/transition.rs | 4 +- .../client/api/block_builder/transaction.rs | 4 +- sdk/src/client/api/mod.rs | 5 +- sdk/src/client/api/types.rs | 45 +- sdk/src/client/error.rs | 6 +- sdk/src/client/secret/ledger_nano.rs | 155 ++- sdk/src/client/secret/manager.rs | 464 +++++++++ sdk/src/client/secret/mnemonic.rs | 235 +++-- sdk/src/client/secret/mod.rs | 895 ++++++++---------- sdk/src/client/secret/private_key.rs | 83 +- sdk/src/client/secret/types.rs | 38 +- sdk/src/client/stronghold/secret.rs | 254 +++-- sdk/src/wallet/core/builder.rs | 142 +-- sdk/src/wallet/core/mod.rs | 125 +-- .../core/operations/address_generation.rs | 178 ++-- .../core/operations/background_syncing.rs | 6 +- sdk/src/wallet/core/operations/client.rs | 2 - sdk/src/wallet/core/operations/storage.rs | 19 +- .../core/operations/stronghold_backup/mod.rs | 197 +--- .../stronghold_backup/stronghold_snapshot.rs | 4 +- sdk/src/wallet/error.rs | 9 +- sdk/src/wallet/events/mod.rs | 14 +- sdk/src/wallet/events/types.rs | 56 +- sdk/src/wallet/operations/balance.rs | 10 +- sdk/src/wallet/operations/block.rs | 12 +- sdk/src/wallet/operations/helpers/time.rs | 4 +- sdk/src/wallet/operations/output_claiming.rs | 21 +- .../wallet/operations/output_consolidation.rs | 39 +- .../wallet/operations/participation/event.rs | 6 +- .../wallet/operations/participation/mod.rs | 12 +- .../wallet/operations/participation/voting.rs | 13 +- .../operations/participation/voting_power.rs | 16 +- sdk/src/wallet/operations/reissue.rs | 12 +- .../addresses/output_ids/account_foundry.rs | 6 +- .../syncing/addresses/output_ids/basic.rs | 5 +- .../syncing/addresses/output_ids/mod.rs | 6 +- .../syncing/addresses/output_ids/nft.rs | 5 +- .../operations/syncing/addresses/outputs.rs | 10 +- .../wallet/operations/syncing/foundries.rs | 6 +- sdk/src/wallet/operations/syncing/mod.rs | 14 +- sdk/src/wallet/operations/syncing/outputs.rs | 21 +- .../wallet/operations/syncing/transactions.rs | 10 +- .../wallet/operations/transaction/account.rs | 40 +- .../transaction/build_transaction.rs | 11 +- .../burning_melting/melt_native_token.rs | 10 +- .../high_level/burning_melting/mod.rs | 9 +- .../transaction/high_level/create_account.rs | 13 +- .../high_level/minting/create_native_token.rs | 20 +- .../high_level/minting/mint_native_token.rs | 8 +- .../high_level/minting/mint_nfts.rs | 8 +- .../operations/transaction/high_level/send.rs | 8 +- .../high_level/send_native_tokens.rs | 8 +- .../transaction/high_level/send_nft.rs | 8 +- .../operations/transaction/input_selection.rs | 16 +- sdk/src/wallet/operations/transaction/mod.rs | 12 +- .../operations/transaction/prepare_output.rs | 8 +- .../transaction/prepare_transaction.rs | 8 +- .../transaction/sign_transaction.rs | 85 +- .../transaction/submit_transaction.rs | 6 +- sdk/src/wallet/storage/manager.rs | 14 +- sdk/src/wallet/types/mod.rs | 25 +- sdk/src/wallet/update.rs | 15 +- .../client/input_selection/foundry_outputs.rs | 14 +- .../client/input_selection/nft_outputs.rs | 2 +- sdk/tests/client/input_signing_data.rs | 4 +- sdk/tests/client/mod.rs | 4 +- sdk/tests/wallet/address_generation.rs | 6 +- sdk/tests/wallet/common/mod.rs | 4 +- sdk/tests/wallet/core.rs | 10 +- sdk/tests/wallet/events.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 2 +- 102 files changed, 1962 insertions(+), 1915 deletions(-) delete mode 100644 sdk/src/client/api/address.rs create mode 100644 sdk/src/client/secret/manager.rs diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index d7dc366cfa..72f3de1a49 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -91,7 +91,7 @@ impl WalletOptions { let mut builder = Wallet::builder() .with_address(self.address) .with_alias(self.alias) - .with_bip_path(self.bip_path) + .with_public_key_options(self.bip_path) .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 b70c10db53..c36feb3580 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -5,7 +5,7 @@ use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::{ client::api::{GetAddressesOptions, PreparedTransactionDataDto}, - types::block::UnsignedBlockDto, + types::block::{protocol::ProtocolParameters, UnsignedBlockDto}, utils::serde::bip44::Bip44Def, }; use serde::{Deserialize, Serialize}; @@ -61,6 +61,7 @@ pub enum SecretManagerMethod { SignTransaction { /// Prepared transaction data prepared_transaction_data: PreparedTransactionDataDto, + protocol_parameters: ProtocolParameters, }, // Sign a block. #[serde(rename_all = "camelCase")] diff --git a/bindings/core/src/method/utils.rs b/bindings/core/src/method/utils.rs index be706f9d46..d667fef73b 100644 --- a/bindings/core/src/method/utils.rs +++ b/bindings/core/src/method/utils.rs @@ -124,7 +124,7 @@ pub enum UtilsMethod { /// Verifies the semantic of a transaction. VerifyTransactionSemantic { transaction: TransactionDto, - inputs: Vec, + inputs: Vec>, unlocks: Option>, }, } diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 3e3ac2ec34..d766194ee1 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -75,9 +75,13 @@ where } SecretManagerMethod::SignTransaction { prepared_transaction_data, + protocol_parameters, } => { let transaction = &secret_manager - .sign_transaction(PreparedTransactionData::try_from_dto(prepared_transaction_data)?) + .sign_transaction( + PreparedTransactionData::try_from_dto(prepared_transaction_data)?, + &protocol_parameters, + ) .await .map_err(iota_sdk::client::Error::from)?; Response::SignedTransaction(transaction.into()) diff --git a/bindings/core/tests/serialize_error.rs b/bindings/core/tests/serialize_error.rs index 67c599b53f..31ab12e43e 100644 --- a/bindings/core/tests/serialize_error.rs +++ b/bindings/core/tests/serialize_error.rs @@ -26,9 +26,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: None, + new: Some(Bip44::new(SHIMMER_COIN_TYPE)), }); assert_eq!( serde_json::to_string(&error).unwrap(), diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 873f4e21ce..28a39204d7 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -289,7 +289,7 @@ pub async fn init_command( .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(init_params.bip_path) .with_address(address) .with_alias(alias) .finish() @@ -345,7 +345,7 @@ pub async fn restore_command(storage_path: &Path, snapshot_path: &Path, backup_p .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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 175f1b5c74..e2b3b523a9 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -1015,7 +1015,7 @@ async fn print_wallet_address(wallet: &Wallet) -> Result<(), Error> { } } - let bip_path = wallet.bip_path().await; + let bip_path = wallet.public_key_options().await; log = format!("{log}\nBIP path: {bip_path:?}"); log = format!( diff --git a/sdk/examples/how_tos/account/implicit_account_creation.rs b/sdk/examples/how_tos/account/implicit_account_creation.rs index 9f565da0b8..f639e611ff 100644 --- a/sdk/examples/how_tos/account/implicit_account_creation.rs +++ b/sdk/examples/how_tos/account/implicit_account_creation.rs @@ -26,7 +26,7 @@ async fn main() -> Result<()> { .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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs index 7d5385ecd9..3488d92c7a 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs @@ -52,7 +52,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Stronghold(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/background_syncing.rs b/sdk/examples/wallet/background_syncing.rs index c2e2ee3407..ac70c6f49c 100644 --- a/sdk/examples/wallet/background_syncing.rs +++ b/sdk/examples/wallet/background_syncing.rs @@ -34,7 +34,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Mnemonic(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/events.rs b/sdk/examples/wallet/events.rs index 0c714a85ba..d992294093 100644 --- a/sdk/examples/wallet/events.rs +++ b/sdk/examples/wallet/events.rs @@ -44,7 +44,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Mnemonic(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/getting_started.rs b/sdk/examples/wallet/getting_started.rs index ca224dd04c..4487ed958a 100644 --- a/sdk/examples/wallet/getting_started.rs +++ b/sdk/examples/wallet/getting_started.rs @@ -40,7 +40,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Stronghold(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(Bip44::new(SHIMMER_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 d00faf9ff7..f94440269e 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -43,7 +43,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::LedgerNano(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index aea7bf146c..38ee2028bd 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -43,7 +43,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Mnemonic(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/offline_signing/0_generate_address.rs b/sdk/examples/wallet/offline_signing/0_generate_address.rs index f54a1b8c95..b418c551d2 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -47,7 +47,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Stronghold(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index d5cfbfca99..529888c501 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -48,7 +48,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Placeholder) .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(Bip44::new(SHIMMER_COIN_TYPE)) .with_address(address) .finish() .await?; diff --git a/sdk/examples/wallet/spammer.rs b/sdk/examples/wallet/spammer.rs index 278ffd8608..98e6554544 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -60,7 +60,7 @@ async fn main() -> Result<()> { let wallet = Wallet::builder() .with_secret_manager(SecretManager::Mnemonic(secret_manager)) .with_client_options(client_options) - .with_bip_path(bip_path) + .with_public_key_options(bip_path) .with_address(address) .finish() .await?; diff --git a/sdk/examples/wallet/storage.rs b/sdk/examples/wallet/storage.rs index d04ec6f656..bc4b747733 100644 --- a/sdk/examples/wallet/storage.rs +++ b/sdk/examples/wallet/storage.rs @@ -34,7 +34,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Mnemonic(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; diff --git a/sdk/examples/wallet/wallet.rs b/sdk/examples/wallet/wallet.rs index de5b8cf48c..10218ad20b 100644 --- a/sdk/examples/wallet/wallet.rs +++ b/sdk/examples/wallet/wallet.rs @@ -60,7 +60,7 @@ async fn create_wallet() -> Result { .with_secret_manager(SecretManager::Mnemonic(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(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await } 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/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index ba4ed047ab..91c175871a 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -31,11 +31,11 @@ use crate::{ }; /// Working state for the input selection algorithm. -pub struct InputSelection { - available_inputs: Vec, +pub struct InputSelection { + available_inputs: Vec>, required_inputs: HashSet, forbidden_inputs: HashSet, - selected_inputs: Vec, + selected_inputs: Vec>, outputs: Vec, addresses: HashSet
, burn: Option, @@ -48,17 +48,17 @@ pub struct InputSelection { /// Result of the input selection algorithm. #[derive(Clone, Debug)] -pub struct Selected { +pub struct Selected { /// Selected inputs. - pub inputs: Vec, + pub inputs: Vec>, /// Provided and created outputs. pub outputs: Vec, /// Remainder, if there was one. - pub remainder: Option, + pub remainder: Option>, } -impl InputSelection { - fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { +impl InputSelection { + fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { let required_address = input .output .required_and_unlocked_address(self.slot_index, input.output_id())? @@ -75,7 +75,7 @@ impl InputSelection { } } - fn select_input(&mut self, input: InputSigningData) -> Result<(), Error> { + fn select_input(&mut self, input: InputSigningData) -> Result<(), Error> { log::debug!("Selecting input {:?}", input.output_id()); if let Some(output) = self.transition_input(&input)? { @@ -145,7 +145,7 @@ impl InputSelection { /// Creates a new [`InputSelection`]. pub fn new( - available_inputs: impl Into>, + available_inputs: impl Into>>, outputs: impl Into>, addresses: impl IntoIterator, protocol_parameters: ProtocolParameters, @@ -249,15 +249,15 @@ impl InputSelection { // Inputs need to be sorted before signing, because the reference unlock conditions can only reference a lower index pub(crate) fn sort_input_signing_data( - mut inputs: Vec, + mut inputs: Vec>, slot_index: SlotIndex, - ) -> Result, Error> { + ) -> Result>, Error> { // initially sort by output to make it deterministic // TODO: rethink this, we only need it deterministic for tests, for the protocol it doesn't matter, also there // might be a more efficient way to do this inputs.sort_by_key(|i| i.output.pack_to_vec()); // filter for ed25519 address first - let (mut sorted_inputs, account_nft_address_inputs): (Vec, Vec) = + let (mut sorted_inputs, account_nft_address_inputs): (Vec>, Vec>) = inputs.into_iter().partition(|input_signing_data| { let (input_address, _) = input_signing_data .output @@ -338,7 +338,7 @@ impl InputSelection { /// Selects inputs that meet the requirements of the outputs to satisfy the semantic validation of the overall /// transaction. Also creates a remainder output and chain transition outputs if required. - pub fn select(mut self) -> Result { + pub fn select(mut self) -> Result, Error> { if !OUTPUT_COUNT_RANGE.contains(&(self.outputs.len() as u16)) { // If burn is provided, outputs will be added later if !(self.outputs.is_empty() && self.burn.is_some()) { 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 e0a37a56fa..5ceab09e72 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::{ amount::amount_sums, @@ -18,9 +16,9 @@ use crate::{ }, }; -impl InputSelection { +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()) { @@ -29,7 +27,7 @@ impl InputSelection { .required_and_unlocked_address(self.slot_index, input.output_id())?; if &required_address == remainder_address { - return Ok(Some((remainder_address.clone(), input.chain))); + return Ok(Some((remainder_address.clone(), input.signing_options))); } } return Ok(Some((remainder_address.clone(), None))); @@ -42,7 +40,7 @@ impl InputSelection { .0; if required_address.is_ed25519() { - return Ok(Some((required_address, input.chain))); + return Ok(Some((required_address, input.signing_options))); } } @@ -81,7 +79,7 @@ impl InputSelection { pub(crate) fn remainder_and_storage_deposit_return_outputs( &self, - ) -> Result<(Option, Vec), Error> { + ) -> Result<(Option>, Vec), Error> { let (inputs_sum, outputs_sum, inputs_sdr, outputs_sdr) = amount_sums(&self.selected_inputs, &self.outputs, self.slot_index); let mut storage_deposit_returns = Vec::new(); @@ -147,7 +145,7 @@ impl InputSelection { Ok(( Some(RemainderData { output: remainder, - chain, + signing_options: chain, address: remainder_address, }), storage_deposit_returns, diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs index 87f8cd20cd..72a6fa9abc 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs @@ -26,12 +26,12 @@ pub(crate) fn is_account_with_id_non_null(output: &Output, account_id: &AccountI } } -impl InputSelection { +impl InputSelection { /// Fulfills an account requirement by selecting the appropriate account from the available inputs. pub(crate) fn fulfill_account_requirement( &mut self, account_id: AccountId, - ) -> Result, Error> { + ) -> Result>, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs index e0822901dc..78ebeeefe1 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs @@ -35,8 +35,8 @@ pub(crate) fn sdruc_not_expired( }) } -pub(crate) fn amount_sums( - selected_inputs: &[InputSigningData], +pub(crate) fn amount_sums( + selected_inputs: &[InputSigningData], outputs: &[Output], slot_index: SlotIndex, ) -> (u64, u64, HashMap, HashMap) { @@ -76,8 +76,8 @@ pub(crate) fn amount_sums( } #[derive(Debug, Clone)] -struct AmountSelection { - newly_selected_inputs: HashMap, +struct AmountSelection { + newly_selected_inputs: HashMap>, inputs_sum: u64, outputs_sum: u64, inputs_sdr: HashMap, @@ -87,8 +87,8 @@ struct AmountSelection { slot_index: SlotIndex, } -impl AmountSelection { - fn new(input_selection: &InputSelection) -> Result { +impl AmountSelection { + fn new(input_selection: &InputSelection) -> Result { let (inputs_sum, outputs_sum, inputs_sdr, outputs_sdr) = amount_sums( &input_selection.selected_inputs, &input_selection.outputs, @@ -127,7 +127,7 @@ impl AmountSelection { } } - fn fulfil<'a>(&mut self, inputs: impl Iterator) -> bool { + fn fulfil<'a>(&mut self, inputs: impl Iterator>) -> bool { for input in inputs { if self.newly_selected_inputs.contains_key(input.output_id()) { continue; @@ -161,16 +161,16 @@ impl AmountSelection { false } - fn into_newly_selected_inputs(self) -> Vec { + fn into_newly_selected_inputs(self) -> Vec> { self.newly_selected_inputs.into_values().collect() } } -impl InputSelection { +impl InputSelection { fn fulfil<'a>( &self, - base_inputs: impl Iterator + Clone, - amount_selection: &mut AmountSelection, + base_inputs: impl Iterator> + Clone, + amount_selection: &mut AmountSelection, ) -> bool { // No native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { @@ -216,7 +216,7 @@ impl InputSelection { false } - fn reduce_funds_of_chains(&mut self, amount_selection: &mut AmountSelection) -> Result<(), Error> { + fn reduce_funds_of_chains(&mut self, amount_selection: &mut AmountSelection) -> Result<(), Error> { // Only consider automatically transitioned outputs. let outputs = self.outputs.iter_mut().filter(|output| { output @@ -273,7 +273,7 @@ impl InputSelection { }) } - pub(crate) fn fulfill_amount_requirement(&mut self) -> Result, Error> { + pub(crate) fn fulfill_amount_requirement(&mut self) -> Result>, Error> { let mut amount_selection = AmountSelection::new(self)?; if amount_selection.missing_amount() == 0 { @@ -341,8 +341,8 @@ impl InputSelection { fn fulfill_amount_requirement_inner( &mut self, - amount_selection: &mut AmountSelection, - ) -> Option> { + amount_selection: &mut AmountSelection, + ) -> Option>> { let basic_ed25519_inputs = self.available_inputs.iter().filter(|input| { if let Output::Basic(output) = &input.output { output diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs b/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs index ce6fb8ee6e..53a4503501 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs @@ -4,9 +4,9 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { // Checks if a selected input unlocks a given ED25519 address. - fn selected_unlocks_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { + fn selected_unlocks_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { // PANIC: safe to unwrap as outputs with no address have been filtered out already. let required_address = input .output @@ -19,7 +19,7 @@ impl InputSelection { // Checks if an available input can unlock a given ED25519 address. // In case an account input is selected, also tells if it needs to be state or governance transitioned. - fn available_has_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { + fn available_has_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { let (required_address, _) = input .output .required_and_unlocked_address(self.slot_index, input.output_id()) @@ -29,7 +29,7 @@ impl InputSelection { } /// Fulfills an ed25519 sender requirement by selecting an available input that unlocks its address. - pub(crate) fn fulfill_ed25519_requirement(&mut self, address: &Address) -> Result, Error> { + pub(crate) fn fulfill_ed25519_requirement(&mut self, address: &Address) -> Result>, Error> { // Checks if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs b/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs index f1a2f5be1b..cf56b37d4c 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs @@ -16,12 +16,12 @@ pub(crate) fn is_foundry_with_id(output: &Output, foundry_id: &FoundryId) -> boo } } -impl InputSelection { +impl InputSelection { /// Fulfills a foundry requirement by selecting the appropriate foundry from the available inputs. pub(crate) fn fulfill_foundry_requirement( &mut self, foundry_id: FoundryId, - ) -> Result, Error> { + ) -> Result>, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs b/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs index 99c961c418..d955eadd6d 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs @@ -4,10 +4,10 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { /// Fulfills an issuer requirement by fulfilling the equivalent sender requirement. /// Potentially converts the error for a more accurate one. - pub(crate) fn fulfill_issuer_requirement(&mut self, address: &Address) -> Result, Error> { + pub(crate) fn fulfill_issuer_requirement(&mut self, address: &Address) -> Result>, Error> { log::debug!("Treating {address:?} issuer requirement as a sender requirement"); match self.fulfill_sender_requirement(address) { diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs index 9da2517062..c8d96c1086 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs @@ -41,10 +41,10 @@ pub enum Requirement { Amount, } -impl InputSelection { +impl InputSelection { /// Fulfills a requirement by selecting the appropriate available inputs. /// Returns the selected inputs and an optional new requirement. - pub(crate) fn fulfill_requirement(&mut self, requirement: Requirement) -> Result, Error> { + pub(crate) fn fulfill_requirement(&mut self, requirement: Requirement) -> Result>, Error> { log::debug!("Fulfilling requirement {requirement:?}"); match requirement { diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs index e355d74dbd..6892d7c00d 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs @@ -23,8 +23,8 @@ pub(crate) fn get_native_tokens<'a>(outputs: impl Iterator) - Ok(required_native_tokens) } -pub(crate) fn get_minted_and_melted_native_tokens( - inputs: &[InputSigningData], +pub(crate) fn get_minted_and_melted_native_tokens( + inputs: &[InputSigningData], outputs: &[Output], ) -> Result<(NativeTokensBuilder, NativeTokensBuilder), Error> { let mut minted_native_tokens = NativeTokensBuilder::new(); @@ -110,8 +110,8 @@ pub(crate) fn get_native_tokens_diff( } } -impl InputSelection { - pub(crate) fn fulfill_native_tokens_requirement(&mut self) -> Result, Error> { +impl InputSelection { + pub(crate) fn fulfill_native_tokens_requirement(&mut self) -> Result>, Error> { let mut input_native_tokens = get_native_tokens(self.selected_inputs.iter().map(|input| &input.output))?; let mut output_native_tokens = get_native_tokens(self.outputs.iter())?; let (minted_native_tokens, melted_native_tokens) = diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs b/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs index 0ae00082c3..3e854b407b 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs @@ -29,9 +29,9 @@ pub(crate) fn is_nft_with_id_non_null(output: &Output, nft_id: &NftId) -> bool { } } -impl InputSelection { +impl InputSelection { /// Fulfills an nft requirement by selecting the appropriate nft from the available inputs. - pub(crate) fn fulfill_nft_requirement(&mut self, nft_id: NftId) -> Result, Error> { + pub(crate) fn fulfill_nft_requirement(&mut self, nft_id: NftId) -> Result>, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs b/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs index e79dfc82cf..ce4273db5b 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs @@ -4,9 +4,9 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { /// Fulfills a sender requirement by selecting an available input that unlocks its address. - pub(crate) fn fulfill_sender_requirement(&mut self, address: &Address) -> Result, Error> { + pub(crate) fn fulfill_sender_requirement(&mut self, address: &Address) -> Result>, Error> { match address { Address::Ed25519(_) => { log::debug!("Treating {address:?} sender requirement as an ed25519 requirement"); diff --git a/sdk/src/client/api/block_builder/input_selection/transition.rs b/sdk/src/client/api/block_builder/input_selection/transition.rs index 18344028c6..03ca7cbe16 100644 --- a/sdk/src/client/api/block_builder/input_selection/transition.rs +++ b/sdk/src/client/api/block_builder/input_selection/transition.rs @@ -13,7 +13,7 @@ use crate::{ }, }; -impl InputSelection { +impl InputSelection { /// Transitions an account input by creating a new account output if required. fn transition_account_input( &mut self, @@ -149,7 +149,7 @@ impl InputSelection { /// Transitions an input by creating a new output if required. /// If no `account_transition` is provided, assumes a state transition. - pub(crate) fn transition_input(&mut self, input: &InputSigningData) -> Result, Error> { + pub(crate) fn transition_input(&mut self, input: &InputSigningData) -> Result, Error> { match &input.output { Output::Account(account_input) => self.transition_account_input(account_input, input.output_id()), Output::Foundry(foundry_input) => self.transition_foundry_input(foundry_input, input.output_id()), diff --git a/sdk/src/client/api/block_builder/transaction.rs b/sdk/src/client/api/block_builder/transaction.rs index 76e01d4991..772a275e0a 100644 --- a/sdk/src/client/api/block_builder/transaction.rs +++ b/sdk/src/client/api/block_builder/transaction.rs @@ -25,8 +25,8 @@ const SINGLE_UNLOCK_LENGTH: usize = 1 + 1 + Ed25519Signature::PUBLIC_KEY_LENGTH const REFERENCE_ACCOUNT_NFT_UNLOCK_LENGTH: usize = 1 + 2; /// Verifies the semantic of a prepared transaction. -pub fn verify_semantic( - input_signing_data: &[InputSigningData], +pub fn verify_semantic( + input_signing_data: &[InputSigningData], transaction_payload: &SignedTransactionPayload, ) -> crate::client::Result> { let inputs = input_signing_data 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 0934655927..2cbd4f3f3e 100644 --- a/sdk/src/client/api/types.rs +++ b/sdk/src/client/api/types.rs @@ -1,7 +1,6 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; use serde::{Deserialize, Serialize}; use crate::{ @@ -22,34 +21,33 @@ use crate::{ }, TryFromDto, }, - utils::serde::bip44::option_bip44, }; /// Helper struct for offline signing #[derive(Clone, Debug, Eq, PartialEq)] -pub struct PreparedTransactionData { +pub struct PreparedTransactionData { /// Transaction pub transaction: Transaction, /// Required input information for signing. Inputs need to be ordered by address type - pub inputs_data: Vec, + pub inputs_data: Vec>, /// Optional remainder output information - pub remainder: Option, + pub remainder: Option>, } /// PreparedTransactionData Dto #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct PreparedTransactionDataDto { +pub struct PreparedTransactionDataDto { /// Transaction pub transaction: TransactionDto, /// Required address information for signing - pub inputs_data: Vec, + pub inputs_data: Vec>, /// Optional remainder output information - pub remainder: Option, + pub remainder: Option>, } -impl From<&PreparedTransactionData> for PreparedTransactionDataDto { - fn from(value: &PreparedTransactionData) -> Self { +impl From<&PreparedTransactionData> for PreparedTransactionDataDto { + fn from(value: &PreparedTransactionData) -> Self { Self { transaction: TransactionDto::from(&value.transaction), inputs_data: value.inputs_data.clone(), @@ -58,11 +56,11 @@ impl From<&PreparedTransactionData> for PreparedTransactionDataDto { } } -impl TryFromDto for PreparedTransactionData { +impl TryFromDto> for PreparedTransactionData { type Error = Error; fn try_from_dto_with_params_inner( - dto: PreparedTransactionDataDto, + dto: PreparedTransactionDataDto, params: Option<&ProtocolParameters>, ) -> Result { Ok(Self { @@ -76,25 +74,25 @@ impl TryFromDto for PreparedTransactionData { /// Helper struct for offline signing #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SignedTransactionData { +pub struct SignedTransactionData { /// Signed transaction payload pub payload: SignedTransactionPayload, /// Required address information for signing - pub inputs_data: Vec, + pub inputs_data: Vec>, } /// SignedTransactionData Dto #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SignedTransactionDataDto { +pub struct SignedTransactionDataDto { /// Signed transaction payload pub payload: SignedTransactionPayloadDto, /// Required address information for signing - pub inputs_data: Vec, + pub inputs_data: Vec>, } -impl From<&SignedTransactionData> for SignedTransactionDataDto { - fn from(value: &SignedTransactionData) -> Self { +impl From<&SignedTransactionData> for SignedTransactionDataDto { + fn from(value: &SignedTransactionData) -> Self { Self { payload: SignedTransactionPayloadDto::from(&value.payload), inputs_data: value.inputs_data.clone(), @@ -102,11 +100,11 @@ impl From<&SignedTransactionData> for SignedTransactionDataDto { } } -impl TryFromDto for SignedTransactionData { +impl TryFromDto> for SignedTransactionData { type Error = Error; fn try_from_dto_with_params_inner( - dto: SignedTransactionDataDto, + dto: SignedTransactionDataDto, params: Option<&ProtocolParameters>, ) -> Result { Ok(Self { @@ -119,12 +117,11 @@ impl TryFromDto for SignedTransactionData { /// Data for a remainder output, used for ledger nano #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct RemainderData { +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 signing options for the remainder addresses + pub signing_options: Option, /// The remainder address pub address: Address, } diff --git a/sdk/src/client/error.rs b/sdk/src/client/error.rs index 3333218288..4c54d6cd45 100644 --- a/sdk/src/client/error.rs +++ b/sdk/src/client/error.rs @@ -151,9 +151,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 0519b5447f..3173211dae 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -5,15 +5,12 @@ //! //! 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, @@ -22,16 +19,15 @@ use iota_ledger_nano::{ use packable::{error::UnexpectedEOF, unpacker::SliceUnpacker, Packable, PackableExt}; use tokio::sync::Mutex; -use super::{GenerateAddressOptions, SecretManage, SecretManagerConfig}; use crate::{ client::secret::{ types::{LedgerApp, LedgerDeviceType}, - LedgerNanoStatus, PreparedTransactionData, + Generate, LedgerNanoStatus, PreparedTransactionData, SecretManagerConfig, Sign, SignTransaction, }, types::block::{ - address::{AccountAddress, Address, AnchorAddress, NftAddress}, + address::{AccountAddress, Address, AnchorAddress, Ed25519Address, NftAddress}, output::Output, - payload::signed_transaction::SignedTransactionPayload, + protocol::ProtocolParameters, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, Error as BlockError, @@ -131,71 +127,62 @@ impl TryFrom for LedgerDeviceType { } #[async_trait] -impl SecretManage for LedgerSecretManager { - type Error = crate::client::Error; +impl Generate for LedgerSecretManager { + type Options = (); - 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> { - // need an update on the ledger C lib - todo!(); - // let options = options.into().unwrap_or_default(); - // let bip32_account = account_index.harden().into(); - - // let bip32 = LedgerBIP32Index { - // bip32_index: address_indexes.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(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 addresses = ledger - // .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len()) - // .map_err(Error::from)?; - - // drop(lock); - - // Ok(addresses.into_iter().map(Ed25519Address::new).collect()) + async fn generate(&self, _options: &Self::Options) -> crate::client::Result { + todo!() } +} - 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 Generate for LedgerSecretManager { + type Options = (); + + 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 = (); + + async fn generate(&self, _options: &Self::Options) -> crate::client::Result> { + todo!() + } +} + +#[async_trait] +impl Generate> for LedgerSecretManager { + type Options = (); + + 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()) } +} - /// 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_trait] +impl Sign for LedgerSecretManager { + type Options = Bip44; + + 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. @@ -234,19 +221,15 @@ 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, - ) -> Result::Error> { + prepared_transaction: &PreparedTransactionData, + _protocol_parameters: &ProtocolParameters, + ) -> crate::client::Result { let mut input_bip32_indices = Vec::new(); let mut coin_type = None; let mut account_index = None; @@ -254,7 +237,7 @@ impl SecretManage for LedgerSecretManager { let input_len = prepared_transaction.inputs_data.len(); for input in &prepared_transaction.inputs_data { - let chain = input.chain.ok_or(Error::MissingBip32Chain)?; + let chain = input.signing_options.ok_or(Error::MissingBip32Chain)?; // coin_type and account_index should be the same in each output if (coin_type.is_some() && coin_type != Some(chain.coin_type)) @@ -303,7 +286,7 @@ impl SecretManage for LedgerSecretManager { #[allow(clippy::option_if_let_else)] let (remainder_output, remainder_bip32) = match &prepared_transaction.remainder { Some(remainder) => { - if let Some(chain) = remainder.chain { + if let Some(chain) = remainder.signing_options { ( Some(&remainder.output), LedgerBIP32Index { @@ -405,13 +388,6 @@ impl SecretManage for LedgerSecretManager { Ok(Unlocks::new(unlocks)?) } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data).await - } } impl SecretManagerConfig for LedgerSecretManager { @@ -421,7 +397,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)) } } @@ -430,10 +406,13 @@ impl SecretManagerConfig for LedgerSecretManager { /// is signed but only with BasicOutputs, without extra-features and if the transaction is not too large. /// If criteria are not met, blind signing is needed. /// This method finds out if we have to switch to blind signing mode. -pub fn needs_blind_signing(prepared_transaction: &PreparedTransactionData, buffer_size: usize) -> bool { - if !prepared_transaction.transaction.outputs().iter().all( - |output| matches!(output, Output::Basic(o) if o.simple_deposit_address().is_some()&& o.address().is_ed25519()), - ) { +pub fn needs_blind_signing(prepared_transaction: &PreparedTransactionData, buffer_size: usize) -> bool { + if !prepared_transaction + .transaction + .outputs() + .iter() + .all(|output| matches!(output, Output::Basic(o) if o.simple_deposit_address().is_some())) + { return true; } @@ -511,7 +490,7 @@ impl LedgerSecretManager { // Merge signature unlocks with Account/Nft/Reference unlocks fn merge_unlocks( - prepared_transaction_data: &PreparedTransactionData, + prepared_transaction_data: &PreparedTransactionData, mut unlocks: impl Iterator, ) -> Result, Error> { let slot_index = prepared_transaction_data.transaction.creation_slot(); @@ -594,7 +573,7 @@ mod tests { use super::*; use crate::{ - client::{api::GetAddressesOptions, constants::IOTA_COIN_TYPE, secret::SecretManager}, + client::{constants::IOTA_COIN_TYPE, secret::SecretManager}, types::block::address::ToBech32Ext, }; diff --git a/sdk/src/client/secret/manager.rs b/sdk/src/client/secret/manager.rs new file mode 100644 index 0000000000..1ef9d528a3 --- /dev/null +++ b/sdk/src/client/secret/manager.rs @@ -0,0 +1,464 @@ +// 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; +use crate::{ + client::{ + secret::{ + mnemonic::MnemonicSecretManager, + types::{EvmSignature, StrongholdDto}, + 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) => Ok(l.generate(&()).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) => Ok(l.generate(&()).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 ee705d0c8e..ddea91916e 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,12 +13,14 @@ use crypto::{ }; use zeroize::Zeroizing; -use super::{GenerateAddressOptions, SecretManage}; use crate::{ - client::{api::PreparedTransactionData, Client, Error}, - types::block::{ - payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, + client::{ + secret::{ + types::EvmSignature, Generate, GenerateMultiKeyOptions, GeneratePublicKeyOptions, Sign, SignTransaction, + }, + Client, Error, }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, }; /// Secret manager that uses only a mnemonic. @@ -35,62 +35,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::>()?) +impl Generate for MnemonicSecretManager { + type Options = GeneratePublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_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 = GeneratePublicKeyOptions; + + 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 = GenerateMultiKeyOptions; + + 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( + &GeneratePublicKeyOptions::default() + .with_coin_type(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 = GenerateMultiKeyOptions; + + 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 = GeneratePublicKeyOptions; + + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + let chain = Bip44::new(options.coin_type) + .with_account(options.account_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 = GeneratePublicKeyOptions; + + 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 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_trait] +impl Generate> for MnemonicSecretManager { + type Options = GenerateMultiKeyOptions; + + 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, + &GeneratePublicKeyOptions::default() + .with_coin_type(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 = GenerateMultiKeyOptions; + + 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 fn sign_ed25519(&self, msg: &[u8], chain: Bip44) -> Result { +#[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(); @@ -98,12 +170,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::()) @@ -111,24 +184,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, - ) -> Result { - super::default_transaction_unlocks(self, prepared_transaction_data).await - } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data).await + Ok(EvmSignature { public_key, signature }) } } +impl SignTransaction for MnemonicSecretManager {} + impl MnemonicSecretManager { /// Create a new [`MnemonicSecretManager`] from a BIP-39 mnemonic in English. /// @@ -160,13 +221,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 = GeneratePublicKeyOptions::default().with_coin_type(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" ); } @@ -178,13 +238,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 = GeneratePublicKeyOptions::default().with_coin_type(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 91a7867860..ac2024e364 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,620 +21,518 @@ pub mod stronghold; /// Signing related types pub mod types; -#[cfg(feature = "stronghold")] -use std::time::Duration; -use std::{collections::HashMap, fmt::Debug, 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::{ input_selection::Error as InputSelectionError, transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData, }, + constants::IOTA_COIN_TYPE, Error, }, types::block::{ - address::{Address, AnchorAddress, Ed25519Address}, + address::{Address, AnchorAddress}, core::UnsignedBlock, output::Output, payload::SignedTransactionPayload, + protocol::ProtocolParameters, signature::{Ed25519Signature, Signature}, unlock::{AccountUnlock, NftUnlock, ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, Block, Error as BlockError, }, }; -/// The secret manager interface. -#[async_trait] -pub trait SecretManage: Send + Sync { - type Error: std::error::Error + Send + Sync; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct GeneratePublicKeyOptions { + pub coin_type: u32, + pub account_index: u32, + pub internal: bool, + pub address_index: u32, +} - /// 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()) +impl Default for GeneratePublicKeyOptions { + fn default() -> Self { + Self { + coin_type: IOTA_COIN_TYPE, + account_index: 0, + internal: false, + address_index: 0, + } } +} - 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; +impl GeneratePublicKeyOptions { + /// Set the coin type + pub fn with_coin_type(mut self, coin_type: u32) -> Self { + self.coin_type = coin_type; + self + } - /// 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?, - )))) + /// Set the account index + pub fn with_account_index(mut self, account_index: u32) -> Self { + self.account_index = account_index; + self } - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - ) -> Result; + /// Set internal flag. + pub fn with_internal(mut self, internal: bool) -> Self { + self.internal = internal; + self + } - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - ) -> Result; + /// Set internal flag. + pub fn with_address_index(mut self, address_index: u32) -> Self { + self.address_index = address_index; + self + } } -pub trait SecretManagerConfig: SecretManage { - type Config: Serialize + DeserializeOwned + Debug + Send + Sync; - - fn to_config(&self) -> Option; - - fn from_config(config: &Self::Config) -> Result - where - Self: Sized; +impl From for GeneratePublicKeyOptions { + fn from(value: Bip44) -> Self { + Self::default() + .with_coin_type(value.coin_type) + .with_account_index(value.account) + .with_internal(value.change != 0) + .with_address_index(value.address_index) + } } -/// 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, +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct GenerateMultiKeyOptions { + pub coin_type: u32, + pub account_index: u32, + pub internal: bool, + pub address_range: Range, } -#[cfg(feature = "stronghold")] -impl From for SecretManager { - fn from(secret_manager: StrongholdSecretManager) -> Self { - Self::Stronghold(secret_manager) +impl Default for GenerateMultiKeyOptions { + fn default() -> Self { + Self { + coin_type: IOTA_COIN_TYPE, + account_index: 0, + internal: false, + address_range: 0..1, + } } } -#[cfg(feature = "ledger_nano")] -impl From for SecretManager { - fn from(secret_manager: LedgerSecretManager) -> Self { - Self::LedgerNano(secret_manager) +impl GenerateMultiKeyOptions { + /// Set the coin type + pub fn with_coin_type(mut self, coin_type: u32) -> Self { + self.coin_type = coin_type; + self } -} -impl From for SecretManager { - fn from(secret_manager: MnemonicSecretManager) -> Self { - Self::Mnemonic(secret_manager) + /// Set the account index + pub fn with_account_index(mut self, account_index: u32) -> Self { + self.account_index = account_index; + self } -} -#[cfg(feature = "private_key_secret_manager")] -impl From for SecretManager { - fn from(secret_manager: PrivateKeySecretManager) -> Self { - Self::PrivateKey(Box::new(secret_manager)) + /// Set internal flag. + pub fn with_internal(mut self, internal: bool) -> Self { + self.internal = internal; + self } -} -impl 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(), - } + /// Set range to the builder + pub fn with_address_range(mut self, range: Range) -> Self { + self.address_range = range; + self } } -impl FromStr for SecretManager { - type Err = Error; - - fn from_str(s: &str) -> crate::client::Result { - Self::try_from(serde_json::from_str::(s)?) - } -} +#[async_trait] +pub trait Generate: Send + Sync { + type Options: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; -/// 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, + async fn generate(&self, options: &Self::Options) -> crate::client::Result; } -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)); - } +#[async_trait] +impl, K> Generate for Arc { + type Options = T::Options; - Self::Stronghold(builder.build(&stronghold_dto.snapshot_path)?) - } + async fn generate(&self, options: &Self::Options) -> crate::client::Result { + self.as_ref().generate(options).await + } +} - #[cfg(feature = "ledger_nano")] - SecretManagerDto::LedgerNano(is_simulator) => Self::LedgerNano(LedgerSecretManager::new(is_simulator)), +#[async_trait] +pub trait Sign: Send + Sync { + type Options: 'static + Send + Sync + Serialize + Clone + Debug + DeserializeOwned + PartialEq; - SecretManagerDto::Mnemonic(mnemonic) => { - Self::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.as_str().to_owned())?) - } + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result; - #[cfg(feature = "private_key_secret_manager")] - SecretManagerDto::PrivateKey(private_key) => { - Self::PrivateKey(Box::new(PrivateKeySecretManager::try_from_hex(private_key)?)) - } + /// Signs `signing_hash` using the given `options`, returning a [`SignatureUnlock`]. + async fn signature_unlock( + &self, + signing_hash: &[u8; 32], + options: &Self::Options, + ) -> crate::client::Result + where + Signature: From, + { + Ok(SignatureUnlock::new(Signature::from( + self.sign(signing_hash, options).await?, + ))) + } +} - 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, S> Sign for Arc { + type Options = T::Options; - SecretManagerDto::Placeholder => Self::Placeholder, - }) + async fn sign(&self, msg: &[u8], options: &Self::Options) -> crate::client::Result { + self.as_ref().sign(msg, 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 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_trait] -impl SecretManage for SecretManager { - type Error = Error; - - async fn generate_ed25519_public_keys( +pub trait SignTransaction: Sign { + async fn transaction_unlocks( &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 + prepared_transaction_data: &PreparedTransactionData, + _protocol_parameters: &ProtocolParameters, + ) -> 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.creation_slot(); + + // 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 (input_address, _) = input + .output + .required_and_unlocked_address(slot_index, input.output_metadata.output_id())?; + + // Check if we already added an [Unlock] for this address + match block_indexes.get(&input_address) { + // If we already have an [Unlock] for this address, add a [Unlock] based on the address type + Some(block_index) => match input_address { + Address::Ed25519(_ed25519) => { + blocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?)); + } + Address::Account(_account) => { + blocks.push(Unlock::Account(AccountUnlock::new(*block_index as u16)?)) + } + Address::Nft(_nft) => blocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)), + Address::Anchor(_) => Err(BlockError::UnsupportedAddressKind(AnchorAddress::KIND))?, + _ => todo!("What do we do here?"), + }, + 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 &input_address { + Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => {} + Address::Restricted(restricted) if restricted.address().is_ed25519() => {} + _ => Err(InputSelectionError::MissingInputWithEd25519Address)?, + } + + let options = input.signing_options.as_ref().ok_or(Error::MissingSigningOptions)?; + + 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(input_address, current_block_index); + } } - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } - } - 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), + // 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, + }; } - } - 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), - } + Ok(Unlocks::new(blocks)?) } - async fn sign_secp256k1_ecdsa( + async fn sign_transaction( &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), - } - } + prepared_transaction_data: PreparedTransactionData, + protocol_parameters: &ProtocolParameters, + ) -> crate::client::Result { + log::debug!("[sign_transaction] {:?}", prepared_transaction_data); - async fn transaction_unlocks( - &self, - prepared_transaction_data: &PreparedTransactionData, - ) -> Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => { - Ok(secret_manager.transaction_unlocks(prepared_transaction_data).await?) - } - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => { - Ok(secret_manager.transaction_unlocks(prepared_transaction_data).await?) - } - Self::Mnemonic(secret_manager) => secret_manager.transaction_unlocks(prepared_transaction_data).await, - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => secret_manager.transaction_unlocks(prepared_transaction_data).await, - Self::Placeholder => Err(Error::PlaceholderSecretManager), - } - } + let unlocks = self + .transaction_unlocks(&prepared_transaction_data, protocol_parameters) + .await?; - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - ) -> Result { - match self { - #[cfg(feature = "stronghold")] - Self::Stronghold(secret_manager) => Ok(secret_manager.sign_transaction(prepared_transaction_data).await?), - #[cfg(feature = "ledger_nano")] - Self::LedgerNano(secret_manager) => Ok(secret_manager.sign_transaction(prepared_transaction_data).await?), - Self::Mnemonic(secret_manager) => secret_manager.sign_transaction(prepared_transaction_data).await, - #[cfg(feature = "private_key_secret_manager")] - Self::PrivateKey(secret_manager) => secret_manager.sign_transaction(prepared_transaction_data).await, - Self::Placeholder => Err(Error::PlaceholderSecretManager), + let PreparedTransactionData { + transaction, + inputs_data, + .. + } = 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)?; + + 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 {} -pub trait DowncastSecretManager: SecretManage { - fn downcast(&self) -> Option<&T>; +/// 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; } -impl DowncastSecretManager for S { - fn downcast(&self) -> Option<&T> { - (self as &(dyn std::any::Any + Send + Sync)).downcast_ref::() - } +#[async_trait] +impl + SignTransaction + SignBlock> SecretManage for T { + type GenerationOptions = >::Options; + type SigningOptions = >::Options; } -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, - } - } +pub trait SecretManagerConfig: SecretManage { + type Config: Serialize + DeserializeOwned + Debug + Send + Sync; - 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 to_config(&self) -> Option; + + fn from_config(config: &Self::Config) -> crate::client::Result + where + Self: Sized; } -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>; + + #[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, -) -> 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.creation_slot(); - - // 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 (input_address, _) = input - .output - .required_and_unlocked_address(slot_index, input.output_metadata.output_id())?; - - // Check if we already added an [Unlock] for this address - match block_indexes.get(&input_address) { - // If we already have an [Unlock] for this address, add a [Unlock] based on the address type - Some(block_index) => match input_address { - Address::Ed25519(_ed25519) => { - blocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?)); - } - Address::Account(_account) => blocks.push(Unlock::Account(AccountUnlock::new(*block_index as u16)?)), - Address::Nft(_nft) => blocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)), - Address::Anchor(_) => Err(BlockError::UnsupportedAddressKind(AnchorAddress::KIND))?, - _ => todo!("What do we do here?"), - }, - 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 &input_address { - Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => {} - Address::Restricted(restricted) if restricted.address().is_ed25519() => {} - _ => 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(input_address, 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) } + } - // 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, - }; + #[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) } - 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, -) -> crate::client::Result -where - crate::client::Error: From, -{ - log::debug!("[sign_transaction] {:?}", prepared_transaction_data); - - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; +impl DowncastSecretManager for S { + fn is(&self) -> bool { + self.as_any().is::() + } - let PreparedTransactionData { - transaction, - inputs_data, - .. - } = prepared_transaction_data; - let tx_payload = SignedTransactionPayload::new(transaction, unlocks)?; + fn downcast_ref(&self) -> Option<&T> { + self.as_any().downcast_ref::() + } - validate_signed_transaction_payload_length(&tx_payload)?; + fn downcast_mut(&mut self) -> Option<&mut T> { + self.as_any_mut().downcast_mut::() + } +} - let conflict = verify_semantic(&inputs_data, &tx_payload)?; +pub trait AsAny: 'static + 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); +} - 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) } #[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 0be00cd7a3..75bed66a31 100644 --- a/sdk/src/client/secret/private_key.rs +++ b/sdk/src/client/secret/private_key.rs @@ -3,24 +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, signature::Ed25519Signature, unlock::Unlocks, + client::{ + secret::{Generate, Sign, SignTransaction}, + Error, }, + types::block::{address::Ed25519Address, signature::Ed25519Signature}, }; /// Secret manager based on a single private key. @@ -33,61 +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, - ) -> Result { - super::default_transaction_unlocks(self, prepared_transaction_data).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, - ) -> Result { - super::default_sign_transaction(self, prepared_transaction_data).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..931705a1fb 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 { @@ -136,19 +115,22 @@ impl LedgerNanoStatus { /// Data for transaction inputs for signing and ordering of unlock blocks #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct InputSigningData { +pub struct InputSigningData { /// The output 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, + pub signing_options: Option, } -impl InputSigningData { +impl InputSigningData { /// Return the [OutputId] pub fn output_id(&self) -> &OutputId { 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 773068d8d8..bbdf28c9be 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -3,8 +3,7 @@ //! The [SecretManage] implementation 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,26 +28,85 @@ use super::{ }; use crate::{ client::{ - api::PreparedTransactionData, - secret::{types::StrongholdDto, GenerateAddressOptions, SecretManage, SecretManagerConfig}, + secret::{ + types::{EvmSignature, StrongholdDto}, + Generate, GenerateMultiKeyOptions, GeneratePublicKeyOptions, SecretManagerConfig, Sign, SignTransaction, + }, stronghold::Error, }, - types::block::{ - payload::signed_transaction::SignedTransactionPayload, 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 = GeneratePublicKeyOptions; - 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_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 = GeneratePublicKeyOptions; + + 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 = GenerateMultiKeyOptions; + + 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). @@ -64,12 +121,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( @@ -108,14 +164,91 @@ 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 = GenerateMultiKeyOptions; + + 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 = GeneratePublicKeyOptions; + + 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_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 = GeneratePublicKeyOptions; + + 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 = GenerateMultiKeyOptions; + + 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). @@ -130,12 +263,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( @@ -169,13 +301,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 = GenerateMultiKeyOptions; + + 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). @@ -202,7 +349,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. @@ -221,12 +368,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). @@ -253,7 +401,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. @@ -270,24 +418,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, - ) -> Result { - crate::client::secret::default_transaction_unlocks(self, prepared_transaction_data).await - } - - async fn sign_transaction( - &self, - prepared_transaction_data: PreparedTransactionData, - ) -> Result { - crate::client::secret::default_sign_transaction(self, prepared_transaction_data).await + Ok(EvmSignature { public_key, signature }) } } +impl SignTransaction for StrongholdAdapter {} + impl SecretManagerConfig for StrongholdAdapter { type Config = StrongholdDto; @@ -299,7 +435,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 { diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 63e87715ee..8536926d36 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -16,10 +16,10 @@ 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, SecretManager}, + types::block::address::{Bech32Address, Ed25519Address, ToBech32Ext}, wallet::{ - core::{Bip44, WalletData, WalletInner}, + core::{WalletData, WalletInner}, operations::syncing::SyncOptions, ClientOptions, Wallet, }, @@ -29,7 +29,8 @@ use crate::{ #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct WalletBuilder { - pub(crate) bip_path: Option, + pub(crate) public_key_options: Option, + pub(crate) signing_options: Option, pub(crate) address: Option, pub(crate) alias: Option, pub(crate) client_options: Option, @@ -42,7 +43,8 @@ pub struct WalletBuilder { impl Default for WalletBuilder { fn default() -> Self { Self { - bip_path: Default::default(), + public_key_options: Default::default(), + signing_options: Default::default(), address: Default::default(), alias: Default::default(), client_options: Default::default(), @@ -53,10 +55,7 @@ impl Default for WalletBuilder { } } -impl WalletBuilder -where - crate::wallet::Error: From, -{ +impl WalletBuilder { /// Initialises a new instance of the wallet builder with the default storage adapter. pub fn new() -> Self { Self { @@ -65,9 +64,15 @@ where } } - /// 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(); + /// Set the public key options. + pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { + self.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.signing_options = signing_options.into(); self } @@ -124,9 +129,8 @@ where 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> { @@ -178,9 +182,11 @@ where self.secret_manager = secret_manager; } - // 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 previously stored options if they weren't provided + if self.public_key_options.is_none() { + self.public_key_options = loaded_wallet_builder + .as_ref() + .and_then(|builder| builder.public_key_options.clone()); } // May use a previously stored wallet alias if it wasn't provided @@ -208,18 +214,21 @@ where let address = self.address.as_ref().unwrap().clone(); #[cfg(feature = "storage")] - let mut wallet_data = storage_manager.load_wallet_data().await?; + let mut wallet_data = storage_manager.load_wallet_data::().await?; - // The bip path must not change. + // The public key options 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, - }); + let old = &wallet_data.public_key_options; + if let Some(new) = self.public_key_options.as_ref() { + if new != old { + return Err(crate::wallet::Error::PublicKeyOptionsMismatch { + new: serde_json::to_value(new)?, + old: serde_json::to_value(old)?, + }); + } + } else { + self.public_key_options = Some(old.clone()); } } @@ -260,7 +269,17 @@ where storage_manager: tokio::sync::RwLock::new(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( + self.public_key_options + .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, + self.signing_options + .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, + address, + self.alias.clone(), + ), + }; #[cfg(not(feature = "storage"))] let wallet_data = WalletData::new(self.bip_path, address, self.alias.clone()); let wallet = Wallet { @@ -286,34 +305,30 @@ 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.public_key_options.as_ref().unwrap(); + + Ok(Ed25519Address::from_public_key_bytes( + self.secret_manager + .as_ref() + .unwrap() + .read() + .await + .generate(options) + .await? + .to_bytes(), + ) + .to_bech32(bech32_hrp)) } #[cfg(feature = "storage")] - pub(crate) async fn from_wallet(wallet: &Wallet) -> Self { + pub(crate) async fn from_wallet(wallet: &Wallet) -> Self + where + S::GenerationOptions: Clone, + S::SigningOptions: Clone, + { Self { - bip_path: wallet.bip_path().await, + public_key_options: Some(wallet.data().await.public_key_options.clone()), + signing_options: Some(wallet.data().await.signing_options.clone()), address: Some(wallet.address().await), alias: wallet.alias().await, client_options: Some(wallet.client_options().await), @@ -326,7 +341,7 @@ where // Check if any of the locked inputs is not used in a transaction and unlock them, so they get available for new // transactions #[cfg(feature = "storage")] -fn unlock_unused_inputs(wallet_data: &mut WalletData) -> crate::wallet::Result<()> { +fn unlock_unused_inputs(wallet_data: &mut WalletData) -> crate::wallet::Result<()> { log::debug!("[unlock_unused_inputs]"); let mut used_inputs = HashSet::new(); for transaction_id in &wallet_data.pending_transactions { @@ -356,9 +371,11 @@ 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(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, #[serde(default, skip_serializing_if = "Option::is_none")] pub(crate) address: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -370,10 +387,11 @@ pub(crate) mod dto { pub(crate) storage_options: Option, } - impl From for WalletBuilder { - fn from(value: WalletBuilderDto) -> Self { + impl From> for WalletBuilder { + fn from(value: WalletBuilderDto) -> Self { Self { - bip_path: value.bip_path, + public_key_options: value.public_key_options, + signing_options: value.signing_options, address: value.address, alias: value.alias, client_options: value.client_options, @@ -384,12 +402,16 @@ pub(crate) mod dto { } } - impl<'de, S: SecretManage> Deserialize<'de> for WalletBuilder { + impl<'de, S: SecretManage> Deserialize<'de> for WalletBuilder + where + S::GenerationOptions: Deserialize<'de>, + S::SigningOptions: Deserialize<'de>, + { 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 50fbaab439..22659c21ee 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -46,7 +46,7 @@ use crate::{ #[derive(Debug)] pub struct Wallet { pub(crate) inner: Arc>, - pub(crate) data: Arc>, + pub(crate) data: Arc>>, } impl Clone for Wallet { @@ -66,10 +66,7 @@ impl core::ops::Deref for Wallet { } } -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Initialises the wallet builder. pub fn builder() -> WalletBuilder { WalletBuilder::::new() @@ -90,7 +87,7 @@ pub struct WalletInner { // TODO: make this optional? pub(crate) secret_manager: Arc>, #[cfg(feature = "events")] - pub(crate) event_emitter: tokio::sync::RwLock, + pub(crate) event_emitter: tokio::sync::RwLock>, #[cfg(feature = "storage")] pub(crate) storage_options: StorageOptions, #[cfg(feature = "storage")] @@ -99,23 +96,25 @@ pub struct WalletInner { /// Wallet data. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct WalletData { - /// The wallet BIP44 path. - pub(crate) bip_path: Option, +pub struct WalletData { + /// The public key generation options. + pub(crate) public_key_options: S::GenerationOptions, + /// The signing options for transactions and blocks. + pub(crate) signing_options: S::SigningOptions, /// The wallet address. pub(crate) address: Bech32Address, /// The wallet alias. pub(crate) alias: Option, /// Outputs // stored separated from the wallet for performance? - pub(crate) outputs: HashMap, + pub(crate) outputs: HashMap>, /// Unspent outputs that are currently used as input for transactions // outputs used in transactions should be locked here so they don't get used again, which would result in a // conflicting transaction pub(crate) locked_outputs: HashSet, /// Unspent outputs // have unspent outputs in a separated hashmap so we don't need to iterate over all outputs we have - pub(crate) unspent_outputs: HashMap, + pub(crate) unspent_outputs: HashMap>, /// Sent transactions // stored separated from the wallet for performance and only the transaction id here? where to add the network id? // transactions: HashSet, @@ -134,10 +133,16 @@ pub struct WalletData { pub(crate) native_token_foundries: HashMap, } -impl WalletData { - pub(crate) fn new(bip_path: Option, address: Bech32Address, alias: Option) -> Self { +impl WalletData { + pub(crate) fn new( + public_key_options: S::GenerationOptions, + signing_options: S::SigningOptions, + address: Bech32Address, + alias: Option, + ) -> Self { Self { - bip_path, + public_key_options, + signing_options, address, alias, outputs: HashMap::new(), @@ -152,9 +157,9 @@ impl WalletData { } fn filter_outputs<'a>( - outputs: impl Iterator, + outputs: impl Iterator>, filter: FilterOptions, - ) -> impl Iterator { + ) -> impl Iterator> { outputs.filter(move |output| { match &output.output { Output::Account(account) => { @@ -232,27 +237,30 @@ impl WalletData { } /// Returns outputs map of the wallet. - pub fn outputs(&self) -> &HashMap { + pub fn outputs(&self) -> &HashMap> { &self.outputs } /// Returns unspent outputs map of the wallet. - pub fn unspent_outputs(&self) -> &HashMap { + pub fn unspent_outputs(&self) -> &HashMap> { &self.unspent_outputs } /// Returns outputs of the wallet. - pub fn filtered_outputs(&self, filter: FilterOptions) -> impl Iterator { + pub fn filtered_outputs(&self, filter: FilterOptions) -> impl Iterator> { Self::filter_outputs(self.outputs.values(), filter) } /// Returns unspent outputs of the wallet. - pub fn filtered_unspent_outputs(&self, filter: FilterOptions) -> impl Iterator { + pub fn filtered_unspent_outputs( + &self, + filter: FilterOptions, + ) -> impl Iterator> { Self::filter_outputs(self.unspent_outputs.values(), filter) } /// Gets the unspent account output matching the given ID. - pub fn unspent_account_output(&self, account_id: &AccountId) -> Option<&OutputData> { + pub fn unspent_account_output(&self, account_id: &AccountId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { account_ids: Some([*account_id].into()), ..Default::default() @@ -261,7 +269,7 @@ impl WalletData { } /// Gets the unspent anchor output matching the given ID. - pub fn unspent_anchor_output(&self, anchor_id: &AnchorId) -> Option<&OutputData> { + pub fn unspent_anchor_output(&self, anchor_id: &AnchorId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { anchor_ids: Some([*anchor_id].into()), ..Default::default() @@ -270,7 +278,7 @@ impl WalletData { } /// Gets the unspent foundry output matching the given ID. - pub fn unspent_foundry_output(&self, foundry_id: &FoundryId) -> Option<&OutputData> { + pub fn unspent_foundry_output(&self, foundry_id: &FoundryId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { foundry_ids: Some([*foundry_id].into()), ..Default::default() @@ -279,7 +287,7 @@ impl WalletData { } /// Gets the unspent nft output matching the given ID. - pub fn unspent_nft_output(&self, nft_id: &NftId) -> Option<&OutputData> { + pub fn unspent_nft_output(&self, nft_id: &NftId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { nft_ids: Some([*nft_id].into()), ..Default::default() @@ -288,7 +296,7 @@ impl WalletData { } /// Gets the unspent delegation output matching the given ID. - pub fn unspent_delegation_output(&self, delegation_id: &DelegationId) -> Option<&OutputData> { + pub fn unspent_delegation_output(&self, delegation_id: &DelegationId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { delegation_ids: Some([*delegation_id].into()), ..Default::default() @@ -297,21 +305,21 @@ impl WalletData { } /// Returns implicit accounts of the wallet. - pub fn implicit_accounts(&self) -> impl Iterator { + pub fn implicit_accounts(&self) -> impl Iterator> { self.unspent_outputs .values() .filter(|output_data| output_data.output.is_implicit_account()) } /// Returns accounts of the wallet. - pub fn accounts(&self) -> impl Iterator { + pub fn accounts(&self) -> impl Iterator> { self.unspent_outputs .values() .filter(|output_data| output_data.output.is_account()) } /// Get the [`OutputData`] of an output stored in the wallet. - pub fn get_output(&self, output_id: &OutputId) -> Option<&OutputData> { + pub fn get_output(&self, output_id: &OutputId) -> Option<&OutputData> { self.outputs.get(output_id) } @@ -344,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) -> Result { #[cfg(feature = "storage")] let default_sync_options = inner .storage_manager @@ -399,7 +403,7 @@ where /// Save the wallet to the database, accepts the updated wallet data as option so we don't need to drop it before /// saving #[cfg(feature = "storage")] - pub(crate) async fn save(&self, updated_wallet: Option<&WalletData>) -> Result<()> { + pub(crate) async fn save(&self, updated_wallet: Option<&WalletData>) -> Result<()> { log::debug!("[save] wallet data"); match updated_wallet { Some(wallet) => { @@ -419,15 +423,15 @@ where } #[cfg(feature = "events")] - pub(crate) async fn emit(&self, wallet_event: super::events::types::WalletEvent) { + pub(crate) async fn emit(&self, wallet_event: super::events::types::WalletEvent) { self.inner.emit(wallet_event).await } - pub async fn data(&self) -> tokio::sync::RwLockReadGuard<'_, WalletData> { + pub async fn data(&self) -> tokio::sync::RwLockReadGuard<'_, WalletData> { self.data.read().await } - pub(crate) async fn data_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, WalletData> { + pub(crate) async fn data_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, WalletData> { self.data.write().await } @@ -459,11 +463,6 @@ 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 WalletInner { @@ -478,7 +477,7 @@ impl WalletInner { pub async fn listen + Send>(&self, events: I, handler: F) where I::IntoIter: Send, - F: Fn(&WalletEvent) + 'static + Send + Sync, + F: Fn(&WalletEvent) + 'static + Send + Sync, { let mut emitter = self.event_emitter.write().await; emitter.on(events, handler); @@ -507,14 +506,14 @@ impl WalletInner { } #[cfg(feature = "events")] - pub(crate) async fn emit(&self, event: crate::wallet::events::types::WalletEvent) { + pub(crate) async fn emit(&self, event: crate::wallet::events::types::WalletEvent) { self.event_emitter.read().await.emit(event); } /// Helper function to test events. #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] - pub async fn emit_test_event(&self, event: crate::wallet::events::types::WalletEvent) { + pub async fn emit_test_event(&self, event: crate::wallet::events::types::WalletEvent) { self.emit(event).await } } @@ -528,13 +527,14 @@ impl Drop for Wallet { /// Dto for the wallet data. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WalletDataDto { - pub bip_path: Option, +pub struct WalletDataDto { + pub public_key_options: G, + pub signing_options: S, pub address: Bech32Address, pub alias: Option, - pub outputs: HashMap, + pub outputs: HashMap>, pub locked_outputs: HashSet, - pub unspent_outputs: HashMap, + pub unspent_outputs: HashMap>, pub transactions: HashMap, pub pending_transactions: HashSet, pub incoming_transactions: HashMap, @@ -542,15 +542,16 @@ pub struct WalletDataDto { pub native_token_foundries: HashMap, } -impl TryFromDto for WalletData { +impl TryFromDto> for WalletData { type Error = crate::wallet::Error; fn try_from_dto_with_params_inner( - dto: WalletDataDto, + dto: WalletDataDto, params: Option<&ProtocolParameters>, ) -> core::result::Result { Ok(Self { - bip_path: dto.bip_path, + public_key_options: dto.public_key_options, + signing_options: dto.signing_options, address: dto.address, alias: dto.alias, outputs: dto.outputs, @@ -573,10 +574,15 @@ impl TryFromDto for WalletData { } } -impl From<&WalletData> for WalletDataDto { - fn from(value: &WalletData) -> Self { +impl From<&WalletData> for WalletDataDto +where + S::GenerationOptions: Clone, + S::SigningOptions: Clone, +{ + fn from(value: &WalletData) -> Self { Self { - bip_path: value.bip_path, + public_key_options: value.public_key_options.clone(), + signing_options: value.signing_options.clone(), address: value.address.clone(), alias: value.alias.clone(), outputs: value.outputs.clone(), @@ -606,6 +612,7 @@ mod test { use super::*; use crate::{ + client::secret::GeneratePublicKeyOptions, types::block::{ address::{Address, Ed25519Address}, input::{Input, UtxoInput}, @@ -689,7 +696,8 @@ mod test { ); let wallet_data = WalletData { - bip_path: Some(Bip44::new(4218)), + public_key_options: GeneratePublicKeyOptions::default().with_coin_type(4218), + signing_options: Bip44::new(4218), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", ) @@ -722,7 +730,8 @@ mod test { #[cfg(feature = "storage")] pub(crate) fn mock() -> Self { Self { - bip_path: Some(Bip44::new(4218)), + public_key_options: GeneratePublicKeyOptions::default().with_coin_type(4218), + signing_options: 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 fe902ee8ec..1e237f318f 100644 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ b/sdk/src/wallet/core/operations/address_generation.rs @@ -1,99 +1,97 @@ // 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(); - if options.as_ref().map_or(false, |o| o.ledger_nano_prompt) { - #[cfg(feature = "events")] - { - 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 +// if options.as_ref().map_or(false, |o| o.ledger_nano_prompt) { +// #[cfg(feature = "events")] +// { +// 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; - } +// 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? - } else { - 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()), - }; +// // Generate with prompt so the user can verify +// ledger_nano +// .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, +// options) .await? +// } else { +// 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 9840b967b6..fb1dcc7c66 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -13,11 +13,7 @@ use crate::{ /// The default interval for background syncing pub(crate) const DEFAULT_BACKGROUNDSYNCING_INTERVAL: Duration = Duration::from_secs(7); -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 0336b61bea..218fa3b593 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -30,8 +30,6 @@ impl Wallet { impl Wallet where - crate::client::Error: From, - crate::wallet::Error: From, WalletBuilder: SaveLoadWallet, { pub async fn set_client_options(&self, client_options: ClientBuilder) -> crate::wallet::Result<()> { diff --git a/sdk/src/wallet/core/operations/storage.rs b/sdk/src/wallet/core/operations/storage.rs index 7ccbc935de..3d1bc28afe 100644 --- a/sdk/src/wallet/core/operations/storage.rs +++ b/sdk/src/wallet/core/operations/storage.rs @@ -7,7 +7,7 @@ mod storage_stub { use crate::{ client::{ - secret::{mnemonic::MnemonicSecretManager, SecretManagerConfig}, + secret::{mnemonic::MnemonicSecretManager, SecretManage, SecretManagerConfig}, storage::StorageAdapter, }, wallet::{ @@ -29,10 +29,7 @@ mod storage_stub { } #[async_trait] - impl SaveLoadWallet for WalletBuilder - where - crate::wallet::Error: From, - { + 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?; @@ -51,7 +48,10 @@ mod storage_stub { storage: &impl StorageAdapter, ) -> crate::wallet::Result> { log::debug!("[load] wallet builder"); - if let Some(wallet_builder_dto) = storage.get::(WALLET_BUILDER_KEY).await? { + 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?; @@ -78,7 +78,12 @@ mod storage_stub { storage: &impl StorageAdapter, ) -> crate::wallet::Result> { log::debug!("[load] wallet builder"); - let res = storage.get::(WALLET_BUILDER_KEY).await?; + let res = storage + .get::::GenerationOptions, + ::SigningOptions, + >>(WALLET_BUILDER_KEY) + .await?; log::debug!("[load] wallet builder: {res:?}"); Ok(res.map(Into::into)) } diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index 81a3181bc5..df1edca544 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -10,14 +10,17 @@ 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, SecretManager, SecretManagerConfig, + SecretManagerDto, + }, utils::Password, }, types::block::address::Hrp, wallet::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( @@ -30,9 +33,9 @@ impl Wallet { log::debug!("[backup] creating a stronghold backup"); 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 @@ -83,7 +86,7 @@ impl Wallet { let mut secret_manager = self.secret_manager.as_ref().write().await; // Get the current snapshot path if set - let new_snapshot_path = if let SecretManager::Stronghold(stronghold) = &mut *secret_manager { + let new_snapshot_path = if let Ok(stronghold) = secret_manager.as_stronghold() { stronghold.snapshot_path.clone() } else { PathBuf::from("wallet.stronghold") @@ -94,42 +97,43 @@ 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) = + 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_wallet_data.as_ref().map(|data| &data.public_key_options); // 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? - wallet_data.bip_path != read_bip_path + loaded_pub_key_opts.is_some_and(|opts| &wallet_data.public_key_options != opts) } else { false } }); if !ignore_backup_values { - wallet_data.bip_path = read_bip_path; + if let Some(opts) = loaded_pub_key_opts { + wallet_data.public_key_options = opts.clone(); + } } - if let Some(mut read_secret_manager) = read_secret_manager { + if let Some(config) = loaded_secret_manager_config { + let mut loaded_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.to_string_lossy().into_owned(); + if let Ok(stronghold_dto) = loaded_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) = loaded_secret_manager.as_stronghold() { // Set password to restored secret manager stronghold.set_password(stronghold_password).await?; } - *secret_manager = restored_secret_manager; + *secret_manager = loaded_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. @@ -140,163 +144,13 @@ impl Wallet { drop(secret_manager); 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 { - *wallet_data = 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.read().await).await?; - - // also save wallet data to db - self.save(Some(&wallet_data)).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")); - } - - // Will be replaced by the restored wallet data - let mut wallet_data = self.data_mut().await; - - // We don't want to overwrite a possible existing wallet - // TODO not too sure about this, it used to check the presence of accounts, this is not 100% equivalent - if !wallet_data.outputs.is_empty() { - return Err(crate::wallet::Error::Backup( - "can't restore backup when there is already a wallet", - )); - } - - let mut secret_manager = self.secret_manager.as_ref().write().await; - // Get the current snapshot path if set - let new_snapshot_path = secret_manager.snapshot_path.clone(); - - // 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? - wallet_data.bip_path != read_bip_path - } else { - false - } - }); - - if !ignore_backup_values { - wallet_data.bip_path = read_bip_path; - } - - if let Some(mut read_secret_manager) = read_secret_manager { - 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?; - *secret_manager = restored_secret_manager; - } - - // drop secret manager, otherwise we get a deadlock in set_client_options() - drop(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 @@ -324,7 +178,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.data().await.public_key_options.clone()) + .with_signing_options(self.data().await.signing_options.clone()); wallet_builder.save(&*self.storage_manager.read().await).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 264962396b..7ef5c40ba4 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs @@ -38,7 +38,7 @@ 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>)> { migrate(stronghold).await?; // Get client_options @@ -64,7 +64,7 @@ pub(crate) async fn read_wallet_data_from_stronghold_snapshot(WALLET_DATA_KEY) + .get::>(WALLET_DATA_KEY) .await? .map(WalletData::try_from_dto) .transpose()?; diff --git a/sdk/src/wallet/error.rs b/sdk/src/wallet/error.rs index a490e5a232..a1ae55356a 100644 --- a/sdk/src/wallet/error.rs +++ b/sdk/src/wallet/error.rs @@ -3,7 +3,6 @@ use std::fmt::Debug; -use crypto::keys::bip44::Bip44; use serde::{ ser::{SerializeMap, Serializer}, Serialize, @@ -28,10 +27,10 @@ pub enum Error { #[error("`{0}`")] Client(Box), /// 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, }, /// Funds are spread over too many outputs #[error("funds are spread over too many outputs {output_count}/{output_count_max}, consolidation required")] diff --git a/sdk/src/wallet/events/mod.rs b/sdk/src/wallet/events/mod.rs index e908a0d1f9..9d75f85f30 100644 --- a/sdk/src/wallet/events/mod.rs +++ b/sdk/src/wallet/events/mod.rs @@ -13,11 +13,11 @@ pub use self::types::{WalletEvent, WalletEventType}; type Handler = Arc; -pub struct EventEmitter { - handlers: HashMap>>, +pub struct EventEmitter { + handlers: HashMap>>>, } -impl EventEmitter { +impl EventEmitter { /// Creates a new instance of `EventEmitter`. pub fn new() -> Self { Self { @@ -29,7 +29,7 @@ impl EventEmitter { /// multiple listeners for a single event. pub fn on(&mut self, events: impl IntoIterator, handler: F) where - F: Fn(&WalletEvent) + 'static + Send + Sync, + F: Fn(&WalletEvent) + 'static + Send + Sync, { let mut events = events.into_iter().peekable(); let handler = Arc::new(handler); @@ -68,7 +68,7 @@ impl EventEmitter { /// Invokes all listeners of `event`, passing a reference to `payload` as an /// argument to each of them. - pub fn emit(&self, event: WalletEvent) { + pub fn emit(&self, event: WalletEvent) { let event_type = match &event { WalletEvent::NewOutput(_) => WalletEventType::NewOutput, WalletEvent::SpentOutput(_) => WalletEventType::SpentOutput, @@ -86,13 +86,13 @@ impl EventEmitter { } } -impl Default for EventEmitter { +impl Default for EventEmitter { fn default() -> Self { Self::new() } } -impl Debug for EventEmitter { +impl Debug for EventEmitter { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!( f, diff --git a/sdk/src/wallet/events/types.rs b/sdk/src/wallet/events/types.rs index 71a4e7b927..04c3b0aa1a 100644 --- a/sdk/src/wallet/events/types.rs +++ b/sdk/src/wallet/events/types.rs @@ -21,44 +21,44 @@ use crate::{ #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum WalletEvent { +pub enum WalletEvent { ConsolidationRequired, #[cfg(feature = "ledger_nano")] #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] LedgerAddressGeneration(AddressData), - NewOutput(Box), - SpentOutput(Box), + NewOutput(Box>), + SpentOutput(Box>), TransactionInclusion(TransactionInclusionEvent), - TransactionProgress(TransactionProgressEvent), + TransactionProgress(TransactionProgressEvent), } -impl Serialize for WalletEvent { +impl Serialize for WalletEvent { fn serialize(&self, serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] - struct TransactionProgressEvent_<'a> { - progress: &'a TransactionProgressEvent, + struct TransactionProgressEvent_<'a, O> { + progress: &'a TransactionProgressEvent, } #[derive(Serialize)] #[serde(untagged)] - enum WalletEvent_<'a> { + enum WalletEvent_<'a, O> { T0, #[cfg(feature = "ledger_nano")] T1(&'a AddressData), - T2(&'a NewOutputEvent), - T3(&'a SpentOutputEvent), + T2(&'a NewOutputEvent), + T3(&'a SpentOutputEvent), T4(&'a TransactionInclusionEvent), - T5(TransactionProgressEvent_<'a>), + T5(TransactionProgressEvent_<'a, O>), } #[derive(Serialize)] - struct TypedWalletEvent_<'a> { + struct TypedWalletEvent_<'a, O> { #[serde(rename = "type")] kind: u8, #[serde(flatten)] - event: WalletEvent_<'a>, + event: WalletEvent_<'a, O>, } let event = match self { Self::ConsolidationRequired => TypedWalletEvent_ { @@ -91,11 +91,11 @@ impl Serialize for WalletEvent { } } -impl<'de> Deserialize<'de> for WalletEvent { +impl<'de, O: Deserialize<'de>> Deserialize<'de> for WalletEvent { fn deserialize>(d: D) -> Result { #[derive(Deserialize)] - struct TransactionProgressEvent_ { - progress: TransactionProgressEvent, + struct TransactionProgressEvent_ { + progress: TransactionProgressEvent, } let value = serde_json::Value::deserialize(d)?; @@ -176,9 +176,9 @@ impl TryFrom for WalletEventType { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct NewOutputEvent { +pub struct NewOutputEvent { /// The new output. - pub output: OutputData, + pub output: OutputData, /// The transaction that created the output. Might be pruned and not available. #[serde(skip_serializing_if = "Option::is_none")] pub transaction: Option, @@ -188,9 +188,9 @@ pub struct NewOutputEvent { } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct SpentOutputEvent { +pub struct SpentOutputEvent { /// The spent output. - pub output: OutputData, + pub output: OutputData, } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -202,13 +202,13 @@ pub struct TransactionInclusionEvent { #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum TransactionProgressEvent { +pub enum TransactionProgressEvent { /// Performing input selection. SelectingInputs, /// Generating remainder value deposit address. GeneratingRemainderDepositAddress(AddressData), /// Prepared transaction. - PreparedTransaction(Box), + PreparedTransaction(Box>), /// Prepared transaction signing hash hex encoded, required for blindsigning with a ledger nano PreparedTransactionSigningHash(String), /// Signing the transaction. @@ -217,7 +217,7 @@ pub enum TransactionProgressEvent { Broadcasting, } -impl Serialize for TransactionProgressEvent { +impl Serialize for TransactionProgressEvent { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -230,20 +230,20 @@ impl Serialize for TransactionProgressEvent { #[derive(Serialize)] #[serde(untagged)] - enum TransactionProgressEvent_<'a> { + enum TransactionProgressEvent_<'a, O> { T0, T1(&'a AddressData), - T2(&'a PreparedTransactionDataDto), + T2(&'a PreparedTransactionDataDto), T3(PreparedTransactionSigningHash_<'a>), T4, T5, } #[derive(Serialize)] - struct TypedTransactionProgressEvent_<'a> { + struct TypedTransactionProgressEvent_<'a, O> { #[serde(rename = "type")] kind: u8, #[serde(flatten)] - event: TransactionProgressEvent_<'a>, + event: TransactionProgressEvent_<'a, O>, } let event = match self { Self::SelectingInputs => TypedTransactionProgressEvent_ { @@ -275,7 +275,7 @@ impl Serialize for TransactionProgressEvent { } } -impl<'de> Deserialize<'de> for TransactionProgressEvent { +impl<'de, O: Deserialize<'de>> Deserialize<'de> for TransactionProgressEvent { fn deserialize>(d: D) -> Result { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index d3bcbdc9de..b269acce17 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -16,11 +16,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"); @@ -33,7 +29,7 @@ where async fn balance_inner( &self, // addresses_with_unspent_outputs: impl Iterator + Send, - wallet_data: &WalletData, + wallet_data: &WalletData, ) -> Result { let network_id = self.client().get_network_id().await?; let storage_score_params = self.client().get_storage_score_parameters().await?; @@ -252,7 +248,7 @@ where fn finish( &self, mut balance: Balance, - wallet_data: &WalletData, + wallet_data: &WalletData, network_id: u64, total_storage_cost: u64, total_native_tokens: NativeTokensBuilder, diff --git a/sdk/src/wallet/operations/block.rs b/sdk/src/wallet/operations/block.rs index d0e988ab60..3327508d39 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::{Result, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { pub(crate) async fn submit_basic_block( &self, payload: Option, @@ -28,7 +24,7 @@ where .await? .sign_ed25519( &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, + &self.data().await.signing_options, ) .await?; diff --git a/sdk/src/wallet/operations/helpers/time.rs b/sdk/src/wallet/operations/helpers/time.rs index ebd3675688..cabbefbb8d 100644 --- a/sdk/src/wallet/operations/helpers/time.rs +++ b/sdk/src/wallet/operations/helpers/time.rs @@ -7,9 +7,9 @@ use crate::{ }; // Check if an output can be unlocked by the wallet address at the current time -pub(crate) fn can_output_be_unlocked_now( +pub(crate) fn can_output_be_unlocked_now( wallet_address: &Address, - output_data: &OutputData, + output_data: &OutputData, slot_index: SlotIndex, ) -> crate::wallet::Result { if let Some(unlock_conditions) = output_data.output.unlock_conditions() { diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index fa64145091..819f4ee999 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -6,7 +6,10 @@ use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use crate::{ - client::{api::PreparedTransactionData, secret::SecretManage}, + client::{ + api::PreparedTransactionData, + secret::{SecretManage, Sign}, + }, types::block::{ address::{Address, Ed25519Address}, output::{ @@ -34,7 +37,7 @@ pub enum OutputsToClaim { All, } -impl WalletData { +impl WalletData { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`] or @@ -122,11 +125,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`] or @@ -143,14 +142,16 @@ where /// Get basic outputs that have only one unlock condition which is [AddressUnlockCondition], so they can be used as /// additional inputs - pub(crate) async fn get_basic_outputs_for_additional_inputs(&self) -> crate::wallet::Result> { + pub(crate) async fn get_basic_outputs_for_additional_inputs( + &self, + ) -> crate::wallet::Result>> { log::debug!("[OUTPUT_CLAIMING] get_basic_outputs_for_additional_inputs"); #[cfg(feature = "participation")] let voting_output = self.get_voting_output().await?; let wallet_data = self.data().await; // Get basic outputs only with AddressUnlockCondition and no other unlock condition - let mut basic_outputs: Vec = Vec::new(); + let mut basic_outputs: Vec> = Vec::new(); for (output_id, output_data) in &wallet_data.unspent_outputs { #[cfg(feature = "participation")] if let Some(ref voting_output) = voting_output { @@ -219,7 +220,7 @@ where pub async fn prepare_claim_outputs + Send>( &self, output_ids_to_claim: I, - ) -> crate::wallet::Result + ) -> crate::wallet::Result> where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index fdb29b815b..1279cd519f 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -65,14 +65,10 @@ impl ConsolidationParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { fn should_consolidate_output( &self, - output_data: &OutputData, + output_data: &OutputData, slot_index: SlotIndex, wallet_address: &Address, ) -> Result { @@ -119,7 +115,10 @@ where } /// 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> { log::debug!("[OUTPUT_CONSOLIDATION] prepare consolidating outputs if needed"); #[cfg(feature = "participation")] let voting_output = self.get_voting_output().await?; @@ -153,21 +152,8 @@ where 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() - { + if secret_manager.as_ledger_nano().is_ok() { DEFAULT_LEDGER_OUTPUT_CONSOLIDATION_THRESHOLD } else { DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD @@ -193,17 +179,8 @@ where #[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) - } else { - None - } - }) - }) { + 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() { diff --git a/sdk/src/wallet/operations/participation/event.rs b/sdk/src/wallet/operations/participation/event.rs index 841a527c21..6bea5f81cf 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 481881c214..8d31b45800 100644 --- a/sdk/src/wallet/operations/participation/mod.rs +++ b/sdk/src/wallet/operations/participation/mod.rs @@ -46,11 +46,7 @@ pub struct ParticipationEventWithNodes { pub nodes: Vec, } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +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( @@ -223,7 +219,7 @@ where /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. - pub async fn get_voting_output(&self) -> Result> { + pub async fn get_voting_output(&self) -> Result>> { self.data().await.get_voting_output() } @@ -277,11 +273,11 @@ where } } -impl WalletData { +impl WalletData { /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. - pub(crate) fn get_voting_output(&self) -> Result> { + pub(crate) fn get_voting_output(&self) -> Result>> { log::debug!("[get_voting_output]"); Ok(self .unspent_outputs diff --git a/sdk/src/wallet/operations/participation/voting.rs b/sdk/src/wallet/operations/participation/voting.rs index b8642af3c6..a4dc030be3 100644 --- a/sdk/src/wallet/operations/participation/voting.rs +++ b/sdk/src/wallet/operations/participation/voting.rs @@ -16,11 +16,7 @@ use crate::{ wallet::{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. @@ -49,7 +45,7 @@ where &self, event_id: impl Into> + Send, answers: impl Into>> + Send, - ) -> Result { + ) -> Result> { let event_id = event_id.into(); let answers = answers.into(); if let Some(event_id) = event_id { @@ -135,7 +131,10 @@ where } /// Prepares the transaction for [Wallet::stop_participating()]. - pub async fn prepare_stop_participating(&self, event_id: ParticipationEventId) -> Result { + pub async fn prepare_stop_participating( + &self, + event_id: ParticipationEventId, + ) -> Result> { let voting_output = self .get_voting_output() .await? diff --git a/sdk/src/wallet/operations/participation/voting_power.rs b/sdk/src/wallet/operations/participation/voting_power.rs index 550ffe64d9..7a4f5fb424 100644 --- a/sdk/src/wallet/operations/participation/voting_power.rs +++ b/sdk/src/wallet/operations/participation/voting_power.rs @@ -17,11 +17,7 @@ use crate::{ wallet::{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 @@ -48,7 +44,10 @@ where } /// Prepares the transaction for [Wallet::increase_voting_power()]. - pub async fn prepare_increase_voting_power(&self, amount: u64) -> Result { + pub async fn prepare_increase_voting_power( + &self, + amount: u64, + ) -> Result> { let (new_output, tx_options) = match self.get_voting_output().await? { Some(current_output_data) => { let output = current_output_data.output.as_basic(); @@ -96,7 +95,10 @@ where } /// Prepares the transaction for [Wallet::decrease_voting_power()]. - pub async fn prepare_decrease_voting_power(&self, amount: u64) -> Result { + pub async fn prepare_decrease_voting_power( + &self, + amount: u64, + ) -> Result> { let current_output_data = self .get_voting_output() .await? diff --git a/sdk/src/wallet/operations/reissue.rs b/sdk/src/wallet/operations/reissue.rs index 7bad812224..186186cd89 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::{ @@ -19,11 +19,7 @@ use crate::{ 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( @@ -63,7 +59,7 @@ where .await? .sign_ed25519( &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, + &self.data().await.signing_options, ) .await? .id(&protocol_parameters), @@ -111,7 +107,7 @@ where .await? .sign_ed25519( &*self.get_secret_manager().read().await, - self.bip_path().await.ok_or(Error::MissingBipPath)?, + &self.data().await.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 779227f649..4ae451adf0 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 @@ -19,11 +19,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..1213cd2b4f 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs @@ -8,10 +8,7 @@ use crate::{ 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..48860984af 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs @@ -23,11 +23,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..bbb566437c 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs @@ -8,10 +8,7 @@ use crate::{ 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 fadc42acd4..d6f374854e 100644 --- a/sdk/src/wallet/operations/syncing/addresses/outputs.rs +++ b/sdk/src/wallet/operations/syncing/addresses/outputs.rs @@ -13,16 +13,12 @@ use crate::{ }, }; -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, addresses_with_unspent_outputs: Vec, - ) -> crate::wallet::Result<(Vec, Vec)> { + ) -> crate::wallet::Result<(Vec, Vec>)> { log::debug!("[SYNC] start get_outputs_from_address_output_ids"); let address_outputs_start_time = Instant::now(); @@ -51,7 +47,7 @@ where } let results = futures::future::try_join_all(tasks).await?; for res in results { - let (address, outputs): (AddressWithUnspentOutputs, Vec) = res?; + let (address, outputs): (AddressWithUnspentOutputs, Vec>) = res?; addresses_with_outputs.push(address); outputs_data.extend(outputs); } diff --git a/sdk/src/wallet/operations/syncing/foundries.rs b/sdk/src/wallet/operations/syncing/foundries.rs index 166c4fd64f..839a11ee1a 100644 --- a/sdk/src/wallet/operations/syncing/foundries.rs +++ b/sdk/src/wallet/operations/syncing/foundries.rs @@ -9,11 +9,7 @@ use crate::{ 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 464ce251ab..d1cc51c6f0 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -23,11 +23,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<()> { @@ -115,7 +111,7 @@ where let (addresses_with_unspent_outputs, spent_or_not_synced_output_ids, outputs_data): ( Vec, Vec, - Vec, + Vec>, ) = self.request_outputs_recursively(address_to_sync, options).await?; // Request possible spent outputs @@ -170,7 +166,11 @@ where &self, addresses_to_sync: Vec, options: &SyncOptions, - ) -> crate::wallet::Result<(Vec, Vec, Vec)> { + ) -> crate::wallet::Result<( + Vec, + Vec, + Vec>, + )> { // Cache the account and nft address with the related ed2559 address, so we can update the account address with // the new output ids diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index 0e18fc8c9c..0213d2662e 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -1,7 +1,6 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::bip44::Bip44; use instant::Instant; use crate::{ @@ -22,17 +21,13 @@ use crate::{ }, }; -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, outputs_with_meta: Vec, associated_address: &AddressWithUnspentOutputs, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result>> { log::debug!("[SYNC] convert output_responses"); // store outputs with network_id let network_id = self.client().get_network_id().await?; @@ -48,14 +43,6 @@ where .get(output_with_meta.metadata().output_id().transaction_id()) .map_or(false, |tx| !tx.incoming); - let chain = wallet_data.bip_path.map(|bip_path| { - // BIP 44 (HD wallets) and 4218 is the registered index for IOTA https://github.com/satoshilabs/slips/blob/master/slip-0044.md - Bip44::new(bip_path.coin_type) - .with_account(bip_path.account) - .with_change(associated_address.internal as _) - .with_address_index(associated_address.key_index) - }); - OutputData { output_id: output_with_meta.metadata().output_id().to_owned(), metadata: *output_with_meta.metadata(), @@ -64,7 +51,9 @@ where address: associated_address.address.inner.clone(), network_id, remainder, - chain, + // TODO: previously we set the internal and address index here, but + // they were always default values anyway. Do we need some mechanism here tho? + signing_options: Some(wallet_data.signing_options.clone()), } }) .collect()) diff --git a/sdk/src/wallet/operations/syncing/transactions.rs b/sdk/src/wallet/operations/syncing/transactions.rs index 609dff8c62..0f7de427f9 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -19,11 +19,7 @@ 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 and reissue them if unconfirmed. Returns the transaction with updated metadata and spent /// 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 @@ -237,8 +233,8 @@ fn updated_transaction_and_outputs( // When a transaction got pruned, the inputs and outputs are also not available, then this could mean that it was // confirmed and the created outputs got also already spent and pruned or the inputs got spent in another transaction -fn process_transaction_with_unknown_state( - wallet_data: &WalletData, +fn process_transaction_with_unknown_state( + wallet_data: &WalletData, mut transaction: TransactionWithMetadata, updated_transactions: &mut Vec, output_ids_to_unlock: &mut Vec, diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 81d64777a3..2301e96848 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -1,8 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::{keys::bip44::Bip44, signatures::ed25519::PublicKey}; -use derive_more::From; +use crypto::signatures::ed25519::PublicKey; use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, @@ -21,16 +20,12 @@ use crate::{ }, }; -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: Option + Send>, + key_source: impl Into>> + Send, ) -> Result { let issuer_id = AccountId::from(output_id); @@ -46,11 +41,8 @@ where pub async fn prepare_implicit_account_transition( &self, output_id: &OutputId, - key_source: Option + Send>, - ) -> Result - where - crate::wallet::Error: From, - { + key_source: impl Into>> + Send, + ) -> Result> { let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); let implicit_account = if let Some(implicit_account_data) = &implicit_account_data { @@ -63,25 +55,14 @@ where return Err(Error::ImplicitAccountNotFound); }; - let key_source = match key_source.map(Into::into) { + let key_source = match key_source.into() { Some(key_source) => key_source, - None => self.bip_path().await.ok_or(Error::MissingBipPath)?.into(), + None => BlockIssuerKeySource::Options(self.data().await.public_key_options.clone()), }; let public_key = match key_source { BlockIssuerKeySource::Key(public_key) => public_key, - BlockIssuerKeySource::Bip44Path(bip_path) => { - 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) => self.secret_manager.read().await.generate(&options).await?, }; let account_id = AccountId::from(output_id); @@ -116,8 +97,7 @@ where } } -#[derive(From)] -pub enum BlockIssuerKeySource { +pub enum BlockIssuerKeySource { Key(PublicKey), - Bip44Path(Bip44), + Options(O), } diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 2f126b6fff..34fb960422 100644 --- a/sdk/src/wallet/operations/transaction/build_transaction.rs +++ b/sdk/src/wallet/operations/transaction/build_transaction.rs @@ -15,23 +15,20 @@ use crate::{ wallet::{operations::transaction::TransactionOptions, Wallet}, }; -impl Wallet -where - crate::wallet::Error: From, -{ +impl Wallet { /// Builds the transaction from the selected in and outputs. pub(crate) async fn build_transaction( &self, - selected_transaction_data: Selected, + selected_transaction_data: Selected, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] build_transaction"); let build_transaction_start_time = Instant::now(); let protocol_parameters = self.client().get_protocol_parameters().await?; let mut inputs: Vec = Vec::new(); - let mut inputs_for_signing: Vec = Vec::new(); + let mut inputs_for_signing: Vec> = Vec::new(); for utxo in &selected_transaction_data.inputs { let input = Input::Utxo(UtxoInput::from(*utxo.output_id())); 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..d42d2b6743 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 @@ -16,11 +16,7 @@ use crate::{ }, }; -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 @@ -47,7 +43,7 @@ where token_id: TokenId, melt_amount: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] prepare_melt_native_token"); let foundry_id = FoundryId::from(token_id); @@ -90,7 +86,7 @@ where &self, account_id: AccountId, foundry_id: FoundryId, - ) -> crate::wallet::Result<(OutputData, OutputData)> { + ) -> crate::wallet::Result<(OutputData, OutputData)> { let mut existing_account_output_data = None; let mut existing_foundry_output = None; 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 3909c7c7f7..be341e5e86 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}, + client::{ + api::{input_selection::Burn, PreparedTransactionData}, + secret::SecretManage, + }, wallet::{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, foundries and accounts. /// /// Note that burning **native tokens** doesn't require the foundry output which minted them, but will not increase @@ -35,7 +38,7 @@ impl Wallet { &self, burn: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { let mut options: TransactionOptions = options.into().unwrap_or_default(); options.burn = Some(burn.into()); 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 9ae930a68f..1a26dd21d3 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -34,11 +34,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 { @@ -71,7 +67,7 @@ where &self, params: Option, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] prepare_create_account_output"); let storage_score_params = self.client().get_storage_score_parameters().await?; @@ -108,7 +104,10 @@ where } /// Gets an existing account output. - pub(crate) async fn get_account_output(&self, account_id: Option) -> Option<(AccountId, OutputData)> { + pub(crate) async fn get_account_output( + &self, + account_id: Option, + ) -> Option<(AccountId, OutputData)> { log::debug!("[get_account_output]"); self.data() .await 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 e74dbc10f4..dc957dabf3 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 @@ -64,21 +64,21 @@ impl From<&CreateNativeTokenTransaction> for CreateNativeTokenTransactionDto { /// The result of preparing a transaction to create a native token #[derive(Debug)] -pub struct PreparedCreateNativeTokenTransaction { +pub struct PreparedCreateNativeTokenTransaction { pub token_id: TokenId, - pub transaction: PreparedTransactionData, + pub transaction: PreparedTransactionData, } /// Dto for PreparedNativeTokenTransaction #[derive(Debug, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -pub struct PreparedCreateNativeTokenTransactionDto { +pub struct PreparedCreateNativeTokenTransactionDto { pub token_id: TokenId, - pub transaction: PreparedTransactionDataDto, + pub transaction: PreparedTransactionDataDto, } -impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTransactionDto { - fn from(value: &PreparedCreateNativeTokenTransaction) -> Self { +impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTransactionDto { + fn from(value: &PreparedCreateNativeTokenTransaction) -> Self { Self { token_id: value.token_id, transaction: PreparedTransactionDataDto::from(&value.transaction), @@ -86,11 +86,7 @@ impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTr } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Creates a new foundry output with minted native tokens. /// /// Calls [Wallet::send_outputs()] internally, the options may define the remainder value strategy or custom inputs. @@ -130,7 +126,7 @@ where &self, params: CreateNativeTokenParams, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] create_native_token"); let storage_score_params = self.client().get_storage_score_parameters().await?; 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..3107c193c4 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 @@ -11,11 +11,7 @@ use crate::{ wallet::{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 @@ -52,7 +48,7 @@ where token_id: TokenId, mint_amount: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] mint_native_token"); let mint_amount = mint_amount.into(); 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 613fd48d19..5b59b1f627 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 @@ -109,11 +109,7 @@ impl MintNftParams { } } -impl Wallet -where - crate::wallet::Error: From, - crate::client::Error: From, -{ +impl Wallet { /// Mints NFTs. /// /// Calls [Wallet::send_outputs()] internally. The options may define the remainder value strategy or custom inputs. @@ -156,7 +152,7 @@ where &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result + ) -> crate::wallet::Result> where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/transaction/high_level/send.rs b/sdk/src/wallet/operations/transaction/high_level/send.rs index f51d01afaf..b9ba07be43 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send.rs @@ -73,11 +73,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. @@ -130,7 +126,7 @@ where &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result + ) -> crate::wallet::Result> where I::IntoIter: Send, { 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..93e176706e 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 @@ -73,11 +73,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 @@ -120,7 +116,7 @@ where &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result + ) -> crate::wallet::Result> where I::IntoIter: Send, { 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 995de07b89..f4cfa12b1e 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs @@ -42,11 +42,7 @@ impl SendNftParams { } } -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`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), so that @@ -88,7 +84,7 @@ where &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result + ) -> crate::wallet::Result> where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 71e437b38c..d7dec257ac 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -21,11 +21,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, @@ -34,7 +30,7 @@ where mandatory_inputs: Option>, remainder_address: Option
, burn: Option<&Burn>, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] select_inputs"); // Voting output needs to be requested before to prevent a deadlock #[cfg(feature = "participation")] @@ -215,13 +211,13 @@ where /// | [Address, StorageDepositReturn, ...] | no | /// | [Address, StorageDepositReturn, expired Expiration] | yes | #[allow(clippy::too_many_arguments)] -fn filter_inputs( - wallet_data: &WalletData, - available_outputs: Values<'_, OutputId, OutputData>, +fn filter_inputs( + wallet_data: &WalletData, + available_outputs: Values<'_, OutputId, OutputData>, slot_index: SlotIndex, custom_inputs: Option<&HashSet>, mandatory_inputs: Option<&HashSet>, -) -> crate::wallet::Result> { +) -> crate::wallet::Result>> { let mut available_outputs_signing_data = Vec::new(); for output_data in available_outputs { diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 84fb9a78b2..932fed8fa5 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -31,11 +31,7 @@ use crate::{ }, }; -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 @@ -99,7 +95,7 @@ where /// Signs a transaction, submit it to a node and store it in the wallet pub async fn sign_and_submit_transaction( &self, - prepared_transaction_data: PreparedTransactionData, + prepared_transaction_data: PreparedTransactionData, issuer_id: impl Into> + Send, options: impl Into> + Send, ) -> crate::wallet::Result { @@ -121,7 +117,7 @@ where /// Validates the transaction, submit it to a node and store it in the wallet pub async fn submit_and_store_transaction( &self, - signed_transaction_data: SignedTransactionData, + signed_transaction_data: SignedTransactionData, issuer_id: impl Into> + Send, options: impl Into> + Send, ) -> crate::wallet::Result { @@ -197,7 +193,7 @@ where } // unlock outputs - async fn unlock_inputs(&self, inputs: &[InputSigningData]) -> crate::wallet::Result<()> { + async fn unlock_inputs(&self, inputs: &[InputSigningData]) -> crate::wallet::Result<()> { let mut wallet_data = self.data_mut().await; for input_signing_data in inputs { let output_id = input_signing_data.output_id(); diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 70d832d510..85b088c7c7 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -27,11 +27,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 @@ -235,7 +231,7 @@ where recipient_address: Bech32Address, nft_id: Option, params: StorageScoreParameters, - ) -> crate::wallet::Result<(OutputBuilder, Option)> { + ) -> crate::wallet::Result<(OutputBuilder, Option>)> { let (mut first_output_builder, existing_nft_output_data) = if let Some(nft_id) = &nft_id { if nft_id.is_null() { // Mint a new NFT output diff --git a/sdk/src/wallet/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/operations/transaction/prepare_transaction.rs index 9b7e9ac490..59f553cabf 100644 --- a/sdk/src/wallet/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/operations/transaction/prepare_transaction.rs @@ -18,17 +18,13 @@ 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, outputs: impl Into> + Send, options: impl Into> + Send, - ) -> crate::wallet::Result { + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] prepare_transaction"); let options = options.into(); let outputs = outputs.into(); diff --git a/sdk/src/wallet/operations/transaction/sign_transaction.rs b/sdk/src/wallet/operations/transaction/sign_transaction.rs index 2421bda089..dd32b00301 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -4,10 +4,7 @@ #[cfg(all(feature = "events", feature = "ledger_nano"))] use { crate::client::api::PreparedTransactionDataDto, - crate::client::secret::{ - ledger_nano::{needs_blind_signing, LedgerSecretManager}, - DowncastSecretManager, - }, + crate::client::secret::ledger_nano::{needs_blind_signing, LedgerSecretManager}, }; #[cfg(feature = "events")] @@ -22,16 +19,12 @@ use crate::{ wallet::{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, - prepared_transaction_data: &PreparedTransactionData, - ) -> crate::wallet::Result { + prepared_transaction_data: &PreparedTransactionData, + ) -> crate::wallet::Result> { log::debug!("[TRANSACTION] sign_transaction"); log::debug!("[TRANSACTION] prepared_transaction_data {prepared_transaction_data:?}"); #[cfg(feature = "events")] @@ -40,45 +33,47 @@ where )) .await; - #[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 - } - }) - }) { - 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) { - self.emit(WalletEvent::TransactionProgress( - TransactionProgressEvent::PreparedTransactionSigningHash( - prepared_transaction_data.transaction.signing_hash().to_string(), - ), - )) - .await; - } else { - self.emit(WalletEvent::TransactionProgress( - TransactionProgressEvent::PreparedTransaction(Box::new(PreparedTransactionDataDto::from( - prepared_transaction_data, - ))), - )) - .await; - } - } - } - } + // #[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 + // } + // }) + // }) { + // 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) { + // self.emit(WalletEvent::TransactionProgress( + // TransactionProgressEvent::PreparedTransactionSigningHash( + // prepared_transaction_data.transaction.signing_hash().to_string(), + // ), + // )) + // .await; + // } else { + // self.emit(WalletEvent::TransactionProgress( + // TransactionProgressEvent::PreparedTransaction(Box::new(PreparedTransactionDataDto::from( + // prepared_transaction_data, + // ))), + // )) + // .await; + // } + // } + // } + // } + + let protocol_parameters = self.client().get_protocol_parameters().await?; let unlocks = match self .secret_manager .read() .await - .transaction_unlocks(prepared_transaction_data) + .transaction_unlocks(prepared_transaction_data, &protocol_parameters) .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 3fffb31b7e..fab7ac0ee7 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -9,11 +9,7 @@ use crate::{ wallet::{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 4da7b634e4..155f2da3e4 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -4,7 +4,7 @@ use zeroize::Zeroizing; use crate::{ - client::storage::StorageAdapter, + client::{secret::SecretManage, storage::StorageAdapter}, types::TryFromDto, wallet::{ core::{WalletData, WalletDataDto}, @@ -49,15 +49,21 @@ impl StorageManager { Ok(storage_manager) } - pub(crate) async fn load_wallet_data(&mut self) -> crate::wallet::Result> { - if let Some(dto) = self.get::(WALLET_DATA_KEY).await? { + pub(crate) async fn load_wallet_data(&mut self) -> crate::wallet::Result>> { + if let Some(dto) = self + .get::>(WALLET_DATA_KEY) + .await? + { Ok(Some(WalletData::try_from_dto(dto)?)) } else { Ok(None) } } - pub(crate) async fn save_wallet_data(&mut self, wallet_data: &WalletData) -> crate::wallet::Result<()> { + pub(crate) async fn save_wallet_data( + &mut self, + wallet_data: &WalletData, + ) -> crate::wallet::Result<()> { self.set(WALLET_DATA_KEY, &WalletDataDto::from(wallet_data)).await } diff --git a/sdk/src/wallet/types/mod.rs b/sdk/src/wallet/types/mod.rs index 2fdc2dd5be..0f5e0e1340 100644 --- a/sdk/src/wallet/types/mod.rs +++ b/sdk/src/wallet/types/mod.rs @@ -9,7 +9,6 @@ pub mod participation; use std::str::FromStr; -use crypto::keys::bip44::Bip44; use serde::{Deserialize, Serialize}; pub use self::{ @@ -17,7 +16,7 @@ pub use self::{ balance::{Balance, BaseCoinBalance, NativeTokensBalance, RequiredStorageDeposit}, }; use crate::{ - client::secret::types::InputSigningData, + client::secret::{types::InputSigningData, SecretManage}, types::{ api::core::OutputWithMetadataResponse, block::{ @@ -30,14 +29,13 @@ use crate::{ }, TryFromDto, }, - utils::serde::bip44::option_bip44, wallet::core::WalletData, }; /// An output with metadata #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct OutputData { +pub struct OutputData { /// The output id pub output_id: OutputId, pub metadata: OutputMetadata, @@ -51,26 +49,23 @@ pub struct OutputData { pub network_id: u64, pub remainder: bool, // bip44 path - #[serde(with = "option_bip44", default)] - pub chain: Option, + pub signing_options: Option, } -impl OutputData { - pub fn input_signing_data( +impl OutputData { + pub fn input_signing_data>( &self, - wallet_data: &WalletData, + wallet_data: &WalletData, slot_index: SlotIndex, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result>> { let (unlock_address, _unlocked_account_or_nft_address) = self.output.required_and_unlocked_address(slot_index, &self.output_id)?; let chain = if unlock_address == self.address { - self.chain + self.signing_options } else if let Address::Ed25519(_) = unlock_address { if wallet_data.address.inner() == &unlock_address { - // TODO #1279: do we need a check to make sure that `wallet_data.address` and `wallet_data.bip_path` are - // never conflicting? - wallet_data.bip_path + Some(wallet_data.signing_options) } else { return Ok(None); } @@ -82,7 +77,7 @@ impl OutputData { Ok(Some(InputSigningData { output: self.output.clone(), output_metadata: self.metadata, - chain, + signing_options: self.signing_options.clone(), })) } } diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 81f5bb44a8..24787a8f72 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -4,8 +4,11 @@ use std::collections::HashMap; use crate::{ - client::secret::SecretManage, - types::block::output::{OutputId, OutputMetadata}, + client::secret::{SecretManage, Sign}, + types::block::{ + output::{OutputId, OutputMetadata}, + signature::Ed25519Signature, + }, wallet::{ types::{InclusionState, OutputData, TransactionWithMetadata}, Wallet, @@ -18,11 +21,7 @@ use crate::{ 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; @@ -35,7 +34,7 @@ where /// Update wallet with newly synced data and emit events for outputs. pub(crate) async fn update_after_sync( &self, - unspent_outputs: Vec, + unspent_outputs: Vec>, spent_or_unsynced_output_metadata_map: HashMap>, ) -> crate::wallet::Result<()> { log::debug!("[SYNC] Update wallet with new synced transactions"); diff --git a/sdk/tests/client/input_selection/foundry_outputs.rs b/sdk/tests/client/input_selection/foundry_outputs.rs index 52c510b70c..b4ca32e705 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -255,7 +255,7 @@ fn melt_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -484,7 +484,7 @@ fn simple_foundry_transition_basic_not_needed() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( @@ -559,7 +559,7 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -700,7 +700,7 @@ fn mint_and_burn_at_the_same_time() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( @@ -762,7 +762,7 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Basic( 3_200_000, @@ -974,7 +974,7 @@ fn foundry_in_outputs_and_required() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -1040,7 +1040,7 @@ fn melt_and_burn_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, diff --git a/sdk/tests/client/input_selection/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 33ddf7c960..35f01b65f9 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -1237,7 +1237,7 @@ fn changed_immutable_metadata() { let inputs = [InputSigningData { output: nft_output.clone(), output_metadata: rand_output_metadata(), - chain: None, + signing_options: None, }]; #[cfg(feature = "irc_27")] diff --git a/sdk/tests/client/input_signing_data.rs b/sdk/tests/client/input_signing_data.rs index 75dfe2658d..872f09c092 100644 --- a/sdk/tests/client/input_signing_data.rs +++ b/sdk/tests/client/input_signing_data.rs @@ -26,14 +26,14 @@ fn input_signing_data_conversion() { let input_signing_data = InputSigningData { output, output_metadata: rand_output_metadata(), - chain: Some(bip44_chain), + signing_options: 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(); + 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 987ef89ea8..b3c8463590 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -208,7 +208,7 @@ fn build_output_inner(build: Build) -> (Output, Option) { } } -fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec { +fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec> { outputs .into_iter() .map(|build| { @@ -217,7 +217,7 @@ fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec Result<()> { let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::Mnemonic(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { @@ -74,7 +74,7 @@ async fn wallet_address_generation_stronghold() -> Result<()> { let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::Stronghold(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { wallet_builder = wallet_builder.with_storage_path(storage_path); @@ -107,7 +107,7 @@ async fn wallet_address_generation_ledger() -> Result<()> { let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::LedgerNano(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { diff --git a/sdk/tests/wallet/common/mod.rs b/sdk/tests/wallet/common/mod.rs index e73a4b2174..ca1de42d69 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -38,7 +38,7 @@ pub(crate) async fn make_wallet(storage_path: &str, mnemonic: Option, let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::Mnemonic(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)); + .with_public_key_options(Bip44::new(SHIMMER_COIN_TYPE)); #[cfg(feature = "storage")] { @@ -59,7 +59,7 @@ pub(crate) async fn make_ledger_nano_wallet(storage_path: &str, node: Option<&st let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::LedgerNano(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)); + .with_public_key_options(Bip44::new(SHIMMER_COIN_TYPE)); #[cfg(feature = "storage")] { wallet_builder = wallet_builder.with_storage_path(storage_path); diff --git a/sdk/tests/wallet/core.rs b/sdk/tests/wallet/core.rs index 8723afe641..14fccdbbc3 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -92,16 +92,16 @@ async fn changed_bip_path() -> Result<()> { .with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic( mnemonic.clone(), )?)) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)) + .with_public_key_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)), + let mismatch_err: Result = Err(Error::PublicKeyOptionsMismatch { + new: Some(Bip44::new(IOTA_COIN_TYPE)), + old: Some(Bip44::new(SHIMMER_COIN_TYPE)), }); assert!(matches!(err, mismatch_err)); @@ -149,7 +149,7 @@ async fn iota_coin_type() -> Result<()> { let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::Mnemonic(secret_manager)) .with_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); + .with_public_key_options(Bip44::new(IOTA_COIN_TYPE)); #[cfg(feature = "storage")] { diff --git a/sdk/tests/wallet/events.rs b/sdk/tests/wallet/events.rs index 65710e679b..cebd9e17d8 100644 --- a/sdk/tests/wallet/events.rs +++ b/sdk/tests/wallet/events.rs @@ -52,7 +52,7 @@ fn wallet_events_serde() { address: Address::Ed25519(Ed25519Address::new([0; Ed25519Address::LENGTH])), network_id: 42, remainder: true, - chain: None, + signing_options: None, }; assert_serde_eq(WalletEvent::NewOutput(Box::new(NewOutputEvent { 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..3e961159f5 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -89,7 +89,7 @@ async fn 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(Bip44::new(IOTA_COIN_TYPE)) .finish() .await .unwrap(); From 8c1f7f9ba30781af39f3ef08e0c52abb0c5e84d4 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 6 Dec 2023 12:23:50 -0500 Subject: [PATCH 02/24] it lives!!! --- bindings/core/src/lib.rs | 22 +- bindings/core/src/method/secret_manager.rs | 34 +-- bindings/core/src/method/utils.rs | 2 +- bindings/core/src/method/wallet.rs | 26 +- .../core/src/method_handler/call_method.rs | 17 +- .../core/src/method_handler/secret_manager.rs | 102 +++---- bindings/core/src/method_handler/wallet.rs | 62 ++--- bindings/core/src/response.rs | 10 +- bindings/core/tests/combined.rs | 8 +- bindings/core/tests/secrets_manager.rs | 12 +- bindings/core/tests/serialize_error.rs | 33 ++- bindings/nodejs/src/wallet.rs | 7 +- bindings/wasm/src/wallet.rs | 16 +- cli/src/cli.rs | 32 ++- cli/src/main.rs | 3 + cli/src/wallet_cli/mod.rs | 15 +- sdk/examples/client/01_generate_addresses.rs | 48 ++-- sdk/examples/client/02_address_balance.rs | 26 +- .../client/block/00_block_no_payload.rs | 6 +- .../block/01_block_confirmation_time.rs | 6 +- .../client/block/02_block_custom_parents.rs | 6 +- .../client/block/03_block_custom_payload.rs | 6 +- .../client/block/04_block_tagged_data.rs | 6 +- sdk/examples/client/ledger_nano.rs | 36 +-- .../client/ledger_nano_transaction.rs | 32 ++- .../client/node_api_core/04_post_block.rs | 6 +- .../client/node_api_core/05_post_block_raw.rs | 6 +- sdk/examples/client/quorum.rs | 31 ++- sdk/examples/client/stronghold.rs | 31 +-- .../account/implicit_account_creation.rs | 10 +- .../accounts_and_addresses/create_wallet.rs | 7 +- .../sign_and_verify_ed25519/sign_ed25519.rs | 7 +- sdk/examples/wallet/background_syncing.rs | 9 +- sdk/examples/wallet/events.rs | 9 +- sdk/examples/wallet/getting_started.rs | 9 +- sdk/examples/wallet/ledger_nano.rs | 25 +- sdk/examples/wallet/logger.rs | 18 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 29 +- .../offline_signing/0_generate_address.rs | 9 +- .../offline_signing/1_prepare_transaction.rs | 7 +- .../offline_signing/2_sign_transaction.rs | 31 ++- .../offline_signing/3_send_transaction.rs | 7 +- sdk/examples/wallet/spammer.rs | 36 +-- sdk/examples/wallet/storage.rs | 13 +- sdk/examples/wallet/wallet.rs | 25 +- .../api/block_builder/input_selection/mod.rs | 2 +- .../input_selection/remainder.rs | 6 +- .../input_selection/requirement/mod.rs | 2 +- sdk/src/client/secret/ledger_nano.rs | 126 +++++++-- sdk/src/client/secret/manager.rs | 11 +- sdk/src/client/secret/mnemonic.rs | 49 +++- sdk/src/client/secret/mod.rs | 103 ++++--- sdk/src/client/stronghold/secret.rs | 36 ++- sdk/src/wallet/core/builder.rs | 8 +- sdk/src/wallet/core/mod.rs | 95 ++++++- sdk/src/wallet/core/operations/client.rs | 8 +- sdk/src/wallet/core/operations/ledger_nano.rs | 25 -- sdk/src/wallet/core/operations/mod.rs | 3 +- sdk/src/wallet/core/operations/storage.rs | 128 +++------ sdk/src/wallet/core/operations/stronghold.rs | 3 +- .../core/operations/stronghold_backup/mod.rs | 10 +- .../stronghold_backup/stronghold_snapshot.rs | 2 +- sdk/src/wallet/events/mod.rs | 2 +- sdk/src/wallet/mod.rs | 2 +- .../wallet/operations/output_consolidation.rs | 6 +- sdk/src/wallet/operations/transaction/mod.rs | 5 +- sdk/src/wallet/storage/manager.rs | 25 +- sdk/src/wallet/types/mod.rs | 4 +- sdk/tests/client/addresses.rs | 256 ++++++++---------- .../client/input_selection/nft_outputs.rs | 3 +- sdk/tests/client/input_selection/outputs.rs | 3 +- sdk/tests/client/input_signing_data.rs | 7 +- sdk/tests/client/mod.rs | 2 +- sdk/tests/client/node_api/core.rs | 18 +- sdk/tests/client/node_api/mod.rs | 28 +- sdk/tests/client/secret_manager/mnemonic.rs | 28 +- .../client/secret_manager/private_key.rs | 79 ++---- sdk/tests/client/secret_manager/stronghold.rs | 57 ++-- sdk/tests/client/signing/account.rs | 51 ++-- sdk/tests/client/signing/basic.rs | 84 +++--- sdk/tests/client/signing/mod.rs | 60 ++-- sdk/tests/client/signing/nft.rs | 31 +-- sdk/tests/wallet/address_generation.rs | 55 ++-- sdk/tests/wallet/burn_outputs.rs | 6 +- sdk/tests/wallet/common/mod.rs | 29 +- sdk/tests/wallet/core.rs | 27 +- sdk/tests/wallet/events.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 45 ++- 88 files changed, 1252 insertions(+), 1178 deletions(-) delete mode 100644 sdk/src/wallet/core/operations/ledger_nano.rs diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 72f3de1a49..d589a5fead 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -11,14 +11,12 @@ 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}, }; 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() .with_address(self.address) .with_alias(self.alias) - .with_public_key_options(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 c36feb3580..57343f9bdc 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}; @@ -21,11 +19,13 @@ use crate::OmittedDebug; pub enum SecretManagerMethod { /// Generate Ed25519 addresses. 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,40 +36,36 @@ 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 + signing_options: serde_json::Value, }, /// Signs a message with an Ed25519 private key. 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 + signing_options: serde_json::Value, }, /// Signs a message with an Secp256k1Ecdsa private key. 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 + signing_options: serde_json::Value, }, /// Sign a transaction #[serde(rename_all = "camelCase")] SignTransaction { /// Prepared transaction data - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, protocol_parameters: ProtocolParameters, }, // 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 + signing_options: serde_json::Value, }, /// Store a mnemonic in the Stronghold vault #[cfg(feature = "stronghold")] diff --git a/bindings/core/src/method/utils.rs b/bindings/core/src/method/utils.rs index d667fef73b..4c07470e92 100644 --- a/bindings/core/src/method/utils.rs +++ b/bindings/core/src/method/utils.rs @@ -124,7 +124,7 @@ pub enum UtilsMethod { /// Verifies the semantic of a transaction. VerifyTransactionSemantic { transaction: TransactionDto, - inputs: Vec>, + inputs: Vec>, unlocks: Option>, }, } diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index 42fc4e4ace..c8381598d9 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -4,7 +4,7 @@ #[cfg(feature = "stronghold")] use std::path::PathBuf; -use crypto::{keys::bip44::Bip44, signatures::ed25519::PublicKey}; +use crypto::keys::bip44::Bip44; use derivative::Derivative; #[cfg(feature = "events")] use iota_sdk::wallet::events::types::{WalletEvent, WalletEventType}; @@ -18,7 +18,6 @@ use iota_sdk::{ client::{ api::{input_selection::Burn, PreparedTransactionDataDto, SignedTransactionDataDto}, node_manager::node::NodeAuth, - secret::GenerateAddressOptions, }, types::block::{ address::{Bech32Address, Hrp}, @@ -200,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) @@ -391,19 +390,19 @@ pub enum WalletMethod { /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) #[serde(rename_all = "camelCase")] SignAndSubmitTransaction { - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, }, /// Sign a prepared transaction. /// Expected response: [`SignedTransactionData`](crate::Response::SignedTransactionData) #[serde(rename_all = "camelCase")] SignTransaction { - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, }, /// Validate the transaction, submit it to a node and store it in the wallet. /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) #[serde(rename_all = "camelCase")] SubmitAndStoreTransaction { - signed_transaction_data: SignedTransactionDataDto, + signed_transaction_data: SignedTransactionDataDto, }, /// Sync the wallet by fetching new information from the nodes. Will also reissue pending transactions /// if necessary. A custom default can be set using SetDefaultSyncOptions. @@ -424,22 +423,9 @@ pub enum WalletMethod { /// Expected response: [`Ok`](crate::Response::Ok) #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] - EmitTestEvent { event: WalletEvent }, + 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..0b20b5789b 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -5,10 +5,7 @@ use std::pin::Pin; use futures::Future; use iota_sdk::{ - client::{ - secret::{DowncastSecretManager, SecretManage}, - Client, - }, + client::{secret::SecretManager, Client}, wallet::Wallet, }; @@ -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 d766194ee1..ab4ae933e4 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; +use crypto::signatures::secp256k1_ecdsa::EvmAddress; #[cfg(feature = "stronghold")] -use iota_sdk::client::secret::{stronghold::StrongholdSecretManager, SecretManager}; +use iota_sdk::client::secret::SecretManager; use iota_sdk::{ client::{ - api::{GetAddressesOptions, PreparedTransactionData}, - secret::{DowncastSecretManager, SecretManage, SignBlock}, + api::PreparedTransactionData, + secret::{types::EvmSignature, BlockSignExt, DowncastSecretManager, Generate, 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,11 +49,7 @@ where } #[cfg(feature = "ledger_nano")] SecretManagerMethod::GetLedgerNanoStatus => { - if let Some(secret_manager) = secret_manager.downcast::() { - Response::LedgerNanoStatus(secret_manager.get_ledger_nano_status().await) - } else { - return Err(iota_sdk::client::Error::SecretManagerMismatch.into()); - } + Response::LedgerNanoStatus(secret_manager.as_ledger_nano()?.get_ledger_nano_status().await) } SecretManagerMethod::SignTransaction { prepared_transaction_data, @@ -86,35 +64,44 @@ where .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 { @@ -125,15 +112,8 @@ 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 } }; Ok(response) diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index 3b088222e0..a9b9617ea2 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -5,17 +5,23 @@ use std::time::Duration; use crypto::signatures::ed25519::PublicKey; use iota_sdk::{ - client::api::{ - PreparedTransactionData, PreparedTransactionDataDto, SignedTransactionData, SignedTransactionDataDto, + client::{ + api::{PreparedTransactionData, PreparedTransactionDataDto, SignedTransactionData, SignedTransactionDataDto}, + secret::{DowncastSecretManager, SecretManager}, + }, + types::TryFromDto, + wallet::{ + types::TransactionWithMetadataDto, BlockIssuerKeySource, PreparedCreateNativeTokenTransactionDto, Wallet, }, - types::{block::address::ToBech32Ext, TryFromDto}, - wallet::{types::TransactionWithMetadataDto, PreparedCreateNativeTokenTransactionDto, 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")] @@ -66,26 +72,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.get_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?; @@ -208,18 +200,20 @@ 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, Some(public_key)) - .await? - } else { - wallet.prepare_implicit_account_transition(&output_id, bip_path).await? - }; - Response::PreparedTransaction(PreparedTransactionDataDto::from(&data)) + let source = public_key + .map(|s| { + crate::Result::Ok(BlockIssuerKeySource::Key( + PublicKey::try_from_bytes(prefix_hex::decode(s)?).map_err(iota_sdk::wallet::Error::from)?, + )) + }) + .transpose()? + .or(public_key_options.map(BlockIssuerKeySource::Options)); + + Response::PreparedTransaction(PreparedTransactionDataDto::from( + &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/src/response.rs b/bindings/core/src/response.rs index 5fc5938060..f8b23d2e99 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -270,11 +270,11 @@ pub enum Response { OutputIds(Vec), /// Response for: /// - [`GetOutput`](crate::method::WalletMethod::GetOutput) - OutputData(Option>), + OutputData(Option>>), /// Response for: /// - [`Outputs`](crate::method::WalletMethod::Outputs), /// - [`UnspentOutputs`](crate::method::WalletMethod::UnspentOutputs) - OutputsData(Vec), + OutputsData(Vec>), /// Response for: /// - [`PrepareBurn`](crate::method::WalletMethod::PrepareBurn), /// - [`PrepareClaimOutputs`](crate::method::WalletMethod::PrepareClaimOutputs) @@ -292,10 +292,10 @@ pub enum Response { /// - [`PrepareTransaction`](crate::method::WalletMethod::PrepareTransaction) /// - [`PrepareVote`](crate::method::WalletMethod::PrepareVote) /// - [`PrepareImplicitAccountTransition`](crate::method::WalletMethod::PrepareImplicitAccountTransition) - PreparedTransaction(PreparedTransactionDataDto), + PreparedTransaction(PreparedTransactionDataDto), /// Response for: /// - [`PrepareCreateNativeToken`](crate::method::WalletMethod::PrepareCreateNativeToken), - PreparedCreateNativeTokenTransaction(PreparedCreateNativeTokenTransactionDto), + PreparedCreateNativeTokenTransaction(PreparedCreateNativeTokenTransactionDto), /// Response for: /// - [`GetIncomingTransaction`](crate::method::WalletMethod::GetIncomingTransaction) /// - [`GetTransaction`](crate::method::WalletMethod::GetTransaction), @@ -307,7 +307,7 @@ pub enum Response { Transactions(Vec), /// Response for: /// - [`SignTransaction`](crate::method::WalletMethod::SignTransaction) - SignedTransactionData(SignedTransactionDataDto), + SignedTransactionData(SignedTransactionDataDto), /// Response for: /// - [`GetBalance`](crate::method::WalletMethod::GetBalance), /// - [`Sync`](crate::method::WalletMethod::Sync) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 2f7a1f7e0e..d52d8d13f4 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_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 31ab12e43e..e374499ec4 100644 --- a/bindings/core/tests/serialize_error.rs +++ b/bindings/core/tests/serialize_error.rs @@ -1,37 +1,50 @@ // 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; use pretty_assertions::assert_eq; +use serde_json::json; #[test] fn custom_error_serialization() { // testing a unit-type-like error let error = Error::Client(ClientError::HealthyNodePoolEmpty); assert_eq!( - serde_json::to_string(&error).unwrap(), - "{\"type\":\"client\",\"error\":\"no healthy node available\"}" + serde_json::to_value(&error).unwrap(), + json!({ + "type": "wallet", + "error:": "no healthy node available" + }) ); // testing a tuple-like error let error = Error::Wallet(WalletError::InvalidMnemonic("nilly willy".to_string())); assert_eq!( - serde_json::to_string(&error).unwrap(), - "{\"type\":\"wallet\",\"error\":\"invalid mnemonic: nilly willy\"}" + serde_json::to_value(&error).unwrap(), + json!({ + "type": "wallet", + "error:": "invalid mnemonic: nilly willy" + }) ); // testing a struct-like error let error = Error::Wallet(WalletError::PublicKeyOptionsMismatch { - old: None, - new: Some(Bip44::new(SHIMMER_COIN_TYPE)), + 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_string(&error).unwrap(), - "{\"type\":\"wallet\",\"error\":\"BIP44 mismatch: Some(Bip44 { coin_type: 4219, account: 0, change: 0, address_index: 0 }), existing bip path is: None\"}" + serde_json::to_value(&error).unwrap(), + json!({ + "type": "wallet", + "error:": "public key options mismatch, new: PublicKeyOptions { coin_type: 4218, account: 0, change: 0, address_index: 0 }, previous: PublicKeyOptions { coin_type: 4219, account: 0, change: 0, address_index: 0 }" + }) ); } diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 140c9ca306..182854e900 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/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::WalletEventType, Wallet}, + iota_sdk::{ + client::secret::SecretManager, + wallet::{events::WalletEventType, Wallet}, + }, Response, WalletMethod, WalletOptions, }; use napi::{bindgen_prelude::External, threadsafe_function::ThreadsafeFunction, Error, Result, Status}; @@ -14,7 +17,7 @@ use tokio::sync::RwLock; use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHandler, NodejsError}; -pub type WalletMethodHandler = Arc>>; +pub type WalletMethodHandler = Arc>>>; #[napi(js_name = "createWallet")] pub async fn create_wallet(options: String) -> Result> { diff --git a/bindings/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index 425b5f3fd2..e5b163cb53 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -5,9 +5,12 @@ 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::{ + events::types::{WalletEvent, WalletEventType}, + Wallet, + }, }, Response, WalletMethod, WalletOptions, }; @@ -22,7 +25,7 @@ use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHand /// The Wallet method handler. #[wasm_bindgen(js_name = WalletMethodHandler)] pub struct WalletMethodHandler { - wallet: Arc>>, + wallet: Arc>>>, } /// Creates a method handler with the given options. @@ -111,7 +114,10 @@ pub async fn listen_wallet( event_types.push(wallet_event_type); } - let (tx, mut rx): (UnboundedSender, UnboundedReceiver) = unbounded_channel(); + let (tx, mut rx): ( + UnboundedSender>, + UnboundedReceiver>, + ) = unbounded_channel(); method_handler .wallet .lock() diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 28a39204d7..c9d6b3ca99 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -7,13 +7,13 @@ use clap::{builder::BoolishValueParser, Args, CommandFactory, Parser, Subcommand use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions}, stronghold::StrongholdAdapter, utils::Password, }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::{ClientOptions, Wallet}, + wallet::ClientOptions, }; use log::LevelFilter; @@ -23,7 +23,7 @@ use crate::{ check_file_exists, enter_or_generate_mnemonic, generate_mnemonic, get_alias, get_decision, get_password, import_mnemonic, }, - println_log_error, println_log_info, + println_log_error, println_log_info, Wallet, }; const DEFAULT_LOG_LEVEL: &str = "debug"; @@ -272,7 +272,6 @@ pub async fn init_command( .password(password) .build(snapshot_path)?; secret_manager.store_mnemonic(mnemonic).await?; - let secret_manager = SecretManager::Stronghold(secret_manager); let alias = if get_decision("Do you want to assign an alias to your wallet?")? { Some(get_alias("New wallet alias").await?) @@ -285,11 +284,19 @@ pub async fn init_command( .map(|addr| Bech32Address::from_str(&addr)) .transpose()?; + let public_key_options = init_params.bip_path.map(|bip| { + PublicKeyOptions::new(bip.coin_type) + .with_account_index(bip.account) + .with_internal(bip.change != 0) + .with_address_index(bip.address_index) + }); + Ok(Wallet::builder() .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_public_key_options(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() @@ -332,11 +339,9 @@ pub async fn restore_command(storage_path: &Path, snapshot_path: &Path, backup_p snapshot_path.to_str().unwrap() ); let password = get_password("Stronghold password", false)?; - let secret_manager = SecretManager::Stronghold( - StrongholdSecretManager::builder() - .password(password) - .build(snapshot_path)?, - ); + let secret_manager = StrongholdSecretManager::builder() + .password(password) + .build(snapshot_path)?; builder = builder.with_secret_manager(secret_manager); } @@ -345,7 +350,8 @@ pub async fn restore_command(storage_path: &Path, snapshot_path: &Path, backup_p .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_public_key_options(Bip44::new(SHIMMER_COIN_TYPE)) + .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .with_signing_options(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; @@ -385,11 +391,11 @@ pub async fn unlock_wallet( ) -> Result { let secret_manager = if let Some(password) = password.into() { let snapshot_path = snapshot_path.into(); - Some(SecretManager::Stronghold( + Some( StrongholdSecretManager::builder() .password(password) .build(snapshot_path.ok_or(Error::Miscellaneous("Snapshot file path is not given".to_string()))?)?, - )) + ) } else { None }; diff --git a/cli/src/main.rs b/cli/src/main.rs index 5c7c29449c..d8e4d83401 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -8,6 +8,7 @@ mod wallet_cli; use clap::Parser; use fern_logger::{LoggerConfigBuilder, LoggerOutputConfigBuilder}; +use iota_sdk::client::secret::stronghold::StrongholdSecretManager; use log::LevelFilter; use self::{ @@ -15,6 +16,8 @@ use self::{ error::Error, }; +pub type Wallet = iota_sdk::wallet::Wallet; + #[macro_export] macro_rules! println_log_info { ($($arg:tt)+) => { diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index e2b3b523a9..a7078b9210 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -9,7 +9,7 @@ use clap::{CommandFactory, Parser, Subcommand}; use colored::Colorize; use iota_sdk::{ client::request_funds_from_faucet, - crypto::signatures::ed25519::PublicKey, + crypto::{keys::bip44::Bip44, signatures::ed25519::PublicKey}, types::{ api::plugins::participation::types::ParticipationEventId, block::{ @@ -24,8 +24,8 @@ use iota_sdk::{ }, utils::ConvertTo, wallet::{ - types::OutputData, ConsolidationParams, CreateNativeTokenParams, MintNftParams, OutputsToClaim, - SendNativeTokenParams, SendNftParams, SendParams, SyncOptions, TransactionOptions, Wallet, + types::OutputData, BlockIssuerKeySource, ConsolidationParams, CreateNativeTokenParams, MintNftParams, + OutputsToClaim, SendNativeTokenParams, SendNftParams, SendParams, SyncOptions, TransactionOptions, }, U256, }; @@ -35,7 +35,7 @@ use self::completer::WalletCommandHelper; use crate::{ error::Error, helper::{bytes_from_hex_or_file, to_utc_date_time}, - println_log_error, println_log_info, + println_log_error, println_log_info, Wallet, }; #[derive(Debug, Parser)] @@ -595,7 +595,8 @@ pub async fn implicit_account_transition_command( PublicKey::try_from_bytes(prefix_hex::decode(s).map_err(|e| Error::Miscellaneous(e.to_string()))?) .map_err(|e| Error::Miscellaneous(e.to_string())) }) - .transpose()?; + .transpose()? + .map(BlockIssuerKeySource::Key); let transaction = wallet.implicit_account_transition(&output_id, public_key).await?; println_log_info!( @@ -1015,7 +1016,7 @@ async fn print_wallet_address(wallet: &Wallet) -> Result<(), Error> { } } - let bip_path = wallet.public_key_options().await; + let bip_path = wallet.data().await.signing_options().clone(); log = format!("{log}\nBIP path: {bip_path:?}"); log = format!( @@ -1235,7 +1236,7 @@ pub async fn prompt_internal( Ok(PromptResponse::Reprompt) } -fn print_outputs(mut outputs: Vec, title: &str) -> Result<(), Error> { +fn print_outputs(mut outputs: Vec>, title: &str) -> Result<(), Error> { if outputs.is_empty() { println_log_info!("No outputs found"); } else { diff --git a/sdk/examples/client/01_generate_addresses.rs b/sdk/examples/client/01_generate_addresses.rs index f4295576a6..53c90d67d3 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 04019f6735..9653f39571 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 4958adf17b..53f2e9f039 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 ca3c644c35..1d090b14ce 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 4eca20cc59..c48a6ee1ab 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 a57f83e564..98892b9a47 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 0ff222b84e..3dafc0fd5b 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 63032331fc..e5951b3814 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 9bec68322e..0b5f82c2fd 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, @@ -37,13 +37,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 3e3e5fc365..cfa165b894 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, SecretManager}, Client, Result, }, types::block::output::AccountId, @@ -37,13 +37,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 06b5233ef7..b6f7b1c455 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] @@ -43,23 +48,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 6bdd1a2776..74d3a29b5a 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] @@ -28,27 +28,22 @@ async fn main() -> Result<()> { std::env::var(var).unwrap_or_else(|_| panic!(".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/implicit_account_creation.rs b/sdk/examples/how_tos/account/implicit_account_creation.rs index f639e611ff..e14ed9fb92 100644 --- a/sdk/examples/how_tos/account/implicit_account_creation.rs +++ b/sdk/examples/how_tos/account/implicit_account_creation.rs @@ -9,7 +9,10 @@ //! ``` use iota_sdk::{ - client::{constants::SHIMMER_COIN_TYPE, secret::SecretManager}, + client::{ + constants::SHIMMER_COIN_TYPE, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManager}, + }, crypto::keys::bip44::Bip44, wallet::{ClientOptions, Result, Wallet}, }; @@ -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() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_storage_path("implicit_account_creation") - .with_public_key_options(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/accounts_and_addresses/create_wallet.rs b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs index 3488d92c7a..2c719e6ee3 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs @@ -13,7 +13,7 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, SecretManager}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManager}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, wallet::{ClientOptions, Result, Wallet}, @@ -49,10 +49,11 @@ async fn main() -> Result<()> { // Create the wallet let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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/sign_and_verify_ed25519/sign_ed25519.rs b/sdk/examples/how_tos/sign_and_verify_ed25519/sign_ed25519.rs index 9304b224ab..fa75273899 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, SecretManage, SecretManageExt, SecretManager}, }, 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().as_ref()), diff --git a/sdk/examples/wallet/background_syncing.rs b/sdk/examples/wallet/background_syncing.rs index ac70c6f49c..4abf8f1aac 100644 --- a/sdk/examples/wallet/background_syncing.rs +++ b/sdk/examples/wallet/background_syncing.rs @@ -10,9 +10,9 @@ 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}, @@ -31,10 +31,11 @@ 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 wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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 d992294093..ed0435e274 100644 --- a/sdk/examples/wallet/events.rs +++ b/sdk/examples/wallet/events.rs @@ -11,8 +11,8 @@ 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::{ @@ -41,10 +41,11 @@ 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)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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 4487ed958a..7f4b5cc154 100644 --- a/sdk/examples/wallet/getting_started.rs +++ b/sdk/examples/wallet/getting_started.rs @@ -10,8 +10,8 @@ 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}, @@ -37,10 +37,11 @@ async fn main() -> Result<()> { // Set up and store the wallet. let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + .with_secret_manager(secret_manager) .with_client_options(client_options) .with_storage_path("getting-started-db") - .with_public_key_options(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 f94440269e..bda465d466 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -16,10 +16,14 @@ 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, + types::block::address::{Ed25519Address, ToBech32Ext}, wallet::{ClientOptions, Result, Wallet}, }; @@ -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 secret_manager = std::sync::Arc::new(LedgerSecretManager::new(true)); let wallet = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + .with_secret_manager(secret_manager.clone()) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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 38ee2028bd..578af986ac 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -10,10 +10,11 @@ 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, + types::block::address::Ed25519Address, wallet::{ClientOptions, Result, Wallet}, }; @@ -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 secret_manager = std::sync::Arc::new(MnemonicSecretManager::try_from_mnemonic( + std::env::var("MNEMONIC").unwrap(), + )?); let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + .with_secret_manager(secret_manager.clone()) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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 b418c551d2..a1d574c747 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -11,7 +11,7 @@ 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}, @@ -44,10 +44,11 @@ async fn main() -> Result<()> { // Create the wallet with the secret_manager and client options let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Stronghold(secret_manager)) + .with_secret_manager(secret_manager) .with_storage_path(OFFLINE_WALLET_DB_PATH) .with_client_options(offline_client) - .with_public_key_options(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 529888c501..48e1643513 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -17,6 +17,7 @@ use iota_sdk::{ crypto::keys::bip44::Bip44, wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet}, }; +use serde::Serialize; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; const ADDRESS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.address.json"; @@ -48,7 +49,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Placeholder) .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) - .with_public_key_options(Bip44::new(SHIMMER_COIN_TYPE)) + // .with_public_key_options(()) .with_address(address) .finish() .await?; @@ -75,7 +76,9 @@ async fn read_address_from_file() -> Result { Ok(serde_json::from_str(&json)?) } -async fn write_transaction_to_file(prepared_transaction: PreparedTransactionData) -> Result<()> { +async fn write_transaction_to_file( + prepared_transaction: PreparedTransactionData, +) -> Result<()> { use tokio::io::AsyncWriteExt; let json = serde_json::to_string_pretty(&PreparedTransactionDataDto::from(&prepared_transaction))?; diff --git a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs index 14b9e0f4b3..442aea0393 100644 --- a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs +++ b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs @@ -11,14 +11,21 @@ use iota_sdk::{ client::{ api::{ - transaction::validate_signed_transaction_payload_length, PreparedTransactionData, - PreparedTransactionDataDto, SignedTransactionData, SignedTransactionDataDto, + transaction::validate_signed_transaction_payload_length, PreparedTransactionData, SignedTransactionData, + SignedTransactionDataDto, }, - secret::{stronghold::StrongholdSecretManager, SecretManage, SecretManager}, + secret::{stronghold::StrongholdSecretManager, SignTransaction}, + }, + types::{ + block::{ + payload::SignedTransactionPayload, + protocol::{protocol_parameters, ProtocolParameters}, + }, + TryFromDto, }, - types::{block::payload::SignedTransactionPayload, TryFromDto}, wallet::Result, }; +use serde::{de::DeserializeOwned, Serialize}; const STRONGHOLD_SNAPSHOT_PATH: &str = "./examples/wallet/offline_signing/example.stronghold"; const PREPARED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.prepared_transaction.json"; @@ -41,9 +48,11 @@ async fn main() -> Result<()> { let prepared_transaction_data = read_prepared_transaction_from_file().await?; + let protocol_parameters = protocol_parameters(); + // Signs prepared transaction offline. - let unlocks = SecretManager::Stronghold(secret_manager) - .transaction_unlocks(&prepared_transaction_data) + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) .await?; let signed_transaction = SignedTransactionPayload::new(prepared_transaction_data.transaction.clone(), unlocks)?; @@ -62,19 +71,19 @@ async fn main() -> Result<()> { Ok(()) } -async fn read_prepared_transaction_from_file() -> Result { +async fn read_prepared_transaction_from_file() -> Result> { use tokio::io::AsyncReadExt; let mut file = tokio::io::BufReader::new(tokio::fs::File::open(PREPARED_TRANSACTION_FILE_PATH).await?); let mut json = String::new(); file.read_to_string(&mut json).await?; - Ok(PreparedTransactionData::try_from_dto(serde_json::from_str::< - PreparedTransactionDataDto, - >(&json)?)?) + Ok(PreparedTransactionData::try_from_dto(serde_json::from_str(&json)?)?) } -async fn write_signed_transaction_to_file(signed_transaction_data: &SignedTransactionData) -> Result<()> { +async fn write_signed_transaction_to_file( + signed_transaction_data: &SignedTransactionData, +) -> Result<()> { use tokio::io::AsyncWriteExt; let dto = SignedTransactionDataDto::from(signed_transaction_data); diff --git a/sdk/examples/wallet/offline_signing/3_send_transaction.rs b/sdk/examples/wallet/offline_signing/3_send_transaction.rs index 9763aec488..3e3675e0bf 100644 --- a/sdk/examples/wallet/offline_signing/3_send_transaction.rs +++ b/sdk/examples/wallet/offline_signing/3_send_transaction.rs @@ -18,6 +18,7 @@ use iota_sdk::{ wallet::Result, Wallet, }; +use serde::de::DeserializeOwned; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; const SIGNED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.signed_transaction.json"; @@ -50,14 +51,16 @@ async fn main() -> Result<()> { Ok(()) } -async fn read_signed_transaction_from_file(client: &Client) -> Result { +async fn read_signed_transaction_from_file( + client: &Client, +) -> Result> { use tokio::io::AsyncReadExt; let mut file = tokio::io::BufReader::new(tokio::fs::File::open(SIGNED_TRANSACTION_FILE_PATH).await?); let mut json = String::new(); file.read_to_string(&mut json).await?; - let dto = serde_json::from_str::(&json)?; + let dto = serde_json::from_str::>(&json)?; Ok(SignedTransactionData::try_from_dto_with_params( dto, diff --git a/sdk/examples/wallet/spammer.rs b/sdk/examples/wallet/spammer.rs index 98e6554544..e497f3af21 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -10,13 +10,13 @@ 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, }, @@ -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)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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 bc4b747733..9cdf963007 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::{types::Bip44Address, ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet}, }; #[tokio::main] @@ -31,10 +31,11 @@ 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)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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 10218ad20b..a5c2973091 100644 --- a/sdk/examples/wallet/wallet.rs +++ b/sdk/examples/wallet/wallet.rs @@ -17,8 +17,8 @@ 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}, @@ -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)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) - .with_public_key_options(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/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 91c175871a..04fb56e061 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -57,7 +57,7 @@ pub struct Selected { pub remainder: Option>, } -impl InputSelection { +impl InputSelection { fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { let required_address = input .output 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 5ceab09e72..ead42f71d0 100644 --- a/sdk/src/client/api/block_builder/input_selection/remainder.rs +++ b/sdk/src/client/api/block_builder/input_selection/remainder.rs @@ -16,7 +16,7 @@ use crate::{ }, }; -impl InputSelection { +impl InputSelection { // Gets the remainder address from configuration of finds one from the inputs. fn get_remainder_address(&self) -> Result)>, Error> { if let Some(remainder_address) = &self.remainder_address { @@ -27,7 +27,7 @@ impl InputSelection { .required_and_unlocked_address(self.slot_index, input.output_id())?; if &required_address == remainder_address { - return Ok(Some((remainder_address.clone(), input.signing_options))); + return Ok(Some((remainder_address.clone(), input.signing_options.clone()))); } } return Ok(Some((remainder_address.clone(), None))); @@ -40,7 +40,7 @@ impl InputSelection { .0; if required_address.is_ed25519() { - return Ok(Some((required_address, input.signing_options))); + return Ok(Some((required_address, input.signing_options.clone()))); } } diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs index c8d96c1086..512323c2d0 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs @@ -41,7 +41,7 @@ pub enum Requirement { Amount, } -impl InputSelection { +impl InputSelection { /// Fulfills a requirement by selecting the appropriate available inputs. /// Returns the selected inputs and an optional new requirement. pub(crate) fn fulfill_requirement(&mut self, requirement: Requirement) -> Result>, Error> { diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index 3173211dae..ffac04f8b6 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -17,12 +17,14 @@ use iota_ledger_nano::{ Packable as LedgerNanoPackable, TransportTypes, }; use packable::{error::UnexpectedEOF, unpacker::SliceUnpacker, Packable, PackableExt}; +use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use crate::{ client::secret::{ types::{LedgerApp, LedgerDeviceType}, - Generate, LedgerNanoStatus, PreparedTransactionData, SecretManagerConfig, Sign, SignTransaction, + Generate, LedgerNanoStatus, MultiKeyOptions, PreparedTransactionData, PublicKeyOptions, SecretManagerConfig, + Sign, SignTransaction, }, types::block::{ address::{AccountAddress, Address, AnchorAddress, Ed25519Address, NftAddress}, @@ -34,6 +36,29 @@ use crate::{ }, }; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct LedgerOptions { + 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] @@ -128,16 +153,46 @@ impl TryFrom for LedgerDeviceType { #[async_trait] impl Generate for LedgerSecretManager { - type Options = (); + 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_index.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) + .map_err(Error::from)?; + } + + let public_key = ed25519::PublicKey::try_from_bytes( + ledger + .get_addresses(*ledger_nano_prompt, bip32, 0) + .map_err(Error::from)?[0], + )?; + + drop(lock); - async fn generate(&self, _options: &Self::Options) -> crate::client::Result { - todo!() + Ok(public_key) } } #[async_trait] impl Generate for LedgerSecretManager { - type Options = (); + type Options = LedgerOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let public_key: ed25519::PublicKey = self.generate(options).await?; @@ -147,16 +202,47 @@ impl Generate for LedgerSecretManager { #[async_trait] impl Generate> for LedgerSecretManager { - type Options = (); + 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) + .map_err(Error::from)?; + } + + let public_keys = ledger + .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); - async fn generate(&self, _options: &Self::Options) -> crate::client::Result> { - todo!() + Ok(public_keys) } } #[async_trait] impl Generate> for LedgerSecretManager { - type Options = (); + type Options = LedgerOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let public_keys: Vec = self.generate(options).await?; @@ -572,10 +658,7 @@ mod tests { use pretty_assertions::assert_eq; use super::*; - use crate::{ - client::{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"] @@ -583,18 +666,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 index 1ef9d528a3..120a03feb0 100644 --- a/sdk/src/client/secret/manager.rs +++ b/sdk/src/client/secret/manager.rs @@ -71,7 +71,10 @@ impl Generate for SecretManager { Ok(s.generate(&options).await?) } #[cfg(feature = "ledger_nano")] - SecretManager::LedgerNano(l) => Ok(l.generate(&()).await?), + 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?) @@ -106,7 +109,11 @@ impl Generate> for SecretManager { Ok(s.generate(&options).await?) } #[cfg(feature = "ledger_nano")] - SecretManager::LedgerNano(l) => Ok(l.generate(&()).await?), + SecretManager::LedgerNano(l) => { + let options = + >>::Options::deserialize(options)?; + Ok(l.generate(&options).await?) + } SecretManager::Mnemonic(m) => { let options = >>::Options::deserialize(options)?; diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index ddea91916e..2289f9f497 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -16,7 +16,8 @@ use zeroize::Zeroizing; use crate::{ client::{ secret::{ - types::EvmSignature, Generate, GenerateMultiKeyOptions, GeneratePublicKeyOptions, Sign, SignTransaction, + types::EvmSignature, Generate, MultiKeyOptions, PublicKeyOptions, SecretManagerConfig, Sign, + SignTransaction, }, Client, Error, }, @@ -36,7 +37,7 @@ impl std::fmt::Debug for MnemonicSecretManager { #[async_trait] impl Generate for MnemonicSecretManager { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let chain = Bip44::new(options.coin_type) @@ -54,7 +55,7 @@ impl Generate for MnemonicSecretManager { #[async_trait] impl Generate for MnemonicSecretManager { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let public_key: ed25519::PublicKey = self.generate(options).await?; @@ -64,15 +65,14 @@ impl Generate for MnemonicSecretManager { #[async_trait] impl Generate> for MnemonicSecretManager { - type Options = GenerateMultiKeyOptions; + 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( - &GeneratePublicKeyOptions::default() - .with_coin_type(options.coin_type) + &PublicKeyOptions::new(options.coin_type) .with_account_index(options.account_index) .with_internal(options.internal) .with_address_index(address_index), @@ -86,7 +86,7 @@ impl Generate> for MnemonicSecretManager { #[async_trait] impl Generate> for MnemonicSecretManager { - type Options = GenerateMultiKeyOptions; + type Options = MultiKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let public_keys: Vec = self.generate(options).await?; @@ -99,7 +99,7 @@ impl Generate> for MnemonicSecretManager { #[async_trait] impl Generate for MnemonicSecretManager { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let chain = Bip44::new(options.coin_type) @@ -117,7 +117,7 @@ impl Generate for MnemonicSecretManager { #[async_trait] impl Generate for MnemonicSecretManager { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let public_key: secp256k1_ecdsa::PublicKey = self.generate(options).await?; @@ -127,7 +127,7 @@ impl Generate for MnemonicSecretManager { #[async_trait] impl Generate> for MnemonicSecretManager { - type Options = GenerateMultiKeyOptions; + type Options = MultiKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let mut res = Vec::with_capacity(options.address_range.len()); @@ -135,8 +135,7 @@ impl Generate> for MnemonicSecretManager { res.push( Generate::::generate( self, - &GeneratePublicKeyOptions::default() - .with_coin_type(options.coin_type) + &PublicKeyOptions::new(options.coin_type) .with_account_index(options.account_index) .with_internal(options.internal) .with_address_index(address_index), @@ -150,7 +149,7 @@ impl Generate> for MnemonicSecretManager { #[async_trait] impl Generate> for MnemonicSecretManager { - type Options = GenerateMultiKeyOptions; + type Options = MultiKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let public_keys: Vec = self.generate(options).await?; @@ -205,6 +204,26 @@ impl MnemonicSecretManager { let seed = Seed::from_bytes(bytes.as_ref()); Ok(Self(seed)) } + + /// Generate a random mnemonic to use for the secret manager. + pub fn generate() -> Result { + Self::try_from_mnemonic(Client::generate_mnemonic()?) + } +} + +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)] @@ -221,7 +240,7 @@ 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 options = GeneratePublicKeyOptions::default().with_coin_type(IOTA_COIN_TYPE); + let options = PublicKeyOptions::new(IOTA_COIN_TYPE); let address: Ed25519Address = secret_manager.generate(&options).await.unwrap(); @@ -238,7 +257,7 @@ mod tests { let seed = "0x256a818b2aac458941f7274985a410e57fb750f3a3a67969ece5bd9ae7eef5b2".to_owned(); let secret_manager = MnemonicSecretManager::try_from_hex_seed(seed).unwrap(); - let options = GeneratePublicKeyOptions::default().with_coin_type(IOTA_COIN_TYPE); + let options = PublicKeyOptions::new(IOTA_COIN_TYPE); let address: Ed25519Address = secret_manager.generate(&options).await.unwrap(); diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index ac2024e364..9c832d564b 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -43,7 +43,6 @@ use crate::{ input_selection::Error as InputSelectionError, transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData, }, - constants::IOTA_COIN_TYPE, Error, }, types::block::{ @@ -59,30 +58,24 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct GeneratePublicKeyOptions { +#[serde(rename_all = "camelCase")] +pub struct PublicKeyOptions { pub coin_type: u32, pub account_index: u32, pub internal: bool, pub address_index: u32, } -impl Default for GeneratePublicKeyOptions { - fn default() -> Self { +impl PublicKeyOptions { + /// Create a new public key generation options + pub fn new(coin_type: u32) -> Self { Self { - coin_type: IOTA_COIN_TYPE, + coin_type, account_index: 0, internal: false, address_index: 0, } } -} - -impl GeneratePublicKeyOptions { - /// 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 { @@ -96,17 +89,16 @@ impl GeneratePublicKeyOptions { self } - /// Set internal flag. + /// Set the address index. pub fn with_address_index(mut self, address_index: u32) -> Self { self.address_index = address_index; self } } -impl From for GeneratePublicKeyOptions { +impl From for PublicKeyOptions { fn from(value: Bip44) -> Self { - Self::default() - .with_coin_type(value.coin_type) + Self::new(value.coin_type) .with_account_index(value.account) .with_internal(value.change != 0) .with_address_index(value.address_index) @@ -114,30 +106,24 @@ impl From for GeneratePublicKeyOptions { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct GenerateMultiKeyOptions { +#[serde(rename_all = "camelCase")] +pub struct MultiKeyOptions { pub coin_type: u32, pub account_index: u32, pub internal: bool, pub address_range: Range, } -impl Default for GenerateMultiKeyOptions { - fn default() -> Self { +impl MultiKeyOptions { + /// Create a new multikey generation options + pub fn new(coin_type: u32) -> Self { Self { - coin_type: IOTA_COIN_TYPE, + coin_type, account_index: 0, internal: false, address_range: 0..1, } } -} - -impl GenerateMultiKeyOptions { - /// 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 { @@ -151,7 +137,7 @@ impl GenerateMultiKeyOptions { self } - /// Set range to the builder + /// Set the address index range pub fn with_address_range(mut self, range: Range) -> Self { self.address_range = range; self @@ -179,20 +165,6 @@ 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; - - /// Signs `signing_hash` using the given `options`, returning a [`SignatureUnlock`]. - async fn signature_unlock( - &self, - signing_hash: &[u8; 32], - options: &Self::Options, - ) -> crate::client::Result - where - Signature: From, - { - Ok(SignatureUnlock::new(Signature::from( - self.sign(signing_hash, options).await?, - ))) - } } #[async_trait] @@ -215,6 +187,17 @@ impl> SignBlock for T {} #[async_trait] pub trait SignTransaction: Sign { + /// Signs `transaction_signing_hash` using the given `options`, returning a [`SignatureUnlock`]. + async fn signature_unlock( + &self, + 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, @@ -336,6 +319,24 @@ impl + SignTransaction + SignBlock> SecretManage type SigningOptions = >::Options; } +#[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 + Debug + Send + Sync; @@ -346,6 +347,18 @@ pub trait SecretManagerConfig: SecretManage { Self: Sized; } +impl SecretManagerConfig for Arc { + type Config = T::Config; + + fn to_config(&self) -> Option { + self.as_ref().to_config() + } + + fn from_config(config: &Self::Config) -> crate::client::Result { + Ok(Arc::new(T::from_config(config)?)) + } +} + pub trait DowncastSecretManager { fn is(&self) -> bool; @@ -498,7 +511,7 @@ impl DowncastSecretManager for S { } } -pub trait AsAny: 'static + Send + Sync { +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); } diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index bbdf28c9be..cc6445f3ce 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -30,7 +30,7 @@ use crate::{ client::{ secret::{ types::{EvmSignature, StrongholdDto}, - Generate, GenerateMultiKeyOptions, GeneratePublicKeyOptions, SecretManagerConfig, Sign, SignTransaction, + Generate, MultiKeyOptions, PublicKeyOptions, SecretManagerConfig, Sign, SignTransaction, }, stronghold::Error, }, @@ -39,7 +39,7 @@ use crate::{ #[async_trait] impl Generate for StrongholdAdapter { - type Options = GeneratePublicKeyOptions; + 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 @@ -94,7 +94,7 @@ impl Generate for StrongholdAdapter { #[async_trait] impl Generate for StrongholdAdapter { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let public_key: ed25519::PublicKey = self.generate(options).await?; @@ -104,7 +104,7 @@ impl Generate for StrongholdAdapter { #[async_trait] impl Generate> for StrongholdAdapter { - type Options = GenerateMultiKeyOptions; + 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 @@ -168,7 +168,7 @@ impl Generate> for StrongholdAdapter { #[async_trait] impl Generate> for StrongholdAdapter { - type Options = GenerateMultiKeyOptions; + type Options = MultiKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let public_keys: Vec = self.generate(options).await?; @@ -181,7 +181,7 @@ impl Generate> for StrongholdAdapter { #[async_trait] impl Generate for StrongholdAdapter { - type Options = GeneratePublicKeyOptions; + 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 @@ -236,7 +236,7 @@ impl Generate for StrongholdAdapter { #[async_trait] impl Generate for StrongholdAdapter { - type Options = GeneratePublicKeyOptions; + type Options = PublicKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result { let public_key: secp256k1_ecdsa::PublicKey = self.generate(options).await?; @@ -246,7 +246,7 @@ impl Generate for StrongholdAdapter { #[async_trait] impl Generate> for StrongholdAdapter { - type Options = GenerateMultiKeyOptions; + 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 @@ -310,7 +310,7 @@ impl Generate> for StrongholdAdapter { #[async_trait] impl Generate> for StrongholdAdapter { - type Options = GenerateMultiKeyOptions; + type Options = MultiKeyOptions; async fn generate(&self, options: &Self::Options) -> crate::client::Result> { let public_keys: Vec = self.generate(options).await?; @@ -653,13 +653,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" ); @@ -685,13 +684,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" ); @@ -721,8 +719,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() ); @@ -730,13 +727,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/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 8536926d36..c9b3ef6d48 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -8,7 +8,6 @@ use std::sync::{atomic::AtomicUsize, 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,7 +15,7 @@ use crate::wallet::storage::adapter::memory::Memory; #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::secret::{SecretManage, SecretManager}, + client::secret::{SecretManage, SecretManager, SecretManagerConfig}, types::block::address::{Bech32Address, Ed25519Address, ToBech32Ext}, wallet::{ core::{WalletData, WalletInner}, @@ -28,7 +27,7 @@ use crate::{ /// Builder for the wallet. #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] -pub struct WalletBuilder { +pub struct WalletBuilder { pub(crate) public_key_options: Option, pub(crate) signing_options: Option, pub(crate) address: Option, @@ -127,9 +126,8 @@ impl WalletBuilder { } } -impl WalletBuilder +impl WalletBuilder where - Self: SaveLoadWallet, for<'a> &'a S::GenerationOptions: PartialEq, { /// Builds the wallet. diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 22659c21ee..90b015acd2 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -9,10 +9,7 @@ use std::{ sync::{atomic::AtomicUsize, Arc}, }; -use crypto::keys::{ - bip39::{Mnemonic, MnemonicRef}, - bip44::Bip44, -}; +use crypto::keys::bip39::{Mnemonic, MnemonicRef}; use serde::{Deserialize, Serialize}; use tokio::sync::{Mutex, RwLock}; @@ -44,7 +41,7 @@ use crate::{ /// The stateful wallet used to interact with an IOTA network. #[derive(Debug)] -pub struct Wallet { +pub struct Wallet { pub(crate) inner: Arc>, pub(crate) data: Arc>>, } @@ -75,7 +72,7 @@ impl Wallet { /// 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 @@ -84,7 +81,6 @@ pub struct WalletInner { // 0 = not running, 1 = running, 2 = stopping pub(crate) background_syncing_status: AtomicUsize, pub(crate) client: Client, - // TODO: make this optional? pub(crate) secret_manager: Arc>, #[cfg(feature = "events")] pub(crate) event_emitter: tokio::sync::RwLock>, @@ -95,7 +91,6 @@ pub struct WalletInner { } /// Wallet data. -#[derive(Clone, Debug, Eq, PartialEq)] pub struct WalletData { /// The public key generation options. pub(crate) public_key_options: S::GenerationOptions, @@ -236,6 +231,16 @@ impl WalletData { }) } + /// Returns the public key options. + pub fn public_key_options(&self) -> &S::GenerationOptions { + &self.public_key_options + } + + /// Returns the signing options. + pub fn signing_options(&self) -> &S::SigningOptions { + &self.signing_options + } + /// Returns outputs map of the wallet. pub fn outputs(&self) -> &HashMap> { &self.outputs @@ -352,6 +357,63 @@ impl WalletData { } } +impl PartialEq for WalletData { + fn eq(&self, other: &Self) -> bool { + self.public_key_options == other.public_key_options + && self.signing_options == other.signing_options + && self.address == other.address + && self.alias == other.alias + && self.outputs == other.outputs + && self.locked_outputs == other.locked_outputs + && self.unspent_outputs == other.unspent_outputs + && self.transactions == other.transactions + && self.pending_transactions == other.pending_transactions + && self.incoming_transactions == other.incoming_transactions + && self.inaccessible_incoming_transactions == other.inaccessible_incoming_transactions + && self.native_token_foundries == other.native_token_foundries + } +} +impl Eq for WalletData {} +impl core::fmt::Debug for WalletData { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("WalletData") + .field("public_key_options", &self.public_key_options) + .field("signing_options", &self.signing_options) + .field("address", &self.address) + .field("alias", &self.alias) + .field("outputs", &self.outputs) + .field("locked_outputs", &self.locked_outputs) + .field("unspent_outputs", &self.unspent_outputs) + .field("transactions", &self.transactions) + .field("pending_transactions", &self.pending_transactions) + .field("incoming_transactions", &self.incoming_transactions) + .field( + "inaccessible_incoming_transactions", + &self.inaccessible_incoming_transactions, + ) + .field("native_token_foundries", &self.native_token_foundries) + .finish() + } +} +impl Clone for WalletData { + fn clone(&self) -> Self { + Self { + public_key_options: self.public_key_options.clone(), + signing_options: self.signing_options.clone(), + address: self.address.clone(), + alias: self.alias.clone(), + outputs: self.outputs.clone(), + locked_outputs: self.locked_outputs.clone(), + unspent_outputs: self.unspent_outputs.clone(), + transactions: self.transactions.clone(), + pending_transactions: self.pending_transactions.clone(), + incoming_transactions: self.incoming_transactions.clone(), + inaccessible_incoming_transactions: self.inaccessible_incoming_transactions.clone(), + native_token_foundries: self.native_token_foundries.clone(), + } + } +} + impl Wallet { /// Create a new wallet. pub(crate) async fn new(inner: Arc>, data: WalletData) -> Result { @@ -608,11 +670,12 @@ where mod test { use core::str::FromStr; + use crypto::keys::bip44::Bip44; use pretty_assertions::assert_eq; use super::*; use crate::{ - client::secret::GeneratePublicKeyOptions, + client::secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, types::block::{ address::{Address, Ed25519Address}, input::{Input, UtxoInput}, @@ -696,7 +759,7 @@ mod test { ); let wallet_data = WalletData { - public_key_options: GeneratePublicKeyOptions::default().with_coin_type(4218), + public_key_options: PublicKeyOptions::new(4218), signing_options: Bip44::new(4218), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", @@ -713,16 +776,18 @@ mod test { native_token_foundries: HashMap::new(), }; - let deser_wallet_data = WalletData::try_from_dto( - serde_json::from_str::(&serde_json::to_string(&WalletDataDto::from(&wallet_data)).unwrap()) - .unwrap(), + let deser_wallet_data = WalletData::::try_from_dto( + serde_json::from_str::>( + &serde_json::to_string(&WalletDataDto::from(&wallet_data)).unwrap(), + ) + .unwrap(), ) .unwrap(); assert_eq!(wallet_data, deser_wallet_data); } - impl WalletData { + impl> WalletData { /// Returns a mock of this type with the following values: /// index: 0, coin_type: 4218, alias: "Alice", address: /// rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy, all other fields are set to their Rust @@ -730,7 +795,7 @@ mod test { #[cfg(feature = "storage")] pub(crate) fn mock() -> Self { Self { - public_key_options: GeneratePublicKeyOptions::default().with_coin_type(4218), + public_key_options: PublicKeyOptions::new(4218), signing_options: Bip44::new(4218), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", diff --git a/sdk/src/wallet/core/operations/client.rs b/sdk/src/wallet/core/operations/client.rs index 218fa3b593..e193b774fa 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -5,14 +5,13 @@ use std::collections::{HashMap, HashSet}; use url::Url; -use super::storage::SaveLoadWallet; use crate::{ client::{ node_manager::{ builder::NodeManagerBuilder, node::{Node, NodeAuth, NodeDto}, }, - secret::SecretManage, + secret::{SecretManage, SecretManagerConfig}, Client, ClientBuilder, }, wallet::{Wallet, WalletBuilder}, @@ -28,10 +27,7 @@ impl Wallet { } } -impl Wallet -where - WalletBuilder: SaveLoadWallet, -{ +impl Wallet { pub async fn set_client_options(&self, client_options: ClientBuilder) -> crate::wallet::Result<()> { let ClientBuilder { node_manager_builder, 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 3d1bc28afe..dad5e85b7f 100644 --- a/sdk/src/wallet/core/operations/storage.rs +++ b/sdk/src/wallet/core/operations/storage.rs @@ -1,97 +1,51 @@ // 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, SecretManage, 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; - } - - #[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?; - - 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:?}"); - - Ok(Some(Self::from(wallet_builder_dto).with_secret_manager( - secret_manager_dto.map(|dto| S::from_config(&dto)).transpose()?, - ))) - } else { - Ok(None) +use crate::{ + client::{secret::SecretManagerConfig, storage::StorageAdapter}, + wallet::{ + core::builder::dto::WalletBuilderDto, + storage::constants::{SECRET_MANAGER_KEY, 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?; + + 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_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::::GenerationOptions, - ::SigningOptions, - >>(WALLET_BUILDER_KEY) - .await?; - log::debug!("[load] wallet builder: {res:?}"); - Ok(res.map(Into::into)) + pub(crate) 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:?}"); + + Ok(Some(Self::from(wallet_builder_dto).with_secret_manager( + secret_manager_dto.map(|dto| S::from_config(&dto)).transpose()?, + ))) + } else { + Ok(None) } } } -#[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..79dd195669 100644 --- a/sdk/src/wallet/core/operations/stronghold.rs +++ b/sdk/src/wallet/core/operations/stronghold.rs @@ -10,7 +10,8 @@ use crate::{ wallet::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(); diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index df1edca544..523935e45c 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -10,10 +10,7 @@ use self::stronghold_snapshot::read_wallet_data_from_stronghold_snapshot; use crate::wallet::WalletBuilder; use crate::{ client::{ - secret::{ - stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManager, SecretManagerConfig, - SecretManagerDto, - }, + secret::{stronghold::StrongholdSecretManager, DowncastSecretManager, SecretManagerConfig}, utils::Password, }, types::block::address::Hrp, @@ -33,7 +30,7 @@ impl Wallet { log::debug!("[backup] creating a stronghold backup"); let secret_manager = self.secret_manager.read().await; - match secret_manager.as_stronghold() { + match (&*secret_manager).as_stronghold() { // Backup with existing stronghold Ok(stronghold) => { stronghold.set_password(stronghold_password).await?; @@ -86,7 +83,7 @@ impl Wallet { let mut secret_manager = self.secret_manager.as_ref().write().await; // Get the current snapshot path if set - let new_snapshot_path = if let Ok(stronghold) = secret_manager.as_stronghold() { + let new_snapshot_path = if let Ok(stronghold) = (&*secret_manager).as_stronghold() { stronghold.snapshot_path.clone() } else { PathBuf::from("wallet.stronghold") @@ -165,7 +162,6 @@ 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_storage_path( 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 7ef5c40ba4..ad9cd80d48 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/stronghold_snapshot.rs @@ -7,7 +7,7 @@ use crate::{ wallet::{ core::{WalletData, WalletDataDto}, migration::{latest_backup_migration_version, migrate, MIGRATION_VERSION_KEY}, - ClientOptions, Error as WalletError, Wallet, + ClientOptions, Wallet, }, }; diff --git a/sdk/src/wallet/events/mod.rs b/sdk/src/wallet/events/mod.rs index 9d75f85f30..f5765a7153 100644 --- a/sdk/src/wallet/events/mod.rs +++ b/sdk/src/wallet/events/mod.rs @@ -122,7 +122,7 @@ mod tests { #[test] fn events() { - let mut emitter = EventEmitter::new(); + let mut emitter = EventEmitter::<()>::new(); let event_counter = Arc::new(AtomicUsize::new(0)); // single event diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 8fbbb3c0b5..0ab4727d0d 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -64,7 +64,7 @@ pub use self::{ send_nft::SendNftParams, }, prepare_output::{Assets, Features, OutputParams, ReturnStrategy, StorageDeposit, Unlocks}, - RemainderValueStrategy, TransactionOptions, + BlockIssuerKeySource, RemainderValueStrategy, TransactionOptions, }, }, types::OutputData, diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index 1279cd519f..a671ddcde9 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -4,7 +4,7 @@ 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::{ @@ -153,7 +153,7 @@ impl Wallet { #[cfg(feature = "ledger_nano")] { let secret_manager = self.secret_manager.read().await; - if secret_manager.as_ledger_nano().is_ok() { + if (&*secret_manager).as_ledger_nano().is_ok() { DEFAULT_LEDGER_OUTPUT_CONSOLIDATION_THRESHOLD } else { DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD @@ -180,7 +180,7 @@ impl Wallet { #[cfg(feature = "ledger_nano")] let max_inputs = { let secret_manager = self.secret_manager.read().await; - if let Ok(ledger) = secret_manager.as_ledger_nano() { + 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() { diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 932fed8fa5..55b599b5b2 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -11,7 +11,10 @@ mod prepare_transaction; mod sign_transaction; pub(crate) mod submit_transaction; -pub use self::options::{RemainderValueStrategy, TransactionOptions}; +pub use self::{ + account::BlockIssuerKeySource, + options::{RemainderValueStrategy, TransactionOptions}, +}; use crate::{ client::{ api::{verify_semantic, PreparedTransactionData, SignedTransactionData}, diff --git a/sdk/src/wallet/storage/manager.rs b/sdk/src/wallet/storage/manager.rs index 155f2da3e4..470f8ce964 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -102,8 +102,8 @@ mod tests { use super::*; use crate::{ - client::secret::SecretManager, - wallet::{core::operations::storage::SaveLoadWallet, storage::adapter::memory::Memory, WalletBuilder}, + client::secret::{mnemonic::MnemonicSecretManager, SecretManager}, + wallet::{storage::adapter::memory::Memory, WalletBuilder}, }; #[tokio::test] @@ -130,12 +130,21 @@ mod tests { #[tokio::test] async fn save_load_wallet_data() { let mut storage_manager = StorageManager::new(Memory::default(), None).await.unwrap(); - assert!(storage_manager.load_wallet_data().await.unwrap().is_none()); + assert!( + storage_manager + .load_wallet_data::() + .await + .unwrap() + .is_none() + ); - let wallet_data = WalletData::mock(); + let wallet_data = WalletData::::mock(); storage_manager.save_wallet_data(&wallet_data).await.unwrap(); - let wallet = storage_manager.load_wallet_data().await.unwrap(); + let wallet = storage_manager + .load_wallet_data::() + .await + .unwrap(); assert!(matches!(wallet, Some(data) if data.alias == Some("Alice".to_string()))); } @@ -143,17 +152,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(); 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 0f5e0e1340..98c7dc9102 100644 --- a/sdk/src/wallet/types/mod.rs +++ b/sdk/src/wallet/types/mod.rs @@ -62,10 +62,10 @@ impl OutputData { self.output.required_and_unlocked_address(slot_index, &self.output_id)?; let chain = if unlock_address == self.address { - self.signing_options + self.signing_options.clone() } else if let Address::Ed25519(_) = unlock_address { if wallet_data.address.inner() == &unlock_address { - Some(wallet_data.signing_options) + Some(wallet_data.signing_options.clone()) } else { return Ok(None); } diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index 33515fe33d..fdd8d8da6d 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)) .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)) .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,32 @@ async fn address_generation() { } #[tokio::test] -async fn search_address() -> Result<()> { +async fn address_search() -> Result<()> { let client = Client::builder().finish().await.unwrap(); - let secret_manager = SecretManager::try_from_mnemonic(generate_mnemonic()?)?; + 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)) .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 +272,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/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 35f01b65f9..a4702de635 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -3,6 +3,7 @@ use std::str::FromStr; +use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ api::input_selection::{Burn, Error, InputSelection, Requirement}, @@ -1234,7 +1235,7 @@ fn changed_immutable_metadata() { .finish_output() .unwrap(); - let inputs = [InputSigningData { + let inputs = [InputSigningData:: { output: nft_output.clone(), output_metadata: rand_output_metadata(), signing_options: None, diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index 7fae73e9c5..ab134ccab9 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -3,6 +3,7 @@ use std::str::FromStr; +use crypto::keys::bip44::Bip44; use iota_sdk::{ client::api::input_selection::{Burn, Error, InputSelection}, types::block::{address::Address, output::AccountId, protocol::protocol_parameters}, @@ -31,7 +32,7 @@ fn no_inputs() { None, )]); - let selected = InputSelection::new( + let selected = InputSelection::::new( inputs, outputs, [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], diff --git a/sdk/tests/client/input_signing_data.rs b/sdk/tests/client/input_signing_data.rs index 872f09c092..11fb0796a4 100644 --- a/sdk/tests/client/input_signing_data.rs +++ b/sdk/tests/client/input_signing_data.rs @@ -29,11 +29,12 @@ fn input_signing_data_conversion() { signing_options: Some(bip44_chain), }; - assert_eq!(input_signing_data.chain.as_ref(), Some(&bip44_chain)); + assert_eq!(input_signing_data.signing_options.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(); + 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)); + assert_eq!(restored_input_signing_data.signing_options.as_ref(), Some(&bip44_chain)); } diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index b3c8463590..f178b58a60 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -208,7 +208,7 @@ fn build_output_inner(build: Build) -> (Output, Option) { } } -fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec> { +fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec> { outputs .into_iter() .map(|build| { diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index 12edd7bf62..434bb3a8eb 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 434c5791ed..30ce4dd47d 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 e88faab90d..08f3107fda 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::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt, SignTransaction}, + Result, }, types::block::{ - address::{AccountAddress, Address}, + address::{AccountAddress, Address, Ed25519Address}, input::{Input, UtxoInput}, output::AccountId, payload::{signed_transaction::Transaction, SignedTransactionPayload}, @@ -34,17 +31,13 @@ use crate::client::{ #[tokio::test] async fn sign_account_state_transition() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = MnemonicSecretManager::generate()?; - 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)?; @@ -77,7 +70,9 @@ async fn sign_account_state_transition() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 1); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); @@ -97,17 +92,13 @@ 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 = MnemonicSecretManager::generate()?; - 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)?; @@ -148,7 +139,9 @@ async fn account_reference_unlocks() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 3); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index 31a60ba833..ea135ea3d8 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,17 +24,13 @@ 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(); @@ -79,7 +73,9 @@ async fn single_ed25519_unlock() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 1); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); @@ -99,17 +95,13 @@ 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(); @@ -174,7 +166,9 @@ async fn ed25519_reference_unlocks() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 3); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); @@ -206,26 +200,18 @@ 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 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 secret_manager = MnemonicSecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + + 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(); @@ -280,7 +266,9 @@ async fn two_signature_unlocks() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 2); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index c5efd789c9..eee9ab1d52 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}, input::{Input, UtxoInput}, output::{AccountId, NftId}, payload::{signed_transaction::Transaction, SignedTransactionPayload}, @@ -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)?; @@ -76,7 +72,7 @@ async fn all_combined() -> Result<()> { Account( 1_000_000, account_id_2, - ed25519_0.clone(), + ed25519_0.into(), None, None, Some(Bip44::new(SHIMMER_COIN_TYPE)), @@ -89,7 +85,7 @@ async fn all_combined() -> Result<()> { Basic(1_000_000, nft_4.clone(), None, None, None, None, None, None), Basic( 1_000_000, - ed25519_0.clone(), + ed25519_0.into(), None, None, None, @@ -99,7 +95,7 @@ async fn all_combined() -> Result<()> { ), Basic( 1_000_000, - ed25519_1.clone(), + ed25519_1.into(), None, None, None, @@ -109,7 +105,7 @@ async fn all_combined() -> Result<()> { ), Basic( 1_000_000, - ed25519_2.clone(), + ed25519_2.into(), None, None, None, @@ -119,7 +115,7 @@ async fn all_combined() -> Result<()> { ), Basic( 1_000_000, - ed25519_2.clone(), + ed25519_2.into(), None, None, None, @@ -130,7 +126,7 @@ async fn all_combined() -> Result<()> { Nft( 1_000_000, nft_id_1, - ed25519_0.clone(), + ed25519_0.into(), None, None, None, @@ -141,7 +137,7 @@ async fn all_combined() -> Result<()> { // Expirations Basic( 2_000_000, - ed25519_0.clone(), + ed25519_0.into(), None, None, None, @@ -151,7 +147,7 @@ async fn all_combined() -> Result<()> { ), Basic( 2_000_000, - ed25519_0.clone(), + ed25519_0.into(), None, None, None, @@ -161,7 +157,7 @@ async fn all_combined() -> Result<()> { ), Basic( 2_000_000, - ed25519_0.clone(), + ed25519_0.into(), None, None, None, @@ -193,12 +189,12 @@ async fn all_combined() -> Result<()> { 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(1_000_000, account_id_2, ed25519_0.into(), None, None, None), + Basic(10_000_000, ed25519_0.into(), None, None, None, None, None, None), + Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None, None), + Nft(1_000_000, nft_id_2, ed25519_0.into(), None, None, None, None, None), + Nft(1_000_000, nft_id_3, ed25519_0.into(), None, None, None, None, None), + Nft(1_000_000, nft_id_4, ed25519_0.into(), None, None, None, None, None), ]); let slot_index = SlotIndex::from(100); @@ -206,7 +202,7 @@ async fn all_combined() -> Result<()> { let selected = InputSelection::new( inputs.clone(), outputs.clone(), - [ed25519_0, ed25519_1, ed25519_2], + [ed25519_0.into(), ed25519_1.into(), ed25519_2.into()], protocol_parameters.clone(), ) .with_slot_index(slot_index) @@ -232,7 +228,9 @@ async fn all_combined() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 15); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index e36ea3c16d..53b184474b 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::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt, SignTransaction}, + Result, }, types::block::{ - address::{Address, NftAddress}, + address::{Address, Ed25519Address, NftAddress}, input::{Input, UtxoInput}, output::NftId, payload::{signed_transaction::Transaction, SignedTransactionPayload}, @@ -34,17 +31,13 @@ use crate::client::{ #[tokio::test] async fn nft_reference_unlocks() -> Result<()> { - let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; + let secret_manager = MnemonicSecretManager::generate()?; - 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)?; @@ -87,7 +80,9 @@ async fn nft_reference_unlocks() -> Result<()> { remainder: None, }; - let unlocks = secret_manager.transaction_unlocks(&prepared_transaction_data).await?; + let unlocks = secret_manager + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .await?; assert_eq!(unlocks.len(), 3); assert_eq!((*unlocks).first().unwrap().kind(), SignatureUnlock::KIND); diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index 9eb85558f2..fcd39b44d7 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}, }; use pretty_assertions::assert_eq; @@ -33,9 +32,10 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { #[allow(unused_mut)] let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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.get_secret_manager().read().await) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await?; assert_eq!( address.to_bech32_unchecked("smr"), @@ -72,16 +74,19 @@ 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)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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.get_secret_manager().read().await) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .await?; assert_eq!( address.to_bech32_unchecked("smr"), @@ -105,9 +110,10 @@ async fn wallet_address_generation_ledger() -> Result<()> { #[allow(unused_mut)] let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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.get_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.get_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"), diff --git a/sdk/tests/wallet/burn_outputs.rs b/sdk/tests/wallet/burn_outputs.rs index 1d2d7330c3..8973700dae 100644 --- a/sdk/tests/wallet/burn_outputs.rs +++ b/sdk/tests/wallet/burn_outputs.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::{ - client::api::input_selection::Burn, + client::{api::input_selection::Burn, secret::SecretManage}, types::block::output::{ unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, NativeToken, NftId, NftOutputBuilder, OutputId, UnlockCondition, @@ -177,7 +177,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()); @@ -200,7 +200,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 ca1de42d69..2748476704 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -8,7 +8,7 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, request_funds_from_faucet, - secret::{mnemonic::MnemonicSecretManager, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, Client, }, wallet::{ClientOptions, Result, Wallet}, @@ -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)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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 14fccdbbc3..c992feb768 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -11,7 +11,7 @@ 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, @@ -89,28 +89,24 @@ async fn changed_bip_path() -> Result<()> { drop(wallet); let err = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic( - mnemonic.clone(), - )?)) - .with_public_key_options(Bip44::new(IOTA_COIN_TYPE)) + .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::PublicKeyOptionsMismatch { - new: Some(Bip44::new(IOTA_COIN_TYPE)), - old: 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_secret_manager(MnemonicSecretManager::try_from_mnemonic(mnemonic,)?) .with_storage_path(storage_path) .finish() .await @@ -147,9 +143,10 @@ async fn iota_coin_type() -> Result<()> { #[allow(unused_mut)] let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + .with_secret_manager(secret_manager) .with_client_options(client_options) - .with_public_key_options(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/events.rs b/sdk/tests/wallet/events.rs index cebd9e17d8..02a027e78f 100644 --- a/sdk/tests/wallet/events.rs +++ b/sdk/tests/wallet/events.rs @@ -27,7 +27,7 @@ use pretty_assertions::assert_eq; const ED25519_ADDRESS: &str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649"; const TRANSACTION_ID: &str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000"; -fn assert_serde_eq(event_0: WalletEvent) { +fn assert_serde_eq(event_0: WalletEvent<()>) { let json = serde_json::to_string(&event_0).unwrap(); let event_1 = serde_json::from_str(&json).unwrap(); 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 3e961159f5..70e2ffedfb 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -5,14 +5,14 @@ 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, + types::block::address::{Ed25519Address, ToBech32Ext}, wallet::{ClientOptions, Error as WalletError, Wallet}, }; 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 @@ -89,7 +84,8 @@ async fn 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_public_key_options(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 From ea20926cf727d0cfe478e3e0e6fcaf75b5b28330 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Thu, 7 Dec 2023 10:42:47 -0500 Subject: [PATCH 03/24] remove generics --- bindings/core/src/method/secret_manager.rs | 4 +- bindings/core/src/method/utils.rs | 2 +- bindings/core/src/method/wallet.rs | 9 +- .../core/src/method_handler/secret_manager.rs | 2 + bindings/core/src/response.rs | 10 +- bindings/wasm/src/wallet.rs | 5 +- cli/src/wallet_cli/mod.rs | 2 +- .../offline_signing/1_prepare_transaction.rs | 4 +- .../offline_signing/2_sign_transaction.rs | 18 ++- .../offline_signing/3_send_transaction.rs | 7 +- .../api/block_builder/input_selection/mod.rs | 28 ++--- .../input_selection/remainder.rs | 15 ++- .../input_selection/requirement/account.rs | 4 +- .../input_selection/requirement/amount.rs | 30 ++--- .../input_selection/requirement/ed25519.rs | 8 +- .../input_selection/requirement/foundry.rs | 4 +- .../input_selection/requirement/issuer.rs | 4 +- .../input_selection/requirement/mod.rs | 4 +- .../requirement/native_tokens.rs | 8 +- .../input_selection/requirement/nft.rs | 4 +- .../input_selection/requirement/sender.rs | 4 +- .../input_selection/transition.rs | 4 +- .../client/api/block_builder/transaction.rs | 4 +- sdk/src/client/api/types.rs | 40 +++---- sdk/src/client/secret/ledger_nano.rs | 29 ++--- sdk/src/client/secret/mod.rs | 10 +- sdk/src/client/secret/types.rs | 5 +- sdk/src/wallet/core/mod.rs | 54 ++++----- sdk/src/wallet/events/mod.rs | 16 +-- sdk/src/wallet/events/types.rs | 61 +++++----- sdk/src/wallet/operations/helpers/time.rs | 4 +- sdk/src/wallet/operations/output_claiming.rs | 8 +- .../wallet/operations/output_consolidation.rs | 7 +- .../wallet/operations/participation/mod.rs | 4 +- .../wallet/operations/participation/voting.rs | 7 +- .../operations/participation/voting_power.rs | 10 +- .../operations/syncing/addresses/outputs.rs | 4 +- sdk/src/wallet/operations/syncing/mod.rs | 8 +- sdk/src/wallet/operations/syncing/outputs.rs | 5 +- .../wallet/operations/transaction/account.rs | 2 +- .../transaction/build_transaction.rs | 6 +- .../burning_melting/melt_native_token.rs | 4 +- .../high_level/burning_melting/mod.rs | 2 +- .../transaction/high_level/create_account.rs | 7 +- .../high_level/minting/create_native_token.rs | 14 +-- .../high_level/minting/mint_native_token.rs | 2 +- .../high_level/minting/mint_nfts.rs | 2 +- .../operations/transaction/high_level/send.rs | 2 +- .../high_level/send_native_tokens.rs | 2 +- .../transaction/high_level/send_nft.rs | 2 +- .../operations/transaction/input_selection.rs | 8 +- sdk/src/wallet/operations/transaction/mod.rs | 6 +- .../operations/transaction/prepare_output.rs | 2 +- .../transaction/prepare_transaction.rs | 2 +- .../transaction/sign_transaction.rs | 10 +- sdk/src/wallet/types/mod.rs | 32 +---- sdk/src/wallet/update.rs | 2 +- .../client/input_selection/account_outputs.rs | 68 ----------- .../client/input_selection/basic_outputs.rs | 106 +--------------- .../client/input_selection/expiration.rs | 46 ------- .../client/input_selection/foundry_outputs.rs | 28 ----- .../client/input_selection/nft_outputs.rs | 57 +-------- sdk/tests/client/input_selection/outputs.rs | 15 +-- .../input_selection/storage_deposit_return.rs | 31 ----- sdk/tests/client/input_selection/timelock.rs | 12 -- sdk/tests/client/input_signing_data.rs | 10 +- sdk/tests/client/mod.rs | 39 +++--- sdk/tests/client/signing/account.rs | 36 ++---- sdk/tests/client/signing/basic.rs | 113 +++--------------- sdk/tests/client/signing/mod.rs | 113 ++++-------------- sdk/tests/client/signing/nft.rs | 23 ++-- sdk/tests/wallet/events.rs | 3 +- 72 files changed, 334 insertions(+), 929 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 57343f9bdc..7e9001ea77 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -57,8 +57,10 @@ pub enum SecretManagerMethod { #[serde(rename_all = "camelCase")] SignTransaction { /// Prepared transaction data - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, protocol_parameters: ProtocolParameters, + /// Options used to sign the transaction + signing_options: serde_json::Value, }, // Sign a block. #[serde(rename_all = "camelCase")] diff --git a/bindings/core/src/method/utils.rs b/bindings/core/src/method/utils.rs index 4c07470e92..be706f9d46 100644 --- a/bindings/core/src/method/utils.rs +++ b/bindings/core/src/method/utils.rs @@ -124,7 +124,7 @@ pub enum UtilsMethod { /// Verifies the semantic of a transaction. VerifyTransactionSemantic { transaction: TransactionDto, - inputs: Vec>, + inputs: Vec, unlocks: Option>, }, } diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index c8381598d9..54718fd730 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; #[cfg(feature = "events")] use iota_sdk::wallet::events::types::{WalletEvent, WalletEventType}; @@ -390,19 +389,19 @@ pub enum WalletMethod { /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) #[serde(rename_all = "camelCase")] SignAndSubmitTransaction { - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, }, /// Sign a prepared transaction. /// Expected response: [`SignedTransactionData`](crate::Response::SignedTransactionData) #[serde(rename_all = "camelCase")] SignTransaction { - prepared_transaction_data: PreparedTransactionDataDto, + prepared_transaction_data: PreparedTransactionDataDto, }, /// Validate the transaction, submit it to a node and store it in the wallet. /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) #[serde(rename_all = "camelCase")] SubmitAndStoreTransaction { - signed_transaction_data: SignedTransactionDataDto, + signed_transaction_data: SignedTransactionDataDto, }, /// Sync the wallet by fetching new information from the nodes. Will also reissue pending transactions /// if necessary. A custom default can be set using SetDefaultSyncOptions. @@ -423,7 +422,7 @@ pub enum WalletMethod { /// Expected response: [`Ok`](crate::Response::Ok) #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] - EmitTestEvent { event: WalletEvent }, + EmitTestEvent { event: WalletEvent }, // TODO: reconsider whether to have the following methods on the wallet /// Get the ledger nano status diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index ab4ae933e4..4d3fe5748b 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -54,11 +54,13 @@ pub(crate) async fn call_secret_manager_method_internal( 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)?; diff --git a/bindings/core/src/response.rs b/bindings/core/src/response.rs index f8b23d2e99..5fc5938060 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -270,11 +270,11 @@ pub enum Response { OutputIds(Vec), /// Response for: /// - [`GetOutput`](crate::method::WalletMethod::GetOutput) - OutputData(Option>>), + OutputData(Option>), /// Response for: /// - [`Outputs`](crate::method::WalletMethod::Outputs), /// - [`UnspentOutputs`](crate::method::WalletMethod::UnspentOutputs) - OutputsData(Vec>), + OutputsData(Vec), /// Response for: /// - [`PrepareBurn`](crate::method::WalletMethod::PrepareBurn), /// - [`PrepareClaimOutputs`](crate::method::WalletMethod::PrepareClaimOutputs) @@ -292,10 +292,10 @@ pub enum Response { /// - [`PrepareTransaction`](crate::method::WalletMethod::PrepareTransaction) /// - [`PrepareVote`](crate::method::WalletMethod::PrepareVote) /// - [`PrepareImplicitAccountTransition`](crate::method::WalletMethod::PrepareImplicitAccountTransition) - PreparedTransaction(PreparedTransactionDataDto), + PreparedTransaction(PreparedTransactionDataDto), /// Response for: /// - [`PrepareCreateNativeToken`](crate::method::WalletMethod::PrepareCreateNativeToken), - PreparedCreateNativeTokenTransaction(PreparedCreateNativeTokenTransactionDto), + PreparedCreateNativeTokenTransaction(PreparedCreateNativeTokenTransactionDto), /// Response for: /// - [`GetIncomingTransaction`](crate::method::WalletMethod::GetIncomingTransaction) /// - [`GetTransaction`](crate::method::WalletMethod::GetTransaction), @@ -307,7 +307,7 @@ pub enum Response { Transactions(Vec), /// Response for: /// - [`SignTransaction`](crate::method::WalletMethod::SignTransaction) - SignedTransactionData(SignedTransactionDataDto), + SignedTransactionData(SignedTransactionDataDto), /// Response for: /// - [`GetBalance`](crate::method::WalletMethod::GetBalance), /// - [`Sync`](crate::method::WalletMethod::Sync) diff --git a/bindings/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index e5b163cb53..ed794d02eb 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -114,10 +114,7 @@ pub async fn listen_wallet( event_types.push(wallet_event_type); } - let (tx, mut rx): ( - UnboundedSender>, - UnboundedReceiver>, - ) = unbounded_channel(); + let (tx, mut rx): (UnboundedSender, UnboundedReceiver) = unbounded_channel(); method_handler .wallet .lock() diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index a7078b9210..5f31a51288 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -1236,7 +1236,7 @@ pub async fn prompt_internal( Ok(PromptResponse::Reprompt) } -fn print_outputs(mut outputs: Vec>, title: &str) -> Result<(), Error> { +fn print_outputs(mut outputs: Vec, title: &str) -> Result<(), Error> { if outputs.is_empty() { println_log_info!("No outputs found"); } else { diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index 48e1643513..7971cc4ee2 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -76,9 +76,7 @@ async fn read_address_from_file() -> Result { Ok(serde_json::from_str(&json)?) } -async fn write_transaction_to_file( - prepared_transaction: PreparedTransactionData, -) -> Result<()> { +async fn write_transaction_to_file(prepared_transaction: PreparedTransactionData) -> Result<()> { use tokio::io::AsyncWriteExt; let json = serde_json::to_string_pretty(&PreparedTransactionDataDto::from(&prepared_transaction))?; diff --git a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs index 442aea0393..aa8db57d84 100644 --- a/sdk/examples/wallet/offline_signing/2_sign_transaction.rs +++ b/sdk/examples/wallet/offline_signing/2_sign_transaction.rs @@ -8,24 +8,22 @@ //! 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, }, + constants::IOTA_COIN_TYPE, secret::{stronghold::StrongholdSecretManager, SignTransaction}, }, types::{ - block::{ - payload::SignedTransactionPayload, - protocol::{protocol_parameters, ProtocolParameters}, - }, + block::{payload::SignedTransactionPayload, protocol::protocol_parameters}, TryFromDto, }, wallet::Result, }; -use serde::{de::DeserializeOwned, Serialize}; const STRONGHOLD_SNAPSHOT_PATH: &str = "./examples/wallet/offline_signing/example.stronghold"; const PREPARED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.prepared_transaction.json"; @@ -46,13 +44,15 @@ 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 = read_prepared_transaction_from_file().await?; let protocol_parameters = protocol_parameters(); // Signs prepared transaction offline. let unlocks = secret_manager - .transaction_unlocks(&prepared_transaction_data, &protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, &protocol_parameters, &signing_options) .await?; let signed_transaction = SignedTransactionPayload::new(prepared_transaction_data.transaction.clone(), unlocks)?; @@ -71,7 +71,7 @@ async fn main() -> Result<()> { Ok(()) } -async fn read_prepared_transaction_from_file() -> Result> { +async fn read_prepared_transaction_from_file() -> Result { use tokio::io::AsyncReadExt; let mut file = tokio::io::BufReader::new(tokio::fs::File::open(PREPARED_TRANSACTION_FILE_PATH).await?); @@ -81,9 +81,7 @@ async fn read_prepared_transaction_from_file() -> Result( - signed_transaction_data: &SignedTransactionData, -) -> Result<()> { +async fn write_signed_transaction_to_file(signed_transaction_data: &SignedTransactionData) -> Result<()> { use tokio::io::AsyncWriteExt; let dto = SignedTransactionDataDto::from(signed_transaction_data); diff --git a/sdk/examples/wallet/offline_signing/3_send_transaction.rs b/sdk/examples/wallet/offline_signing/3_send_transaction.rs index 3e3675e0bf..9763aec488 100644 --- a/sdk/examples/wallet/offline_signing/3_send_transaction.rs +++ b/sdk/examples/wallet/offline_signing/3_send_transaction.rs @@ -18,7 +18,6 @@ use iota_sdk::{ wallet::Result, Wallet, }; -use serde::de::DeserializeOwned; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; const SIGNED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.signed_transaction.json"; @@ -51,16 +50,14 @@ async fn main() -> Result<()> { Ok(()) } -async fn read_signed_transaction_from_file( - client: &Client, -) -> Result> { +async fn read_signed_transaction_from_file(client: &Client) -> Result { use tokio::io::AsyncReadExt; let mut file = tokio::io::BufReader::new(tokio::fs::File::open(SIGNED_TRANSACTION_FILE_PATH).await?); let mut json = String::new(); file.read_to_string(&mut json).await?; - let dto = serde_json::from_str::>(&json)?; + let dto = serde_json::from_str::(&json)?; Ok(SignedTransactionData::try_from_dto_with_params( dto, diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 04fb56e061..ba4ed047ab 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -31,11 +31,11 @@ use crate::{ }; /// Working state for the input selection algorithm. -pub struct InputSelection { - available_inputs: Vec>, +pub struct InputSelection { + available_inputs: Vec, required_inputs: HashSet, forbidden_inputs: HashSet, - selected_inputs: Vec>, + selected_inputs: Vec, outputs: Vec, addresses: HashSet
, burn: Option, @@ -48,17 +48,17 @@ pub struct InputSelection { /// Result of the input selection algorithm. #[derive(Clone, Debug)] -pub struct Selected { +pub struct Selected { /// Selected inputs. - pub inputs: Vec>, + pub inputs: Vec, /// Provided and created outputs. pub outputs: Vec, /// Remainder, if there was one. - pub remainder: Option>, + pub remainder: Option, } -impl InputSelection { - fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { +impl InputSelection { + fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { let required_address = input .output .required_and_unlocked_address(self.slot_index, input.output_id())? @@ -75,7 +75,7 @@ impl InputSelection { } } - fn select_input(&mut self, input: InputSigningData) -> Result<(), Error> { + fn select_input(&mut self, input: InputSigningData) -> Result<(), Error> { log::debug!("Selecting input {:?}", input.output_id()); if let Some(output) = self.transition_input(&input)? { @@ -145,7 +145,7 @@ impl InputSelection { /// Creates a new [`InputSelection`]. pub fn new( - available_inputs: impl Into>>, + available_inputs: impl Into>, outputs: impl Into>, addresses: impl IntoIterator, protocol_parameters: ProtocolParameters, @@ -249,15 +249,15 @@ impl InputSelection { // Inputs need to be sorted before signing, because the reference unlock conditions can only reference a lower index pub(crate) fn sort_input_signing_data( - mut inputs: Vec>, + mut inputs: Vec, slot_index: SlotIndex, - ) -> Result>, Error> { + ) -> Result, Error> { // initially sort by output to make it deterministic // TODO: rethink this, we only need it deterministic for tests, for the protocol it doesn't matter, also there // might be a more efficient way to do this inputs.sort_by_key(|i| i.output.pack_to_vec()); // filter for ed25519 address first - let (mut sorted_inputs, account_nft_address_inputs): (Vec>, Vec>) = + let (mut sorted_inputs, account_nft_address_inputs): (Vec, Vec) = inputs.into_iter().partition(|input_signing_data| { let (input_address, _) = input_signing_data .output @@ -338,7 +338,7 @@ impl InputSelection { /// Selects inputs that meet the requirements of the outputs to satisfy the semantic validation of the overall /// transaction. Also creates a remainder output and chain transition outputs if required. - pub fn select(mut self) -> Result, Error> { + pub fn select(mut self) -> Result { if !OUTPUT_COUNT_RANGE.contains(&(self.outputs.len() as u16)) { // If burn is provided, outputs will be added later if !(self.outputs.is_empty() && self.burn.is_some()) { 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 ead42f71d0..0e786d0797 100644 --- a/sdk/src/client/api/block_builder/input_selection/remainder.rs +++ b/sdk/src/client/api/block_builder/input_selection/remainder.rs @@ -16,9 +16,9 @@ use crate::{ }, }; -impl InputSelection { +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()) { @@ -27,10 +27,10 @@ impl InputSelection { .required_and_unlocked_address(self.slot_index, input.output_id())?; if &required_address == remainder_address { - return Ok(Some((remainder_address.clone(), input.signing_options.clone()))); + 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 { @@ -40,7 +40,7 @@ impl InputSelection { .0; if required_address.is_ed25519() { - return Ok(Some((required_address, input.signing_options.clone()))); + return Ok(Some(required_address)); } } @@ -79,7 +79,7 @@ impl InputSelection { pub(crate) fn remainder_and_storage_deposit_return_outputs( &self, - ) -> Result<(Option>, Vec), Error> { + ) -> Result<(Option, Vec), Error> { let (inputs_sum, outputs_sum, inputs_sdr, outputs_sdr) = amount_sums(&self.selected_inputs, &self.outputs, self.slot_index); let mut storage_deposit_returns = Vec::new(); @@ -120,7 +120,7 @@ impl InputSelection { return Ok((None, storage_deposit_returns)); } - let Some((remainder_address, chain)) = self.get_remainder_address()? else { + let Some(remainder_address) = self.get_remainder_address()? else { return Err(Error::MissingInputWithEd25519Address); }; @@ -145,7 +145,6 @@ impl InputSelection { Ok(( Some(RemainderData { output: remainder, - signing_options: chain, address: remainder_address, }), storage_deposit_returns, diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs index 72a6fa9abc..87f8cd20cd 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs @@ -26,12 +26,12 @@ pub(crate) fn is_account_with_id_non_null(output: &Output, account_id: &AccountI } } -impl InputSelection { +impl InputSelection { /// Fulfills an account requirement by selecting the appropriate account from the available inputs. pub(crate) fn fulfill_account_requirement( &mut self, account_id: AccountId, - ) -> Result>, Error> { + ) -> Result, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs index 78ebeeefe1..e0822901dc 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs @@ -35,8 +35,8 @@ pub(crate) fn sdruc_not_expired( }) } -pub(crate) fn amount_sums( - selected_inputs: &[InputSigningData], +pub(crate) fn amount_sums( + selected_inputs: &[InputSigningData], outputs: &[Output], slot_index: SlotIndex, ) -> (u64, u64, HashMap, HashMap) { @@ -76,8 +76,8 @@ pub(crate) fn amount_sums( } #[derive(Debug, Clone)] -struct AmountSelection { - newly_selected_inputs: HashMap>, +struct AmountSelection { + newly_selected_inputs: HashMap, inputs_sum: u64, outputs_sum: u64, inputs_sdr: HashMap, @@ -87,8 +87,8 @@ struct AmountSelection { slot_index: SlotIndex, } -impl AmountSelection { - fn new(input_selection: &InputSelection) -> Result { +impl AmountSelection { + fn new(input_selection: &InputSelection) -> Result { let (inputs_sum, outputs_sum, inputs_sdr, outputs_sdr) = amount_sums( &input_selection.selected_inputs, &input_selection.outputs, @@ -127,7 +127,7 @@ impl AmountSelection { } } - fn fulfil<'a>(&mut self, inputs: impl Iterator>) -> bool { + fn fulfil<'a>(&mut self, inputs: impl Iterator) -> bool { for input in inputs { if self.newly_selected_inputs.contains_key(input.output_id()) { continue; @@ -161,16 +161,16 @@ impl AmountSelection { false } - fn into_newly_selected_inputs(self) -> Vec> { + fn into_newly_selected_inputs(self) -> Vec { self.newly_selected_inputs.into_values().collect() } } -impl InputSelection { +impl InputSelection { fn fulfil<'a>( &self, - base_inputs: impl Iterator> + Clone, - amount_selection: &mut AmountSelection, + base_inputs: impl Iterator + Clone, + amount_selection: &mut AmountSelection, ) -> bool { // No native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { @@ -216,7 +216,7 @@ impl InputSelection { false } - fn reduce_funds_of_chains(&mut self, amount_selection: &mut AmountSelection) -> Result<(), Error> { + fn reduce_funds_of_chains(&mut self, amount_selection: &mut AmountSelection) -> Result<(), Error> { // Only consider automatically transitioned outputs. let outputs = self.outputs.iter_mut().filter(|output| { output @@ -273,7 +273,7 @@ impl InputSelection { }) } - pub(crate) fn fulfill_amount_requirement(&mut self) -> Result>, Error> { + pub(crate) fn fulfill_amount_requirement(&mut self) -> Result, Error> { let mut amount_selection = AmountSelection::new(self)?; if amount_selection.missing_amount() == 0 { @@ -341,8 +341,8 @@ impl InputSelection { fn fulfill_amount_requirement_inner( &mut self, - amount_selection: &mut AmountSelection, - ) -> Option>> { + amount_selection: &mut AmountSelection, + ) -> Option> { let basic_ed25519_inputs = self.available_inputs.iter().filter(|input| { if let Output::Basic(output) = &input.output { output diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs b/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs index 53a4503501..ce6fb8ee6e 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/ed25519.rs @@ -4,9 +4,9 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { // Checks if a selected input unlocks a given ED25519 address. - fn selected_unlocks_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { + fn selected_unlocks_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { // PANIC: safe to unwrap as outputs with no address have been filtered out already. let required_address = input .output @@ -19,7 +19,7 @@ impl InputSelection { // Checks if an available input can unlock a given ED25519 address. // In case an account input is selected, also tells if it needs to be state or governance transitioned. - fn available_has_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { + fn available_has_ed25519_address(&self, input: &InputSigningData, address: &Address) -> bool { let (required_address, _) = input .output .required_and_unlocked_address(self.slot_index, input.output_id()) @@ -29,7 +29,7 @@ impl InputSelection { } /// Fulfills an ed25519 sender requirement by selecting an available input that unlocks its address. - pub(crate) fn fulfill_ed25519_requirement(&mut self, address: &Address) -> Result>, Error> { + pub(crate) fn fulfill_ed25519_requirement(&mut self, address: &Address) -> Result, Error> { // Checks if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs b/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs index cf56b37d4c..f1a2f5be1b 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/foundry.rs @@ -16,12 +16,12 @@ pub(crate) fn is_foundry_with_id(output: &Output, foundry_id: &FoundryId) -> boo } } -impl InputSelection { +impl InputSelection { /// Fulfills a foundry requirement by selecting the appropriate foundry from the available inputs. pub(crate) fn fulfill_foundry_requirement( &mut self, foundry_id: FoundryId, - ) -> Result>, Error> { + ) -> Result, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs b/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs index d955eadd6d..99c961c418 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/issuer.rs @@ -4,10 +4,10 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { /// Fulfills an issuer requirement by fulfilling the equivalent sender requirement. /// Potentially converts the error for a more accurate one. - pub(crate) fn fulfill_issuer_requirement(&mut self, address: &Address) -> Result>, Error> { + pub(crate) fn fulfill_issuer_requirement(&mut self, address: &Address) -> Result, Error> { log::debug!("Treating {address:?} issuer requirement as a sender requirement"); match self.fulfill_sender_requirement(address) { diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs index 512323c2d0..9da2517062 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/mod.rs @@ -41,10 +41,10 @@ pub enum Requirement { Amount, } -impl InputSelection { +impl InputSelection { /// Fulfills a requirement by selecting the appropriate available inputs. /// Returns the selected inputs and an optional new requirement. - pub(crate) fn fulfill_requirement(&mut self, requirement: Requirement) -> Result>, Error> { + pub(crate) fn fulfill_requirement(&mut self, requirement: Requirement) -> Result, Error> { log::debug!("Fulfilling requirement {requirement:?}"); match requirement { diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs index 6892d7c00d..e355d74dbd 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs @@ -23,8 +23,8 @@ pub(crate) fn get_native_tokens<'a>(outputs: impl Iterator) - Ok(required_native_tokens) } -pub(crate) fn get_minted_and_melted_native_tokens( - inputs: &[InputSigningData], +pub(crate) fn get_minted_and_melted_native_tokens( + inputs: &[InputSigningData], outputs: &[Output], ) -> Result<(NativeTokensBuilder, NativeTokensBuilder), Error> { let mut minted_native_tokens = NativeTokensBuilder::new(); @@ -110,8 +110,8 @@ pub(crate) fn get_native_tokens_diff( } } -impl InputSelection { - pub(crate) fn fulfill_native_tokens_requirement(&mut self) -> Result>, Error> { +impl InputSelection { + pub(crate) fn fulfill_native_tokens_requirement(&mut self) -> Result, Error> { let mut input_native_tokens = get_native_tokens(self.selected_inputs.iter().map(|input| &input.output))?; let mut output_native_tokens = get_native_tokens(self.outputs.iter())?; let (minted_native_tokens, melted_native_tokens) = diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs b/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs index 3e854b407b..0ae00082c3 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/nft.rs @@ -29,9 +29,9 @@ pub(crate) fn is_nft_with_id_non_null(output: &Output, nft_id: &NftId) -> bool { } } -impl InputSelection { +impl InputSelection { /// Fulfills an nft requirement by selecting the appropriate nft from the available inputs. - pub(crate) fn fulfill_nft_requirement(&mut self, nft_id: NftId) -> Result>, Error> { + pub(crate) fn fulfill_nft_requirement(&mut self, nft_id: NftId) -> Result, Error> { // Check if the requirement is already fulfilled. if let Some(input) = self .selected_inputs diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs b/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs index ce4273db5b..e79dfc82cf 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/sender.rs @@ -4,9 +4,9 @@ use super::{Error, InputSelection, Requirement}; use crate::{client::secret::types::InputSigningData, types::block::address::Address}; -impl InputSelection { +impl InputSelection { /// Fulfills a sender requirement by selecting an available input that unlocks its address. - pub(crate) fn fulfill_sender_requirement(&mut self, address: &Address) -> Result>, Error> { + pub(crate) fn fulfill_sender_requirement(&mut self, address: &Address) -> Result, Error> { match address { Address::Ed25519(_) => { log::debug!("Treating {address:?} sender requirement as an ed25519 requirement"); diff --git a/sdk/src/client/api/block_builder/input_selection/transition.rs b/sdk/src/client/api/block_builder/input_selection/transition.rs index 03ca7cbe16..18344028c6 100644 --- a/sdk/src/client/api/block_builder/input_selection/transition.rs +++ b/sdk/src/client/api/block_builder/input_selection/transition.rs @@ -13,7 +13,7 @@ use crate::{ }, }; -impl InputSelection { +impl InputSelection { /// Transitions an account input by creating a new account output if required. fn transition_account_input( &mut self, @@ -149,7 +149,7 @@ impl InputSelection { /// Transitions an input by creating a new output if required. /// If no `account_transition` is provided, assumes a state transition. - pub(crate) fn transition_input(&mut self, input: &InputSigningData) -> Result, Error> { + pub(crate) fn transition_input(&mut self, input: &InputSigningData) -> Result, Error> { match &input.output { Output::Account(account_input) => self.transition_account_input(account_input, input.output_id()), Output::Foundry(foundry_input) => self.transition_foundry_input(foundry_input, input.output_id()), diff --git a/sdk/src/client/api/block_builder/transaction.rs b/sdk/src/client/api/block_builder/transaction.rs index 772a275e0a..76e01d4991 100644 --- a/sdk/src/client/api/block_builder/transaction.rs +++ b/sdk/src/client/api/block_builder/transaction.rs @@ -25,8 +25,8 @@ const SINGLE_UNLOCK_LENGTH: usize = 1 + 1 + Ed25519Signature::PUBLIC_KEY_LENGTH const REFERENCE_ACCOUNT_NFT_UNLOCK_LENGTH: usize = 1 + 2; /// Verifies the semantic of a prepared transaction. -pub fn verify_semantic( - input_signing_data: &[InputSigningData], +pub fn verify_semantic( + input_signing_data: &[InputSigningData], transaction_payload: &SignedTransactionPayload, ) -> crate::client::Result> { let inputs = input_signing_data diff --git a/sdk/src/client/api/types.rs b/sdk/src/client/api/types.rs index 2cbd4f3f3e..85c30f21ba 100644 --- a/sdk/src/client/api/types.rs +++ b/sdk/src/client/api/types.rs @@ -25,29 +25,29 @@ use crate::{ /// Helper struct for offline signing #[derive(Clone, Debug, Eq, PartialEq)] -pub struct PreparedTransactionData { +pub struct PreparedTransactionData { /// Transaction pub transaction: Transaction, /// Required input information for signing. Inputs need to be ordered by address type - pub inputs_data: Vec>, + pub inputs_data: Vec, /// Optional remainder output information - pub remainder: Option>, + pub remainder: Option, } /// PreparedTransactionData Dto #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct PreparedTransactionDataDto { +pub struct PreparedTransactionDataDto { /// Transaction pub transaction: TransactionDto, /// Required address information for signing - pub inputs_data: Vec>, + pub inputs_data: Vec, /// Optional remainder output information - pub remainder: Option>, + pub remainder: Option, } -impl From<&PreparedTransactionData> for PreparedTransactionDataDto { - fn from(value: &PreparedTransactionData) -> Self { +impl From<&PreparedTransactionData> for PreparedTransactionDataDto { + fn from(value: &PreparedTransactionData) -> Self { Self { transaction: TransactionDto::from(&value.transaction), inputs_data: value.inputs_data.clone(), @@ -56,11 +56,11 @@ impl From<&PreparedTransactionData> for PreparedTransactionDataDto< } } -impl TryFromDto> for PreparedTransactionData { +impl TryFromDto for PreparedTransactionData { type Error = Error; fn try_from_dto_with_params_inner( - dto: PreparedTransactionDataDto, + dto: PreparedTransactionDataDto, params: Option<&ProtocolParameters>, ) -> Result { Ok(Self { @@ -74,25 +74,25 @@ impl TryFromDto> for PreparedTransactionData /// Helper struct for offline signing #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SignedTransactionData { +pub struct SignedTransactionData { /// Signed transaction payload pub payload: SignedTransactionPayload, /// Required address information for signing - pub inputs_data: Vec>, + pub inputs_data: Vec, } /// SignedTransactionData Dto #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SignedTransactionDataDto { +pub struct SignedTransactionDataDto { /// Signed transaction payload pub payload: SignedTransactionPayloadDto, /// Required address information for signing - pub inputs_data: Vec>, + pub inputs_data: Vec, } -impl From<&SignedTransactionData> for SignedTransactionDataDto { - fn from(value: &SignedTransactionData) -> Self { +impl From<&SignedTransactionData> for SignedTransactionDataDto { + fn from(value: &SignedTransactionData) -> Self { Self { payload: SignedTransactionPayloadDto::from(&value.payload), inputs_data: value.inputs_data.clone(), @@ -100,11 +100,11 @@ impl From<&SignedTransactionData> for SignedTransactionDataDto { } } -impl TryFromDto> for SignedTransactionData { +impl TryFromDto for SignedTransactionData { type Error = Error; fn try_from_dto_with_params_inner( - dto: SignedTransactionDataDto, + dto: SignedTransactionDataDto, params: Option<&ProtocolParameters>, ) -> Result { Ok(Self { @@ -117,11 +117,9 @@ impl TryFromDto> for SignedTransactionData { /// Data for a remainder output, used for ledger nano #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct RemainderData { +pub struct RemainderData { /// The remainder output pub output: Output, - /// The signing options for the remainder addresses - pub signing_options: Option, /// The remainder address pub address: Address, } diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index ffac04f8b6..229fb66ad5 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -313,8 +313,9 @@ impl Sign for LedgerSecretManager { impl SignTransaction for LedgerSecretManager { async fn transaction_unlocks( &self, - prepared_transaction: &PreparedTransactionData, + prepared_transaction: &PreparedTransactionData, _protocol_parameters: &ProtocolParameters, + chain: &Self::Options, ) -> crate::client::Result { let mut input_bip32_indices = Vec::new(); let mut coin_type = None; @@ -323,8 +324,6 @@ impl SignTransaction for LedgerSecretManager { let input_len = prepared_transaction.inputs_data.len(); for input in &prepared_transaction.inputs_data { - let chain = input.signing_options.ok_or(Error::MissingBip32Chain)?; - // 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)) @@ -371,19 +370,13 @@ impl SignTransaction for LedgerSecretManager { // figure out the remainder output and bip32 index (if there is one) #[allow(clippy::option_if_let_else)] let (remainder_output, remainder_bip32) = match &prepared_transaction.remainder { - Some(remainder) => { - if let Some(chain) = remainder.signing_options { - ( - Some(&remainder.output), - LedgerBIP32Index { - bip32_change: chain.change.harden().into(), - bip32_index: chain.address_index.harden().into(), - }, - ) - } else { - (None, LedgerBIP32Index::default()) - } - } + Some(remainder) => ( + Some(&remainder.output), + LedgerBIP32Index { + bip32_change: chain.change.harden().into(), + bip32_index: chain.address_index.harden().into(), + }, + ), None => (None, LedgerBIP32Index::default()), }; @@ -492,7 +485,7 @@ impl SecretManagerConfig for LedgerSecretManager { /// is signed but only with BasicOutputs, without extra-features and if the transaction is not too large. /// If criteria are not met, blind signing is needed. /// This method finds out if we have to switch to blind signing mode. -pub fn needs_blind_signing(prepared_transaction: &PreparedTransactionData, buffer_size: usize) -> bool { +pub fn needs_blind_signing(prepared_transaction: &PreparedTransactionData, buffer_size: usize) -> bool { if !prepared_transaction .transaction .outputs() @@ -576,7 +569,7 @@ impl LedgerSecretManager { // Merge signature unlocks with Account/Nft/Reference unlocks fn merge_unlocks( - prepared_transaction_data: &PreparedTransactionData, + prepared_transaction_data: &PreparedTransactionData, mut unlocks: impl Iterator, ) -> Result, Error> { let slot_index = prepared_transaction_data.transaction.creation_slot(); diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 9c832d564b..f298b1ec63 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -200,8 +200,9 @@ pub trait SignTransaction: Sign { async fn transaction_unlocks( &self, - prepared_transaction_data: &PreparedTransactionData, + prepared_transaction_data: &PreparedTransactionData, _protocol_parameters: &ProtocolParameters, + options: &Self::Options, ) -> crate::client::Result { let transaction_signing_hash = prepared_transaction_data.transaction.signing_hash(); let mut blocks = Vec::new(); @@ -239,8 +240,6 @@ pub trait SignTransaction: Sign { _ => Err(InputSelectionError::MissingInputWithEd25519Address)?, } - let options = input.signing_options.as_ref().ok_or(Error::MissingSigningOptions)?; - let block = self.signature_unlock(&transaction_signing_hash, options).await?; blocks.push(block.into()); @@ -271,13 +270,14 @@ pub trait SignTransaction: Sign { async fn sign_transaction( &self, - prepared_transaction_data: PreparedTransactionData, + prepared_transaction_data: PreparedTransactionData, protocol_parameters: &ProtocolParameters, + options: &Self::Options, ) -> crate::client::Result { log::debug!("[sign_transaction] {:?}", prepared_transaction_data); let unlocks = self - .transaction_unlocks(&prepared_transaction_data, protocol_parameters) + .transaction_unlocks(&prepared_transaction_data, protocol_parameters, options) .await?; let PreparedTransactionData { diff --git a/sdk/src/client/secret/types.rs b/sdk/src/client/secret/types.rs index 931705a1fb..8aa4047bb5 100644 --- a/sdk/src/client/secret/types.rs +++ b/sdk/src/client/secret/types.rs @@ -115,15 +115,14 @@ impl LedgerNanoStatus { /// Data for transaction inputs for signing and ordering of unlock blocks #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct InputSigningData { +pub struct InputSigningData { /// The output pub output: Output, /// The output metadata pub output_metadata: OutputMetadata, - pub signing_options: Option, } -impl InputSigningData { +impl InputSigningData { /// Return the [OutputId] pub fn output_id(&self) -> &OutputId { self.output_metadata.output_id() diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 90b015acd2..ea47dba06e 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -23,10 +23,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}, @@ -83,7 +80,7 @@ pub struct WalletInner { pub(crate) client: Client, pub(crate) secret_manager: Arc>, #[cfg(feature = "events")] - pub(crate) event_emitter: tokio::sync::RwLock>, + pub(crate) event_emitter: tokio::sync::RwLock, #[cfg(feature = "storage")] pub(crate) storage_options: StorageOptions, #[cfg(feature = "storage")] @@ -102,14 +99,14 @@ pub struct WalletData { pub(crate) alias: Option, /// Outputs // stored separated from the wallet for performance? - pub(crate) outputs: HashMap>, + pub(crate) outputs: HashMap, /// Unspent outputs that are currently used as input for transactions // outputs used in transactions should be locked here so they don't get used again, which would result in a // conflicting transaction pub(crate) locked_outputs: HashSet, /// Unspent outputs // have unspent outputs in a separated hashmap so we don't need to iterate over all outputs we have - pub(crate) unspent_outputs: HashMap>, + pub(crate) unspent_outputs: HashMap, /// Sent transactions // stored separated from the wallet for performance and only the transaction id here? where to add the network id? // transactions: HashSet, @@ -152,9 +149,9 @@ impl WalletData { } fn filter_outputs<'a>( - outputs: impl Iterator>, + outputs: impl Iterator, filter: FilterOptions, - ) -> impl Iterator> { + ) -> impl Iterator { outputs.filter(move |output| { match &output.output { Output::Account(account) => { @@ -242,30 +239,27 @@ impl WalletData { } /// Returns outputs map of the wallet. - pub fn outputs(&self) -> &HashMap> { + pub fn outputs(&self) -> &HashMap { &self.outputs } /// Returns unspent outputs map of the wallet. - pub fn unspent_outputs(&self) -> &HashMap> { + pub fn unspent_outputs(&self) -> &HashMap { &self.unspent_outputs } /// Returns outputs of the wallet. - pub fn filtered_outputs(&self, filter: FilterOptions) -> impl Iterator> { + pub fn filtered_outputs(&self, filter: FilterOptions) -> impl Iterator { Self::filter_outputs(self.outputs.values(), filter) } /// Returns unspent outputs of the wallet. - pub fn filtered_unspent_outputs( - &self, - filter: FilterOptions, - ) -> impl Iterator> { + pub fn filtered_unspent_outputs(&self, filter: FilterOptions) -> impl Iterator { Self::filter_outputs(self.unspent_outputs.values(), filter) } /// Gets the unspent account output matching the given ID. - pub fn unspent_account_output(&self, account_id: &AccountId) -> Option<&OutputData> { + pub fn unspent_account_output(&self, account_id: &AccountId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { account_ids: Some([*account_id].into()), ..Default::default() @@ -274,7 +268,7 @@ impl WalletData { } /// Gets the unspent anchor output matching the given ID. - pub fn unspent_anchor_output(&self, anchor_id: &AnchorId) -> Option<&OutputData> { + pub fn unspent_anchor_output(&self, anchor_id: &AnchorId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { anchor_ids: Some([*anchor_id].into()), ..Default::default() @@ -283,7 +277,7 @@ impl WalletData { } /// Gets the unspent foundry output matching the given ID. - pub fn unspent_foundry_output(&self, foundry_id: &FoundryId) -> Option<&OutputData> { + pub fn unspent_foundry_output(&self, foundry_id: &FoundryId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { foundry_ids: Some([*foundry_id].into()), ..Default::default() @@ -292,7 +286,7 @@ impl WalletData { } /// Gets the unspent nft output matching the given ID. - pub fn unspent_nft_output(&self, nft_id: &NftId) -> Option<&OutputData> { + pub fn unspent_nft_output(&self, nft_id: &NftId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { nft_ids: Some([*nft_id].into()), ..Default::default() @@ -301,7 +295,7 @@ impl WalletData { } /// Gets the unspent delegation output matching the given ID. - pub fn unspent_delegation_output(&self, delegation_id: &DelegationId) -> Option<&OutputData> { + pub fn unspent_delegation_output(&self, delegation_id: &DelegationId) -> Option<&OutputData> { self.filtered_unspent_outputs(FilterOptions { delegation_ids: Some([*delegation_id].into()), ..Default::default() @@ -310,21 +304,21 @@ impl WalletData { } /// Returns implicit accounts of the wallet. - pub fn implicit_accounts(&self) -> impl Iterator> { + pub fn implicit_accounts(&self) -> impl Iterator { self.unspent_outputs .values() .filter(|output_data| output_data.output.is_implicit_account()) } /// Returns accounts of the wallet. - pub fn accounts(&self) -> impl Iterator> { + pub fn accounts(&self) -> impl Iterator { self.unspent_outputs .values() .filter(|output_data| output_data.output.is_account()) } /// Get the [`OutputData`] of an output stored in the wallet. - pub fn get_output(&self, output_id: &OutputId) -> Option<&OutputData> { + pub fn get_output(&self, output_id: &OutputId) -> Option<&OutputData> { self.outputs.get(output_id) } @@ -485,7 +479,7 @@ impl Wallet { } #[cfg(feature = "events")] - pub(crate) async fn emit(&self, wallet_event: super::events::types::WalletEvent) { + pub(crate) async fn emit(&self, wallet_event: super::events::types::WalletEvent) { self.inner.emit(wallet_event).await } @@ -539,7 +533,7 @@ impl WalletInner { pub async fn listen + Send>(&self, events: I, handler: F) where I::IntoIter: Send, - F: Fn(&WalletEvent) + 'static + Send + Sync, + F: Fn(&WalletEvent) + 'static + Send + Sync, { let mut emitter = self.event_emitter.write().await; emitter.on(events, handler); @@ -568,14 +562,14 @@ impl WalletInner { } #[cfg(feature = "events")] - pub(crate) async fn emit(&self, event: crate::wallet::events::types::WalletEvent) { + pub(crate) async fn emit(&self, event: crate::wallet::events::types::WalletEvent) { self.event_emitter.read().await.emit(event); } /// Helper function to test events. #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] - pub async fn emit_test_event(&self, event: crate::wallet::events::types::WalletEvent) { + pub async fn emit_test_event(&self, event: crate::wallet::events::types::WalletEvent) { self.emit(event).await } } @@ -594,9 +588,9 @@ pub struct WalletDataDto { pub signing_options: S, pub address: Bech32Address, pub alias: Option, - pub outputs: HashMap>, + pub outputs: HashMap, pub locked_outputs: HashSet, - pub unspent_outputs: HashMap>, + pub unspent_outputs: HashMap, pub transactions: HashMap, pub pending_transactions: HashSet, pub incoming_transactions: HashMap, diff --git a/sdk/src/wallet/events/mod.rs b/sdk/src/wallet/events/mod.rs index f5765a7153..e908a0d1f9 100644 --- a/sdk/src/wallet/events/mod.rs +++ b/sdk/src/wallet/events/mod.rs @@ -13,11 +13,11 @@ pub use self::types::{WalletEvent, WalletEventType}; type Handler = Arc; -pub struct EventEmitter { - handlers: HashMap>>>, +pub struct EventEmitter { + handlers: HashMap>>, } -impl EventEmitter { +impl EventEmitter { /// Creates a new instance of `EventEmitter`. pub fn new() -> Self { Self { @@ -29,7 +29,7 @@ impl EventEmitter { /// multiple listeners for a single event. pub fn on(&mut self, events: impl IntoIterator, handler: F) where - F: Fn(&WalletEvent) + 'static + Send + Sync, + F: Fn(&WalletEvent) + 'static + Send + Sync, { let mut events = events.into_iter().peekable(); let handler = Arc::new(handler); @@ -68,7 +68,7 @@ impl EventEmitter { /// Invokes all listeners of `event`, passing a reference to `payload` as an /// argument to each of them. - pub fn emit(&self, event: WalletEvent) { + pub fn emit(&self, event: WalletEvent) { let event_type = match &event { WalletEvent::NewOutput(_) => WalletEventType::NewOutput, WalletEvent::SpentOutput(_) => WalletEventType::SpentOutput, @@ -86,13 +86,13 @@ impl EventEmitter { } } -impl Default for EventEmitter { +impl Default for EventEmitter { fn default() -> Self { Self::new() } } -impl Debug for EventEmitter { +impl Debug for EventEmitter { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!( f, @@ -122,7 +122,7 @@ mod tests { #[test] fn events() { - let mut emitter = EventEmitter::<()>::new(); + let mut emitter = EventEmitter::new(); let event_counter = Arc::new(AtomicUsize::new(0)); // single event diff --git a/sdk/src/wallet/events/types.rs b/sdk/src/wallet/events/types.rs index 04c3b0aa1a..bb08fff0bd 100644 --- a/sdk/src/wallet/events/types.rs +++ b/sdk/src/wallet/events/types.rs @@ -13,52 +13,49 @@ use crate::{ payload::signed_transaction::{dto::SignedTransactionPayloadDto, TransactionId}, }, }, - wallet::{ - types::{InclusionState, OutputData}, - Error, - }, + wallet::{types::InclusionState, Error, OutputData}, }; #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum WalletEvent { +pub enum WalletEvent { ConsolidationRequired, #[cfg(feature = "ledger_nano")] #[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))] LedgerAddressGeneration(AddressData), - NewOutput(Box>), - SpentOutput(Box>), + NewOutput(Box), + SpentOutput(Box), TransactionInclusion(TransactionInclusionEvent), - TransactionProgress(TransactionProgressEvent), + TransactionProgress(TransactionProgressEvent), } -impl Serialize for WalletEvent { +impl Serialize for WalletEvent { fn serialize(&self, serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] - struct TransactionProgressEvent_<'a, O> { - progress: &'a TransactionProgressEvent, + struct TransactionProgressEvent_<'a> { + progress: &'a TransactionProgressEvent, } #[derive(Serialize)] #[serde(untagged)] - enum WalletEvent_<'a, O> { + enum WalletEvent_<'a> { T0, #[cfg(feature = "ledger_nano")] T1(&'a AddressData), - T2(&'a NewOutputEvent), - T3(&'a SpentOutputEvent), + T2(&'a NewOutputEvent), + T3(&'a SpentOutputEvent), T4(&'a TransactionInclusionEvent), - T5(TransactionProgressEvent_<'a, O>), + T5(TransactionProgressEvent_<'a>), } #[derive(Serialize)] - struct TypedWalletEvent_<'a, O> { + struct TypedWalletEvent_<'a> { #[serde(rename = "type")] kind: u8, #[serde(flatten)] - event: WalletEvent_<'a, O>, + event: WalletEvent_<'a>, } let event = match self { Self::ConsolidationRequired => TypedWalletEvent_ { @@ -91,11 +88,11 @@ impl Serialize for WalletEvent { } } -impl<'de, O: Deserialize<'de>> Deserialize<'de> for WalletEvent { +impl<'de> Deserialize<'de> for WalletEvent { fn deserialize>(d: D) -> Result { #[derive(Deserialize)] - struct TransactionProgressEvent_ { - progress: TransactionProgressEvent, + struct TransactionProgressEvent_ { + progress: TransactionProgressEvent, } let value = serde_json::Value::deserialize(d)?; @@ -176,9 +173,9 @@ impl TryFrom for WalletEventType { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct NewOutputEvent { +pub struct NewOutputEvent { /// The new output. - pub output: OutputData, + pub output: OutputData, /// The transaction that created the output. Might be pruned and not available. #[serde(skip_serializing_if = "Option::is_none")] pub transaction: Option, @@ -188,9 +185,9 @@ pub struct NewOutputEvent { } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct SpentOutputEvent { +pub struct SpentOutputEvent { /// The spent output. - pub output: OutputData, + pub output: OutputData, } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -202,13 +199,13 @@ pub struct TransactionInclusionEvent { #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum TransactionProgressEvent { +pub enum TransactionProgressEvent { /// Performing input selection. SelectingInputs, /// Generating remainder value deposit address. GeneratingRemainderDepositAddress(AddressData), /// Prepared transaction. - PreparedTransaction(Box>), + PreparedTransaction(Box), /// Prepared transaction signing hash hex encoded, required for blindsigning with a ledger nano PreparedTransactionSigningHash(String), /// Signing the transaction. @@ -217,7 +214,7 @@ pub enum TransactionProgressEvent { Broadcasting, } -impl Serialize for TransactionProgressEvent { +impl Serialize for TransactionProgressEvent { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -230,20 +227,20 @@ impl Serialize for TransactionProgressEvent { #[derive(Serialize)] #[serde(untagged)] - enum TransactionProgressEvent_<'a, O> { + enum TransactionProgressEvent_<'a> { T0, T1(&'a AddressData), - T2(&'a PreparedTransactionDataDto), + T2(&'a PreparedTransactionDataDto), T3(PreparedTransactionSigningHash_<'a>), T4, T5, } #[derive(Serialize)] - struct TypedTransactionProgressEvent_<'a, O> { + struct TypedTransactionProgressEvent_<'a> { #[serde(rename = "type")] kind: u8, #[serde(flatten)] - event: TransactionProgressEvent_<'a, O>, + event: TransactionProgressEvent_<'a>, } let event = match self { Self::SelectingInputs => TypedTransactionProgressEvent_ { @@ -275,7 +272,7 @@ impl Serialize for TransactionProgressEvent { } } -impl<'de, O: Deserialize<'de>> Deserialize<'de> for TransactionProgressEvent { +impl<'de> Deserialize<'de> for TransactionProgressEvent { fn deserialize>(d: D) -> Result { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] diff --git a/sdk/src/wallet/operations/helpers/time.rs b/sdk/src/wallet/operations/helpers/time.rs index cabbefbb8d..ebd3675688 100644 --- a/sdk/src/wallet/operations/helpers/time.rs +++ b/sdk/src/wallet/operations/helpers/time.rs @@ -7,9 +7,9 @@ use crate::{ }; // Check if an output can be unlocked by the wallet address at the current time -pub(crate) fn can_output_be_unlocked_now( +pub(crate) fn can_output_be_unlocked_now( wallet_address: &Address, - output_data: &OutputData, + output_data: &OutputData, slot_index: SlotIndex, ) -> crate::wallet::Result { if let Some(unlock_conditions) = output_data.output.unlock_conditions() { diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index 819f4ee999..2e887bc1f4 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -142,16 +142,14 @@ impl Wallet { /// Get basic outputs that have only one unlock condition which is [AddressUnlockCondition], so they can be used as /// additional inputs - pub(crate) async fn get_basic_outputs_for_additional_inputs( - &self, - ) -> crate::wallet::Result>> { + pub(crate) async fn get_basic_outputs_for_additional_inputs(&self) -> crate::wallet::Result> { log::debug!("[OUTPUT_CLAIMING] get_basic_outputs_for_additional_inputs"); #[cfg(feature = "participation")] let voting_output = self.get_voting_output().await?; let wallet_data = self.data().await; // Get basic outputs only with AddressUnlockCondition and no other unlock condition - let mut basic_outputs: Vec> = Vec::new(); + let mut basic_outputs: Vec = Vec::new(); for (output_id, output_data) in &wallet_data.unspent_outputs { #[cfg(feature = "participation")] if let Some(ref voting_output) = voting_output { @@ -220,7 +218,7 @@ impl Wallet { pub async fn prepare_claim_outputs + Send>( &self, output_ids_to_claim: I, - ) -> crate::wallet::Result> + ) -> crate::wallet::Result where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index a671ddcde9..2de51f570c 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -68,7 +68,7 @@ impl ConsolidationParams { impl Wallet { fn should_consolidate_output( &self, - output_data: &OutputData, + output_data: &OutputData, slot_index: SlotIndex, wallet_address: &Address, ) -> Result { @@ -115,10 +115,7 @@ 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 { log::debug!("[OUTPUT_CONSOLIDATION] prepare consolidating outputs if needed"); #[cfg(feature = "participation")] let voting_output = self.get_voting_output().await?; diff --git a/sdk/src/wallet/operations/participation/mod.rs b/sdk/src/wallet/operations/participation/mod.rs index 8d31b45800..28690f3380 100644 --- a/sdk/src/wallet/operations/participation/mod.rs +++ b/sdk/src/wallet/operations/participation/mod.rs @@ -219,7 +219,7 @@ impl Wallet { /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. - pub async fn get_voting_output(&self) -> Result>> { + pub async fn get_voting_output(&self) -> Result> { self.data().await.get_voting_output() } @@ -277,7 +277,7 @@ impl WalletData { /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. - pub(crate) fn get_voting_output(&self) -> Result>> { + pub(crate) fn get_voting_output(&self) -> Result> { log::debug!("[get_voting_output]"); Ok(self .unspent_outputs diff --git a/sdk/src/wallet/operations/participation/voting.rs b/sdk/src/wallet/operations/participation/voting.rs index a4dc030be3..cb7a62ead5 100644 --- a/sdk/src/wallet/operations/participation/voting.rs +++ b/sdk/src/wallet/operations/participation/voting.rs @@ -45,7 +45,7 @@ impl Wallet { &self, event_id: impl Into> + Send, answers: impl Into>> + Send, - ) -> Result> { + ) -> Result { let event_id = event_id.into(); let answers = answers.into(); if let Some(event_id) = event_id { @@ -131,10 +131,7 @@ impl Wallet { } /// Prepares the transaction for [Wallet::stop_participating()]. - pub async fn prepare_stop_participating( - &self, - event_id: ParticipationEventId, - ) -> Result> { + pub async fn prepare_stop_participating(&self, event_id: ParticipationEventId) -> Result { let voting_output = self .get_voting_output() .await? diff --git a/sdk/src/wallet/operations/participation/voting_power.rs b/sdk/src/wallet/operations/participation/voting_power.rs index 7a4f5fb424..cca6c50b4a 100644 --- a/sdk/src/wallet/operations/participation/voting_power.rs +++ b/sdk/src/wallet/operations/participation/voting_power.rs @@ -44,10 +44,7 @@ impl Wallet { } /// Prepares the transaction for [Wallet::increase_voting_power()]. - pub async fn prepare_increase_voting_power( - &self, - amount: u64, - ) -> Result> { + pub async fn prepare_increase_voting_power(&self, amount: u64) -> Result { let (new_output, tx_options) = match self.get_voting_output().await? { Some(current_output_data) => { let output = current_output_data.output.as_basic(); @@ -95,10 +92,7 @@ impl Wallet { } /// Prepares the transaction for [Wallet::decrease_voting_power()]. - pub async fn prepare_decrease_voting_power( - &self, - amount: u64, - ) -> Result> { + pub async fn prepare_decrease_voting_power(&self, amount: u64) -> Result { let current_output_data = self .get_voting_output() .await? diff --git a/sdk/src/wallet/operations/syncing/addresses/outputs.rs b/sdk/src/wallet/operations/syncing/addresses/outputs.rs index d6f374854e..a2db37f604 100644 --- a/sdk/src/wallet/operations/syncing/addresses/outputs.rs +++ b/sdk/src/wallet/operations/syncing/addresses/outputs.rs @@ -18,7 +18,7 @@ impl Wallet { pub(crate) async fn get_outputs_from_address_output_ids( &self, addresses_with_unspent_outputs: Vec, - ) -> crate::wallet::Result<(Vec, Vec>)> { + ) -> crate::wallet::Result<(Vec, Vec)> { log::debug!("[SYNC] start get_outputs_from_address_output_ids"); let address_outputs_start_time = Instant::now(); @@ -47,7 +47,7 @@ impl Wallet { } let results = futures::future::try_join_all(tasks).await?; for res in results { - let (address, outputs): (AddressWithUnspentOutputs, Vec>) = res?; + let (address, outputs): (AddressWithUnspentOutputs, Vec) = res?; addresses_with_outputs.push(address); outputs_data.extend(outputs); } diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index d1cc51c6f0..31ff45f093 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -111,7 +111,7 @@ impl Wallet { let (addresses_with_unspent_outputs, spent_or_not_synced_output_ids, outputs_data): ( Vec, Vec, - Vec>, + Vec, ) = self.request_outputs_recursively(address_to_sync, options).await?; // Request possible spent outputs @@ -166,11 +166,7 @@ impl Wallet { &self, addresses_to_sync: Vec, options: &SyncOptions, - ) -> crate::wallet::Result<( - Vec, - Vec, - Vec>, - )> { + ) -> crate::wallet::Result<(Vec, Vec, Vec)> { // Cache the account and nft address with the related ed2559 address, so we can update the account address with // the new output ids diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index 0213d2662e..06aec25554 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -27,7 +27,7 @@ impl Wallet { &self, outputs_with_meta: Vec, associated_address: &AddressWithUnspentOutputs, - ) -> crate::wallet::Result>> { + ) -> crate::wallet::Result> { log::debug!("[SYNC] convert output_responses"); // store outputs with network_id let network_id = self.client().get_network_id().await?; @@ -51,9 +51,6 @@ impl Wallet { address: associated_address.address.inner.clone(), network_id, remainder, - // TODO: previously we set the internal and address index here, but - // they were always default values anyway. Do we need some mechanism here tho? - signing_options: Some(wallet_data.signing_options.clone()), } }) .collect()) diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 2301e96848..0732cc1256 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -42,7 +42,7 @@ impl Wallet { &self, output_id: &OutputId, key_source: impl Into>> + Send, - ) -> Result> { + ) -> Result { let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); let implicit_account = if let Some(implicit_account_data) = &implicit_account_data { diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 34fb960422..3651052793 100644 --- a/sdk/src/wallet/operations/transaction/build_transaction.rs +++ b/sdk/src/wallet/operations/transaction/build_transaction.rs @@ -19,16 +19,16 @@ impl Wallet { /// Builds the transaction from the selected in and outputs. pub(crate) async fn build_transaction( &self, - selected_transaction_data: Selected, + selected_transaction_data: Selected, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] build_transaction"); let build_transaction_start_time = Instant::now(); let protocol_parameters = self.client().get_protocol_parameters().await?; let mut inputs: Vec = Vec::new(); - let mut inputs_for_signing: Vec> = Vec::new(); + let mut inputs_for_signing: Vec = Vec::new(); for utxo in &selected_transaction_data.inputs { let input = Input::Utxo(UtxoInput::from(*utxo.output_id())); 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 d42d2b6743..ee17b2f5d9 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 @@ -43,7 +43,7 @@ impl Wallet { token_id: TokenId, melt_amount: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_melt_native_token"); let foundry_id = FoundryId::from(token_id); @@ -86,7 +86,7 @@ impl Wallet { &self, account_id: AccountId, foundry_id: FoundryId, - ) -> crate::wallet::Result<(OutputData, OutputData)> { + ) -> crate::wallet::Result<(OutputData, OutputData)> { let mut existing_account_output_data = None; let mut existing_foundry_output = None; 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 be341e5e86..1d22610a7b 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 @@ -38,7 +38,7 @@ impl Wallet { &self, burn: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { let mut options: TransactionOptions = options.into().unwrap_or_default(); options.burn = Some(burn.into()); 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 1a26dd21d3..c9adb9cfc5 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -67,7 +67,7 @@ impl Wallet { &self, params: Option, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_create_account_output"); let storage_score_params = self.client().get_storage_score_parameters().await?; @@ -104,10 +104,7 @@ impl Wallet { } /// Gets an existing account output. - pub(crate) async fn get_account_output( - &self, - account_id: Option, - ) -> Option<(AccountId, OutputData)> { + pub(crate) async fn get_account_output(&self, account_id: Option) -> Option<(AccountId, OutputData)> { log::debug!("[get_account_output]"); self.data() .await 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 dc957dabf3..38d5886117 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 @@ -64,21 +64,21 @@ impl From<&CreateNativeTokenTransaction> for CreateNativeTokenTransactionDto { /// The result of preparing a transaction to create a native token #[derive(Debug)] -pub struct PreparedCreateNativeTokenTransaction { +pub struct PreparedCreateNativeTokenTransaction { pub token_id: TokenId, - pub transaction: PreparedTransactionData, + pub transaction: PreparedTransactionData, } /// Dto for PreparedNativeTokenTransaction #[derive(Debug, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -pub struct PreparedCreateNativeTokenTransactionDto { +pub struct PreparedCreateNativeTokenTransactionDto { pub token_id: TokenId, - pub transaction: PreparedTransactionDataDto, + pub transaction: PreparedTransactionDataDto, } -impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTransactionDto { - fn from(value: &PreparedCreateNativeTokenTransaction) -> Self { +impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTransactionDto { + fn from(value: &PreparedCreateNativeTokenTransaction) -> Self { Self { token_id: value.token_id, transaction: PreparedTransactionDataDto::from(&value.transaction), @@ -126,7 +126,7 @@ impl Wallet { &self, params: CreateNativeTokenParams, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] create_native_token"); let storage_score_params = self.client().get_storage_score_parameters().await?; 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 3107c193c4..87a233f898 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 @@ -48,7 +48,7 @@ impl Wallet { token_id: TokenId, mint_amount: impl Into + Send, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] mint_native_token"); let mint_amount = mint_amount.into(); 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 5b59b1f627..f120e95ef8 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 @@ -152,7 +152,7 @@ impl Wallet { &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result> + ) -> crate::wallet::Result where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/transaction/high_level/send.rs b/sdk/src/wallet/operations/transaction/high_level/send.rs index b9ba07be43..84f1b4bf5c 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send.rs @@ -126,7 +126,7 @@ impl Wallet { &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result> + ) -> crate::wallet::Result where I::IntoIter: Send, { 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 93e176706e..7702871d65 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 @@ -116,7 +116,7 @@ impl Wallet { &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result> + ) -> crate::wallet::Result where I::IntoIter: Send, { 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 f4cfa12b1e..820ccbf505 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs @@ -84,7 +84,7 @@ impl Wallet { &self, params: I, options: impl Into> + Send, - ) -> crate::wallet::Result> + ) -> crate::wallet::Result where I::IntoIter: Send, { diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index d7dec257ac..82e0b5db39 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -30,7 +30,7 @@ impl Wallet { mandatory_inputs: Option>, remainder_address: Option
, burn: Option<&Burn>, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] select_inputs"); // Voting output needs to be requested before to prevent a deadlock #[cfg(feature = "participation")] @@ -213,11 +213,11 @@ impl Wallet { #[allow(clippy::too_many_arguments)] fn filter_inputs( wallet_data: &WalletData, - available_outputs: Values<'_, OutputId, OutputData>, + available_outputs: Values<'_, OutputId, OutputData>, slot_index: SlotIndex, custom_inputs: Option<&HashSet>, mandatory_inputs: Option<&HashSet>, -) -> crate::wallet::Result>> { +) -> crate::wallet::Result> { let mut available_outputs_signing_data = Vec::new(); for output_data in available_outputs { @@ -242,7 +242,7 @@ fn filter_inputs( } } - if let Some(available_input) = output_data.input_signing_data(wallet_data, slot_index)? { + if let Some(available_input) = output_data.input_signing_data(slot_index)? { available_outputs_signing_data.push(available_input); } } diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 55b599b5b2..574f4d8c6b 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -98,7 +98,7 @@ impl Wallet { /// Signs a transaction, submit it to a node and store it in the wallet pub async fn sign_and_submit_transaction( &self, - prepared_transaction_data: PreparedTransactionData, + prepared_transaction_data: PreparedTransactionData, issuer_id: impl Into> + Send, options: impl Into> + Send, ) -> crate::wallet::Result { @@ -120,7 +120,7 @@ impl Wallet { /// Validates the transaction, submit it to a node and store it in the wallet pub async fn submit_and_store_transaction( &self, - signed_transaction_data: SignedTransactionData, + signed_transaction_data: SignedTransactionData, issuer_id: impl Into> + Send, options: impl Into> + Send, ) -> crate::wallet::Result { @@ -196,7 +196,7 @@ impl Wallet { } // unlock outputs - async fn unlock_inputs(&self, inputs: &[InputSigningData]) -> crate::wallet::Result<()> { + async fn unlock_inputs(&self, inputs: &[InputSigningData]) -> crate::wallet::Result<()> { let mut wallet_data = self.data_mut().await; for input_signing_data in inputs { let output_id = input_signing_data.output_id(); diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 85b088c7c7..758b87c6fe 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -231,7 +231,7 @@ impl Wallet { recipient_address: Bech32Address, nft_id: Option, params: StorageScoreParameters, - ) -> crate::wallet::Result<(OutputBuilder, Option>)> { + ) -> crate::wallet::Result<(OutputBuilder, Option)> { let (mut first_output_builder, existing_nft_output_data) = if let Some(nft_id) = &nft_id { if nft_id.is_null() { // Mint a new NFT output diff --git a/sdk/src/wallet/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/operations/transaction/prepare_transaction.rs index 59f553cabf..dfde411a99 100644 --- a/sdk/src/wallet/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/operations/transaction/prepare_transaction.rs @@ -24,7 +24,7 @@ impl Wallet { &self, outputs: impl Into> + Send, options: impl Into> + Send, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_transaction"); let options = options.into(); let outputs = outputs.into(); diff --git a/sdk/src/wallet/operations/transaction/sign_transaction.rs b/sdk/src/wallet/operations/transaction/sign_transaction.rs index dd32b00301..f8a5b2008d 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -23,8 +23,8 @@ impl Wallet { /// Signs a transaction. pub async fn sign_transaction( &self, - prepared_transaction_data: &PreparedTransactionData, - ) -> crate::wallet::Result> { + prepared_transaction_data: &PreparedTransactionData, + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] sign_transaction"); log::debug!("[TRANSACTION] prepared_transaction_data {prepared_transaction_data:?}"); #[cfg(feature = "events")] @@ -73,7 +73,11 @@ impl Wallet { .secret_manager .read() .await - .transaction_unlocks(prepared_transaction_data, &protocol_parameters) + .transaction_unlocks( + prepared_transaction_data, + &protocol_parameters, + self.data().await.signing_options(), + ) .await { Ok(res) => res, diff --git a/sdk/src/wallet/types/mod.rs b/sdk/src/wallet/types/mod.rs index 98c7dc9102..188620cef0 100644 --- a/sdk/src/wallet/types/mod.rs +++ b/sdk/src/wallet/types/mod.rs @@ -16,7 +16,7 @@ pub use self::{ balance::{Balance, BaseCoinBalance, NativeTokensBalance, RequiredStorageDeposit}, }; use crate::{ - client::secret::{types::InputSigningData, SecretManage}, + client::secret::types::InputSigningData, types::{ api::core::OutputWithMetadataResponse, block::{ @@ -29,13 +29,12 @@ use crate::{ }, TryFromDto, }, - wallet::core::WalletData, }; /// An output with metadata #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct OutputData { +pub struct OutputData { /// The output id pub output_id: OutputId, pub metadata: OutputMetadata, @@ -48,36 +47,13 @@ pub struct OutputData { /// Network ID pub network_id: u64, pub remainder: bool, - // bip44 path - pub signing_options: Option, } -impl OutputData { - pub fn input_signing_data>( - &self, - wallet_data: &WalletData, - slot_index: SlotIndex, - ) -> crate::wallet::Result>> { - let (unlock_address, _unlocked_account_or_nft_address) = - self.output.required_and_unlocked_address(slot_index, &self.output_id)?; - - let chain = if unlock_address == self.address { - self.signing_options.clone() - } else if let Address::Ed25519(_) = unlock_address { - if wallet_data.address.inner() == &unlock_address { - Some(wallet_data.signing_options.clone()) - } else { - return Ok(None); - } - } else { - // Account and NFT addresses have no chain - None - }; - +impl OutputData { + pub fn input_signing_data(&self, slot_index: SlotIndex) -> crate::wallet::Result> { Ok(Some(InputSigningData { output: self.output.clone(), output_metadata: self.metadata, - signing_options: self.signing_options.clone(), })) } } diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 24787a8f72..4e8ed4fbba 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -34,7 +34,7 @@ impl Wallet { /// Update wallet with newly synced data and emit events for outputs. pub(crate) async fn update_after_sync( &self, - unspent_outputs: Vec>, + unspent_outputs: Vec, spent_or_unsynced_output_metadata_map: HashMap>, ) -> crate::wallet::Result<()> { log::debug!("[SYNC] Update wallet with new synced transactions"); diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index a350d1a584..76df1dbd57 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -31,7 +31,6 @@ fn input_account_eq_output_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -39,7 +38,6 @@ fn input_account_eq_output_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -66,7 +64,6 @@ fn transition_account_id_zero() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let account_id = AccountId::from(inputs[0].output_id()); let outputs = build_outputs([Account( @@ -75,7 +72,6 @@ fn transition_account_id_zero() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -238,7 +234,6 @@ fn create_account() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -246,7 +241,6 @@ fn create_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -282,7 +276,6 @@ fn burn_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -292,7 +285,6 @@ fn burn_account() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -367,7 +359,6 @@ fn missing_input_for_account_output() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -375,7 +366,6 @@ fn missing_input_for_account_output() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -405,7 +395,6 @@ fn missing_input_for_account_output_2() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -415,7 +404,6 @@ fn missing_input_for_account_output_2() { None, None, None, - None, ), ]); let outputs = build_outputs([Account( @@ -424,7 +412,6 @@ fn missing_input_for_account_output_2() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -454,7 +441,6 @@ fn missing_input_for_account_output_but_created() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -462,7 +448,6 @@ fn missing_input_for_account_output_but_created() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -488,7 +473,6 @@ fn account_in_output_and_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -498,7 +482,6 @@ fn account_in_output_and_sender() { None, None, None, - None, ), ]); let account_output = AccountOutputBuilder::from(inputs[0].output.as_account()) @@ -512,7 +495,6 @@ fn account_in_output_and_sender() { None, None, None, - None, )]); outputs.push(account_output); @@ -540,7 +522,6 @@ fn missing_ed25519_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -548,7 +529,6 @@ fn missing_ed25519_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), None, - None, )]); let selected = InputSelection::new( @@ -578,7 +558,6 @@ fn missing_ed25519_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -586,7 +565,6 @@ fn missing_ed25519_issuer_created() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -614,7 +592,6 @@ fn missing_ed25519_issuer_transition() { 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( 1_000_000, @@ -622,7 +599,6 @@ fn missing_ed25519_issuer_transition() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -647,7 +623,6 @@ fn missing_account_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -655,7 +630,6 @@ fn missing_account_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), None, - None, )]); let selected = InputSelection::new( @@ -685,7 +659,6 @@ fn missing_account_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -693,7 +666,6 @@ fn missing_account_issuer_created() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -721,7 +693,6 @@ fn missing_account_issuer_transition() { 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( 1_000_000, @@ -729,7 +700,6 @@ fn missing_account_issuer_transition() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -754,7 +724,6 @@ fn missing_nft_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -762,7 +731,6 @@ fn missing_nft_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), None, - None, )]); let selected = InputSelection::new( @@ -792,7 +760,6 @@ fn missing_nft_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -800,7 +767,6 @@ fn missing_nft_issuer_created() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -828,7 +794,6 @@ fn missing_nft_issuer_transition() { 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( 1_000_000, @@ -836,7 +801,6 @@ fn missing_nft_issuer_transition() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), - None, )]); let selected = InputSelection::new( @@ -862,7 +826,6 @@ fn increase_account_amount() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -872,7 +835,6 @@ fn increase_account_amount() { None, None, None, - None, ), ]); let outputs = build_outputs([Account( @@ -881,7 +843,6 @@ fn increase_account_amount() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -909,7 +870,6 @@ fn decrease_account_amount() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -919,7 +879,6 @@ fn decrease_account_amount() { None, None, None, - None, ), ]); let outputs = build_outputs([Account( @@ -928,7 +887,6 @@ fn decrease_account_amount() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -968,7 +926,6 @@ fn prefer_basic_to_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -978,7 +935,6 @@ fn prefer_basic_to_account() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -989,7 +945,6 @@ fn prefer_basic_to_account() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1018,7 +973,6 @@ fn take_amount_from_account_to_fund_basic() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -1028,7 +982,6 @@ fn take_amount_from_account_to_fund_basic() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1039,7 +992,6 @@ fn take_amount_from_account_to_fund_basic() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1084,7 +1036,6 @@ fn account_burn_should_validate_account_sender() { None, None, None, - None, ), Account( 1_000_000, @@ -1092,7 +1043,6 @@ fn account_burn_should_validate_account_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1103,7 +1053,6 @@ fn account_burn_should_validate_account_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1146,7 +1095,6 @@ fn account_burn_should_validate_account_address() { None, None, None, - None, ), Account( 1_000_000, @@ -1154,7 +1102,6 @@ fn account_burn_should_validate_account_address() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1165,7 +1112,6 @@ fn account_burn_should_validate_account_address() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1205,7 +1151,6 @@ fn transitioned_zero_account_id_no_longer_is_zero() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1215,7 +1160,6 @@ fn transitioned_zero_account_id_no_longer_is_zero() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1259,7 +1203,6 @@ fn two_accounts_required() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Account( 2_000_000, @@ -1267,7 +1210,6 @@ fn two_accounts_required() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1278,7 +1220,6 @@ fn two_accounts_required() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1326,7 +1267,6 @@ fn state_controller_sender_required() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1336,7 +1276,6 @@ fn state_controller_sender_required() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1364,7 +1303,6 @@ fn state_controller_sender_required_already_selected() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([ Account( @@ -1373,7 +1311,6 @@ fn state_controller_sender_required_already_selected() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 1_000_000, @@ -1383,7 +1320,6 @@ fn state_controller_sender_required_already_selected() { None, None, None, - None, ), ]); @@ -1412,7 +1348,6 @@ fn state_transition_and_required() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 2_000_000, @@ -1420,7 +1355,6 @@ fn state_transition_and_required() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( @@ -1448,7 +1382,6 @@ fn remainder_address_in_state_controller() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -1456,7 +1389,6 @@ fn remainder_address_in_state_controller() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/basic_outputs.rs b/sdk/tests/client/input_selection/basic_outputs.rs index 10af45e799..180b7b1414 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -32,7 +32,6 @@ fn input_amount_equal_output_amount() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -42,7 +41,6 @@ fn input_amount_equal_output_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -70,7 +68,6 @@ fn input_amount_lower_than_output_amount() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -80,7 +77,6 @@ fn input_amount_lower_than_output_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -113,7 +109,6 @@ fn input_amount_lower_than_output_amount_2() { None, None, None, - None, ), Basic( 2_000_000, @@ -123,7 +118,6 @@ fn input_amount_lower_than_output_amount_2() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -134,7 +128,6 @@ fn input_amount_lower_than_output_amount_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -166,7 +159,6 @@ fn input_amount_greater_than_output_amount() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 500_000, @@ -176,7 +168,6 @@ fn input_amount_greater_than_output_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -217,7 +208,6 @@ fn input_amount_greater_than_output_amount_with_remainder_address() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 500_000, @@ -227,7 +217,6 @@ fn input_amount_greater_than_output_amount_with_remainder_address() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -269,7 +258,6 @@ fn two_same_inputs_one_needed() { None, None, None, - None, ), Basic( 2_000_000, @@ -279,7 +267,6 @@ fn two_same_inputs_one_needed() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -290,7 +277,6 @@ fn two_same_inputs_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -332,7 +318,6 @@ fn two_inputs_one_needed() { None, None, None, - None, ), Basic( 2_000_000, @@ -342,7 +327,6 @@ fn two_inputs_one_needed() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -353,7 +337,6 @@ fn two_inputs_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -382,7 +365,6 @@ fn two_inputs_one_needed_reversed() { None, None, None, - None, ), Basic( 1_000_000, @@ -392,7 +374,6 @@ fn two_inputs_one_needed_reversed() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -403,7 +384,6 @@ fn two_inputs_one_needed_reversed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -432,7 +412,6 @@ fn two_inputs_both_needed() { None, None, None, - None, ), Basic( 2_000_000, @@ -442,7 +421,6 @@ fn two_inputs_both_needed() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -453,7 +431,6 @@ fn two_inputs_both_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -482,7 +459,6 @@ fn two_inputs_remainder() { None, None, None, - None, ), Basic( 2_000_000, @@ -492,7 +468,6 @@ fn two_inputs_remainder() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -503,7 +478,6 @@ fn two_inputs_remainder() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -587,7 +561,6 @@ fn ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -597,7 +570,6 @@ fn ed25519_sender() { None, None, None, - None, ), Basic( 1_000_000, @@ -607,7 +579,6 @@ fn ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -617,7 +588,6 @@ fn ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -627,7 +597,6 @@ fn ed25519_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -638,7 +607,6 @@ fn ed25519_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -677,7 +645,6 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -687,7 +654,6 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -718,7 +684,6 @@ fn account_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -728,7 +693,6 @@ fn account_sender() { None, None, None, - None, ), Account( 1_000_000, @@ -736,7 +700,6 @@ fn account_sender() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Basic( 2_000_000, @@ -746,7 +709,6 @@ fn account_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -756,7 +718,6 @@ fn account_sender() { None, None, None, - None, ), ]); @@ -768,7 +729,6 @@ fn account_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -807,7 +767,6 @@ fn account_sender_zero_id() { None, None, None, - None, ), Account( 1_000_000, @@ -815,7 +774,6 @@ fn account_sender_zero_id() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let account_id = AccountId::from(inputs[1].output_id()); @@ -827,7 +785,6 @@ fn account_sender_zero_id() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -861,7 +818,6 @@ fn missing_account_sender() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -871,7 +827,6 @@ fn missing_account_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -902,7 +857,6 @@ fn nft_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -912,7 +866,6 @@ fn nft_sender() { None, None, None, - None, ), Nft( 1_000_000, @@ -922,7 +875,6 @@ fn nft_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -932,7 +884,6 @@ fn nft_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -942,7 +893,6 @@ fn nft_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -953,7 +903,6 @@ fn nft_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -993,7 +942,6 @@ fn nft_sender_zero_id() { None, None, None, - None, ), Nft( 1_000_000, @@ -1003,7 +951,6 @@ fn nft_sender_zero_id() { None, None, None, - None, ), ]); let nft_id = NftId::from(inputs[1].output_id()); @@ -1015,7 +962,6 @@ fn nft_sender_zero_id() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1049,7 +995,6 @@ fn missing_nft_sender() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1059,7 +1004,6 @@ fn missing_nft_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1088,7 +1032,6 @@ fn simple_remainder() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 500_000, @@ -1098,7 +1041,6 @@ fn simple_remainder() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1217,7 +1159,6 @@ fn one_provided_one_needed() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1227,7 +1168,6 @@ fn one_provided_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1255,7 +1195,6 @@ fn insufficient_amount() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_250_000, @@ -1265,7 +1204,6 @@ fn insufficient_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1298,7 +1236,6 @@ fn two_inputs_remainder_2() { None, None, None, - None, ), Basic( 2_000_000, @@ -1308,7 +1245,6 @@ fn two_inputs_remainder_2() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1319,7 +1255,6 @@ fn two_inputs_remainder_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1360,7 +1295,6 @@ fn two_inputs_remainder_3() { None, None, None, - None, ), Basic( 2_000_000, @@ -1370,7 +1304,6 @@ fn two_inputs_remainder_3() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1381,7 +1314,6 @@ fn two_inputs_remainder_3() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1460,7 +1392,6 @@ fn sender_already_selected() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1470,7 +1401,6 @@ fn sender_already_selected() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1502,7 +1432,6 @@ fn single_mandatory_input() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1512,7 +1441,6 @@ fn single_mandatory_input() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1547,7 +1475,6 @@ fn too_many_inputs() { None, None, None, - None, ) }) .take(129), @@ -1561,7 +1488,6 @@ fn too_many_inputs() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1593,7 +1519,6 @@ fn more_than_max_inputs_only_one_needed() { None, None, None, - None, ) }) .take(1000), @@ -1607,7 +1532,6 @@ fn more_than_max_inputs_only_one_needed() { None, None, None, - None, )]); inputs.push(needed_input[0].clone()); @@ -1619,7 +1543,6 @@ fn more_than_max_inputs_only_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1647,7 +1570,6 @@ fn too_many_outputs() { None, None, None, - None, )]); let outputs = build_outputs( @@ -1660,7 +1582,6 @@ fn too_many_outputs() { None, None, None, - None, ) }) .take(129), @@ -1692,7 +1613,6 @@ fn too_many_outputs_with_remainder() { None, None, None, - None, )]); let outputs = build_outputs( @@ -1705,7 +1625,6 @@ fn too_many_outputs_with_remainder() { None, None, None, - None, ) }) .take(128), @@ -1741,7 +1660,6 @@ fn restricted_ed25519() { None, None, None, - None, ), Basic( 1_000_000, @@ -1751,9 +1669,8 @@ fn restricted_ed25519() { None, None, None, - None, ), - Basic(1_000_000, restricted, None, None, None, None, None, None), + Basic(1_000_000, restricted, None, None, None, None, None), Basic( 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), @@ -1762,7 +1679,6 @@ fn restricted_ed25519() { None, None, None, - None, ), Basic( 1_000_000, @@ -1772,7 +1688,6 @@ fn restricted_ed25519() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1783,7 +1698,6 @@ fn restricted_ed25519() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1808,7 +1722,7 @@ fn restricted_nft() { let restricted = Address::from(RestrictedAddress::new(nft_address.clone()).unwrap()); let inputs = build_inputs([ - Basic(2_000_000, restricted, None, None, None, None, None, None), + Basic(2_000_000, restricted, None, None, None, None, None), Nft( 2_000_000, nft_id_1, @@ -1817,7 +1731,6 @@ fn restricted_nft() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1828,7 +1741,6 @@ fn restricted_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1853,14 +1765,13 @@ fn restricted_account() { let restricted = Address::from(RestrictedAddress::new(account_address.clone()).unwrap()); let inputs = build_inputs([ - Basic(2_000_000, restricted, None, None, None, None, None, None), + Basic(2_000_000, restricted, None, None, None, None, None), Account( 2_000_000, account_id_1, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); @@ -1872,7 +1783,6 @@ fn restricted_account() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1904,7 +1814,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -1914,7 +1823,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, ), Basic( 1_000_000, @@ -1924,7 +1832,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -1934,7 +1841,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, ), Basic( 2_000_000, @@ -1944,7 +1850,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1955,7 +1860,6 @@ fn restricted_ed25519_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -2009,7 +1913,6 @@ fn multi_address_sender_already_fulfilled() { None, None, None, - None, ), Basic( 1_000_000, @@ -2019,7 +1922,6 @@ fn multi_address_sender_already_fulfilled() { None, None, None, - None, ), Basic( 1_000_000, @@ -2029,7 +1931,6 @@ fn multi_address_sender_already_fulfilled() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -2040,7 +1941,6 @@ fn multi_address_sender_already_fulfilled() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/expiration.rs b/sdk/tests/client/input_selection/expiration.rs index 08852b876f..f731019f05 100644 --- a/sdk/tests/client/input_selection/expiration.rs +++ b/sdk/tests/client/input_selection/expiration.rs @@ -32,7 +32,6 @@ fn one_output_expiration_not_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -42,7 +41,6 @@ fn one_output_expiration_not_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -69,7 +67,6 @@ fn expiration_equal_timestamp() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -79,7 +76,6 @@ fn expiration_equal_timestamp() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -108,7 +104,6 @@ fn one_output_expiration_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -118,7 +113,6 @@ fn one_output_expiration_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -148,7 +142,6 @@ fn two_outputs_one_expiration_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, ), Basic( 2_000_000, @@ -158,7 +151,6 @@ fn two_outputs_one_expiration_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, ), ]); let outputs = build_outputs([Basic( @@ -169,7 +161,6 @@ fn two_outputs_one_expiration_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -200,7 +191,6 @@ fn two_outputs_one_unexpired_one_missing() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 200)), - None, ), Basic( 2_000_000, @@ -210,7 +200,6 @@ fn two_outputs_one_unexpired_one_missing() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -221,7 +210,6 @@ fn two_outputs_one_unexpired_one_missing() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -252,7 +240,6 @@ fn two_outputs_two_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 100)), - None, ), Basic( 2_000_000, @@ -262,7 +249,6 @@ fn two_outputs_two_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), - None, ), Basic( 2_000_000, @@ -272,7 +258,6 @@ fn two_outputs_two_expired() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -283,7 +268,6 @@ fn two_outputs_two_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -314,7 +298,6 @@ fn two_outputs_two_expired_2() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 100)), - None, ), Basic( 2_000_000, @@ -324,7 +307,6 @@ fn two_outputs_two_expired_2() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 100)), - None, ), ]); let outputs = build_outputs([Basic( @@ -335,7 +317,6 @@ fn two_outputs_two_expired_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -367,7 +348,6 @@ fn expiration_expired_with_sdr() { 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, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -377,7 +357,6 @@ fn expiration_expired_with_sdr() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -406,7 +385,6 @@ fn expiration_expired_with_sdr_2() { 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, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -416,7 +394,6 @@ fn expiration_expired_with_sdr_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -445,7 +422,6 @@ fn expiration_expired_with_sdr_and_timelock() { 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, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -455,7 +431,6 @@ fn expiration_expired_with_sdr_and_timelock() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -484,7 +459,6 @@ fn expiration_expired_with_sdr_and_timelock_2() { 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, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -494,7 +468,6 @@ fn expiration_expired_with_sdr_and_timelock_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -524,7 +497,6 @@ fn sender_in_expiration() { None, None, None, - None, ), Basic( 1_000_000, @@ -534,7 +506,6 @@ fn sender_in_expiration() { None, None, None, - None, ), Basic( 1_000_000, @@ -544,7 +515,6 @@ fn sender_in_expiration() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, ), Basic( 1_000_000, @@ -554,7 +524,6 @@ fn sender_in_expiration() { None, None, None, - None, ), Basic( 1_000_000, @@ -564,7 +533,6 @@ fn sender_in_expiration() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -575,7 +543,6 @@ fn sender_in_expiration() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -608,7 +575,6 @@ fn sender_in_expiration_already_selected() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -618,7 +584,6 @@ fn sender_in_expiration_already_selected() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -651,7 +616,6 @@ fn remainder_in_expiration() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -661,7 +625,6 @@ fn remainder_in_expiration() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -704,7 +667,6 @@ fn expiration_expired_non_ed25519_in_address_unlock_condition() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -714,7 +676,6 @@ fn expiration_expired_non_ed25519_in_address_unlock_condition() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -745,7 +706,6 @@ fn expiration_expired_only_account_addresses() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), 50)), - None, ), Account( 1_000_000, @@ -753,7 +713,6 @@ fn expiration_expired_only_account_addresses() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); @@ -765,7 +724,6 @@ fn expiration_expired_only_account_addresses() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -795,7 +753,6 @@ fn one_nft_output_expiration_unexpired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 150)), - None, )]); let outputs = build_outputs([Nft( 2_000_000, @@ -805,7 +762,6 @@ fn one_nft_output_expiration_unexpired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -835,7 +791,6 @@ fn one_nft_output_expiration_expired() { None, None, Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), 50)), - None, )]); let outputs = build_outputs([Nft( 2_000_000, @@ -845,7 +800,6 @@ fn one_nft_output_expiration_expired() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/foundry_outputs.rs b/sdk/tests/client/input_selection/foundry_outputs.rs index b4ca32e705..58dc54f754 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -39,7 +39,6 @@ fn missing_input_account_for_foundry() { None, None, None, - None, )]); let outputs = build_outputs([Foundry( 1_000_000, @@ -115,7 +114,6 @@ fn minted_native_tokens_in_new_remainder() { None, None, None, - None, ), Account( 1_000_000, @@ -123,7 +121,6 @@ fn minted_native_tokens_in_new_remainder() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Foundry( @@ -171,7 +168,6 @@ fn minted_native_tokens_in_provided_output() { None, None, None, - None, ), Account( 1_000_000, @@ -179,7 +175,6 @@ fn minted_native_tokens_in_provided_output() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([ @@ -198,7 +193,6 @@ fn minted_native_tokens_in_provided_output() { None, None, None, - None, ), ]); @@ -232,7 +226,6 @@ fn melt_native_tokens() { None, None, None, - None, ), Foundry( 1_000_000, @@ -255,7 +248,6 @@ fn melt_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -299,7 +291,6 @@ fn destroy_foundry_with_account_state_transition() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 52_800, @@ -343,7 +334,6 @@ fn destroy_foundry_with_account_burn() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 1_000_000, @@ -361,7 +351,6 @@ fn destroy_foundry_with_account_burn() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -405,7 +394,6 @@ fn prefer_basic_to_foundry() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 1_000_000, @@ -422,7 +410,6 @@ fn prefer_basic_to_foundry() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -433,7 +420,6 @@ fn prefer_basic_to_foundry() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -464,7 +450,6 @@ fn simple_foundry_transition_basic_not_needed() { None, None, None, - None, ), Foundry( 1_000_000, @@ -484,7 +469,6 @@ fn simple_foundry_transition_basic_not_needed() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( @@ -539,7 +523,6 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { None, None, None, - None, ), Foundry( 2_000_000, @@ -559,7 +542,6 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -700,7 +682,6 @@ fn mint_and_burn_at_the_same_time() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( @@ -742,7 +723,6 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { None, None, None, - None, ), Foundry( 1_000_000, @@ -762,7 +742,6 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Basic( 3_200_000, @@ -772,7 +751,6 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -809,7 +787,6 @@ fn create_native_token_but_burn_account() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 1_000_000, @@ -867,7 +844,6 @@ fn melted_tokens_not_provided() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 1_000_000, @@ -916,7 +892,6 @@ fn burned_tokens_not_provided() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), Foundry( 1_000_000, @@ -974,7 +949,6 @@ fn foundry_in_outputs_and_required() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, @@ -1020,7 +994,6 @@ fn melt_and_burn_native_tokens() { None, None, None, - None, ), Foundry( 1_000_000, @@ -1040,7 +1013,6 @@ fn melt_and_burn_native_tokens() { inputs.push(InputSigningData { output: account_output, output_metadata: rand_output_metadata(), - signing_options: None, }); let outputs = build_outputs([Foundry( 1_000_000, diff --git a/sdk/tests/client/input_selection/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index a4702de635..ae8e7ce116 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -38,7 +38,6 @@ fn input_nft_eq_output_nft() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -48,7 +47,6 @@ fn input_nft_eq_output_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -77,7 +75,6 @@ fn transition_nft_id_zero() { None, None, None, - None, )]); let nft_id = NftId::from(inputs[0].output_id()); let outputs = build_outputs([Nft( @@ -88,7 +85,6 @@ fn transition_nft_id_zero() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -205,7 +201,6 @@ fn mint_nft() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -215,7 +210,6 @@ fn mint_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -253,7 +247,6 @@ fn burn_nft() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -263,7 +256,6 @@ fn burn_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -338,7 +330,6 @@ fn missing_input_for_nft_output() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -348,7 +339,6 @@ fn missing_input_for_nft_output() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -378,7 +368,6 @@ fn missing_input_for_nft_output_but_created() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -388,7 +377,6 @@ fn missing_input_for_nft_output_but_created() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -416,7 +404,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), Basic( 1_000_000, @@ -426,7 +413,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([ @@ -438,7 +424,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), Basic( 1_000_000, @@ -448,7 +433,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), ]); @@ -486,7 +470,6 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -496,7 +479,6 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -526,7 +508,6 @@ fn missing_ed25519_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -536,7 +517,6 @@ fn missing_ed25519_issuer_created() { Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -566,7 +546,6 @@ fn missing_ed25519_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -576,7 +555,6 @@ fn missing_ed25519_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -603,7 +581,6 @@ fn missing_account_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -613,7 +590,6 @@ fn missing_account_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -643,7 +619,6 @@ fn missing_account_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -653,7 +628,6 @@ fn missing_account_issuer_created() { Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -683,7 +657,6 @@ fn missing_account_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -693,7 +666,6 @@ fn missing_account_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -720,7 +692,6 @@ fn missing_nft_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -730,7 +701,6 @@ fn missing_nft_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -760,7 +730,6 @@ fn missing_nft_issuer_created() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -770,7 +739,6 @@ fn missing_nft_issuer_created() { Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -800,7 +768,6 @@ fn missing_nft_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -810,7 +777,6 @@ fn missing_nft_issuer_transition() { Some(Address::try_from_bech32(BECH32_ADDRESS_NFT_1).unwrap()), None, None, - None, )]); let selected = InputSelection::new( @@ -838,7 +804,6 @@ fn increase_nft_amount() { None, None, None, - None, ), Basic( 1_000_000, @@ -848,7 +813,6 @@ fn increase_nft_amount() { None, None, None, - None, ), ]); let outputs = build_outputs([Nft( @@ -859,7 +823,6 @@ fn increase_nft_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -889,7 +852,6 @@ fn decrease_nft_amount() { None, None, None, - None, ), Basic( 1_000_000, @@ -899,7 +861,6 @@ fn decrease_nft_amount() { None, None, None, - None, ), ]); let outputs = build_outputs([Nft( @@ -910,7 +871,6 @@ fn decrease_nft_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -952,7 +912,6 @@ fn prefer_basic_to_nft() { None, None, None, - None, ), Basic( 1_000_000, @@ -962,7 +921,6 @@ fn prefer_basic_to_nft() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -973,7 +931,6 @@ fn prefer_basic_to_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1004,7 +961,6 @@ fn take_amount_from_nft_to_fund_basic() { None, None, None, - None, ), Basic( 1_000_000, @@ -1014,7 +970,6 @@ fn take_amount_from_nft_to_fund_basic() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1025,7 +980,6 @@ fn take_amount_from_nft_to_fund_basic() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1068,7 +1022,6 @@ fn nft_burn_should_validate_nft_sender() { None, None, None, - None, ), Nft( 1_000_000, @@ -1078,7 +1031,6 @@ fn nft_burn_should_validate_nft_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1089,7 +1041,6 @@ fn nft_burn_should_validate_nft_sender() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1120,7 +1071,6 @@ fn nft_burn_should_validate_nft_address() { None, None, None, - None, ), Nft( 1_000_000, @@ -1130,7 +1080,6 @@ fn nft_burn_should_validate_nft_address() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1141,7 +1090,6 @@ fn nft_burn_should_validate_nft_address() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1171,7 +1119,6 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1181,7 +1128,6 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1235,10 +1181,9 @@ fn changed_immutable_metadata() { .finish_output() .unwrap(); - let inputs = [InputSigningData:: { + let inputs = [InputSigningData { output: nft_output.clone(), output_metadata: rand_output_metadata(), - signing_options: None, }]; #[cfg(feature = "irc_27")] diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index ab134ccab9..249b51c3e6 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -29,10 +29,9 @@ fn no_inputs() { None, None, None, - None, )]); - let selected = InputSelection::::new( + let selected = InputSelection::new( inputs, outputs, [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], @@ -55,7 +54,6 @@ fn no_outputs() { None, None, None, - None, )]); let outputs = Vec::new(); @@ -81,7 +79,6 @@ fn no_outputs_but_burn() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, )]); let outputs = Vec::new(); @@ -117,7 +114,6 @@ fn no_address_provided() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -127,7 +123,6 @@ fn no_address_provided() { None, None, None, - None, )]); let selected = InputSelection::new(inputs, outputs, [], protocol_parameters).select(); @@ -147,7 +142,6 @@ fn no_matching_address_provided() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -157,7 +151,6 @@ fn no_matching_address_provided() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -184,7 +177,6 @@ fn two_addresses_one_missing() { None, None, None, - None, ), Basic( 1_000_000, @@ -194,7 +186,6 @@ fn two_addresses_one_missing() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -205,7 +196,6 @@ fn two_addresses_one_missing() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -238,7 +228,6 @@ fn two_addresses() { None, None, None, - None, ), Basic( 1_000_000, @@ -248,7 +237,6 @@ fn two_addresses() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -259,7 +247,6 @@ fn two_addresses() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/storage_deposit_return.rs b/sdk/tests/client/input_selection/storage_deposit_return.rs index 5c7ba2b633..8dfb63c8cc 100644 --- a/sdk/tests/client/input_selection/storage_deposit_return.rs +++ b/sdk/tests/client/input_selection/storage_deposit_return.rs @@ -28,7 +28,6 @@ fn sdruc_output_not_provided_no_remainder() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -38,7 +37,6 @@ fn sdruc_output_not_provided_no_remainder() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -77,7 +75,6 @@ fn sdruc_output_provided_no_remainder() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, )]); let outputs = build_outputs([ Basic( @@ -88,7 +85,6 @@ fn sdruc_output_provided_no_remainder() { None, None, None, - None, ), Basic( 1_000_000, @@ -98,7 +94,6 @@ fn sdruc_output_provided_no_remainder() { None, None, None, - None, ), ]); @@ -127,7 +122,6 @@ fn sdruc_output_provided_remainder() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -137,7 +131,6 @@ fn sdruc_output_provided_remainder() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -177,7 +170,6 @@ fn two_sdrucs_to_the_same_address_both_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), Basic( 2_000_000, @@ -187,7 +179,6 @@ fn two_sdrucs_to_the_same_address_both_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -198,7 +189,6 @@ fn two_sdrucs_to_the_same_address_both_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -238,7 +228,6 @@ fn two_sdrucs_to_the_same_address_one_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), Basic( 1_000_000, @@ -248,7 +237,6 @@ fn two_sdrucs_to_the_same_address_one_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -259,7 +247,6 @@ fn two_sdrucs_to_the_same_address_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -300,7 +287,6 @@ fn two_sdrucs_to_different_addresses_both_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), Basic( 2_000_000, @@ -310,7 +296,6 @@ fn two_sdrucs_to_different_addresses_both_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -321,7 +306,6 @@ fn two_sdrucs_to_different_addresses_both_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -367,7 +351,6 @@ fn two_sdrucs_to_different_addresses_one_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, ), Basic( 1_000_000, @@ -377,7 +360,6 @@ fn two_sdrucs_to_different_addresses_one_needed() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -388,7 +370,6 @@ fn two_sdrucs_to_different_addresses_one_needed() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -428,7 +409,6 @@ fn insufficient_amount_because_of_sdruc() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 1_000_000)), None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -438,7 +418,6 @@ fn insufficient_amount_because_of_sdruc() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -471,7 +450,6 @@ fn useless_sdruc_required_for_sender_feature() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), None, None, - None, ), Basic( 1_000_000, @@ -481,7 +459,6 @@ fn useless_sdruc_required_for_sender_feature() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -492,7 +469,6 @@ fn useless_sdruc_required_for_sender_feature() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -536,7 +512,6 @@ fn sdruc_required_non_ed25519_in_address_unlock() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), None, None, - None, ), Account( 1_000_000, @@ -544,7 +519,6 @@ fn sdruc_required_non_ed25519_in_address_unlock() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -555,7 +529,6 @@ fn sdruc_required_non_ed25519_in_address_unlock() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -596,7 +569,6 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), 1_000_000)), None, None, - None, ), Basic( 1_000_000, @@ -606,7 +578,6 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { None, None, None, - None, ), Account( 1_000_000, @@ -614,7 +585,6 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -625,7 +595,6 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/timelock.rs b/sdk/tests/client/input_selection/timelock.rs index 7c27a9bad9..da6f3ffaa7 100644 --- a/sdk/tests/client/input_selection/timelock.rs +++ b/sdk/tests/client/input_selection/timelock.rs @@ -23,7 +23,6 @@ fn one_output_timelock_not_expired() { None, Some(200), None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -33,7 +32,6 @@ fn one_output_timelock_not_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -60,7 +58,6 @@ fn timelock_equal_timestamp() { None, Some(200), None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -70,7 +67,6 @@ fn timelock_equal_timestamp() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -100,7 +96,6 @@ fn two_outputs_one_timelock_expired() { None, Some(200), None, - None, ), Basic( 2_000_000, @@ -110,7 +105,6 @@ fn two_outputs_one_timelock_expired() { None, Some(50), None, - None, ), ]); let outputs = build_outputs([Basic( @@ -121,7 +115,6 @@ fn two_outputs_one_timelock_expired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -152,7 +145,6 @@ fn two_outputs_one_timelocked_one_missing() { None, Some(200), None, - None, ), Basic( 2_000_000, @@ -162,7 +154,6 @@ fn two_outputs_one_timelocked_one_missing() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -173,7 +164,6 @@ fn two_outputs_one_timelocked_one_missing() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -203,7 +193,6 @@ fn one_output_timelock_expired() { None, Some(50), None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -213,7 +202,6 @@ fn one_output_timelock_expired() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_signing_data.rs b/sdk/tests/client/input_signing_data.rs index 11fb0796a4..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,15 +23,10 @@ fn input_signing_data_conversion() { let input_signing_data = InputSigningData { output, output_metadata: rand_output_metadata(), - signing_options: Some(bip44_chain), }; - assert_eq!(input_signing_data.signing_options.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(); + 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.signing_options.as_ref(), Some(&bip44_chain)); } diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index f178b58a60..888b443041 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -17,7 +17,6 @@ mod signing; use std::{collections::HashMap, hash::Hash, str::FromStr}; -use crypto::keys::bip44::Bip44; use iota_sdk::{ client::secret::types::InputSigningData, types::block::{ @@ -64,7 +63,6 @@ enum Build<'a> { Option<(Address, u64)>, Option, Option<(Address, u32)>, - Option, ), Nft( u64, @@ -74,9 +72,8 @@ enum Build<'a> { Option
, Option<(Address, u64)>, Option<(Address, u32)>, - Option, ), - Account(u64, AccountId, Address, Option
, Option
, Option), + Account(u64, AccountId, Address, Option
, Option
), Foundry(u64, AccountId, u32, SimpleTokenScheme, Option<(&'a str, u64)>), } @@ -188,43 +185,39 @@ fn build_foundry_output( builder.finish_output().unwrap() } -fn build_output_inner(build: Build) -> (Output, Option) { +fn build_output_inner(build: Build) -> Output { 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) + Build::Basic(amount, address, native_token, sender, sdruc, timelock, expiration) => { + build_basic_output(amount, address, native_token, sender, sdruc, timelock, expiration) + } + Build::Nft(amount, nft_id, address, sender, issuer, sdruc, expiration) => { + build_nft_output(amount, nft_id, address, sender, issuer, sdruc, expiration) + } + Build::Account(amount, account_id, address, sender, issuer) => { + build_account_output(amount, account_id, address, sender, issuer) + } + Build::Foundry(amount, account_id, serial_number, token_scheme, native_token) => { + build_foundry_output(amount, account_id, serial_number, token_scheme, native_token) } - 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>) -> Vec> { +fn build_inputs<'a>(outputs: impl IntoIterator>) -> Vec { outputs .into_iter() .map(|build| { - let (output, chain) = build_output_inner(build); + let output = build_output_inner(build); InputSigningData { output, output_metadata: rand_output_metadata_with_id(OutputId::new(rand_transaction_id(), 0)), - signing_options: chain, } }) .collect() } fn build_outputs<'a>(outputs: impl IntoIterator>) -> Vec { - outputs.into_iter().map(|build| build_output_inner(build).0).collect() + outputs.into_iter().map(|build| build_output_inner(build)).collect() } fn unsorted_eq(a: &[T], b: &[T]) -> bool diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index 08f3107fda..fb1dc9b946 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -42,16 +42,11 @@ async fn sign_account_state_transition() -> Result<()> { let protocol_parameters = protocol_parameters(); let account_id = AccountId::from_str(ACCOUNT_ID_1)?; - let inputs = build_inputs([Account( - 1_000_000, - account_id, - address.clone(), - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); + let signing_options = Bip44::new(SHIMMER_COIN_TYPE); - let outputs = build_outputs([Account(1_000_000, account_id, address.clone(), None, None, None)]); + let inputs = build_inputs([Account(1_000_000, account_id, address.clone(), None, None)]); + + let outputs = build_outputs([Account(1_000_000, account_id, address.clone(), None, None)]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -71,7 +66,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); @@ -104,22 +99,17 @@ async fn account_reference_unlocks() -> Result<()> { let account_id = AccountId::from_str(ACCOUNT_ID_1)?; let account_address = Address::Account(AccountAddress::new(account_id)); + 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(1_000_000, account_id, address.clone(), None, None), + Basic(1_000_000, account_address.clone(), None, None, None, None, None), + Basic(1_000_000, account_address.clone(), None, None, None, None, None), ]); 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(1_000_000, account_id, address, None, None), + Basic(2_000_000, account_address, None, None, None, None, None), ]); let transaction = Transaction::builder(protocol_parameters.network_id()) @@ -140,7 +130,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 ea135ea3d8..09d726662b 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -34,27 +34,9 @@ async fn single_ed25519_unlock() -> Result<()> { let protocol_parameters = protocol_parameters(); - let inputs = build_inputs([Basic( - 1_000_000, - address_0.clone(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); - - let outputs = build_outputs([Basic( - 1_000_000, - address_0, - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - )]); + let inputs = build_inputs([Basic(1_000_000, address_0.clone(), None, None, None, None, None)]); + + let outputs = build_outputs([Basic(1_000_000, address_0, None, None, None, None, None)]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -73,8 +55,10 @@ async fn single_ed25519_unlock() -> Result<()> { remainder: None, }; + 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); @@ -106,48 +90,12 @@ async fn ed25519_reference_unlocks() -> Result<()> { let protocol_parameters = protocol_parameters(); 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(1_000_000, address_0.clone(), None, None, None, None, None), + Basic(1_000_000, address_0.clone(), None, None, None, None, None), + Basic(1_000_000, address_0.clone(), None, None, None, None, None), ]); - 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(3_000_000, address_0, None, None, None, None, None)]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -166,8 +114,10 @@ async fn ed25519_reference_unlocks() -> Result<()> { remainder: None, }; + 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); @@ -216,38 +166,11 @@ async fn two_signature_unlocks() -> Result<()> { let protocol_parameters = protocol_parameters(); 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(1_000_000, address_0.clone(), None, None, None, None, None), + Basic(1_000_000, address_1, None, None, None, None, None), ]); - 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(2_000_000, address_0, None, None, None, None, None)]); let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs( @@ -266,8 +189,10 @@ async fn two_signature_unlocks() -> Result<()> { remainder: None, }; + 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 eee9ab1d52..bf58102ca0 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -68,72 +68,20 @@ async fn all_combined() -> Result<()> { let nft_4 = Address::Nft(NftAddress::new(nft_id_4)); 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.into(), - 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.into(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE)), - ), - Basic( - 1_000_000, - ed25519_1.into(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(1)), - ), - Basic( - 1_000_000, - ed25519_2.into(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(2)), - ), - Basic( - 1_000_000, - ed25519_2.into(), - None, - None, - None, - None, - None, - Some(Bip44::new(SHIMMER_COIN_TYPE).with_address_index(2)), - ), - Nft( - 1_000_000, - nft_id_1, - ed25519_0.into(), - 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(1_000_000, account_id_1, nft_1.clone(), None, None), + Account(1_000_000, account_id_2, ed25519_0.into(), None, None), + Basic(1_000_000, account_1.clone(), None, None, None, None, None), + Basic(1_000_000, account_2.clone(), None, None, None, None, None), + Basic(1_000_000, account_2, None, None, None, None, None), + Basic(1_000_000, nft_2.clone(), None, None, None, None, None), + Basic(1_000_000, nft_2, None, None, None, None, None), + Basic(1_000_000, nft_4.clone(), None, None, None, None, None), + Basic(1_000_000, ed25519_0.into(), None, None, None, None, None), + Basic(1_000_000, ed25519_1.into(), None, None, None, None, None), + Basic(1_000_000, ed25519_2.into(), None, None, None, None, None), + Basic(1_000_000, ed25519_2.into(), None, None, None, None, None), + Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None), + Nft(1_000_000, nft_id_2, account_1.clone(), None, None, None, None), // Expirations Basic( 2_000_000, @@ -143,7 +91,6 @@ async fn all_combined() -> Result<()> { None, None, Some((account_1.clone(), 50)), - None, ), Basic( 2_000_000, @@ -153,7 +100,6 @@ async fn all_combined() -> Result<()> { None, None, Some((nft_3.clone(), 50)), - None, ), Basic( 2_000_000, @@ -163,7 +109,6 @@ async fn all_combined() -> Result<()> { None, None, Some((nft_3.clone(), 150)), - Some(Bip44::new(SHIMMER_COIN_TYPE)), ), Nft( 1_000_000, @@ -173,28 +118,18 @@ async fn all_combined() -> Result<()> { None, None, Some((nft_4, 50)), - None, - ), - Nft( - 1_000_000, - nft_id_4, - account_1, - None, - None, - None, - Some((nft_3, 150)), - None, ), + Nft(1_000_000, nft_id_4, account_1, None, None, None, Some((nft_3, 150))), ]); 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.into(), None, None, None), - Basic(10_000_000, ed25519_0.into(), None, None, None, None, None, None), - Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None, None), - Nft(1_000_000, nft_id_2, ed25519_0.into(), None, None, None, None, None), - Nft(1_000_000, nft_id_3, ed25519_0.into(), None, None, None, None, None), - Nft(1_000_000, nft_id_4, ed25519_0.into(), None, None, None, None, None), + Account(1_000_000, account_id_1, nft_1, None, None), + Account(1_000_000, account_id_2, ed25519_0.into(), None, None), + Basic(10_000_000, ed25519_0.into(), None, None, None, None, None), + Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None), + Nft(1_000_000, nft_id_2, ed25519_0.into(), None, None, None, None), + Nft(1_000_000, nft_id_3, ed25519_0.into(), None, None, None, None), + Nft(1_000_000, nft_id_4, ed25519_0.into(), None, None, None, None), ]); let slot_index = SlotIndex::from(100); @@ -228,8 +163,10 @@ async fn all_combined() -> Result<()> { remainder: None, }; + 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 53b184474b..ed1370f613 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -44,23 +44,14 @@ async fn nft_reference_unlocks() -> Result<()> { let nft_address = Address::Nft(NftAddress::new(nft_id)); 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(1_000_000, nft_id, address_0.clone(), None, None, None, None), + Basic(1_000_000, nft_address.clone(), None, None, None, None, None), + Basic(1_000_000, nft_address.clone(), None, None, None, None, None), ]); 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(1_000_000, nft_id, address_0, None, None, None, None), + Basic(2_000_000, nft_address, None, None, None, None, None), ]); let transaction = Transaction::builder(protocol_parameters.network_id()) @@ -80,8 +71,10 @@ async fn nft_reference_unlocks() -> Result<()> { remainder: None, }; + 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/events.rs b/sdk/tests/wallet/events.rs index 02a027e78f..0495b82189 100644 --- a/sdk/tests/wallet/events.rs +++ b/sdk/tests/wallet/events.rs @@ -27,7 +27,7 @@ use pretty_assertions::assert_eq; const ED25519_ADDRESS: &str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649"; const TRANSACTION_ID: &str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000"; -fn assert_serde_eq(event_0: WalletEvent<()>) { +fn assert_serde_eq(event_0: WalletEvent) { let json = serde_json::to_string(&event_0).unwrap(); let event_1 = serde_json::from_str(&json).unwrap(); @@ -52,7 +52,6 @@ fn wallet_events_serde() { address: Address::Ed25519(Ed25519Address::new([0; Ed25519Address::LENGTH])), network_id: 42, remainder: true, - signing_options: None, }; assert_serde_eq(WalletEvent::NewOutput(Box::new(NewOutputEvent { From 8eebdef60bbff18d7c231fd6f2a65b53dd3de092 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Thu, 7 Dec 2023 12:47:43 -0500 Subject: [PATCH 04/24] overhaul --- bindings/core/src/lib.rs | 6 +- .../core/src/method_handler/call_method.rs | 6 +- bindings/core/src/method_handler/wallet.rs | 7 +- bindings/nodejs/src/wallet.rs | 6 +- bindings/python/src/wallet.rs | 2 +- bindings/wasm/src/wallet.rs | 5 +- cli/src/cli.rs | 8 +- cli/src/main.rs | 4 +- cli/src/wallet_cli/mod.rs | 2 +- sdk/examples/how_tos/account/create.rs | 3 +- sdk/examples/how_tos/account/destroy.rs | 3 +- .../account/implicit_account_creation.rs | 4 +- .../how_tos/account_wallet/request_funds.rs | 3 +- .../how_tos/account_wallet/transaction.rs | 6 +- .../accounts_and_addresses/check_balance.rs | 3 +- .../consolidate_outputs.rs | 2 + .../accounts_and_addresses/create_wallet.rs | 4 +- .../accounts_and_addresses/list_outputs.rs | 3 +- .../list_transactions.rs | 2 + .../advanced_transaction.rs | 2 + .../claim_transaction.rs | 2 + .../send_micro_transaction.rs | 2 + sdk/examples/how_tos/native_tokens/burn.rs | 2 + sdk/examples/how_tos/native_tokens/create.rs | 2 + .../how_tos/native_tokens/destroy_foundry.rs | 3 +- sdk/examples/how_tos/native_tokens/melt.rs | 3 +- sdk/examples/how_tos/native_tokens/mint.rs | 3 +- sdk/examples/how_tos/native_tokens/send.rs | 2 + .../nft_collection/00_mint_issuer_nft.rs | 2 + .../nft_collection/01_mint_collection_nft.rs | 2 + sdk/examples/how_tos/nfts/burn_nft.rs | 3 +- sdk/examples/how_tos/nfts/mint_nft.rs | 2 + sdk/examples/how_tos/nfts/send_nft.rs | 2 + .../simple_transaction/request_funds.rs | 7 +- .../simple_transaction/simple_transaction.rs | 3 +- .../wallet/17_check_unlock_conditions.rs | 2 + sdk/examples/wallet/background_syncing.rs | 4 +- sdk/examples/wallet/events.rs | 4 +- sdk/examples/wallet/getting_started.rs | 4 +- sdk/examples/wallet/ledger_nano.rs | 4 +- sdk/examples/wallet/logger.rs | 4 +- .../offline_signing/0_generate_address.rs | 6 +- .../offline_signing/1_prepare_transaction.rs | 4 +- sdk/examples/wallet/participation.rs | 3 +- sdk/examples/wallet/spammer.rs | 10 +- sdk/examples/wallet/storage.rs | 6 +- sdk/examples/wallet/wallet.rs | 10 +- sdk/src/lib.rs | 4 +- sdk/src/wallet/core/builder.rs | 466 ++++++++++++++---- sdk/src/wallet/core/mod.rs | 189 +++---- .../core/operations/address_generation.rs | 2 +- .../core/operations/background_syncing.rs | 7 +- sdk/src/wallet/core/operations/client.rs | 11 +- sdk/src/wallet/core/operations/storage.rs | 39 +- sdk/src/wallet/core/operations/stronghold.rs | 30 +- .../core/operations/stronghold_backup/mod.rs | 23 +- .../stronghold_backup/stronghold_snapshot.rs | 24 +- sdk/src/wallet/operations/balance.rs | 6 +- sdk/src/wallet/operations/block.rs | 9 +- sdk/src/wallet/operations/output_claiming.rs | 10 +- .../wallet/operations/output_consolidation.rs | 9 +- .../wallet/operations/participation/event.rs | 2 +- .../wallet/operations/participation/mod.rs | 4 +- .../wallet/operations/participation/voting.rs | 34 +- .../operations/participation/voting_power.rs | 39 +- sdk/src/wallet/operations/reissue.rs | 14 +- .../addresses/output_ids/account_foundry.rs | 2 +- .../syncing/addresses/output_ids/basic.rs | 2 +- .../syncing/addresses/output_ids/mod.rs | 7 +- .../syncing/addresses/output_ids/nft.rs | 2 +- .../operations/syncing/addresses/outputs.rs | 15 +- .../wallet/operations/syncing/foundries.rs | 2 +- sdk/src/wallet/operations/syncing/mod.rs | 4 +- sdk/src/wallet/operations/syncing/outputs.rs | 2 +- .../wallet/operations/syncing/transactions.rs | 23 +- .../wallet/operations/transaction/account.rs | 7 +- .../transaction/build_transaction.rs | 2 +- .../burning_melting/melt_native_token.rs | 5 +- .../high_level/burning_melting/mod.rs | 6 +- .../transaction/high_level/create_account.rs | 5 +- .../high_level/minting/create_native_token.rs | 5 +- .../high_level/minting/mint_native_token.rs | 8 +- .../high_level/minting/mint_nfts.rs | 5 +- .../operations/transaction/high_level/send.rs | 5 +- .../high_level/send_native_tokens.rs | 5 +- .../transaction/high_level/send_nft.rs | 5 +- .../operations/transaction/input_selection.rs | 6 +- sdk/src/wallet/operations/transaction/mod.rs | 5 +- .../operations/transaction/prepare_output.rs | 2 +- .../transaction/prepare_transaction.rs | 2 +- .../transaction/sign_transaction.rs | 18 +- .../transaction/submit_transaction.rs | 4 +- sdk/src/wallet/storage/manager.rs | 52 +- sdk/src/wallet/update.rs | 20 +- sdk/tests/wallet/address_generation.rs | 16 +- sdk/tests/wallet/backup_restore.rs | 4 +- sdk/tests/wallet/burn_outputs.rs | 6 +- sdk/tests/wallet/common/mod.rs | 14 +- sdk/tests/wallet/core.rs | 8 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 4 +- 100 files changed, 814 insertions(+), 568 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index d589a5fead..2c2dd4e9db 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -17,7 +17,7 @@ pub use iota_sdk; use iota_sdk::{ client::secret::{SecretManager, SecretManagerDto}, types::block::address::Bech32Address, - wallet::{ClientOptions, Wallet}, + wallet::{core::SecretData, ClientOptions, Wallet, WalletBuilder}, }; use serde::Deserialize; @@ -91,9 +91,9 @@ 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_public_key_options(self.public_key_options) diff --git a/bindings/core/src/method_handler/call_method.rs b/bindings/core/src/method_handler/call_method.rs index 0b20b5789b..134ba9da75 100644 --- a/bindings/core/src/method_handler/call_method.rs +++ b/bindings/core/src/method_handler/call_method.rs @@ -6,7 +6,7 @@ use std::pin::Pin; use futures::Future; use iota_sdk::{ client::{secret::SecretManager, Client}, - wallet::Wallet, + wallet::{core::SecretData, Wallet}, }; use crate::{ @@ -35,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>> { @@ -55,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; diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index a9b9617ea2..a99df5715b 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -11,7 +11,8 @@ use iota_sdk::{ }, types::TryFromDto, wallet::{ - types::TransactionWithMetadataDto, BlockIssuerKeySource, PreparedCreateNativeTokenTransactionDto, Wallet, + core::SecretData, types::TransactionWithMetadataDto, BlockIssuerKeySource, + PreparedCreateNativeTokenTransactionDto, Wallet, }, }; @@ -19,7 +20,7 @@ use crate::{method::WalletMethod, response::Response}; /// Call a wallet method. pub(crate) async fn call_wallet_method_internal( - wallet: &Wallet, + wallet: &Wallet>, method: WalletMethod, ) -> crate::Result { let response = match method { @@ -72,7 +73,7 @@ pub(crate) async fn call_wallet_method_internal( } #[cfg(feature = "ledger_nano")] WalletMethod::GetLedgerNanoStatus => { - let ledger_nano_status = (&*wallet.get_secret_manager().read().await) + let ledger_nano_status = (&*wallet.secret_manager().read().await) .as_ledger_nano()? .get_ledger_nano_status() .await; diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 182854e900..bf3f426ed8 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/src/wallet.rs @@ -7,7 +7,7 @@ use iota_sdk_bindings_core::{ call_wallet_method as rust_call_wallet_method, iota_sdk::{ client::secret::SecretManager, - wallet::{events::WalletEventType, Wallet}, + wallet::{core::SecretData, events::WalletEventType, Wallet}, }, Response, WalletMethod, WalletOptions, }; @@ -17,7 +17,7 @@ use tokio::sync::RwLock; use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHandler, NodejsError}; -pub type WalletMethodHandler = Arc>>>; +pub type WalletMethodHandler = Arc>>>>; #[napi(js_name = "createWallet")] pub async fn create_wallet(options: String) -> Result> { @@ -100,7 +100,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(Error::new( Status::GenericFailure, diff --git a/bindings/python/src/wallet.rs b/bindings/python/src/wallet.rs index 3a5e1ed57e..b5f60be504 100644 --- a/bindings/python/src/wallet.rs +++ b/bindings/python/src/wallet.rs @@ -120,7 +120,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 got destroyed".into())) diff --git a/bindings/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index ed794d02eb..8d6bb9d1fe 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -8,6 +8,7 @@ use iota_sdk_bindings_core::{ iota_sdk::{ client::secret::SecretManager, wallet::{ + core::SecretData, events::types::{WalletEvent, WalletEventType}, Wallet, }, @@ -25,7 +26,7 @@ use crate::{client::ClientMethodHandler, secret_manager::SecretManagerMethodHand /// The Wallet method handler. #[wasm_bindgen(js_name = WalletMethodHandler)] pub struct WalletMethodHandler { - wallet: Arc>>>, + wallet: Arc>>>>, } /// Creates a method handler with the given options. @@ -69,7 +70,7 @@ pub async fn get_secret_manager(method_handler: &WalletMethodHandler) -> Result< .await .as_ref() .ok_or_else(|| "wallet got destroyed".to_string())? - .get_secret_manager() + .secret_manager() .clone(); Ok(SecretManagerMethodHandler { secret_manager }) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index c9d6b3ca99..9b6fb22945 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -13,7 +13,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::ClientOptions, + wallet::{ClientOptions, WalletBuilder}, }; use log::LevelFilter; @@ -291,7 +291,7 @@ pub async fn init_command( .with_address_index(bip.address_index) }); - Ok(Wallet::builder() + 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")) @@ -332,7 +332,7 @@ pub async fn node_info_command(storage_path: &Path) -> Result { pub async fn restore_command(storage_path: &Path, snapshot_path: &Path, backup_path: &Path) -> Result { check_file_exists(backup_path).await?; - let mut builder = Wallet::builder(); + let mut builder = WalletBuilder::new().with_secret_type(); if check_file_exists(snapshot_path).await.is_ok() { println!( "Detected a stronghold file at {}. Enter password to unlock:", @@ -400,7 +400,7 @@ pub async fn unlock_wallet( None }; - let maybe_wallet = Wallet::builder() + let maybe_wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(storage_path.to_str().expect("invalid unicode")) .finish() diff --git a/cli/src/main.rs b/cli/src/main.rs index d8e4d83401..73e938f11f 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -8,7 +8,7 @@ mod wallet_cli; use clap::Parser; use fern_logger::{LoggerConfigBuilder, LoggerOutputConfigBuilder}; -use iota_sdk::client::secret::stronghold::StrongholdSecretManager; +use iota_sdk::{client::secret::stronghold::StrongholdSecretManager, wallet::core::SecretData}; use log::LevelFilter; use self::{ @@ -16,7 +16,7 @@ use self::{ error::Error, }; -pub type Wallet = iota_sdk::wallet::Wallet; +pub type Wallet = iota_sdk::wallet::Wallet>; #[macro_export] macro_rules! println_log_info { diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 5f31a51288..6e4ab55887 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -1016,7 +1016,7 @@ async fn print_wallet_address(wallet: &Wallet) -> Result<(), Error> { } } - let bip_path = wallet.data().await.signing_options().clone(); + let bip_path = wallet.signing_options().clone(); log = format!("{log}\nBIP path: {bip_path:?}"); log = format!( diff --git a/sdk/examples/how_tos/account/create.rs b/sdk/examples/how_tos/account/create.rs index a9d44a25ca..cf50f18822 100644 --- a/sdk/examples/how_tos/account/create.rs +++ b/sdk/examples/how_tos/account/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/destroy.rs b/sdk/examples/how_tos/account/destroy.rs index 20930776f6..c6b1a2f561 100644 --- a/sdk/examples/how_tos/account/destroy.rs +++ b/sdk/examples/how_tos/account/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/implicit_account_creation.rs b/sdk/examples/how_tos/account/implicit_account_creation.rs index e14ed9fb92..720bf930e1 100644 --- a/sdk/examples/how_tos/account/implicit_account_creation.rs +++ b/sdk/examples/how_tos/account/implicit_account_creation.rs @@ -14,7 +14,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManager}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -25,7 +25,7 @@ async fn main() -> Result<()> { 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") diff --git a/sdk/examples/how_tos/account_wallet/request_funds.rs b/sdk/examples/how_tos/account_wallet/request_funds.rs index 2604143aea..cedd9e84a5 100644 --- a/sdk/examples/how_tos/account_wallet/request_funds.rs +++ b/sdk/examples/how_tos/account_wallet/request_funds.rs @@ -7,7 +7,7 @@ //! `cargo run --release --all-features --example account_wallet_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, @@ -26,6 +26,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_wallet/transaction.rs b/sdk/examples/how_tos/account_wallet/transaction.rs index a6183ef651..e937c3ecea 100644 --- a/sdk/examples/how_tos/account_wallet/transaction.rs +++ b/sdk/examples/how_tos/account_wallet/transaction.rs @@ -7,7 +7,10 @@ //! `cargo run --release --all-features --example account_wallet_transaction` use iota_sdk::{ - client::node_api::indexer::query_parameters::BasicOutputQueryParameters, + client::{ + node_api::indexer::query_parameters::BasicOutputQueryParameters, + secret::{stronghold::StrongholdSecretManager, SecretManager}, + }, types::block::address::{AccountAddress, ToBech32Ext}, wallet::{AccountSyncOptions, Result, SyncOptions, TransactionOptions}, Wallet, @@ -32,6 +35,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/accounts_and_addresses/check_balance.rs b/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs index 6cfda4f7a1..cffdf2a962 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/check_balance.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/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/accounts_and_addresses/consolidate_outputs.rs b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs index 6280965836..7b6b238901 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs @@ -13,6 +13,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, types::block::address::ToBech32Ext, wallet::{ConsolidationParams, Result}, Wallet, @@ -30,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/accounts_and_addresses/create_wallet.rs b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs index 2c719e6ee3..993eb0c021 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs @@ -16,7 +16,7 @@ use iota_sdk::{ secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManager}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -48,7 +48,7 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; // Create the wallet - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) diff --git a/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs b/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs index 08b416c09f..62306048c1 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/list_outputs.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/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<()> { @@ -21,6 +21,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/accounts_and_addresses/list_transactions.rs b/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs index 3b416eabad..0e7f41bd35 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/list_transactions.rs @@ -9,6 +9,7 @@ //! ``` use iota_sdk::{ + client::secret::SecretManager, wallet::{Result, SyncOptions}, Wallet, }; @@ -24,6 +25,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/advanced_transactions/advanced_transaction.rs b/sdk/examples/how_tos/advanced_transactions/advanced_transaction.rs index 6b07de8487..ee4e58b3d1 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 6e8a8a60f3..41b44c11a4 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 80b50eae56..04a058f4d6 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 42e2a3773e..4b50dc78e5 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 467162c741..03db46d979 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 3304548b9d..37565c5542 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 779beda4fe..bad1480f5a 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 44ed6db3ab..2da22d3fa9 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 5e765bd153..392edaafca 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 2a0e5bca56..c22c1143c4 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::{stronghold::StrongholdSecretManager, SecretManager}, types::block::{ output::{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 914897800e..a481383c8b 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::{feature::Irc27Metadata, NftId}, @@ -44,6 +45,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 227a777063..fa31d7be81 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 10264f07c9..92ea359535 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, 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 ba4b29d288..c61cf0650c 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/simple_transaction/request_funds.rs b/sdk/examples/how_tos/simple_transaction/request_funds.rs index 13a0de5254..71448d930e 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 9990e6843e..673bbd30a7 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/wallet/17_check_unlock_conditions.rs b/sdk/examples/wallet/17_check_unlock_conditions.rs index dda853bc04..fa902694f4 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, @@ -30,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/wallet/background_syncing.rs b/sdk/examples/wallet/background_syncing.rs index 4abf8f1aac..6aa8ebf860 100644 --- a/sdk/examples/wallet/background_syncing.rs +++ b/sdk/examples/wallet/background_syncing.rs @@ -15,7 +15,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -30,7 +30,7 @@ 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() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) diff --git a/sdk/examples/wallet/events.rs b/sdk/examples/wallet/events.rs index ed0435e274..0feab0a067 100644 --- a/sdk/examples/wallet/events.rs +++ b/sdk/examples/wallet/events.rs @@ -19,7 +19,7 @@ use iota_sdk::{ 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,7 +40,7 @@ async fn main() -> Result<()> { let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) diff --git a/sdk/examples/wallet/getting_started.rs b/sdk/examples/wallet/getting_started.rs index 7f4b5cc154..bf41adec67 100644 --- a/sdk/examples/wallet/getting_started.rs +++ b/sdk/examples/wallet/getting_started.rs @@ -14,7 +14,7 @@ use iota_sdk::{ secret::{stronghold::StrongholdSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -36,7 +36,7 @@ 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() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_storage_path("getting-started-db") diff --git a/sdk/examples/wallet/ledger_nano.rs b/sdk/examples/wallet/ledger_nano.rs index bda465d466..7ffeba5d6d 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -24,7 +24,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::{Ed25519Address, ToBech32Ext}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; // The address to send coins to @@ -43,7 +43,7 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = std::sync::Arc::new(LedgerSecretManager::new(true)); - let wallet = Wallet::builder() + 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) diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index 578af986ac..9197d65f82 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -15,7 +15,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::Ed25519Address, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -42,7 +42,7 @@ async fn main() -> Result<()> { let secret_manager = std::sync::Arc::new(MnemonicSecretManager::try_from_mnemonic( std::env::var("MNEMONIC").unwrap(), )?); - let wallet = Wallet::builder() + 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) diff --git a/sdk/examples/wallet/offline_signing/0_generate_address.rs b/sdk/examples/wallet/offline_signing/0_generate_address.rs index a1d574c747..ca6701bff0 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -14,7 +14,7 @@ use iota_sdk::{ 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,7 +43,7 @@ async fn main() -> Result<()> { secret_manager.store_mnemonic(mnemonic).await?; // Create the wallet with the secret_manager and client options - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(OFFLINE_WALLET_DB_PATH) .with_client_options(offline_client) @@ -57,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 7971cc4ee2..4fcb84fe84 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -15,7 +15,7 @@ use iota_sdk::{ secret::SecretManager, }, crypto::keys::bip44::Bip44, - wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet}, + wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet, WalletBuilder}, }; use serde::Serialize; @@ -45,7 +45,7 @@ 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() + let wallet = WalletBuilder::new() .with_secret_manager(SecretManager::Placeholder) .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) diff --git a/sdk/examples/wallet/participation.rs b/sdk/examples/wallet/participation.rs index 190ff79462..83fefe3c40 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 e497f3af21..488656d5f2 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -20,7 +20,7 @@ use iota_sdk::{ 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. @@ -52,7 +52,7 @@ async fn main() -> Result<()> { .await? .to_bech32_unchecked("smr"); - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) @@ -156,8 +156,8 @@ async fn main() -> Result<()> { Ok(()) } -async fn ensure_enough_funds( - wallet: &Wallet, +async fn ensure_enough_funds( + wallet: &Wallet, bech32_address: &Bech32Address, ) -> Result<()> { let balance = wallet.sync(None).await?; @@ -201,7 +201,7 @@ async fn ensure_enough_funds( } async fn wait_for_inclusion( - wallet: &Wallet, + wallet: &Wallet>, transaction_id: &TransactionId, ) -> Result<()> { println!( diff --git a/sdk/examples/wallet/storage.rs b/sdk/examples/wallet/storage.rs index 9cdf963007..a624b096d4 100644 --- a/sdk/examples/wallet/storage.rs +++ b/sdk/examples/wallet/storage.rs @@ -14,7 +14,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManage}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; #[tokio::main] @@ -30,7 +30,7 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let wallet = Wallet::builder() + let wallet = WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) @@ -49,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 a5c2973091..4a4268aade 100644 --- a/sdk/examples/wallet/wallet.rs +++ b/sdk/examples/wallet/wallet.rs @@ -21,7 +21,7 @@ use iota_sdk::{ 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 @@ -53,10 +53,10 @@ 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() + WalletBuilder::new() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) @@ -66,7 +66,7 @@ async fn create_wallet() -> Result> { .await } -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()); @@ -79,7 +79,7 @@ async fn sync_print_balance(wallet: &Wallet, full_ } async fn wait_for_inclusion( - wallet: &Wallet, + wallet: &Wallet>, transaction_id: &TransactionId, ) -> Result<()> { println!( diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index ce004f33d2..97cfe39c79 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -28,5 +28,7 @@ pub use crypto; pub use packable; pub use primitive_types::U256; +use crate::wallet::core::SecretData; + #[cfg(feature = "wallet")] -pub type Wallet = self::wallet::Wallet; +pub type Wallet = self::wallet::Wallet>; diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index c9b3ef6d48..e18f48583a 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -15,66 +15,48 @@ use crate::wallet::storage::adapter::memory::Memory; #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::secret::{SecretManage, SecretManager, SecretManagerConfig}, + client::secret::{SecretManage, SecretManagerConfig}, types::block::address::{Bech32Address, Ed25519Address, ToBech32Ext}, wallet::{ - core::{WalletData, WalletInner}, + core::{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) public_key_options: Option, - pub(crate) signing_options: 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 { public_key_options: Default::default(), signing_options: Default::default(), - address: Default::default(), - alias: Default::default(), - client_options: Default::default(), - #[cfg(feature = "storage")] - storage_options: Default::default(), secret_manager: Default::default(), } } } -impl WalletBuilder { - /// 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 public key options. - pub fn with_public_key_options(mut self, public_key_options: impl Into>) -> Self { - self.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.signing_options = signing_options.into(); - self - } - +impl WalletBuilder { /// Set the wallet address. pub fn with_address(mut self, address: impl Into>) -> Self { self.address = address.into(); @@ -101,37 +83,222 @@ impl WalletBuilder { 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: &str) -> 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, + storage_options: self.storage_options, + } + } + + /// Set the public key options. + pub fn with_public_key_options( + mut 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( + mut 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( + mut 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( + mut 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: &str) -> 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 mut 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?; + + #[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")] + 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?; + + // Build the wallet. + let wallet_inner = WalletInner { + default_sync_options: Mutex::new(SyncOptions::default()), + last_synced: Mutex::new(0), + background_syncing_status: AtomicUsize::new(0), + client, + #[cfg(feature = "events")] + event_emitter, + #[cfg(feature = "storage")] + storage_options, + #[cfg(feature = "storage")] + storage_manager: tokio::sync::RwLock::new(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(self.bip_path, 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 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")] @@ -153,7 +320,7 @@ where let mut 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; @@ -171,20 +338,39 @@ 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()); + } + + #[cfg(feature = "storage")] + let secret_data = storage_manager.load_secret_data::().await?; - self.secret_manager = secret_manager; + // The public key options must not change. + #[cfg(feature = "storage")] + if let Some(secret_data) = &secret_data { + let old = &secret_data.public_key_options; + if let Some(new) = self.secret_data.public_key_options.as_ref() { + if new != old { + return Err(crate::wallet::Error::PublicKeyOptionsMismatch { + new: serde_json::to_value(new)?, + old: serde_json::to_value(old)?, + }); + } + } else { + self.secret_data.public_key_options = Some(old.clone()); + } } - // May use previously stored options if they weren't provided - if self.public_key_options.is_none() { - self.public_key_options = loaded_wallet_builder + // 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.public_key_options.clone()); + .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 @@ -201,7 +387,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 { @@ -212,23 +398,7 @@ where let address = self.address.as_ref().unwrap().clone(); #[cfg(feature = "storage")] - let mut wallet_data = storage_manager.load_wallet_data::().await?; - - // The public key options must not change. - #[cfg(feature = "storage")] - if let Some(wallet_data) = &wallet_data { - let old = &wallet_data.public_key_options; - if let Some(new) = self.public_key_options.as_ref() { - if new != old { - return Err(crate::wallet::Error::PublicKeyOptionsMismatch { - new: serde_json::to_value(new)?, - old: serde_json::to_value(old)?, - }); - } - } else { - self.public_key_options = Some(old.clone()); - } - } + let mut wallet_data = storage_manager.load_wallet_data().await?; // Store the wallet builder (for convenience reasons) #[cfg(feature = "storage")] @@ -258,7 +428,6 @@ where last_synced: Mutex::new(0), background_syncing_status: AtomicUsize::new(0), client, - secret_manager: self.secret_manager.expect("make WalletInner::secret_manager optional?"), #[cfg(feature = "events")] event_emitter, #[cfg(feature = "storage")] @@ -269,20 +438,27 @@ where #[cfg(feature = "storage")] let wallet_data = match wallet_data { Some(d) => d, - None => WalletData::new( - self.public_key_options - .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, - self.signing_options - .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, - address, - self.alias.clone(), - ), + 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 = Wallet { inner: Arc::new(wallet_inner), data: Arc::new(RwLock::new(wallet_data)), + secret_data: SecretData { + public_key_options: self + .secret_data + .public_key_options + .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, + signing_options: self + .secret_data + .signing_options + .ok_or(crate::wallet::Error::MissingParameter("public_key_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. @@ -303,10 +479,11 @@ where .network_info .protocol_parameters .bech32_hrp; - let options = self.public_key_options.as_ref().unwrap(); + let options = self.secret_data.public_key_options.as_ref().unwrap(); Ok(Ed25519Address::from_public_key_bytes( - self.secret_manager + self.secret_data + .secret_manager .as_ref() .unwrap() .read() @@ -317,21 +494,72 @@ where ) .to_bech32(bech32_hrp)) } +} +impl WalletBuilder { #[cfg(feature = "storage")] - pub(crate) async fn from_wallet(wallet: &Wallet) -> Self + pub(crate) async fn from_wallet(wallet: &Wallet) -> Self where - S::GenerationOptions: Clone, - S::SigningOptions: Clone, + Wallet: BuilderFrom, { - Self { - public_key_options: Some(wallet.data().await.public_key_options.clone()), - signing_options: Some(wallet.data().await.signing_options.clone()), - 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()), + BuilderFrom::from(wallet).await + } +} + +#[async_trait::async_trait] +pub trait BuilderFrom { + type Builder; + + async fn from(&self) -> Self::Builder; +} + +#[cfg(feature = "storage")] +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.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), + storage_options: Some(self.storage_options.clone()), + secret_data: BuilderFrom::from(&self.secret_data).await, + } } } } @@ -339,7 +567,7 @@ where // Check if any of the locked inputs is not used in a transaction and unlock them, so they get available for new // transactions #[cfg(feature = "storage")] -fn unlock_unused_inputs(wallet_data: &mut WalletData) -> crate::wallet::Result<()> { +fn unlock_unused_inputs(wallet_data: &mut WalletData) -> crate::wallet::Result<()> { log::debug!("[unlock_unused_inputs]"); let mut used_inputs = HashSet::new(); for transaction_id in &wallet_data.pending_transactions { @@ -369,11 +597,9 @@ pub(crate) mod dto { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] - pub struct WalletBuilderDto { - #[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, + 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")] @@ -385,22 +611,39 @@ 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 { 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>, @@ -409,7 +652,16 @@ pub(crate) mod dto { where D: serde::Deserializer<'de>, { - WalletBuilderDto::::deserialize(d).map(Into::into) + 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) } } } diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index ea47dba06e..587f3276f3 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -37,39 +37,50 @@ use crate::{ }; /// The stateful wallet used to interact with an IOTA network. +#[derive(Debug, Clone)] +pub struct Wallet { + pub(crate) inner: Arc, + pub(crate) data: Arc>, + pub(crate) secret_data: T, +} + #[derive(Debug)] -pub struct Wallet { - pub(crate) inner: Arc>, - pub(crate) data: Arc>>, +pub struct SecretData { + /// The public key generation options. + pub(crate) public_key_options: S::GenerationOptions, + /// 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 { +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 @@ -78,7 +89,7 @@ pub struct WalletInner { // 0 = not running, 1 = running, 2 = stopping pub(crate) background_syncing_status: AtomicUsize, pub(crate) client: Client, - pub(crate) secret_manager: Arc>, + #[cfg(feature = "events")] pub(crate) event_emitter: tokio::sync::RwLock, #[cfg(feature = "storage")] @@ -88,11 +99,8 @@ pub struct WalletInner { } /// Wallet data. -pub struct WalletData { - /// The public key generation options. - pub(crate) public_key_options: S::GenerationOptions, - /// The signing options for transactions and blocks. - pub(crate) signing_options: S::SigningOptions, +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct WalletData { /// The wallet address. pub(crate) address: Bech32Address, /// The wallet alias. @@ -125,16 +133,9 @@ pub struct WalletData { pub(crate) native_token_foundries: HashMap, } -impl WalletData { - pub(crate) fn new( - public_key_options: S::GenerationOptions, - signing_options: S::SigningOptions, - address: Bech32Address, - alias: Option, - ) -> Self { +impl WalletData { + pub(crate) fn new(address: Bech32Address, alias: Option) -> Self { Self { - public_key_options, - signing_options, address, alias, outputs: HashMap::new(), @@ -228,16 +229,6 @@ impl WalletData { }) } - /// Returns the public key options. - pub fn public_key_options(&self) -> &S::GenerationOptions { - &self.public_key_options - } - - /// Returns the signing options. - pub fn signing_options(&self) -> &S::SigningOptions { - &self.signing_options - } - /// Returns outputs map of the wallet. pub fn outputs(&self) -> &HashMap { &self.outputs @@ -351,66 +342,9 @@ impl WalletData { } } -impl PartialEq for WalletData { - fn eq(&self, other: &Self) -> bool { - self.public_key_options == other.public_key_options - && self.signing_options == other.signing_options - && self.address == other.address - && self.alias == other.alias - && self.outputs == other.outputs - && self.locked_outputs == other.locked_outputs - && self.unspent_outputs == other.unspent_outputs - && self.transactions == other.transactions - && self.pending_transactions == other.pending_transactions - && self.incoming_transactions == other.incoming_transactions - && self.inaccessible_incoming_transactions == other.inaccessible_incoming_transactions - && self.native_token_foundries == other.native_token_foundries - } -} -impl Eq for WalletData {} -impl core::fmt::Debug for WalletData { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("WalletData") - .field("public_key_options", &self.public_key_options) - .field("signing_options", &self.signing_options) - .field("address", &self.address) - .field("alias", &self.alias) - .field("outputs", &self.outputs) - .field("locked_outputs", &self.locked_outputs) - .field("unspent_outputs", &self.unspent_outputs) - .field("transactions", &self.transactions) - .field("pending_transactions", &self.pending_transactions) - .field("incoming_transactions", &self.incoming_transactions) - .field( - "inaccessible_incoming_transactions", - &self.inaccessible_incoming_transactions, - ) - .field("native_token_foundries", &self.native_token_foundries) - .finish() - } -} -impl Clone for WalletData { - fn clone(&self) -> Self { - Self { - public_key_options: self.public_key_options.clone(), - signing_options: self.signing_options.clone(), - address: self.address.clone(), - alias: self.alias.clone(), - outputs: self.outputs.clone(), - locked_outputs: self.locked_outputs.clone(), - unspent_outputs: self.unspent_outputs.clone(), - transactions: self.transactions.clone(), - pending_transactions: self.pending_transactions.clone(), - incoming_transactions: self.incoming_transactions.clone(), - inaccessible_incoming_transactions: self.inaccessible_incoming_transactions.clone(), - native_token_foundries: self.native_token_foundries.clone(), - } - } -} - -impl Wallet { +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 @@ -433,6 +367,7 @@ impl Wallet { Ok(Self { inner, data: Arc::new(RwLock::new(data)), + secret_data, }) } @@ -459,7 +394,7 @@ impl Wallet { /// Save the wallet to the database, accepts the updated wallet data as option so we don't need to drop it before /// saving #[cfg(feature = "storage")] - pub(crate) async fn save(&self, updated_wallet: Option<&WalletData>) -> Result<()> { + pub(crate) async fn save(&self, updated_wallet: Option<&WalletData>) -> Result<()> { log::debug!("[save] wallet data"); match updated_wallet { Some(wallet) => { @@ -483,11 +418,11 @@ impl Wallet { self.inner.emit(wallet_event).await } - pub async fn data(&self) -> tokio::sync::RwLockReadGuard<'_, WalletData> { + pub async fn data(&self) -> tokio::sync::RwLockReadGuard<'_, WalletData> { self.data.read().await } - pub(crate) async fn data_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, WalletData> { + pub(crate) async fn data_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, WalletData> { self.data.write().await } @@ -521,12 +456,22 @@ impl Wallet { } } -impl WalletInner { +impl Wallet> { /// Get the [SecretManager] - pub fn get_secret_manager(&self) -> &Arc> { - &self.secret_manager + pub fn secret_manager(&self) -> &Arc> { + &self.secret_data.secret_manager } + pub fn public_key_options(&self) -> &S::GenerationOptions { + &self.secret_data.public_key_options + } + + 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")))] @@ -574,18 +519,10 @@ impl WalletInner { } } -impl Drop for Wallet { - fn drop(&mut self) { - log::debug!("drop Wallet"); - } -} - /// Dto for the wallet data. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct WalletDataDto { - pub public_key_options: G, - pub signing_options: S, +pub struct WalletDataDto { pub address: Bech32Address, pub alias: Option, pub outputs: HashMap, @@ -598,16 +535,14 @@ pub struct WalletDataDto { pub native_token_foundries: HashMap, } -impl TryFromDto> for WalletData { +impl TryFromDto for WalletData { type Error = crate::wallet::Error; fn try_from_dto_with_params_inner( - dto: WalletDataDto, + dto: WalletDataDto, params: Option<&ProtocolParameters>, ) -> core::result::Result { Ok(Self { - public_key_options: dto.public_key_options, - signing_options: dto.signing_options, address: dto.address, alias: dto.alias, outputs: dto.outputs, @@ -630,15 +565,9 @@ impl TryFromDto From<&WalletData> for WalletDataDto -where - S::GenerationOptions: Clone, - S::SigningOptions: Clone, -{ - fn from(value: &WalletData) -> Self { +impl From<&WalletData> for WalletDataDto { + fn from(value: &WalletData) -> Self { Self { - public_key_options: value.public_key_options.clone(), - signing_options: value.signing_options.clone(), address: value.address.clone(), alias: value.alias.clone(), outputs: value.outputs.clone(), @@ -753,8 +682,6 @@ mod test { ); let wallet_data = WalletData { - public_key_options: PublicKeyOptions::new(4218), - signing_options: Bip44::new(4218), address: crate::types::block::address::Bech32Address::from_str( "rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy", ) @@ -770,18 +697,16 @@ mod test { native_token_foundries: HashMap::new(), }; - let deser_wallet_data = WalletData::::try_from_dto( - serde_json::from_str::>( - &serde_json::to_string(&WalletDataDto::from(&wallet_data)).unwrap(), - ) - .unwrap(), + let deser_wallet_data = WalletData::try_from_dto( + serde_json::from_str::(&serde_json::to_string(&WalletDataDto::from(&wallet_data)).unwrap()) + .unwrap(), ) .unwrap(); assert_eq!(wallet_data, deser_wallet_data); } - impl> WalletData { + impl WalletData { /// Returns a mock of this type with the following values: /// index: 0, coin_type: 4218, alias: "Alice", address: /// rms1qpllaj0pyveqfkwxmnngz2c488hfdtmfrj3wfkgxtk4gtyrax0jaxzt70zy, all other fields are set to their Rust @@ -789,8 +714,6 @@ mod test { #[cfg(feature = "storage")] pub(crate) fn mock() -> Self { Self { - public_key_options: PublicKeyOptions::new(4218), - signing_options: 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 1e237f318f..2700e93c2b 100644 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ b/sdk/src/wallet/core/operations/address_generation.rs @@ -12,7 +12,7 @@ // wallet::events::types::{AddressData, WalletEvent}, // }; -// impl Wallet { +// impl Wallet { // /// Generate an address without storing it // /// ```ignore // /// let public_addresses = wallet diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index fb1dcc7c66..9a68dcb284 100644 --- a/sdk/src/wallet/core/operations/background_syncing.rs +++ b/sdk/src/wallet/core/operations/background_syncing.rs @@ -5,15 +5,12 @@ use std::{sync::atomic::Ordering, time::Duration}; use tokio::time::sleep; -use crate::{ - client::secret::SecretManage, - wallet::{operations::syncing::SyncOptions, Wallet}, -}; +use crate::wallet::{operations::syncing::SyncOptions, Wallet}; /// The default interval for background syncing pub(crate) const DEFAULT_BACKGROUNDSYNCING_INTERVAL: Duration = Duration::from_secs(7); -impl Wallet { +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 e193b774fa..a3f6f8b142 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet}; +use serde::Serialize; use url::Url; use crate::{ @@ -11,13 +12,12 @@ use crate::{ builder::NodeManagerBuilder, node::{Node, NodeAuth, NodeDto}, }, - secret::{SecretManage, SecretManagerConfig}, Client, ClientBuilder, }, - wallet::{Wallet, WalletBuilder}, + wallet::{core::builder::BuilderFrom, Wallet, WalletBuilder}, }; -impl Wallet { +impl Wallet { pub fn client(&self) -> &Client { &self.client } @@ -27,7 +27,10 @@ impl Wallet { } } -impl Wallet { +impl Wallet +where + T::Builder: Send + Sync + Serialize, +{ pub async fn set_client_options(&self, client_options: ClientBuilder) -> crate::wallet::Result<()> { let ClientBuilder { node_manager_builder, diff --git a/sdk/src/wallet/core/operations/storage.rs b/sdk/src/wallet/core/operations/storage.rs index dad5e85b7f..b0036ce8e8 100644 --- a/sdk/src/wallet/core/operations/storage.rs +++ b/sdk/src/wallet/core/operations/storage.rs @@ -1,49 +1,34 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use serde::{de::DeserializeOwned, Serialize}; + use crate::{ - client::{secret::SecretManagerConfig, storage::StorageAdapter}, - wallet::{ - core::builder::dto::WalletBuilderDto, - storage::constants::{SECRET_MANAGER_KEY, WALLET_BUILDER_KEY}, - WalletBuilder, - }, + client::storage::StorageAdapter, + wallet::{core::builder::dto::WalletBuilderDto, storage::constants::WALLET_BUILDER_KEY, WalletBuilder}, }; -impl 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?; - - 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(()) } - pub(crate) async fn load( + pub(crate) async fn load( storage: &impl StorageAdapter, - ) -> crate::wallet::Result> { + ) -> crate::wallet::Result> + where + T: From, + { log::debug!("[load] wallet builder"); - if let Some(wallet_builder_dto) = storage - .get::>(WALLET_BUILDER_KEY) - .await? - { + 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:?}"); - - Ok(Some(Self::from(wallet_builder_dto).with_secret_manager( - secret_manager_dto.map(|dto| S::from_config(&dto)).transpose()?, - ))) + Ok(Some(Self::from(wallet_builder_dto))) } else { Ok(None) } diff --git a/sdk/src/wallet/core/operations/stronghold.rs b/sdk/src/wallet/core/operations/stronghold.rs index 79dd195669..1b634f5ed3 100644 --- a/sdk/src/wallet/core/operations/stronghold.rs +++ b/sdk/src/wallet/core/operations/stronghold.rs @@ -7,16 +7,16 @@ use crypto::keys::bip39::Mnemonic; use crate::{ client::{secret::SecretManager, stronghold::StrongholdAdapter, utils::Password}, - wallet::Wallet, + wallet::{core::SecretData, Wallet}, }; // TODO: Remove these and just use the secret manager directly -impl Wallet { +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 { @@ -33,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(()) @@ -44,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 { @@ -54,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 { @@ -65,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 { @@ -76,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()) @@ -84,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. @@ -96,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(()) @@ -104,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 523935e45c..99506b9426 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -14,10 +14,10 @@ use crate::{ 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,7 +28,7 @@ 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).as_stronghold() { // Backup with existing stronghold @@ -81,7 +81,7 @@ impl Wallet { let mut wallet_data = self.data.write().await; - let mut secret_manager = self.secret_manager.as_ref().write().await; + let mut secret_manager = self.secret_manager().as_ref().write().await; // Get the current snapshot path if set let new_snapshot_path = if let Ok(stronghold) = (&*secret_manager).as_stronghold() { stronghold.snapshot_path.clone() @@ -94,16 +94,16 @@ impl Wallet { .password(stronghold_password.clone()) .build(backup_path.clone())?; - let (loaded_client_options, loaded_secret_manager_config, loaded_wallet_data) = + let (loaded_client_options, loaded_secret_manager_config, loaded_wallet_data, loaded_secret_data) = read_wallet_data_from_stronghold_snapshot::(&new_stronghold).await?; - let loaded_pub_key_opts = loaded_wallet_data.as_ref().map(|data| &data.public_key_options); + let loaded_pub_key_opts = loaded_secret_data.as_ref().map(|data| &data.public_key_options); // 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? - loaded_pub_key_opts.is_some_and(|opts| &wallet_data.public_key_options != opts) + loaded_pub_key_opts.is_some_and(|opts| self.public_key_options() != opts) } else { false } @@ -111,7 +111,8 @@ impl Wallet { if !ignore_backup_values { if let Some(opts) = loaded_pub_key_opts { - wallet_data.public_key_options = opts.clone(); + // TODO + // self.secret_data.public_key_options = opts.clone(); } } @@ -163,7 +164,7 @@ impl Wallet { #[cfg(feature = "storage")] { 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 @@ -174,8 +175,8 @@ impl Wallet { .expect("can't convert os string"), ) .with_client_options(self.client_options().await) - .with_public_key_options(self.data().await.public_key_options.clone()) - .with_signing_options(self.data().await.signing_options.clone()); + .with_public_key_options(self.public_key_options().clone()) + .with_signing_options(self.signing_options().clone()); wallet_builder.save(&*self.storage_manager.read().await).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 ad9cd80d48..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 @@ -64,10 +69,17 @@ pub(crate) async fn read_wallet_data_from_stronghold_snapshot>(WALLET_DATA_KEY) + .get::(WALLET_DATA_KEY) .await? .map(WalletData::try_from_dto) .transpose()?; - Ok((client_options, restored_secret_manager, restored_wallet_data)) + let restored_secret_data = todo!(); + + Ok(( + client_options, + restored_secret_manager, + restored_wallet_data, + restored_secret_data, + )) } diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index b269acce17..3d3112cc04 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -16,7 +16,7 @@ use crate::{ }, }; -impl Wallet { +impl Wallet { /// Get the balance of the wallet. pub async fn balance(&self) -> Result { log::debug!("[BALANCE] balance"); @@ -29,7 +29,7 @@ impl Wallet { async fn balance_inner( &self, // addresses_with_unspent_outputs: impl Iterator + Send, - wallet_data: &WalletData, + wallet_data: &WalletData, ) -> Result { let network_id = self.client().get_network_id().await?; let storage_score_params = self.client().get_storage_score_parameters().await?; @@ -248,7 +248,7 @@ impl Wallet { fn finish( &self, mut balance: Balance, - wallet_data: &WalletData, + wallet_data: &WalletData, network_id: u64, total_storage_cost: u64, total_native_tokens: NativeTokensBuilder, diff --git a/sdk/src/wallet/operations/block.rs b/sdk/src/wallet/operations/block.rs index 3327508d39..bcf85520e3 100644 --- a/sdk/src/wallet/operations/block.rs +++ b/sdk/src/wallet/operations/block.rs @@ -4,10 +4,10 @@ use crate::{ client::secret::{BlockSignExt, SecretManage}, types::block::{output::AccountId, payload::Payload, BlockId}, - wallet::{Result, Wallet}, + wallet::{core::SecretData, Result, Wallet}, }; -impl Wallet { +impl Wallet> { pub(crate) async fn submit_basic_block( &self, payload: Option, @@ -22,10 +22,7 @@ impl Wallet { .client() .build_basic_block(issuer_id, payload) .await? - .sign_ed25519( - &*self.get_secret_manager().read().await, - &self.data().await.signing_options, - ) + .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 2e887bc1f4..d86f056846 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -19,7 +19,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, @@ -37,7 +37,7 @@ pub enum OutputsToClaim { All, } -impl WalletData { +impl WalletData { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`] or @@ -125,7 +125,7 @@ impl WalletData { } } -impl Wallet { +impl Wallet { /// Get basic and nft outputs that have /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), /// [`StorageDepositReturnUnlockCondition`] or @@ -174,7 +174,9 @@ impl Wallet { 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>( @@ -213,7 +215,9 @@ impl Wallet { ); 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 2de51f570c..dd51ef18df 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -15,6 +15,7 @@ use crate::{ }, wallet::{ constants::DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD, + core::SecretData, operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, Result, Wallet, @@ -65,7 +66,7 @@ impl ConsolidationParams { } } -impl Wallet { +impl Wallet { fn should_consolidate_output( &self, output_data: &OutputData, @@ -94,7 +95,9 @@ impl Wallet { false }) } +} +impl Wallet> { /// Consolidates basic outputs with only an [AddressUnlockCondition] 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 @@ -149,7 +152,7 @@ impl Wallet { None => { #[cfg(feature = "ledger_nano")] { - let secret_manager = self.secret_manager.read().await; + let secret_manager = self.secret_manager().read().await; if (&*secret_manager).as_ledger_nano().is_ok() { DEFAULT_LEDGER_OUTPUT_CONSOLIDATION_THRESHOLD } else { @@ -176,7 +179,7 @@ impl Wallet { #[cfg(feature = "ledger_nano")] let max_inputs = { - let secret_manager = self.secret_manager.read().await; + 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; // With blind signing we are only limited by the protocol diff --git a/sdk/src/wallet/operations/participation/event.rs b/sdk/src/wallet/operations/participation/event.rs index 6bea5f81cf..21862b3ddd 100644 --- a/sdk/src/wallet/operations/participation/event.rs +++ b/sdk/src/wallet/operations/participation/event.rs @@ -14,7 +14,7 @@ use crate::{ }, }; -impl Wallet { +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 28690f3380..800385668e 100644 --- a/sdk/src/wallet/operations/participation/mod.rs +++ b/sdk/src/wallet/operations/participation/mod.rs @@ -46,7 +46,7 @@ pub struct ParticipationEventWithNodes { pub nodes: Vec, } -impl Wallet { +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( @@ -273,7 +273,7 @@ impl Wallet { } } -impl WalletData { +impl WalletData { /// Returns the voting output ("PARTICIPATION" tag). /// /// If multiple outputs with this tag exist, the one with the largest amount will be returned. diff --git a/sdk/src/wallet/operations/participation/voting.rs b/sdk/src/wallet/operations/participation/voting.rs index cb7a62ead5..65e86f8e36 100644 --- a/sdk/src/wallet/operations/participation/voting.rs +++ b/sdk/src/wallet/operations/participation/voting.rs @@ -13,10 +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 { +impl Wallet> { /// Casts a given number of votes for a given (voting) event. /// /// If voting for other events, continues voting for them. @@ -39,7 +41,23 @@ impl Wallet { 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, @@ -118,18 +136,6 @@ impl Wallet { .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 cca6c50b4a..722b5a1c40 100644 --- a/sdk/src/wallet/operations/participation/voting_power.rs +++ b/sdk/src/wallet/operations/participation/voting_power.rs @@ -14,10 +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 { +impl Wallet> { /// Returns an account's total voting power (voting or NOT voting). pub async fn get_voting_power(&self) -> Result { Ok(self @@ -43,6 +46,23 @@ impl Wallet { 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? { @@ -76,21 +96,6 @@ impl Wallet { 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 186186cd89..7eec5af561 100644 --- a/sdk/src/wallet/operations/reissue.rs +++ b/sdk/src/wallet/operations/reissue.rs @@ -13,13 +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 { +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( @@ -57,10 +57,7 @@ impl Wallet { Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? - .sign_ed25519( - &*self.get_secret_manager().read().await, - &self.data().await.signing_options, - ) + .sign_ed25519(&*self.secret_manager().read().await, self.signing_options()) .await? .id(&protocol_parameters), }; @@ -105,10 +102,7 @@ impl Wallet { Some(Payload::SignedTransaction(Box::new(transaction.payload.clone()))), ) .await? - .sign_ed25519( - &*self.get_secret_manager().read().await, - &self.data().await.signing_options, - ) + .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 4ae451adf0..59b13a7646 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 @@ -19,7 +19,7 @@ use crate::{ wallet::{operations::syncing::SyncOptions, task, Wallet}, }; -impl Wallet { +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 1213cd2b4f..ee94d49f7a 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/basic.rs @@ -8,7 +8,7 @@ use crate::{ wallet::Wallet, }; -impl Wallet { +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 48860984af..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,7 +20,7 @@ use crate::{ }, }; -impl Wallet { +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 bbb566437c..b5c28b5948 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/nft.rs @@ -8,7 +8,7 @@ use crate::{ wallet::Wallet, }; -impl Wallet { +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 a2db37f604..9b0cafca17 100644 --- a/sdk/src/wallet/operations/syncing/addresses/outputs.rs +++ b/sdk/src/wallet/operations/syncing/addresses/outputs.rs @@ -3,17 +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 { +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 839a11ee1a..44bb5f6ce9 100644 --- a/sdk/src/wallet/operations/syncing/foundries.rs +++ b/sdk/src/wallet/operations/syncing/foundries.rs @@ -9,7 +9,7 @@ use crate::{ wallet::{task, Wallet}, }; -impl Wallet { +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 31ff45f093..98eafef0f1 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -23,7 +23,7 @@ use crate::{ }, }; -impl Wallet { +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<()> { @@ -41,7 +41,9 @@ impl Wallet { 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 06aec25554..14f73638a1 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -21,7 +21,7 @@ use crate::{ }, }; -impl Wallet { +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 0f7de427f9..478c3d0e9a 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -19,7 +19,7 @@ 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 { +impl Wallet { /// Sync transactions and reissue them if unconfirmed. Returns the transaction with updated metadata and spent /// 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 @@ -196,14 +196,15 @@ impl Wallet { } drop(wallet_data); - for mut transaction in transactions_to_reissue { - log::debug!("[SYNC] reissue transaction"); - let reissued_block = self - .submit_signed_transaction(transaction.payload.clone(), None) - .await?; - transaction.block_id.replace(reissued_block); - updated_transactions.push(transaction); - } + // TODO: this is a problem + // for mut transaction in transactions_to_reissue { + // log::debug!("[SYNC] reissue transaction"); + // let reissued_block = self + // .submit_signed_transaction(transaction.payload.clone(), None) + // .await?; + // transaction.block_id.replace(reissued_block); + // updated_transactions.push(transaction); + // } // updates account with balances, output ids, outputs self.update_with_transactions(updated_transactions, spent_output_ids, output_ids_to_unlock) @@ -233,8 +234,8 @@ fn updated_transaction_and_outputs( // When a transaction got pruned, the inputs and outputs are also not available, then this could mean that it was // confirmed and the created outputs got also already spent and pruned or the inputs got spent in another transaction -fn process_transaction_with_unknown_state( - wallet_data: &WalletData, +fn process_transaction_with_unknown_state( + wallet_data: &WalletData, mut transaction: TransactionWithMetadata, updated_transactions: &mut Vec, output_ids_to_unlock: &mut Vec, diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 0732cc1256..ee219e76dc 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -15,12 +15,13 @@ use crate::{ }, }, wallet::{ + core::SecretData, operations::transaction::{TransactionOptions, TransactionWithMetadata}, Error, Result, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Transitions an implicit account to an account. pub async fn implicit_account_transition( &self, @@ -57,12 +58,12 @@ impl Wallet { let key_source = match key_source.into() { Some(key_source) => key_source, - None => BlockIssuerKeySource::Options(self.data().await.public_key_options.clone()), + None => BlockIssuerKeySource::Options(self.public_key_options().clone()), }; let public_key = match key_source { BlockIssuerKeySource::Key(public_key) => public_key, - BlockIssuerKeySource::Options(options) => self.secret_manager.read().await.generate(&options).await?, + BlockIssuerKeySource::Options(options) => self.secret_manager().read().await.generate(&options).await?, }; let account_id = AccountId::from(output_id); diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 3651052793..d9dc3d1378 100644 --- a/sdk/src/wallet/operations/transaction/build_transaction.rs +++ b/sdk/src/wallet/operations/transaction/build_transaction.rs @@ -15,7 +15,7 @@ use crate::{ wallet::{operations::transaction::TransactionOptions, Wallet}, }; -impl Wallet { +impl Wallet { /// Builds the transaction from the selected in and outputs. pub(crate) async fn build_transaction( &self, 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 ee17b2f5d9..8c7454ace2 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,13 +10,14 @@ use crate::{ TokenScheme, }, wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Error, Wallet, }, }; -impl Wallet { +impl Wallet> { /// Melts native tokens. /// /// This happens with the foundry output which minted them, by increasing it's @@ -36,7 +37,9 @@ impl Wallet { 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 1d22610a7b..3dc65168ec 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 @@ -6,12 +6,12 @@ use crate::{ api::{input_selection::Burn, PreparedTransactionData}, secret::SecretManage, }, - wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, + 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, foundries and accounts. /// /// Note that burning **native tokens** doesn't require the foundry output which minted them, but will not increase @@ -27,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, 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 c9adb9cfc5..56a151880c 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -13,6 +13,7 @@ use crate::{ }, utils::serde::option_prefix_hex_bytes, wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::{OutputData, TransactionWithMetadata}, Wallet, @@ -34,7 +35,7 @@ pub struct CreateAccountParams { pub metadata: Option>, } -impl Wallet { +impl Wallet> { /// Creates an account output. /// ```ignore /// let params = CreateAccountParams { @@ -61,7 +62,9 @@ impl Wallet { 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/minting/create_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs index 38d5886117..67b1edefb6 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 @@ -17,6 +17,7 @@ use crate::{ }, }, wallet::{ + core::SecretData, operations::transaction::TransactionOptions, types::{TransactionWithMetadata, TransactionWithMetadataDto}, Wallet, @@ -86,7 +87,7 @@ impl From<&PreparedCreateNativeTokenTransaction> for PreparedCreateNativeTokenTr } } -impl Wallet { +impl Wallet> { /// Creates a new foundry output with minted native tokens. /// /// Calls [Wallet::send_outputs()] internally, the options may define the remainder value strategy or custom inputs. @@ -120,7 +121,9 @@ impl Wallet { 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 87a233f898..b04c11102c 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,10 +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 { +impl Wallet> { /// Mints additional native tokens. /// /// The max supply must not be reached yet. The foundry needs to be @@ -41,7 +43,9 @@ impl Wallet { 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 f120e95ef8..018a85e54d 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, }, @@ -109,7 +110,7 @@ impl MintNftParams { } } -impl Wallet { +impl Wallet> { /// Mints NFTs. /// /// Calls [Wallet::send_outputs()] internally. The options may define the remainder value strategy or custom inputs. @@ -146,7 +147,9 @@ impl Wallet { 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 84f1b4bf5c..7866ce1ba1 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,7 +74,7 @@ impl SendParams { } } -impl Wallet { +impl Wallet> { /// Sends a certain amount of base coins to a single address. /// /// Calls [Wallet::send_with_params()] internally. @@ -120,7 +121,9 @@ impl Wallet { 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 7702871d65..7669e65b11 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,7 +74,7 @@ impl SendNativeTokenParams { } } -impl Wallet { +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 @@ -110,7 +111,9 @@ impl Wallet { 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 820ccbf505..18ce7d5d23 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,7 +43,7 @@ impl SendNftParams { } } -impl Wallet { +impl Wallet> { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) and an /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), so that @@ -78,7 +79,9 @@ impl Wallet { 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/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 82e0b5db39..e6d4b12727 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -21,7 +21,7 @@ use crate::{ }, }; -impl Wallet { +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, @@ -211,8 +211,8 @@ impl Wallet { /// | [Address, StorageDepositReturn, ...] | no | /// | [Address, StorageDepositReturn, expired Expiration] | yes | #[allow(clippy::too_many_arguments)] -fn filter_inputs( - wallet_data: &WalletData, +fn filter_inputs( + wallet_data: &WalletData, available_outputs: Values<'_, OutputId, OutputData>, slot_index: SlotIndex, custom_inputs: Option<&HashSet>, diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 574f4d8c6b..16dced0a62 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -29,12 +29,13 @@ use crate::{ }, }, wallet::{ + core::SecretData, types::{InclusionState, TransactionWithMetadata}, Wallet, }, }; -impl Wallet { +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 @@ -194,7 +195,9 @@ impl Wallet { 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 758b87c6fe..85c282d1a1 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -27,7 +27,7 @@ use crate::{ }, }; -impl Wallet { +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 dfde411a99..98c25f381d 100644 --- a/sdk/src/wallet/operations/transaction/prepare_transaction.rs +++ b/sdk/src/wallet/operations/transaction/prepare_transaction.rs @@ -18,7 +18,7 @@ use crate::{ }, }; -impl Wallet { +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 f8a5b2008d..a5470fb692 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -1,12 +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}, -}; - #[cfg(feature = "events")] use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ @@ -16,10 +10,10 @@ use crate::{ }, secret::SecretManage, }, - wallet::{operations::transaction::SignedTransactionPayload, Wallet}, + wallet::{core::SecretData, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet { +impl Wallet> { /// Signs a transaction. pub async fn sign_transaction( &self, @@ -70,14 +64,10 @@ impl Wallet { 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, - self.data().await.signing_options(), - ) + .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 fab7ac0ee7..9135ffeb23 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -6,10 +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 { +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 470f8ce964..dde6019356 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -7,7 +7,7 @@ use crate::{ client::{secret::SecretManage, storage::StorageAdapter}, types::TryFromDto, wallet::{ - core::{WalletData, WalletDataDto}, + core::{SecretData, WalletData, WalletDataDto}, migration::migrate, operations::syncing::SyncOptions, storage::{constants::*, DynStorageAdapter, Storage}, @@ -49,22 +49,27 @@ impl StorageManager { Ok(storage_manager) } - pub(crate) async fn load_wallet_data(&mut self) -> crate::wallet::Result>> { - if let Some(dto) = self - .get::>(WALLET_DATA_KEY) - .await? - { + pub(crate) async fn load_wallet_data(&mut self) -> crate::wallet::Result> { + if let Some(dto) = self.get::(WALLET_DATA_KEY).await? { Ok(Some(WalletData::try_from_dto(dto)?)) } else { Ok(None) } } - pub(crate) async fn save_wallet_data( + pub(crate) async fn save_wallet_data(&mut self, wallet_data: &WalletData) -> crate::wallet::Result<()> { + self.set(WALLET_DATA_KEY, &WalletDataDto::from(wallet_data)).await + } + + pub(crate) async fn load_secret_data(&mut self) -> crate::wallet::Result>> { + todo!() + } + + pub(crate) async fn save_secret_data( &mut self, - wallet_data: &WalletData, + secret_data: &SecretData, ) -> crate::wallet::Result<()> { - self.set(WALLET_DATA_KEY, &WalletDataDto::from(wallet_data)).await + todo!() } pub(crate) async fn set_default_sync_options(&self, sync_options: &SyncOptions) -> crate::wallet::Result<()> { @@ -102,8 +107,12 @@ mod tests { use super::*; use crate::{ - client::secret::{mnemonic::MnemonicSecretManager, SecretManager}, - wallet::{storage::adapter::memory::Memory, WalletBuilder}, + client::secret::mnemonic::MnemonicSecretManager, + wallet::{ + core::builder::{dto::SecretDataDto, SecretDataBuilder}, + storage::adapter::memory::Memory, + WalletBuilder, + }, }; #[tokio::test] @@ -130,21 +139,12 @@ mod tests { #[tokio::test] async fn save_load_wallet_data() { let mut storage_manager = StorageManager::new(Memory::default(), None).await.unwrap(); - assert!( - storage_manager - .load_wallet_data::() - .await - .unwrap() - .is_none() - ); + assert!(storage_manager.load_wallet_data().await.unwrap().is_none()); - let wallet_data = WalletData::::mock(); + let wallet_data = WalletData::mock(); storage_manager.save_wallet_data(&wallet_data).await.unwrap(); - let wallet = storage_manager - .load_wallet_data::() - .await - .unwrap(); + let wallet = storage_manager.load_wallet_data().await.unwrap(); assert!(matches!(wallet, Some(data) if data.alias == Some("Alice".to_string()))); } @@ -152,17 +152,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/update.rs b/sdk/src/wallet/update.rs index 4e8ed4fbba..2d41e826db 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -3,25 +3,21 @@ use std::collections::HashMap; -use crate::{ - client::secret::{SecretManage, Sign}, - types::block::{ - output::{OutputId, OutputMetadata}, - signature::Ed25519Signature, - }, - wallet::{ - types::{InclusionState, OutputData, TransactionWithMetadata}, - Wallet, - }, -}; #[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::{ + types::block::output::{OutputId, OutputMetadata}, + wallet::{ + types::{InclusionState, OutputData, TransactionWithMetadata}, + Wallet, + }, +}; -impl Wallet { +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/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index fcd39b44d7..18b17f85a2 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -16,7 +16,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt}, }, types::block::address::{Ed25519Address, ToBech32Ext}, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, Wallet, WalletBuilder}, }; use pretty_assertions::assert_eq; @@ -31,7 +31,7 @@ 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() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) @@ -43,7 +43,7 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { } let wallet = wallet_builder.finish().await?; - let address = (*wallet.get_secret_manager().read().await) + let address = (*wallet.secret_manager().read().await) .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) .await?; @@ -73,7 +73,7 @@ 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() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) @@ -84,7 +84,7 @@ async fn wallet_address_generation_stronghold() -> Result<()> { } let wallet = wallet_builder.finish().await?; - let address = (*wallet.get_secret_manager().read().await) + let address = (*wallet.secret_manager().read().await) .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) .await?; @@ -109,7 +109,7 @@ async fn wallet_address_generation_ledger() -> Result<()> { secret_manager.non_interactive = true; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) @@ -121,7 +121,7 @@ async fn wallet_address_generation_ledger() -> Result<()> { } let wallet = wallet_builder.finish().await?; - let address = (*wallet.get_secret_manager().read().await) + let address = (*wallet.secret_manager().read().await) .generate::(&LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE))) .await? .to_bech32(SHIMMER_TESTNET_BECH32_HRP); @@ -149,7 +149,7 @@ async fn wallet_address_generation_ledger() -> Result<()> { }) .await; - let address = (*wallet.get_secret_manager().read().await) + let address = (*wallet.secret_manager().read().await) .generate::( &LedgerOptions::new(PublicKeyOptions::new(IOTA_COIN_TYPE)).with_ledger_nano_prompt(true), ) 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 8973700dae..e1866d9ca2 100644 --- a/sdk/tests/wallet/burn_outputs.rs +++ b/sdk/tests/wallet/burn_outputs.rs @@ -7,7 +7,7 @@ use iota_sdk::{ 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; @@ -177,7 +177,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()); @@ -200,7 +200,7 @@ async fn destroy_foundry(wallet: &Wallet) -> Resul 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 2748476704..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, PublicKeyOptions, SecretManage}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, Client, }, - wallet::{ClientOptions, Result, Wallet}, + wallet::{core::SecretData, ClientOptions, Result, Wallet, WalletBuilder}, }; pub use self::constants::*; @@ -33,13 +33,13 @@ pub(crate) async fn make_wallet( storage_path: &str, mnemonic: Option, node: Option<&str>, -) -> Result> { +) -> 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() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(PublicKeyOptions::new(SHIMMER_COIN_TYPE)) @@ -58,7 +58,7 @@ pub(crate) async fn make_wallet( pub(crate) async fn make_ledger_nano_wallet( storage_path: &str, node: Option<&str>, -) -> Result> { +) -> Result>> { use iota_sdk::client::secret::ledger_nano::{LedgerOptions, LedgerSecretManager}; let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; @@ -66,7 +66,7 @@ pub(crate) async fn make_ledger_nano_wallet( secret_manager.non_interactive = true; #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(LedgerOptions::new(PublicKeyOptions::new(SHIMMER_COIN_TYPE))) @@ -81,7 +81,7 @@ pub(crate) async fn make_ledger_nano_wallet( /// 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 c992feb768..c532cf869b 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -15,7 +15,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::Bech32Address, - wallet::{ClientOptions, Result, Wallet}, + wallet::{ClientOptions, Result, WalletBuilder}, }; use pretty_assertions::assert_eq; use url::Url; @@ -88,7 +88,7 @@ async fn changed_bip_path() -> Result<()> { drop(wallet); - let err = Wallet::builder() + 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)) @@ -105,7 +105,7 @@ async fn changed_bip_path() -> Result<()> { // Building the wallet with the same coin type still works assert!( - Wallet::builder() + WalletBuilder::new() .with_secret_manager(MnemonicSecretManager::try_from_mnemonic(mnemonic,)?) .with_storage_path(storage_path) .finish() @@ -142,7 +142,7 @@ 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() + let mut wallet_builder = WalletBuilder::new() .with_secret_manager(secret_manager) .with_client_options(client_options) .with_public_key_options(PublicKeyOptions::new(IOTA_COIN_TYPE)) 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 70e2ffedfb..820bd82a7d 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -13,7 +13,7 @@ use iota_sdk::{ }, crypto::keys::bip44::Bip44, types::block::address::{Ed25519Address, ToBech32Ext}, - wallet::{ClientOptions, Error as WalletError, Wallet}, + wallet::{ClientOptions, Error as WalletError, Wallet, WalletBuilder}, }; use pretty_assertions::assert_eq; @@ -79,7 +79,7 @@ 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()) From e2cb9a8de98b1237dbe5da78cd30d41e045454f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Mon, 11 Dec 2023 11:25:26 +0100 Subject: [PATCH 05/24] Add wallet_address_generation_custom_secret_manager test --- sdk/tests/wallet/address_generation.rs | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index 18b17f85a2..deca01d055 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -209,3 +209,100 @@ 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_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) +} From 88ba8f7f27f6472c4856122d8d92e388f3c7db1c Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:06:52 -0500 Subject: [PATCH 06/24] Merge secret data with wallet key --- sdk/src/wallet/core/builder.rs | 24 ++++++++++-------------- sdk/src/wallet/storage/manager.rs | 11 ----------- sdk/tests/client/addresses.rs | 2 +- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index e889d7e2f1..31c59619f3 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -113,7 +113,7 @@ impl WalletBuilder { /// Set the public key options. pub fn with_public_key_options( - mut self, + self, public_key_options: impl Into>, ) -> WalletBuilder> { self.with_secret_type::().with_public_key_options(public_key_options) @@ -121,7 +121,7 @@ impl WalletBuilder { /// Set the signing options. pub fn with_signing_options( - mut self, + self, signing_options: impl Into>, ) -> WalletBuilder> { self.with_secret_type::().with_signing_options(signing_options) @@ -129,7 +129,7 @@ impl WalletBuilder { /// Set the secret_manager to be used. pub fn with_secret_manager( - mut self, + self, secret_manager: impl Into>, ) -> WalletBuilder> { self.with_secret_type::().with_secret_manager(secret_manager) @@ -138,7 +138,7 @@ impl WalletBuilder { /// 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, + self, secret_manager: impl Into>>>, ) -> WalletBuilder> { self.with_secret_type::().with_secret_manager_arc(secret_manager) @@ -345,22 +345,18 @@ where .and_then(|builder| builder.secret_data.public_key_options.clone()); } - #[cfg(feature = "storage")] - let secret_data = storage_manager.load_secret_data::().await?; - // The public key options must not change. #[cfg(feature = "storage")] - if let Some(secret_data) = &secret_data { - let old = &secret_data.public_key_options; - if let Some(new) = self.secret_data.public_key_options.as_ref() { - if new != old { + 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(new)?, - old: serde_json::to_value(old)?, + 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 = Some(old.clone()); + self.secret_data.public_key_options = secret_data.public_key_options.clone(); } } diff --git a/sdk/src/wallet/storage/manager.rs b/sdk/src/wallet/storage/manager.rs index dde6019356..65e0fcbf4e 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -61,17 +61,6 @@ impl StorageManager { self.set(WALLET_DATA_KEY, &WalletDataDto::from(wallet_data)).await } - pub(crate) async fn load_secret_data(&mut self) -> crate::wallet::Result>> { - todo!() - } - - pub(crate) async fn save_secret_data( - &mut self, - secret_data: &SecretData, - ) -> crate::wallet::Result<()> { - todo!() - } - pub(crate) async fn set_default_sync_options(&self, sync_options: &SyncOptions) -> crate::wallet::Result<()> { let key = format!("{WALLET_DATA_KEY}-{WALLET_SYNC_OPTIONS}"); self.set(&key, &sync_options).await diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index fdd8d8da6d..43ab8abe61 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -148,7 +148,7 @@ async fn mnemonic_address_generation_shimmer() { // account 1 let address = secret_manager - .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE)) + .generate::(&PublicKeyOptions::new(SHIMMER_COIN_TYPE).with_account_index(1)) .await .unwrap() .to_bech32(SHIMMER_BECH32_HRP); From 3587c9807f30a9d15b3fee7c05992a44de201f52 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:08:31 -0500 Subject: [PATCH 07/24] fix no_std --- sdk/src/lib.rs | 4 +--- sdk/src/types/block/semantic/mod.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 97cfe39c79..f19de056f8 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -28,7 +28,5 @@ pub use crypto; pub use packable; pub use primitive_types::U256; -use crate::wallet::core::SecretData; - #[cfg(feature = "wallet")] -pub type Wallet = self::wallet::Wallet>; +pub type Wallet = self::wallet::Wallet>; diff --git a/sdk/src/types/block/semantic/mod.rs b/sdk/src/types/block/semantic/mod.rs index 109915b869..1bfe4b98d5 100644 --- a/sdk/src/types/block/semantic/mod.rs +++ b/sdk/src/types/block/semantic/mod.rs @@ -17,7 +17,7 @@ pub use self::{ use crate::types::block::{ address::Address, output::{AccountId, AnchorOutput, ChainId, FoundryId, NativeTokens, Output, OutputId, TokenId}, - payload::signed_transaction::{Transaction, TransactionCapabilityFlag, TransactionSigningHash}, + payload::signed_transaction::{Transaction, TransactionSigningHash}, protocol::ProtocolParameters, unlock::Unlock, Error, From 7c2814cbd4e62c7a82f6bda27da590ecdd0c1893 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:11:17 -0500 Subject: [PATCH 08/24] docs --- sdk/src/client/stronghold/secret.rs | 2 +- sdk/src/wallet/core/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index cc6445f3ce..31a137b7d8 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -1,7 +1,7 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//! The [SecretManage] implementation for [StrongholdAdapter]. +//! The secret implementations for [StrongholdAdapter]. use core::{borrow::Borrow, time::Duration}; diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 88ee2d62e3..7c9c7840af 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -459,7 +459,7 @@ impl Wallet { } impl Wallet> { - /// Get the [SecretManager] + /// Gets the secret manager. pub fn secret_manager(&self) -> &Arc> { &self.secret_data.secret_manager } From fa21f9f0b7e34ac810718254ae450e7d06895421 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:13:45 -0500 Subject: [PATCH 09/24] fix feature sets --- sdk/src/client/secret/manager.rs | 6 ++---- sdk/src/client/secret/mod.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sdk/src/client/secret/manager.rs b/sdk/src/client/secret/manager.rs index 120a03feb0..01caf6ce73 100644 --- a/sdk/src/client/secret/manager.rs +++ b/sdk/src/client/secret/manager.rs @@ -19,13 +19,11 @@ 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; +use crate::client::secret::{stronghold::StrongholdSecretManager, types::StrongholdDto}; use crate::{ client::{ secret::{ - mnemonic::MnemonicSecretManager, - types::{EvmSignature, StrongholdDto}, - Generate, SecretManagerConfig, Sign, SignTransaction, + mnemonic::MnemonicSecretManager, types::EvmSignature, Generate, SecretManagerConfig, Sign, SignTransaction, }, Error, }, diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index e9f0e70953..a398dcc2ee 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -46,7 +46,7 @@ use crate::{ Error, }, types::block::{ - address::{Address, AnchorAddress, Ed25519Address}, + address::Address, core::UnsignedBlock, output::Output, payload::SignedTransactionPayload, From 4791224bab2177071ebd54fae6b27756a23357ba Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:15:06 -0500 Subject: [PATCH 10/24] fix merge --- bindings/core/src/method_handler/secret_manager.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 611f9514ed..8f475ee6f8 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -119,14 +119,7 @@ pub(crate) async fn call_secret_manager_method_internal( } #[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 } }; From bf813824e61ccaffd22bbb46b4da7fed33079e7c Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:32:16 -0500 Subject: [PATCH 11/24] feature gate --- sdk/src/wallet/core/builder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 31c59619f3..b6c325c1cc 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -107,6 +107,7 @@ impl WalletBuilder { address: self.address, alias: self.alias, client_options: self.client_options, + #[cfg(feature = "storage")] storage_options: self.storage_options, } } From 44914cff0cbf1b2967a891b3e37fe815dcd4af8d Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:36:25 -0500 Subject: [PATCH 12/24] more features --- sdk/src/wallet/core/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index b6c325c1cc..d7f639f337 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -277,7 +277,7 @@ impl WalletBuilder { 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)), @@ -441,7 +441,7 @@ where 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)), From fa04b0561d23721bcb4d2c3356b7171f6e9217eb Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:38:50 -0500 Subject: [PATCH 13/24] wasm --- bindings/core/src/method_handler/secret_manager.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 8f475ee6f8..0a505cc7d2 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crypto::signatures::secp256k1_ecdsa::EvmAddress; -#[cfg(feature = "stronghold")] -use iota_sdk::client::secret::SecretManager; use iota_sdk::{ client::{ api::PreparedTransactionData, - secret::{types::EvmSignature, BlockSignExt, DowncastSecretManager, Generate, Sign, SignTransaction}, + secret::{ + types::EvmSignature, BlockSignExt, DowncastSecretManager, Generate, SecretManager, Sign, SignTransaction, + }, }, types::{ block::{ From e8e901312ccaaa6f083420c995a6000934e45e72 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 14:49:30 -0500 Subject: [PATCH 14/24] fix more gates --- sdk/src/wallet/core/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index d7f639f337..ef601680c5 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -513,7 +513,6 @@ pub trait BuilderFrom { async fn from(&self) -> Self::Builder; } -#[cfg(feature = "storage")] mod builder_from { use async_trait::async_trait; @@ -557,6 +556,7 @@ mod builder_from { 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, } From ff8d5972c69164f437f13e3e557cd0c3ba4661f5 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 15:03:39 -0500 Subject: [PATCH 15/24] fix address generation --- sdk/src/client/secret/mnemonic.rs | 2 ++ sdk/src/client/stronghold/secret.rs | 2 ++ sdk/tests/client/addresses.rs | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index 2289f9f497..6cd18dc079 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -42,6 +42,7 @@ impl Generate for MnemonicSecretManager { 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 @@ -104,6 +105,7 @@ impl Generate for MnemonicSecretManager { 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 diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index 31a137b7d8..edde0b9add 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -56,6 +56,7 @@ impl Generate for StrongholdAdapter { 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( @@ -198,6 +199,7 @@ impl Generate for StrongholdAdapter { 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( diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index 43ab8abe61..e87320fb88 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -112,7 +112,7 @@ async fn mnemonic_address_generation_iota() { // account 1 let address = secret_manager - .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE)) + .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_account_index(1)) .await .unwrap() .to_bech32(IOTA_BECH32_HRP); From e67f74aacd06a36eb65993c2deae89e21354c845 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 15:36:01 -0500 Subject: [PATCH 16/24] fix some more tests --- bindings/core/src/method/secret_manager.rs | 47 ++++++++++++---------- bindings/core/tests/secrets_debug.rs | 2 +- sdk/src/wallet/core/builder.rs | 4 +- sdk/tests/wallet/address_generation.rs | 4 +- sdk/tests/wallet/core.rs | 18 ++++----- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index dec4fbba09..8150919868 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -40,6 +40,7 @@ pub enum SecretManagerMethod { 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, @@ -47,6 +48,7 @@ pub enum SecretManagerMethod { 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, @@ -89,14 +91,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(), @@ -104,20 +108,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(), @@ -125,20 +129,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(), @@ -146,11 +151,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/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/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index ef601680c5..bb5ddd8acd 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -449,11 +449,11 @@ where public_key_options: self .secret_data .public_key_options - .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, + .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, signing_options: self .secret_data .signing_options - .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, + .ok_or(crate::wallet::Error::MissingParameter("signing_options"))?, secret_manager: self .secret_data .secret_manager diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index deca01d055..9fe1cce9fe 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -286,8 +286,10 @@ async fn wallet_address_generation_custom_secret_manager() -> Result<()> { let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; #[allow(unused_mut)] - let mut wallet_builder = Wallet::::builder() + 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")] diff --git a/sdk/tests/wallet/core.rs b/sdk/tests/wallet/core.rs index c532cf869b..f26cab0b8d 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -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()); @@ -104,14 +104,14 @@ async fn changed_bip_path() -> Result<()> { )); // Building the wallet with the same coin type still works - assert!( - WalletBuilder::new() - .with_secret_manager(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) } From 10af7c55b9f0b203edf30d4d654060dd9287f361 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 10 Jan 2024 15:56:39 -0500 Subject: [PATCH 17/24] fix address search --- sdk/tests/client/addresses.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index e87320fb88..32ea7244a7 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -239,8 +239,6 @@ async fn address_generation() { #[tokio::test] async fn address_search() -> Result<()> { - let client = Client::builder().finish().await.unwrap(); - let secret_manager = MnemonicSecretManager::try_from_mnemonic(generate_mnemonic()?)?; // Public @@ -255,7 +253,11 @@ async fn address_search() -> Result<()> { // Internal let address = secret_manager - .generate::(&PublicKeyOptions::new(IOTA_COIN_TYPE).with_address_index(9)) + .generate::( + &PublicKeyOptions::new(IOTA_COIN_TYPE) + .with_address_index(9) + .with_internal(true), + ) .await?; let res = search_address(&secret_manager, IOTA_BECH32_HRP, IOTA_COIN_TYPE, 0, 0..10, &address).await?; From 9b8a7f6de2decca8791eb57c098ae23398dca12f Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Mon, 22 Jan 2024 09:14:25 -0500 Subject: [PATCH 18/24] make tests easier to understand --- .../client/input_selection/account_outputs.rs | 1046 ++++----- .../client/input_selection/basic_outputs.rs | 1874 +++++++++-------- .../client/input_selection/expiration.rs | 824 ++++---- .../client/input_selection/foundry_outputs.rs | 696 +++--- .../client/input_selection/nft_outputs.rs | 971 +++++---- sdk/tests/client/input_selection/outputs.rs | 231 +- .../input_selection/storage_deposit_return.rs | 550 ++--- sdk/tests/client/input_selection/timelock.rs | 216 +- sdk/tests/client/mod.rs | 300 +-- sdk/tests/client/signing/account.rs | 62 +- sdk/tests/client/signing/basic.rs | 90 +- sdk/tests/client/signing/mod.rs | 284 ++- sdk/tests/client/signing/nft.rs | 50 +- 13 files changed, 3776 insertions(+), 3418 deletions(-) diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index 2bf2e0858f..937a70f2d3 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -26,22 +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, - )], + [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, - )]); + 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(), @@ -63,23 +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, - )], + [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, - )]); + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -235,24 +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, - )], + [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, - )]); + 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(), @@ -283,24 +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, - )], + [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, - )]); + 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(), @@ -368,24 +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, - )], + [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, - )]); + 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, @@ -410,32 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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, @@ -458,24 +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, - )], + [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, - )]); + 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, @@ -496,37 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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( @@ -549,22 +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, - )], + [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, - )]); + 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, @@ -587,24 +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, - )], + [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()), - )]); + 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, @@ -627,22 +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()), - )], + [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()), - )]); + 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, @@ -662,22 +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, - )], + [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, - )]); + 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, @@ -700,24 +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, - )], + [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()), - )]); + 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, @@ -740,22 +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()), - )], + [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()), - )]); + 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, @@ -775,22 +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, - )], + [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, - )]); + 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, @@ -813,24 +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, - )], + [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()), - )]); + 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, @@ -853,22 +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()), - )], + [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()), - )]); + 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, @@ -889,32 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -937,32 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -997,34 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1048,34 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1113,34 +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, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1176,34 +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, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1238,24 +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, - )], + [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, - )]); + 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(), @@ -1294,32 +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, - ), - Account( - 2_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1362,24 +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, - )], + [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, - )]); + 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(), @@ -1402,32 +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, - )], + [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, - ), - 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, - ), + 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( @@ -1451,22 +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, - )], + [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, - )]); + 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(), @@ -1489,22 +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, - )], + [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, - )]); + 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 f4a7742be7..46035ea8ea 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -25,26 +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, - )], + [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, - )]); + 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(), @@ -65,26 +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, - )], + [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, - )]); + 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, @@ -110,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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, @@ -164,26 +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, - )], + [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, - )]); + 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(), @@ -217,26 +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, - )], + [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, - )]); + 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(), @@ -271,36 +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, - ), - Basic( - 2_000_000, - 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, + }, + 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, - )]); + 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, @@ -335,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -386,36 +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, - ), - Basic( - 1_000_000, - 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, + }, + 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, - )]); + 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(), @@ -437,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -488,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -594,63 +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, - ), - Basic( - 2_000_000, - 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_1).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - 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, - ), + 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, - )]); + 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, @@ -682,26 +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, - )], + [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, - )]); + 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, @@ -725,61 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - ), - Basic( - 2_000_000, - 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, - ), + 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, - )]); + 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, @@ -811,35 +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, - ), - Account( - 1_000_000, - account_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -866,26 +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, - )], + [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, - )]); + 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, @@ -909,63 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - ), - Basic( - 2_000_000, - 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, - ), + 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, - )]); + 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(), @@ -998,37 +998,37 @@ fn nft_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, - ), - Nft( - 1_000_000, - nft_id_0, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1055,26 +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, - )], + [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, - )]); + 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, @@ -1096,26 +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, - )], + [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, - )]); + 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(), @@ -1227,26 +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, - )], + [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, - )]); + 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(), @@ -1267,26 +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, - )], + [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, - )]); + 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, @@ -1312,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1375,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1476,26 +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, - )], + [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, - )]); + 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(), @@ -1520,26 +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, - )], + [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, - )]); + 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(), @@ -1565,29 +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, - ) + 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, - )]); + 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, @@ -1610,44 +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, - ) + 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, - )], + [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, - )]); + 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, @@ -1668,28 +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, - )], + [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, - ) + 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), ); @@ -1714,29 +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, - )], + [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, - ) + 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), ); @@ -1765,55 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - None, - None, - ), - Basic(1_000_000, restricted, None, None, None, None, None), - Basic( - 1_000_000, - 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, - ), + 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, - )]); + 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(), @@ -1839,28 +1839,36 @@ fn restricted_nft() { let inputs = build_inputs( [ - Basic(2_000_000, restricted, 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, - ), + 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, - )]); + 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(), @@ -1886,26 +1894,34 @@ fn restricted_account() { let inputs = build_inputs( [ - Basic(3_000_000, restricted, None, None, None, None, None), - Account( - 2_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1930,63 +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, - ), - Basic( - 2_000_000, - 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_1).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 2_000_000, - 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, - ), + 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, - )]); + 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(), @@ -2033,45 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - None, - None, - None, - None, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - 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, - )]); + 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(), @@ -2104,30 +2120,46 @@ fn ed25519_backed_available_address() { let inputs = build_inputs( [ - Basic(1_000_000, restricted_address.clone(), None, None, None, None, None), - Basic(1_000_000, ed25519.clone(), 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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - Some(restricted_address.clone()), - 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/expiration.rs b/sdk/tests/client/input_selection/expiration.rs index f41d9a3ca6..63e2f627be 100644 --- a/sdk/tests/client/input_selection/expiration.rs +++ b/sdk/tests/client/input_selection/expiration.rs @@ -26,26 +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)), - )], + [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, - )]); + 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, @@ -64,26 +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)), - )], + [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, - )]); + 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(), @@ -104,26 +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)), - )], + [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, - )]); + 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(), @@ -145,36 +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)), - ), - 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)), - ), + 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, - )]); + 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(), @@ -197,36 +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)), - ), - Basic( - 2_000_000, - 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_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, - )]); + 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(), @@ -249,45 +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)), - ), - 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)), - ), - Basic( - 2_000_000, - 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_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, - )]); + 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(), @@ -310,36 +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)), - ), - 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)), - ), + 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, - )]); + 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(), @@ -363,26 +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)), - )], + [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, - )]); + 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(), @@ -403,26 +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)), - )], + [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, - )]); + 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(), @@ -443,26 +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)), - )], + [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, - )]); + 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(), @@ -483,26 +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)), - )], + [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, - )]); + 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(), @@ -524,63 +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, - ), - Basic( - 1_000_000, - 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, - Some((Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), 50)), - ), - Basic( - 1_000_000, - 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, - ), + 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, - )]); + 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(), @@ -605,26 +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)), - )], + [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, - )]); + 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(), @@ -649,26 +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)), - )], + [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, - )]); + 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(), @@ -703,26 +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)), - )], + [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, - )]); + 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(), @@ -745,35 +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)), - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -795,26 +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)), - )], + [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, - )]); + 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(), @@ -836,26 +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)), - )], + [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, - )]); + 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 47cf8ba831..113cc52fcd 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -32,24 +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, - )], + [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, @@ -111,32 +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, - ), - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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(), @@ -169,42 +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, - ), - Account( - 1_000_000, - account_id_2, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - ), + 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( @@ -231,25 +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, - ), - 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), ); @@ -264,14 +264,13 @@ fn melt_native_tokens() { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - 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(), @@ -302,20 +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, - ), - 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), ); @@ -349,32 +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, - ), - 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, - )]); + 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(), @@ -413,41 +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, - ), - 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, - ), + 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, - )]); + 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(), @@ -471,22 +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, - ), - 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), ); @@ -502,13 +501,13 @@ fn simple_foundry_transition_basic_not_needed() { output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - 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(), @@ -548,22 +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, - ), - 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), ); @@ -578,13 +577,13 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - 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(), @@ -702,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) @@ -723,13 +722,13 @@ fn mint_and_burn_at_the_same_time() { output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - 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(), @@ -756,22 +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, - ), - 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), ); @@ -786,15 +785,15 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - let outputs = build_outputs([Basic( - 3_200_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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(), @@ -826,30 +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, - ), - 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(), @@ -887,30 +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, - ), - 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, @@ -939,30 +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, - ), - 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, @@ -989,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) @@ -1009,13 +1008,13 @@ fn foundry_in_outputs_and_required() { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(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.clone(), @@ -1047,22 +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, - ), - 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), ); @@ -1077,14 +1076,13 @@ fn melt_and_burn_native_tokens() { output: account_output, output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), }); - 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/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 0bc3a79e6e..46ab76ac70 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -3,7 +3,6 @@ use std::str::FromStr; -use crypto::keys::bip44::Bip44; use iota_sdk::{ client::{ api::input_selection::{Burn, Error, InputSelection, Requirement}, @@ -31,26 +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, - )], + [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, - )]); + 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(), @@ -72,27 +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, - )], + [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, - )]); + address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + sender: None, + issuer: None, + sdruc: None, + expiration: None, + }]); let selected = InputSelection::new( inputs.clone(), @@ -202,26 +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, - )], + [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, - )]); + 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(), @@ -252,26 +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, - )], + [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, - )]); + 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(), @@ -339,26 +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, - )], + [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, - )]); + 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, @@ -381,26 +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, - )], + [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, - )]); + 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, @@ -421,46 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - ), - 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, - ), + 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( @@ -491,26 +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, - )], + [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, - )]); + 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, @@ -533,26 +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, - )], + [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, - )]); + 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, @@ -575,26 +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, - )], + [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, - )]); + 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, @@ -614,26 +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, - )], + [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, - )]); + 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, @@ -656,26 +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, - )], + [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, - )]); + 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, @@ -698,26 +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, - )], + [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, - )]); + 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, @@ -737,26 +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, - )], + [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, - )]); + 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, @@ -779,26 +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, - )], + [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, - )]); + 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, @@ -821,26 +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, - )], + [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, - )]); + 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, @@ -861,36 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -913,36 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -977,36 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1030,36 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1095,36 +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, - ), - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1148,36 +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, - ), - Nft( - 1_000_000, - nft_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -1200,26 +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, - )], + [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, - )]); + 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(), diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index b781ebe1e4..2fe1bf4f32 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -3,7 +3,6 @@ use std::str::FromStr; -use crypto::keys::bip44::Bip44; use iota_sdk::{ client::api::input_selection::{Burn, Error, InputSelection}, types::block::{address::Address, output::AccountId, protocol::protocol_parameters}, @@ -21,15 +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, - )]); + 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,15 +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, - )], + [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,13 +78,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, - )], + [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(); @@ -116,26 +115,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, - )], + [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, - )]); + 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(); @@ -147,26 +146,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, - )], + [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, - )]); + 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, @@ -186,36 +185,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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - 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, - )]); + 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, @@ -241,36 +240,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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - 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, - )]); + 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 fd2549980c..800c9e9f14 100644 --- a/sdk/tests/client/input_selection/storage_deposit_return.rs +++ b/sdk/tests/client/input_selection/storage_deposit_return.rs @@ -21,26 +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, - )], + [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, - )]); + 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(), @@ -72,36 +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, - )], + [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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - 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( @@ -123,26 +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, - )], + [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, - )]); + 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(), @@ -175,36 +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, - ), - 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, - ), + 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, - )]); + 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(), @@ -237,36 +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, - ), - 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, - ), + 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, - )]); + 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(), @@ -300,36 +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, - ), - 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, - ), + 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, - )]); + 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(), @@ -368,36 +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, - ), - 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, - ), + 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, - )]); + 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(), @@ -430,26 +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, - )], + [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, - )]); + 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, @@ -475,36 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - 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, - )]); + 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(), @@ -541,34 +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, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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(), @@ -602,43 +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, - ), - Basic( - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ACCOUNT_1).unwrap(), - None, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_1, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - 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, - )]); + 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 9b56d1b0cd..9bcc6dbd4d 100644 --- a/sdk/tests/client/input_selection/timelock.rs +++ b/sdk/tests/client/input_selection/timelock.rs @@ -16,26 +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, - )], + [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, - )]); + 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, @@ -54,26 +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, - )], + [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, - )]); + 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(), @@ -95,36 +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, - ), - Basic( - 2_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None, - None, - None, - Some(50), - 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, - )]); + 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(), @@ -147,36 +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, - ), - Basic( - 2_000_000, - 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: 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, - )]); + 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(), @@ -198,26 +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, - )], + [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, - )]); + 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/mod.rs b/sdk/tests/client/mod.rs index cc17b9a5a6..07052d00e7 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -59,162 +59,164 @@ 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)>, - ), - Nft( - u64, - NftId, - Address, - Option
, - Option
, - Option<(Address, u64)>, - Option<(Address, u32)>, - ), - Account(u64, AccountId, Address, 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 { - match build { - Build::Basic(amount, address, native_token, sender, sdruc, timelock, expiration) => { - build_basic_output(amount, address, native_token, sender, sdruc, timelock, expiration) - } - Build::Nft(amount, nft_id, address, sender, issuer, sdruc, expiration) => { - build_nft_output(amount, nft_id, address, sender, issuer, sdruc, expiration) - } - Build::Account(amount, account_id, address, sender, issuer) => { - build_account_output(amount, account_id, address, sender, issuer) - } - Build::Foundry(amount, account_id, serial_number, token_scheme, native_token) => { - build_foundry_output(amount, account_id, serial_number, token_scheme, native_token) +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() + } } } } -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 = 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 { @@ -225,8 +227,8 @@ fn build_inputs<'a>( .collect() } -fn build_outputs<'a>(outputs: impl IntoIterator>) -> Vec { - outputs.into_iter().map(|build| build_output_inner(build)).collect() +fn build_outputs(outputs: impl IntoIterator) -> Vec { + outputs.into_iter().map(Build::build).collect() } fn unsorted_eq(a: &[T], b: &[T]) -> bool diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index b1d63e6950..0fedb4b90c 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -46,11 +46,23 @@ async fn sign_account_state_transition() -> Result<()> { let signing_options = Bip44::new(SHIMMER_COIN_TYPE); let inputs = build_inputs( - [Account(1_000_000, account_id, address.clone(), None, None)], + [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)]); + 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( @@ -108,16 +120,52 @@ async fn account_reference_unlocks() -> Result<()> { let inputs = build_inputs( [ - Account(1_000_000, account_id, address.clone(), None, None), - Basic(1_000_000, account_address.clone(), None, None, None, None, None), - Basic(1_000_000, account_address.clone(), 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), - Basic(2_000_000, account_address, 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()) diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index a8e0904f5a..68af465175 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -36,11 +36,27 @@ async fn single_ed25519_unlock() -> Result<()> { let slot_index = SlotIndex::from(10); let inputs = build_inputs( - [Basic(1_000_000, address_0.clone(), None, None, None, None, 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(1_000_000, address_0, None, None, None, None, None)]); + 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( @@ -96,14 +112,46 @@ async fn ed25519_reference_unlocks() -> Result<()> { let inputs = build_inputs( [ - Basic(1_000_000, address_0.clone(), None, None, None, None, None), - Basic(1_000_000, address_0.clone(), None, None, None, None, None), - Basic(1_000_000, address_0.clone(), None, None, None, None, 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, + }, + 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)]); + 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( @@ -176,13 +224,37 @@ async fn two_signature_unlocks() -> Result<()> { let inputs = build_inputs( [ - Basic(1_000_000, address_0.clone(), None, None, None, None, None), - Basic(1_000_000, address_1, None, None, None, None, 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_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)]); + 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( diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index 83065b00e3..36dcbfaafe 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -71,70 +71,238 @@ async fn all_combined() -> Result<()> { let inputs = build_inputs( [ - Account(1_000_000, account_id_1, nft_1.clone(), None, None), - Account(1_000_000, account_id_2, ed25519_0.into(), None, None), - Basic(1_000_000, account_1.clone(), None, None, None, None, None), - Basic(1_000_000, account_2.clone(), None, None, None, None, None), - Basic(1_000_000, account_2, None, None, None, None, None), - Basic(1_000_000, nft_2.clone(), None, None, None, None, None), - Basic(1_000_000, nft_2, None, None, None, None, None), - Basic(1_000_000, nft_4.clone(), None, None, None, None, None), - Basic(1_000_000, ed25519_0.into(), None, None, None, None, None), - Basic(1_000_000, ed25519_1.into(), None, None, None, None, None), - Basic(1_000_000, ed25519_2.into(), None, None, None, None, None), - Basic(1_000_000, ed25519_2.into(), None, None, None, None, None), - Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None), - Nft(1_000_000, nft_id_2, account_1.clone(), 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.into(), - None, - None, - None, - None, - Some((account_1.clone(), 50)), - ), - Basic( - 2_000_000, - ed25519_0.into(), - None, - None, - None, - None, - Some((nft_3.clone(), 50)), - ), - Basic( - 2_000_000, - ed25519_0.into(), - None, - None, - None, - None, - Some((nft_3.clone(), 150)), - ), - Nft( - 1_000_000, - nft_id_3, - account_1.clone(), - None, - None, - None, - Some((nft_4, 50)), - ), - Nft(1_000_000, nft_id_4, account_1, None, None, None, Some((nft_3, 150))), + 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), - Account(1_000_000, account_id_2, ed25519_0.into(), None, None), - Basic(10_000_000, ed25519_0.into(), None, None, None, None, None), - Nft(1_000_000, nft_id_1, ed25519_0.into(), None, None, None, None), - Nft(1_000_000, nft_id_2, ed25519_0.into(), None, None, None, None), - Nft(1_000_000, nft_id_3, ed25519_0.into(), None, None, None, None), - Nft(1_000_000, nft_id_4, ed25519_0.into(), 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( diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index 01a3b2cb88..bbb8c28201 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -46,16 +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), - Basic(1_000_000, nft_address.clone(), None, None, None, None, None), - Basic(1_000_000, nft_address.clone(), 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), - Basic(2_000_000, nft_address, 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()) From 490dc20e31bae16d95902d856c73dc0e74cfa696 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Mon, 22 Jan 2024 09:19:55 -0500 Subject: [PATCH 19/24] Update bindings/core/src/method/secret_manager.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- bindings/core/src/method/secret_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index be225b3929..4e005fc0eb 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -18,6 +18,7 @@ use crate::OmittedDebug; #[non_exhaustive] pub enum SecretManagerMethod { /// Generate Ed25519 addresses. + #[serde(rename_all = "camelCase")] GenerateEd25519Addresses { /// The Bech32 human-readable part bech32_hrp: Hrp, From a3b1d7508a7db87a13a0471e497bba9c42787b8d Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Tue, 30 Jan 2024 08:30:21 -0500 Subject: [PATCH 20/24] make signing options default to null --- bindings/core/src/method/secret_manager.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 4e005fc0eb..2b80ff869f 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -38,6 +38,7 @@ pub enum SecretManagerMethod { /// Transaction signing hash transaction_signing_hash: String, /// Options used to sign the hash + #[serde(default)] signing_options: serde_json::Value, }, /// Signs a message with an Ed25519 private key. @@ -46,6 +47,7 @@ pub enum SecretManagerMethod { /// The message to sign, hex encoded String message: String, /// Options used to sign the message + #[serde(default)] signing_options: serde_json::Value, }, /// Signs a message with an Secp256k1Ecdsa private key. @@ -54,6 +56,7 @@ pub enum SecretManagerMethod { /// The message to sign, hex encoded String message: String, /// Options used to sign the hash + #[serde(default)] signing_options: serde_json::Value, }, /// Sign a transaction @@ -63,6 +66,7 @@ pub enum SecretManagerMethod { prepared_transaction_data: PreparedTransactionDataDto, protocol_parameters: Box, /// Options used to sign the transaction + #[serde(default)] signing_options: serde_json::Value, }, // Sign a block. @@ -70,6 +74,7 @@ pub enum SecretManagerMethod { SignBlock { unsigned_block: UnsignedBlockDto, /// Options used to sign the block + #[serde(default)] signing_options: serde_json::Value, }, /// Store a mnemonic in the Stronghold vault From 193300fc664b8dfc70529c745c0c1083cadb7f07 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Wed, 31 Jan 2024 09:07:07 -0500 Subject: [PATCH 21/24] comments --- .../wallet/offline_signing/1_prepare_transaction.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index b2766cd848..0d7d0db832 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -9,11 +9,9 @@ //! ``` use iota_sdk::{ - client::{api::PreparedTransactionDataDto, constants::SHIMMER_COIN_TYPE, secret::SecretManager}, - crypto::keys::bip44::Bip44, - wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet, WalletBuilder}, + client::api::PreparedTransactionDataDto, + wallet::{types::Bip44Address, ClientOptions, Result, SendParams, WalletBuilder}, }; -use serde::Serialize; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; const ADDRESS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.address.json"; @@ -41,12 +39,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 + // Create the wallet with the client options and address let wallet = WalletBuilder::new() - .with_secret_manager(SecretManager::Placeholder) .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) - // .with_public_key_options(()) .with_address(address) .finish() .await?; From 9dcf11d91c4f83f0dad7bd3e3ce682c7e4abbfaa Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Fri, 2 Feb 2024 09:50:55 -0500 Subject: [PATCH 22/24] remove generate_random --- sdk/src/client/secret/mnemonic.rs | 5 ----- sdk/tests/client/mod.rs | 6 +++++- sdk/tests/client/signing/account.rs | 8 ++++---- sdk/tests/client/signing/nft.rs | 6 +++--- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index a1f464ab00..9bae4ac36c 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -206,11 +206,6 @@ impl MnemonicSecretManager { let seed = Seed::from_bytes(bytes.as_ref()); Ok(Self(seed)) } - - /// Generate a random mnemonic to use for the secret manager. - pub fn generate_random() -> Result { - Self::try_from_mnemonic(Client::generate_mnemonic()?) - } } impl SecretManagerConfig for MnemonicSecretManager { diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index 1a24c79c67..d4fb769c28 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -18,7 +18,7 @@ mod signing; use std::{collections::HashMap, hash::Hash, str::FromStr}; use iota_sdk::{ - client::secret::types::InputSigningData, + client::secret::{mnemonic::MnemonicSecretManager, types::InputSigningData}, types::block::{ address::{AccountAddress, Address}, output::{ @@ -283,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/signing/account.rs b/sdk/tests/client/signing/account.rs index ac04b470c5..4776cf71ab 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -8,7 +8,7 @@ use iota_sdk::{ client::{ api::{transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData}, constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt, SignTransaction}, + secret::{PublicKeyOptions, SecretManageExt, SignTransaction}, Result, }, types::block::{ @@ -24,14 +24,14 @@ 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 = MnemonicSecretManager::generate_random()?; + let secret_manager = random_mnemonic_secret_manager()?; let address = Address::from( secret_manager @@ -103,7 +103,7 @@ async fn sign_account_state_transition() -> Result<()> { #[tokio::test] async fn account_reference_unlocks() -> Result<()> { - let secret_manager = MnemonicSecretManager::generate_random()?; + let secret_manager = random_mnemonic_secret_manager()?; let address = Address::from( secret_manager diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index 4bf5952281..f7e99ff414 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -8,7 +8,7 @@ use iota_sdk::{ client::{ api::{transaction::validate_signed_transaction_payload_length, verify_semantic, PreparedTransactionData}, constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManageExt, SignTransaction}, + secret::{PublicKeyOptions, SecretManageExt, SignTransaction}, Result, }, types::block::{ @@ -24,14 +24,14 @@ 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 = MnemonicSecretManager::generate_random()?; + let secret_manager = random_mnemonic_secret_manager()?; let address_0 = Address::from( secret_manager From 99bc0dded98d39d35ce766e48bc33ede900d0621 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Mon, 5 Feb 2024 08:16:05 -0500 Subject: [PATCH 23/24] make public key opts mutable --- sdk/src/client/secret/mod.rs | 9 ++++++++ sdk/src/wallet/core/builder.rs | 11 +++++---- sdk/src/wallet/core/mod.rs | 6 ++--- .../core/operations/stronghold_backup/mod.rs | 23 +++++++++++-------- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 6fc4cdf7e4..04267cac16 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -105,6 +105,15 @@ impl From for PublicKeyOptions { } } +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) + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct MultiKeyOptions { diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 2a4413fc53..02fb6db485 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -446,10 +446,11 @@ where inner: Arc::new(wallet_inner), data: Arc::new(RwLock::new(wallet_data)), secret_data: SecretData { - public_key_options: self - .secret_data - .public_key_options - .ok_or(crate::wallet::Error::MissingParameter("public_key_options"))?, + 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 @@ -531,7 +532,7 @@ mod builder_from { async fn from(&self) -> Self::Builder { Self::Builder { - public_key_options: Some(self.public_key_options.clone()), + 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()), } diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index b7b9d5f0c5..594fe1f34a 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -48,7 +48,7 @@ pub struct Wallet { #[derive(Debug)] pub struct SecretData { /// The public key generation options. - pub(crate) public_key_options: S::GenerationOptions, + pub(crate) public_key_options: Arc>, /// The signing options for transactions and blocks. pub(crate) signing_options: S::SigningOptions, pub(crate) secret_manager: Arc>, @@ -453,8 +453,8 @@ impl Wallet> { &self.secret_data.secret_manager } - pub fn public_key_options(&self) -> &S::GenerationOptions { - &self.secret_data.public_key_options + 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 { diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index 14bf60ade1..d64bfec1b8 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -99,22 +99,27 @@ impl Wallet> { let (loaded_client_options, loaded_secret_manager_config, loaded_wallet_data, loaded_secret_data) = read_wallet_data_from_stronghold_snapshot::(&new_stronghold).await?; - let loaded_pub_key_opts = loaded_secret_data.as_ref().map(|data| &data.public_key_options); + 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? - loaded_pub_key_opts.is_some_and(|opts| self.public_key_options() != opts) + 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 { if let Some(opts) = loaded_pub_key_opts { - // TODO - // self.secret_data.public_key_options = opts.clone(); + *self.secret_data.public_key_options.write().await = opts; } } @@ -181,7 +186,7 @@ impl Wallet> { .expect("can't convert os string"), ) .with_client_options(self.client_options().await) - .with_public_key_options(self.public_key_options().clone()) + .with_public_key_options(self.public_key_options().await.clone()) .with_signing_options(self.signing_options().clone()); wallet_builder.save(self.storage_manager()).await?; From b79e3616b8faab5e89dfa6e6848003e31136be90 Mon Sep 17 00:00:00 2001 From: Alex Coats Date: Fri, 9 Feb 2024 09:27:13 -0500 Subject: [PATCH 24/24] cleanup --- .../client/node_api_core/05_post_block_raw.rs | 2 +- .../account/implicit_account_creation.rs | 4 +- .../how_tos/account_wallet/transaction.rs | 5 +- .../accounts_and_addresses/create_wallet.rs | 4 +- .../nft_collection/00_mint_issuer_nft.rs | 2 +- .../sign_and_verify_ed25519/sign_ed25519.rs | 2 +- sdk/src/wallet/core/mod.rs | 2 - .../core/operations/background_syncing.rs | 5 +- sdk/src/wallet/operations/balance.rs | 1 - sdk/src/wallet/operations/output_claiming.rs | 7 +- .../wallet/operations/participation/mod.rs | 2 +- .../addresses/output_ids/account_foundry.rs | 5 +- .../syncing/addresses/output_ids/basic.rs | 2 +- .../syncing/addresses/output_ids/nft.rs | 2 +- .../wallet/operations/syncing/foundries.rs | 1 - sdk/src/wallet/operations/syncing/mod.rs | 1 - sdk/src/wallet/operations/syncing/outputs.rs | 2 +- .../wallet/operations/syncing/transactions.rs | 2 +- .../wallet/operations/transaction/account.rs | 2 +- .../transaction/build_transaction.rs | 5 +- .../transaction/high_level/allot_mana.rs | 2 +- .../burning_melting/melt_native_token.rs | 2 +- .../high_level/burning_melting/mod.rs | 2 +- .../transaction/high_level/create_account.rs | 2 +- .../high_level/minting/create_native_token.rs | 2 +- .../high_level/minting/mint_native_token.rs | 2 +- .../high_level/minting/mint_nfts.rs | 2 +- .../operations/transaction/high_level/send.rs | 2 +- .../high_level/send_native_tokens.rs | 2 +- .../transaction/high_level/send_nft.rs | 2 +- .../operations/transaction/input_selection.rs | 2 +- sdk/src/wallet/operations/transaction/mod.rs | 2 +- .../operations/transaction/prepare_output.rs | 1 - .../transaction/prepare_transaction.rs | 2 +- .../transaction/sign_transaction.rs | 64 ++++++++----------- sdk/src/wallet/storage/manager.rs | 4 +- sdk/src/wallet/update.rs | 13 ++-- 37 files changed, 67 insertions(+), 99 deletions(-) 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 cfa165b894..37bee6258d 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::{mnemonic::MnemonicSecretManager, BlockSignExt, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, BlockSignExt}, Client, Result, }, types::block::output::AccountId, diff --git a/sdk/examples/how_tos/account/implicit_account_creation.rs b/sdk/examples/how_tos/account/implicit_account_creation.rs index 720bf930e1..af93e9a229 100644 --- a/sdk/examples/how_tos/account/implicit_account_creation.rs +++ b/sdk/examples/how_tos/account/implicit_account_creation.rs @@ -11,10 +11,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions, SecretManager}, + secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, }, crypto::keys::bip44::Bip44, - wallet::{ClientOptions, Result, Wallet, WalletBuilder}, + wallet::{ClientOptions, Result, WalletBuilder}, }; #[tokio::main] diff --git a/sdk/examples/how_tos/account_wallet/transaction.rs b/sdk/examples/how_tos/account_wallet/transaction.rs index e937c3ecea..e616044f12 100644 --- a/sdk/examples/how_tos/account_wallet/transaction.rs +++ b/sdk/examples/how_tos/account_wallet/transaction.rs @@ -7,10 +7,7 @@ //! `cargo run --release --all-features --example account_wallet_transaction` use iota_sdk::{ - client::{ - node_api::indexer::query_parameters::BasicOutputQueryParameters, - secret::{stronghold::StrongholdSecretManager, SecretManager}, - }, + client::{node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManager}, types::block::address::{AccountAddress, ToBech32Ext}, wallet::{AccountSyncOptions, Result, SyncOptions, TransactionOptions}, Wallet, diff --git a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs index 993eb0c021..4e17bf1561 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/create_wallet.rs @@ -13,10 +13,10 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, - secret::{stronghold::StrongholdSecretManager, PublicKeyOptions, SecretManager}, + secret::{stronghold::StrongholdSecretManager, PublicKeyOptions}, }, crypto::keys::{bip39::Mnemonic, bip44::Bip44}, - wallet::{ClientOptions, Result, Wallet, WalletBuilder}, + wallet::{ClientOptions, Result, WalletBuilder}, }; #[tokio::main] 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 cd0acc5e68..4dddaee3ab 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,7 +15,7 @@ //! ``` use iota_sdk::{ - client::secret::{stronghold::StrongholdSecretManager, SecretManager}, + client::secret::SecretManager, types::block::{ output::{feature::MetadataFeature, NftId, Output, OutputId}, payload::signed_transaction::TransactionId, 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 fa75273899..71918573c4 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,7 +13,7 @@ use iota_sdk::{ client::{ constants::SHIMMER_COIN_TYPE, hex_public_key_to_bech32_address, - secret::{stronghold::StrongholdSecretManager, SecretManage, SecretManageExt, SecretManager}, + secret::{stronghold::StrongholdSecretManager, SecretManageExt}, }, crypto::keys::bip39::Mnemonic, types::block::signature::Ed25519Signature, diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 594fe1f34a..aebc781794 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -600,12 +600,10 @@ impl OptionalSecretManager for Wallet> { mod test { use core::str::FromStr; - use crypto::keys::bip44::Bip44; use pretty_assertions::assert_eq; use super::*; use crate::{ - client::secret::{mnemonic::MnemonicSecretManager, PublicKeyOptions}, types::block::{ address::{Address, Ed25519Address}, input::{Input, UtxoInput}, diff --git a/sdk/src/wallet/core/operations/background_syncing.rs b/sdk/src/wallet/core/operations/background_syncing.rs index 27dc147ad9..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); diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index a552dc0069..d02c7dd149 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, }, diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index 7eaf568371..7cfd463963 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -6,10 +6,7 @@ use std::collections::HashSet; use serde::{Deserialize, Serialize}; use crate::{ - client::{ - api::PreparedTransactionData, - secret::{SecretManage, Sign}, - }, + client::{api::PreparedTransactionData, secret::SecretManage}, types::block::{ address::{Address, Ed25519Address}, output::{ @@ -188,7 +185,7 @@ impl Wallet { } } -impl Wallet> { +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>( diff --git a/sdk/src/wallet/operations/participation/mod.rs b/sdk/src/wallet/operations/participation/mod.rs index 6d8c560d01..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, 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 3fb6f4e359..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::{ 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 ee94d49f7a..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,7 +2,7 @@ // 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, 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 b5c28b5948..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,7 +2,7 @@ // 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, diff --git a/sdk/src/wallet/operations/syncing/foundries.rs b/sdk/src/wallet/operations/syncing/foundries.rs index d7ac8fdf11..2730d2e88f 100644 --- a/sdk/src/wallet/operations/syncing/foundries.rs +++ b/sdk/src/wallet/operations/syncing/foundries.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use crate::{ - client::secret::SecretManage, types::block::output::{FoundryId, Output}, wallet::{task, Wallet}, }; diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index b11aafbb35..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}, diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index ccfd6bbd33..cd5c01a26d 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::{ diff --git a/sdk/src/wallet/operations/syncing/transactions.rs b/sdk/src/wallet/operations/syncing/transactions.rs index 18ca2306f0..92d7f8efec 100644 --- a/sdk/src/wallet/operations/syncing/transactions.rs +++ b/sdk/src/wallet/operations/syncing/transactions.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::{secret::SecretManage, unix_timestamp_now}, + client::unix_timestamp_now, types::{ api::core::TransactionState, block::{input::Input, output::OutputId, BlockId}, diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 268fd74e96..63c88f3e86 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -22,7 +22,7 @@ use crate::{ }, }; -impl Wallet> { +impl Wallet> { /// Transitions an implicit account to an account. pub async fn implicit_account_transition( &self, diff --git a/sdk/src/wallet/operations/transaction/build_transaction.rs b/sdk/src/wallet/operations/transaction/build_transaction.rs index 627b8efe1c..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}, 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 7bdc1f1ea6..2ac6053c94 100644 --- a/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs +++ b/sdk/src/wallet/operations/transaction/high_level/allot_mana.rs @@ -11,7 +11,7 @@ use crate::{ }, }; -impl Wallet> { +impl Wallet> { pub async fn 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 8c7454ace2..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 @@ -17,7 +17,7 @@ use crate::{ }, }; -impl Wallet> { +impl Wallet> { /// Melts native tokens. /// /// This happens with the foundry output which minted them, by increasing it's 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 03d4a21d9a..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 @@ -11,7 +11,7 @@ use crate::{ 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 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 ed0e6c1e3a..f9281a5ef2 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -32,7 +32,7 @@ pub struct CreateAccountParams { pub metadata: Option, } -impl Wallet> { +impl Wallet> { /// Creates an account output. /// ```ignore /// let params = CreateAccountParams { 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 2d33bb9fb7..d9281f60dc 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 @@ -47,7 +47,7 @@ pub struct PreparedCreateNativeTokenTransaction { pub transaction: PreparedTransactionData, } -impl Wallet> { +impl Wallet> { /// Creates a new foundry output with minted native tokens. /// /// Calls [Wallet::send_outputs()] internally, the options may define the remainder value strategy or custom inputs. 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 b04c11102c..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 @@ -13,7 +13,7 @@ use crate::{ }, }; -impl Wallet> { +impl Wallet> { /// Mints additional native tokens. /// /// The max supply must not be reached yet. The foundry needs to be 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 8f33bd8e8f..dade240609 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 @@ -108,7 +108,7 @@ impl MintNftParams { } } -impl Wallet> { +impl Wallet> { /// Mints NFTs. /// /// Calls [Wallet::send_outputs()] internally. The options may define the remainder value strategy or custom inputs. diff --git a/sdk/src/wallet/operations/transaction/high_level/send.rs b/sdk/src/wallet/operations/transaction/high_level/send.rs index 7866ce1ba1..f388a10a59 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send.rs @@ -74,7 +74,7 @@ impl SendParams { } } -impl Wallet> { +impl Wallet> { /// Sends a certain amount of base coins to a single address. /// /// Calls [Wallet::send_with_params()] internally. 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 7669e65b11..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 @@ -74,7 +74,7 @@ impl SendNativeTokenParams { } } -impl Wallet> { +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 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 18ce7d5d23..e22710d161 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_nft.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_nft.rs @@ -43,7 +43,7 @@ impl SendNftParams { } } -impl Wallet> { +impl Wallet> { /// Sends native tokens in basic outputs with a /// [`StorageDepositReturnUnlockCondition`](crate::types::block::output::unlock_condition::StorageDepositReturnUnlockCondition) and an /// [`ExpirationUnlockCondition`](crate::types::block::output::unlock_condition::ExpirationUnlockCondition), so that diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 1382d9c113..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, diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 5ca8678270..35fba6f23e 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -32,7 +32,7 @@ use crate::{ }, }; -impl Wallet> { +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 diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 5519d3d665..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::{ diff --git a/sdk/src/wallet/operations/transaction/prepare_transaction.rs b/sdk/src/wallet/operations/transaction/prepare_transaction.rs index 723b5fb2a5..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}, diff --git a/sdk/src/wallet/operations/transaction/sign_transaction.rs b/sdk/src/wallet/operations/transaction/sign_transaction.rs index bb35037674..c16e42304c 100644 --- a/sdk/src/wallet/operations/transaction/sign_transaction.rs +++ b/sdk/src/wallet/operations/transaction/sign_transaction.rs @@ -8,12 +8,12 @@ use crate::{ api::{ transaction::validate_signed_transaction_payload_length, PreparedTransactionData, SignedTransactionData, }, - secret::SecretManage, + secret::{DowncastSecretManager, SecretManage}, }, wallet::{core::SecretData, operations::transaction::SignedTransactionPayload, Wallet}, }; -impl Wallet> { +impl Wallet> { /// Signs a transaction. pub async fn sign_transaction( &self, @@ -27,41 +27,31 @@ impl Wallet> { )) .await; - // #[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 - // } - // }) - // }) { - // 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) { - // self.emit(WalletEvent::TransactionProgress( - // TransactionProgressEvent::PreparedTransactionSigningHash( - // prepared_transaction_data.transaction.signing_hash().to_string(), - // ), - // )) - // .await; - // } else { - // self.emit(WalletEvent::TransactionProgress( - // TransactionProgressEvent::PreparedTransaction(Box::new(PreparedTransactionDataDto::from( - // prepared_transaction_data, - // ))), - // )) - // .await; - // } - // } - // } - // } - - let protocol_parameters = self.client().get_protocol_parameters().await?; + #[cfg(all(feature = "events", feature = "ledger_nano"))] + { + 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) { + self.emit(WalletEvent::TransactionProgress( + TransactionProgressEvent::PreparedTransactionSigningHash( + prepared_transaction_data.transaction.signing_hash().to_string(), + ), + )) + .await; + } else { + self.emit(WalletEvent::TransactionProgress( + TransactionProgressEvent::PreparedTransaction(Box::new(PreparedTransactionDataDto::from( + prepared_transaction_data, + ))), + )) + .await; + } + } + } + } let protocol_parameters = self.client().get_protocol_parameters().await?; let unlocks = match self diff --git a/sdk/src/wallet/storage/manager.rs b/sdk/src/wallet/storage/manager.rs index 6721054a84..5086dcd461 100644 --- a/sdk/src/wallet/storage/manager.rs +++ b/sdk/src/wallet/storage/manager.rs @@ -4,10 +4,10 @@ use zeroize::Zeroizing; use crate::{ - client::{secret::SecretManage, storage::StorageAdapter}, + client::storage::StorageAdapter, types::TryFromDto, wallet::{ - core::{SecretData, WalletData, WalletDataDto}, + core::{WalletData, WalletDataDto}, migration::migrate, operations::syncing::SyncOptions, storage::{constants::*, DynStorageAdapter, Storage}, diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 505d538a4d..12f05dec57 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,12 +19,6 @@ use crate::{ Wallet, }, }; -#[cfg(feature = "events")] -use crate::{ - types::api::core::OutputWithMetadataResponse, - types::block::payload::signed_transaction::dto::SignedTransactionPayloadDto, - wallet::events::types::{NewOutputEvent, SpentOutputEvent, TransactionInclusionEvent, WalletEvent}, -}; impl Wallet { /// Set the alias for the wallet.