From 8fd2992fd5b4884c70be6f64efcce3f28f5b73e5 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Tue, 7 Nov 2023 12:10:47 +0100 Subject: [PATCH 01/38] rm ed25519 address generation from wallet --- bindings/core/src/method/wallet.rs | 16 --- bindings/core/src/method_handler/wallet.rs | 17 --- sdk/examples/wallet/ledger_nano.rs | 24 ++-- sdk/examples/wallet/logger.rs | 19 ++- sdk/src/types/block/output/mod.rs | 2 +- sdk/src/wallet/core/builder.rs | 1 + .../core/operations/address_generation.rs | 99 ------------- sdk/src/wallet/core/operations/mod.rs | 1 - sdk/tests/wallet/address_generation.rs | 133 ++++-------------- 9 files changed, 58 insertions(+), 254 deletions(-) delete mode 100644 sdk/src/wallet/core/operations/address_generation.rs diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index 3a578919f0..1734ba89b9 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -402,27 +402,11 @@ pub enum WalletMethod { /// Expected response: [`OutputsData`](crate::Response::OutputsData) #[serde(rename_all = "camelCase")] UnspentOutputs { filter_options: Option }, - /// Emits an event for testing if the event system is working /// Expected response: [`Ok`](crate::Response::Ok) #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] 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/wallet.rs b/bindings/core/src/method_handler/wallet.rs index 50948dadb7..fea94f71d1 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -73,23 +73,6 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM let ledger_nano_status = wallet.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?; diff --git a/sdk/examples/wallet/ledger_nano.rs b/sdk/examples/wallet/ledger_nano.rs index e428af78cb..d5937b7c86 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -16,6 +16,7 @@ use iota_sdk::{ client::{ + api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, secret::{ledger_nano::LedgerSecretManager, SecretManager}, }, @@ -34,24 +35,29 @@ async fn main() -> Result<()> { dotenvy::dotenv().ok(); let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let secret_manager = LedgerSecretManager::new(true); + let secret_manager = SecretManager::LedgerNano(LedgerSecretManager::new(true)); + + println!("Generating address..."); + let now = tokio::time::Instant::now(); + let address = secret_manager + .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(SHIMMER_COIN_TYPE)) + .await? + .pop() + .unwrap(); + println!("took: {:.2?}", now.elapsed()); + + println!("ADDRESS:\n{address:#?}"); let wallet = Wallet::builder() - .with_secret_manager(SecretManager::LedgerNano(secret_manager)) + .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_address(address) .finish() .await?; println!("{:?}", wallet.get_ledger_nano_status().await?); - println!("Generating address..."); - let now = tokio::time::Instant::now(); - let address = wallet.generate_ed25519_address(0, 0, None).await?; - println!("took: {:.2?}", now.elapsed()); - - println!("ADDRESS:\n{address:#?}"); - let now = tokio::time::Instant::now(); let balance = wallet.sync(None).await?; println!("Wallet synced in: {:.2?}", now.elapsed()); diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index 43033a3bef..cf8ae32505 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -10,6 +10,7 @@ use iota_sdk::{ client::{ + api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, secret::{mnemonic::MnemonicSecretManager, SecretManager}, }, @@ -34,18 +35,24 @@ async fn main() -> Result<()> { // Restore a wallet let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; - let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; - let wallet = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) + let secret_manager = SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic( + std::env::var("MNEMONIC").unwrap(), + )?); + + let address = secret_manager + .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(SHIMMER_COIN_TYPE)) + .await? + .pop() + .unwrap(); + + let wallet = Wallet::::builder() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) + .with_address(address) .finish() .await?; - println!("Generating address..."); - let _ = wallet.generate_ed25519_address(0, 0, None).await?; - println!("Syncing wallet"); wallet.sync(None).await?; diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index cf3621c937..892838984a 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -254,7 +254,7 @@ impl Output { /// Checks whether the output is an implicit account. pub fn is_implicit_account(&self) -> bool { - if let Output::Basic(output) = self { + if let Self::Basic(output) = self { output.is_implicit_account() } else { false diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 06a24ebb16..1247b01678 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -253,6 +253,7 @@ where last_synced: Mutex::new(0), background_syncing_status: AtomicUsize::new(0), client, + // TODO: make secret manager optional secret_manager: self.secret_manager.expect("make WalletInner::secret_manager optional?"), #[cfg(feature = "events")] event_emitter, diff --git a/sdk/src/wallet/core/operations/address_generation.rs b/sdk/src/wallet/core/operations/address_generation.rs deleted file mode 100644 index fe902ee8ec..0000000000 --- a/sdk/src/wallet/core/operations/address_generation.rs +++ /dev/null @@ -1,99 +0,0 @@ -// 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}, -}; - -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; - - 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 bech32_hrp = self.bech32_hrp().await; - - self.emit(WalletEvent::LedgerAddressGeneration(AddressData { - address: address[0].to_bech32(bech32_hrp), - })) - .await; - } - - // Generate with prompt so the user can verify - ledger_nano - .generate_ed25519_addresses(coin_type, account_index, address_index..address_index + 1, options) - .await? - } 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"))?) - } -} diff --git a/sdk/src/wallet/core/operations/mod.rs b/sdk/src/wallet/core/operations/mod.rs index e01ca173a6..058c1e84dc 100644 --- a/sdk/src/wallet/core/operations/mod.rs +++ b/sdk/src/wallet/core/operations/mod.rs @@ -1,7 +1,6 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -pub(crate) mod address_generation; pub(crate) mod background_syncing; pub(crate) mod client; #[cfg(feature = "ledger_nano")] diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index eccd3aa430..304b814c15 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -12,6 +12,7 @@ use iota_sdk::client::secret::{ledger_nano::LedgerSecretManager, GenerateAddress use iota_sdk::wallet::events::{WalletEvent, WalletEventType}; use iota_sdk::{ client::{ + api::GetAddressesOptions, constants::IOTA_COIN_TYPE, secret::{mnemonic::MnemonicSecretManager, SecretManager}, Error as ClientError, @@ -24,26 +25,15 @@ use pretty_assertions::assert_eq; use crate::wallet::common::{setup, tear_down, DEFAULT_MNEMONIC, NODE_LOCAL}; #[tokio::test] -async fn wallet_address_generation_mnemonic() -> Result<()> { - let storage_path = "test-storage/wallet_address_generation_mnemonic"; - setup(storage_path)?; +async fn address_generation_mnemonic() -> Result<()> { + let secret_manager = + SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?); - let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; - let secret_manager = MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?; - - #[allow(unused_mut)] - let mut wallet_builder = Wallet::builder() - .with_secret_manager(SecretManager::Mnemonic(secret_manager)) - .with_client_options(client_options) - .with_bip_path(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 = secret_manager + .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) + .await? + .pop() + .unwrap(); assert_eq!( address.to_bech32_unchecked("smr"), @@ -51,15 +41,12 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { "smr1qrpwecegav7eh0z363ca69laxej64rrt4e3u0rtycyuh0mam3vq3ulygj9p" ); - tear_down(storage_path) + Ok(()) } #[cfg(feature = "stronghold")] #[tokio::test] -async fn wallet_address_generation_stronghold() -> Result<()> { - let storage_path = "test-storage/wallet_address_generation_stronghold"; - setup(storage_path)?; - +async fn address_generation_stronghold() -> Result<()> { iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); let secret_manager = StrongholdSecretManager::builder() @@ -69,19 +56,13 @@ async fn wallet_address_generation_stronghold() -> Result<()> { .store_mnemonic(Mnemonic::from(DEFAULT_MNEMONIC.to_string())) .await?; - 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_client_options(client_options) - .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); - #[cfg(feature = "storage")] - { - wallet_builder = wallet_builder.with_storage_path(storage_path); - } - let wallet = wallet_builder.finish().await?; + let secret_manager = SecretManager::Stronghold(secret_manager); - let address = wallet.generate_ed25519_address(0, 0, None).await?; + let address = secret_manager + .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) + .await? + .pop() + .unwrap(); assert_eq!( address.to_bech32_unchecked("smr"), @@ -89,67 +70,23 @@ async fn wallet_address_generation_stronghold() -> Result<()> { "smr1qrpwecegav7eh0z363ca69laxej64rrt4e3u0rtycyuh0mam3vq3ulygj9p" ); - tear_down(storage_path) + Ok(()) } #[tokio::test] -#[cfg(all(feature = "ledger_nano", feature = "events"))] +#[cfg(feature = "ledger_nano")] #[ignore = "requires ledger nano instance"] -async fn wallet_address_generation_ledger() -> Result<()> { - let storage_path = "test-storage/wallet_address_generation_ledger"; - setup(storage_path)?; - - let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; +async fn address_generation_ledger() -> Result<()> { 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_client_options(client_options) - .with_bip_path(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?; - - assert_eq!( - address.to_bech32_unchecked("smr"), - // Address generated with bip32 path: [44, 4218, 0, 0, 0]. - // This address was generated with a MnemonicSecretManager and the ledger simulator mnemonic. - // "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster - // seven myth punch hobby comfort wild raise skin". - "smr1qqdnv60ryxynaeyu8paq3lp9rkll7d7d92vpumz88fdj4l0pn5mruy3qdpm" - ); + let secret_manager = SecretManager::LedgerNano(secret_manager); - let (sender, mut receiver) = tokio::sync::mpsc::channel(1); - - wallet - .listen([WalletEventType::LedgerAddressGeneration], move |event| { - if let WalletEvent::LedgerAddressGeneration(address) = event { - sender - .try_send(address.address.clone()) - .expect("too many LedgerAddressGeneration events"); - } else { - panic!("expected LedgerAddressGeneration event") - } - }) - .await; - - let address = wallet - .generate_ed25519_address( - 0, - 0, - Some(GenerateAddressOptions { - ledger_nano_prompt: true, - ..Default::default() - }), - ) - .await?; + let address = secret_manager + .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) + .await? + .pop() + .unwrap(); assert_eq!( address.to_bech32_unchecked("smr"), @@ -160,25 +97,11 @@ async fn wallet_address_generation_ledger() -> Result<()> { "smr1qqdnv60ryxynaeyu8paq3lp9rkll7d7d92vpumz88fdj4l0pn5mruy3qdpm" ); - assert_eq!( - receiver - .recv() - .await - .expect("never received event") - .into_inner() - .to_bech32_unchecked("smr"), - // Address generated with bip32 path: [44, 4218, 0, 0, 0]. - // This address was generated with a MnemonicSecretManager and the ledger simulator mnemonic. - // "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster - // seven myth punch hobby comfort wild raise skin". - "smr1qqdnv60ryxynaeyu8paq3lp9rkll7d7d92vpumz88fdj4l0pn5mruy3qdpm" - ); - - tear_down(storage_path) + Ok(()) } // #[tokio::test] -// async fn wallet_address_generation_placeholder() -> Result<()> { +// async fn address_generation_placeholder() -> Result<()> { // let storage_path = "test-storage/wallet_address_generation_placeholder"; // setup(storage_path)?; From 565a28b8e40aeca7303215f90021a1d59793e3a2 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Dec 2023 08:51:59 +0100 Subject: [PATCH 02/38] rename fn --- bindings/nodejs/src/wallet.rs | 2 +- bindings/wasm/src/wallet.rs | 2 +- sdk/src/wallet/core/mod.rs | 8 ++++---- sdk/src/wallet/operations/block.rs | 2 +- sdk/src/wallet/operations/reissue.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bindings/nodejs/src/wallet.rs b/bindings/nodejs/src/wallet.rs index 140c9ca306..e79f23d401 100644 --- a/bindings/nodejs/src/wallet.rs +++ b/bindings/nodejs/src/wallet.rs @@ -97,7 +97,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/wasm/src/wallet.rs b/bindings/wasm/src/wallet.rs index 425b5f3fd2..55b2be22bc 100644 --- a/bindings/wasm/src/wallet.rs +++ b/bindings/wasm/src/wallet.rs @@ -66,7 +66,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/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 50fbaab439..d9b00db41f 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -467,12 +467,12 @@ where } impl WalletInner { - /// Get the [SecretManager] - pub fn get_secret_manager(&self) -> &Arc> { + /// Get the [`SecretManager`] of the wallet. + pub fn secret_manager(&self) -> &Arc> { &self.secret_manager } - /// Listen to wallet events, empty vec will listen to all events + /// Listen to wallet events, empty vec will listen to all events. #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] pub async fn listen + Send>(&self, events: I, handler: F) @@ -484,7 +484,7 @@ impl WalletInner { emitter.on(events, handler); } - /// Remove wallet event listeners, empty vec will remove all listeners + /// Remove wallet event listeners, empty vec will remove all listeners. #[cfg(feature = "events")] #[cfg_attr(docsrs, doc(cfg(feature = "events")))] pub async fn clear_listeners + Send>(&self, events: I) diff --git a/sdk/src/wallet/operations/block.rs b/sdk/src/wallet/operations/block.rs index 0026ede84c..32bd1a1d47 100644 --- a/sdk/src/wallet/operations/block.rs +++ b/sdk/src/wallet/operations/block.rs @@ -35,7 +35,7 @@ where .build_basic_block(issuer_id, payload) .await? .sign_ed25519( - &*self.get_secret_manager().read().await, + &*self.secret_manager().read().await, self.bip_path().await.ok_or(Error::MissingBipPath)?, ) .await?; diff --git a/sdk/src/wallet/operations/reissue.rs b/sdk/src/wallet/operations/reissue.rs index 7bad812224..0d6437c915 100644 --- a/sdk/src/wallet/operations/reissue.rs +++ b/sdk/src/wallet/operations/reissue.rs @@ -62,7 +62,7 @@ where ) .await? .sign_ed25519( - &*self.get_secret_manager().read().await, + &*self.secret_manager().read().await, self.bip_path().await.ok_or(Error::MissingBipPath)?, ) .await? @@ -110,7 +110,7 @@ where ) .await? .sign_ed25519( - &*self.get_secret_manager().read().await, + &*self.secret_manager().read().await, self.bip_path().await.ok_or(Error::MissingBipPath)?, ) .await?; From e8e05fc72a7a23be13000e255480f207b41341ca Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Dec 2023 10:36:57 +0100 Subject: [PATCH 03/38] rm with_address --- bindings/core/src/lib.rs | 1 - cli/src/cli.rs | 10 -- sdk/examples/wallet/ledger_nano.rs | 18 +-- sdk/examples/wallet/logger.rs | 7 - .../offline_signing/0_generate_address.rs | 15 +-- .../offline_signing/1_prepare_transaction.rs | 17 +-- sdk/examples/wallet/spammer.rs | 10 -- sdk/src/wallet/core/builder.rs | 125 ++++++++++-------- 8 files changed, 75 insertions(+), 128 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index d7dc366cfa..7d4df57e2d 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -89,7 +89,6 @@ impl WalletOptions { 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_bip_path(self.bip_path) .with_client_options(self.client_options); diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 873f4e21ce..af4b38d149 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -66,9 +66,6 @@ pub struct InitParameters { /// Set the BIP path, `4219/0/0/0` if not provided. #[arg(short, long, value_parser = parse_bip_path)] pub bip_path: Option, - /// Set the Bech32-encoded wallet address. - #[arg(short, long)] - pub address: Option, } impl Default for InitParameters { @@ -77,7 +74,6 @@ impl Default for InitParameters { mnemonic_file_path: None, node_url: DEFAULT_NODE_URL.to_string(), bip_path: Some(Bip44::new(SHIMMER_COIN_TYPE)), - address: None, } } } @@ -280,17 +276,11 @@ pub async fn init_command( None }; - let address = init_params - .address - .map(|addr| Bech32Address::from_str(&addr)) - .transpose()?; - 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_bip_path(init_params.bip_path) - .with_address(address) .with_alias(alias) .finish() .await?) diff --git a/sdk/examples/wallet/ledger_nano.rs b/sdk/examples/wallet/ledger_nano.rs index 2fb4b1044f..86a2765429 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -16,7 +16,6 @@ use iota_sdk::{ client::{ - api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, secret::{ledger_nano::LedgerSecretManager, SecretManager}, }, @@ -24,8 +23,6 @@ use iota_sdk::{ wallet::{ClientOptions, Result, Wallet}, }; -// The address to send coins to -const RECV_ADDRESS: &str = "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu"; // The amount of base coins we'll send const SEND_AMOUNT: u64 = 1_000_000; @@ -41,25 +38,16 @@ async fn main() -> Result<()> { let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; let secret_manager = SecretManager::LedgerNano(LedgerSecretManager::new(true)); - println!("Generating address..."); - let now = tokio::time::Instant::now(); - let address = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(SHIMMER_COIN_TYPE)) - .await? - .pop() - .unwrap(); - println!("took: {:.2?}", now.elapsed()); - - println!("ADDRESS:\n{address:#?}"); let wallet = Wallet::builder() .with_secret_manager(secret_manager) .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) - .with_address(address) .finish() .await?; + let recv_address = wallet.address().await; + println!("receive address: {recv_address}"); println!("{:?}", wallet.get_ledger_nano_status().await?); let now = tokio::time::Instant::now(); @@ -69,7 +57,7 @@ async fn main() -> Result<()> { println!("Balance BEFORE:\n{:?}", balance.base_coin()); println!("Sending the coin-transfer transaction..."); - let transaction = wallet.send(SEND_AMOUNT, RECV_ADDRESS, None).await?; + let transaction = wallet.send(SEND_AMOUNT, recv_address, None).await?; println!("Transaction sent: {}", transaction.transaction_id); let block_id = wallet diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index 796d9e77b2..ebc550d6fd 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -43,17 +43,10 @@ async fn main() -> Result<()> { std::env::var("MNEMONIC").unwrap(), )?); - let address = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(SHIMMER_COIN_TYPE)) - .await? - .pop() - .unwrap(); - let wallet = Wallet::::builder() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) - .with_address(address) .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..8af939fd31 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -19,7 +19,6 @@ use iota_sdk::{ const OFFLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-offline-walletdb"; const STRONGHOLD_SNAPSHOT_PATH: &str = "./examples/wallet/offline_signing/example.stronghold"; -const ADDRESS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.address.json"; #[tokio::main] async fn main() -> Result<()> { @@ -43,7 +42,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() + Wallet::builder() .with_secret_manager(SecretManager::Stronghold(secret_manager)) .with_storage_path(OFFLINE_WALLET_DB_PATH) .with_client_options(offline_client) @@ -53,17 +52,5 @@ async fn main() -> Result<()> { println!("Generated a new wallet"); - write_wallet_address_to_file(&wallet).await -} - -async fn write_wallet_address_to_file(wallet: &Wallet) -> Result<()> { - use tokio::io::AsyncWriteExt; - - let wallet_address = wallet.address().await; - let json = serde_json::to_string_pretty(&wallet_address)?; - let mut file = tokio::io::BufWriter::new(tokio::fs::File::create(ADDRESS_FILE_PATH).await?); - println!("example.address.json:\n{json}"); - file.write_all(json.as_bytes()).await?; - file.flush().await?; Ok(()) } diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index d5cfbfca99..e811f60ada 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -15,11 +15,10 @@ use iota_sdk::{ secret::SecretManager, }, crypto::keys::bip44::Bip44, - wallet::{types::Bip44Address, ClientOptions, Result, SendParams, Wallet}, + wallet::{ClientOptions, Result, SendParams, Wallet}, }; 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"; const PREPARED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.prepared_transaction.json"; // Address to which we want to send the amount. const RECV_ADDRESS: &str = "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu"; @@ -38,9 +37,6 @@ async fn main() -> Result<()> { let params = [SendParams::new(SEND_AMOUNT, RECV_ADDRESS)?]; - // Recovers addresses from example `0_address_generation`. - let address = read_address_from_file().await?.into_bech32(); - let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; // Create the wallet with the secret_manager and client options @@ -49,7 +45,6 @@ async fn main() -> Result<()> { .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) - .with_address(address) .finish() .await?; @@ -65,16 +60,6 @@ async fn main() -> Result<()> { Ok(()) } -async fn read_address_from_file() -> Result { - use tokio::io::AsyncReadExt; - - let mut file = tokio::io::BufReader::new(tokio::fs::File::open(ADDRESS_FILE_PATH).await?); - let mut json = String::new(); - file.read_to_string(&mut json).await?; - - Ok(serde_json::from_str(&json)?) -} - async fn write_transaction_to_file(prepared_transaction: PreparedTransactionData) -> Result<()> { use tokio::io::AsyncWriteExt; diff --git a/sdk/examples/wallet/spammer.rs b/sdk/examples/wallet/spammer.rs index 278ffd8608..ac417b924b 100644 --- a/sdk/examples/wallet/spammer.rs +++ b/sdk/examples/wallet/spammer.rs @@ -48,20 +48,10 @@ async fn main() -> Result<()> { 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 wallet = Wallet::builder() .with_secret_manager(SecretManager::Mnemonic(secret_manager)) .with_client_options(client_options) .with_bip_path(bip_path) - .with_address(address) .finish() .await?; diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 6647bcac96..bef0b9a042 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -16,7 +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}, + client::{ + api::GetAddressesOptions, + secret::{GenerateAddressOptions, SecretManage, SecretManager}, + }, types::block::address::{Address, Bech32Address}, wallet::{ core::{Bip44, WalletData, WalletInner}, @@ -71,11 +74,12 @@ where self } - /// Set the wallet address. - pub fn with_address(mut self, address: impl Into>) -> Self { - self.address = address.into(); - self - } + // TODO: only add this fn if the SecretManager is optional. Otherwise the address should be generated. + // /// Set the wallet address. + // pub fn with_address(mut self, address: impl Into>) -> Self { + // self.address = address.into(); + // self + // } /// Set the alias of the wallet. pub fn with_alias(mut self, alias: impl Into>) -> Self { @@ -169,19 +173,31 @@ where true }; + // Panic: client options must exist at this point + let client_options = self.client_options.as_ref().unwrap(); + // May use a previously stored secret manager if it wasn't provided if self.secret_manager.is_none() { - let secret_manager = loaded_wallet_builder + self.secret_manager = loaded_wallet_builder .as_ref() .and_then(|builder| builder.secret_manager.clone()); - - self.secret_manager = secret_manager; + if self.secret_manager.is_none() { + return Err(crate::wallet::Error::MissingParameter("secret_manager")); + } } + // Panic: a secret manager must exist at this point + let secret_manager = self.secret_manager.as_ref().unwrap(); + // 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); + if self.bip_path.is_none() { + return Err(crate::wallet::Error::MissingParameter("bip_path")); + } } + // Panic: a bip path must exist at this point + let bip_path = self.bip_path.as_ref().unwrap(); // May use a previously stored wallet alias if it wasn't provided if self.alias.is_none() { @@ -189,22 +205,24 @@ where } // 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()); - } - - // May create a default Ed25519 wallet address if there's a secret manager. - if self.address.is_none() { - if self.secret_manager.is_some() { - let address = self.create_default_wallet_address().await?; - self.address = Some(address); - } else { + // Since we don't allow setting it `address` must be None at this point. + self.address = loaded_wallet_builder + .as_ref() + .and_then(|builder| builder.address.clone()); + + let generated_address = Self::generate_wallet_address(client_options, bip_path, secret_manager).await?; + if let Some(address) = &self.address { + // Make sure the provided or loaded address doesn't conflict with the secret manager (private key) and the + // bip path. + if address != &generated_address { + // TODO: change to appropriate error, e.g. Error::ConflictingWalletAddress or smth. return Err(crate::wallet::Error::MissingParameter("address")); } + } else { + self.address = Some(generated_address); } - // Panic: can be safely unwrapped now + + // Panic: an address must exist at this point let address = self.address.as_ref().unwrap().clone(); #[cfg(feature = "storage")] @@ -278,39 +296,6 @@ where Ok(wallet) } - /// Generate the wallet address. - pub(crate) async fn create_default_wallet_address(&self) -> crate::wallet::Result { - let bech32_hrp = self - .client_options - .as_ref() - .unwrap() - .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], - ), - )) - } - #[cfg(feature = "storage")] pub(crate) async fn from_wallet(wallet: &Wallet) -> Self { Self { @@ -322,6 +307,36 @@ where secret_manager: Some(wallet.secret_manager.clone()), } } + + async fn generate_wallet_address( + client_options: &ClientOptions, + bip_path: &Bip44, + secret_manager: &Arc>, + ) -> crate::wallet::Result { + let hrp = client_options.network_info.protocol_parameters.bech32_hrp; + + let ed25519_address = secret_manager + .read() + .await + .generate_ed25519_addresses( + bip_path.coin_type, + bip_path.account, + bip_path.address_index..bip_path.address_index + 1, + Some(GenerateAddressOptions { + internal: bip_path.change != 0, + ledger_nano_prompt: false, + }), + ) + .await? + .pop() + // Panic: there must be at least one address + .unwrap(); + + Ok(Bech32Address { + hrp, + inner: ed25519_address.into(), + }) + } } // Check if any of the locked inputs is not used in a transaction and unlock them, so they get available for new From 456c5e527f5357ac03f988b3bf5e1796e6af6123 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Dec 2023 10:45:40 +0100 Subject: [PATCH 04/38] update bindings --- bindings/core/src/lib.rs | 7 ------- .../how_tos/accounts_and_addresses/create-wallet.ts | 11 ----------- bindings/nodejs/examples/wallet/getting-started.ts | 11 ----------- bindings/nodejs/lib/types/wallet/wallet.ts | 2 -- 4 files changed, 31 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 7d4df57e2d..5f7a7bfe8b 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -17,7 +17,6 @@ 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}, }; @@ -44,7 +43,6 @@ pub fn init_logger(config: String) -> std::result::Result<(), fern_logger::Error #[derivative(Debug)] #[serde(rename_all = "camelCase")] pub struct WalletOptions { - pub address: Option, pub alias: Option, #[serde(with = "option_bip44", default)] pub bip_path: Option, @@ -55,11 +53,6 @@ pub struct WalletOptions { } impl WalletOptions { - pub fn with_address(mut self, address: impl Into>) -> Self { - self.address = address.into(); - self - } - pub fn with_alias(mut self, alias: impl Into>) -> Self { self.alias = alias.into(); self diff --git a/bindings/nodejs/examples/how_tos/accounts_and_addresses/create-wallet.ts b/bindings/nodejs/examples/how_tos/accounts_and_addresses/create-wallet.ts index a873310b18..af8dbc646b 100644 --- a/bindings/nodejs/examples/how_tos/accounts_and_addresses/create-wallet.ts +++ b/bindings/nodejs/examples/how_tos/accounts_and_addresses/create-wallet.ts @@ -44,18 +44,7 @@ async function run() { // The mnemonic can't be retrieved from the Stronghold file, so make a backup in a secure place! await secretManager.storeMnemonic(process.env.MNEMONIC as string); - const walletAddress = await secretManager.generateEd25519Addresses({ - coinType: CoinType.IOTA, - accountIndex: 0, - range: { - start: 0, - end: 1, - }, - bech32Hrp: 'tst', - }); - const walletOptions: WalletOptions = { - address: walletAddress[0], storagePath: process.env.WALLET_DB_PATH, clientOptions: { nodes: [process.env.NODE_URL as string], diff --git a/bindings/nodejs/examples/wallet/getting-started.ts b/bindings/nodejs/examples/wallet/getting-started.ts index 4343021912..0212570332 100644 --- a/bindings/nodejs/examples/wallet/getting-started.ts +++ b/bindings/nodejs/examples/wallet/getting-started.ts @@ -44,18 +44,7 @@ async function main() { // The mnemonic can't be retrieved from the Stronghold file, so make a backup in a secure place! await secretManager.storeMnemonic(mnemonic); - const wallet_address = await secretManager.generateEd25519Addresses({ - coinType: CoinType.IOTA, - accountIndex: 0, - range: { - start: 0, - end: 1, - }, - bech32Hrp: 'tst', - }); - const walletOptions: WalletOptions = { - address: wallet_address[0], storagePath: WALLET_DB_PATH, clientOptions: { nodes: [NODE_URL as string], diff --git a/bindings/nodejs/lib/types/wallet/wallet.ts b/bindings/nodejs/lib/types/wallet/wallet.ts index bcf3141e93..b7e0b42616 100644 --- a/bindings/nodejs/lib/types/wallet/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/wallet.ts @@ -9,8 +9,6 @@ import { Bech32Address } from '../block'; /** Options for the Wallet builder. */ export interface WalletOptions { - /** The wallet address. */ - address?: Bech32Address; /** The alias of the wallet. */ alias?: string; /** The the BIP44 path of the wallet. */ From 5aee8e9ebfa7cc514d66e621d1e77422f37bf4d5 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 11 Dec 2023 11:24:54 +0100 Subject: [PATCH 05/38] handle builder address cases --- bindings/core/src/method/wallet.rs | 1 - bindings/core/src/method_handler/wallet.rs | 2 +- sdk/src/wallet/core/builder.rs | 46 +++++++++++----------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index fa428a83bb..9126ad217c 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -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}, diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index 287c882433..8306d68b20 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -8,7 +8,7 @@ use iota_sdk::{ client::api::{ PreparedTransactionData, PreparedTransactionDataDto, SignedTransactionData, SignedTransactionDataDto, }, - types::{block::address::ToBech32Ext, TryFromDto}, + types::TryFromDto, wallet::{types::TransactionWithMetadataDto, PreparedCreateNativeTokenTransactionDto, Wallet}, }; diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index bef0b9a042..9ce97f26ec 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -16,11 +16,8 @@ use crate::wallet::storage::adapter::memory::Memory; #[cfg(feature = "storage")] use crate::wallet::storage::{StorageManager, StorageOptions}; use crate::{ - client::{ - api::GetAddressesOptions, - secret::{GenerateAddressOptions, SecretManage, SecretManager}, - }, - types::block::address::{Address, Bech32Address}, + client::secret::{GenerateAddressOptions, SecretManage, SecretManager}, + types::block::address::Bech32Address, wallet::{ core::{Bip44, WalletData, WalletInner}, operations::syncing::SyncOptions, @@ -74,12 +71,11 @@ where self } - // TODO: only add this fn if the SecretManager is optional. Otherwise the address should be generated. - // /// Set the wallet address. - // pub fn with_address(mut self, address: impl Into>) -> Self { - // self.address = address.into(); - // self - // } + /// Set the wallet address. + pub fn with_address(mut self, address: impl Into>) -> Self { + self.address = address.into(); + self + } /// Set the alias of the wallet. pub fn with_alias(mut self, alias: impl Into>) -> Self { @@ -204,23 +200,25 @@ where 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 - // Since we don't allow setting it `address` must be None at this point. - self.address = loaded_wallet_builder + let provided_address = self.address; + let restored_address = loaded_wallet_builder .as_ref() .and_then(|builder| builder.address.clone()); - let generated_address = Self::generate_wallet_address(client_options, bip_path, secret_manager).await?; - if let Some(address) = &self.address { - // Make sure the provided or loaded address doesn't conflict with the secret manager (private key) and the - // bip path. - if address != &generated_address { - // TODO: change to appropriate error, e.g. Error::ConflictingWalletAddress or smth. - return Err(crate::wallet::Error::MissingParameter("address")); + self.address = Some(match (provided_address, restored_address) { + (Some(provided), Some(restored)) => { + // error early if they conflict + if provided != restored { + // TODO: change to appropriate error, e.g. Error::ConflictingWalletAddress or smth. + return Err(crate::wallet::Error::MissingParameter("address")); + } else { + restored + } } - } else { - self.address = Some(generated_address); - } + (Some(provided), None) => provided, + (None, Some(restored)) => restored, + (None, None) => Self::generate_wallet_address(client_options, bip_path, secret_manager).await?, + }); // Panic: an address must exist at this point let address = self.address.as_ref().unwrap().clone(); From a3cc1970c8619f55ebf82f435fc7458f4567cb29 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 12 Feb 2024 15:58:54 +0100 Subject: [PATCH 06/38] unused import --- bindings/nodejs/lib/types/wallet/wallet.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/bindings/nodejs/lib/types/wallet/wallet.ts b/bindings/nodejs/lib/types/wallet/wallet.ts index 0fb69ecb37..a0c2d350be 100644 --- a/bindings/nodejs/lib/types/wallet/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/wallet.ts @@ -11,7 +11,6 @@ import { import { DecayedMana, HexEncodedString, u256, u64 } from '../utils'; import { IClientOptions } from '../client'; import { Bip44, SecretManagerType } from '../secret_manager/secret-manager'; -import { Bech32Address } from '../block'; /** Options for the Wallet builder. */ export interface WalletOptions { From 6f2b916566bc44b0fa091244ab1d55f004c43912 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sat, 17 Feb 2024 00:04:04 +0100 Subject: [PATCH 07/38] re-add address to wallet options --- bindings/core/src/lib.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 5f7a7bfe8b..45e1e13a4b 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -17,6 +17,7 @@ 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}, }; @@ -43,6 +44,7 @@ pub fn init_logger(config: String) -> std::result::Result<(), fern_logger::Error #[derivative(Debug)] #[serde(rename_all = "camelCase")] pub struct WalletOptions { + pub address: Option, pub alias: Option, #[serde(with = "option_bip44", default)] pub bip_path: Option, @@ -53,8 +55,8 @@ pub struct WalletOptions { } impl WalletOptions { - pub fn with_alias(mut self, alias: impl Into>) -> Self { - self.alias = alias.into(); + pub fn with_address(mut self, address: impl Into>) -> Self { + self.address = address.into(); self } @@ -63,6 +65,11 @@ impl WalletOptions { self } + pub fn with_alias(mut self, alias: impl Into>) -> Self { + self.alias = alias.into(); + self + } + pub fn with_client_options(mut self, client_options: impl Into>) -> Self { self.client_options = client_options.into(); self @@ -82,8 +89,9 @@ impl WalletOptions { pub async fn build(self) -> iota_sdk::wallet::Result { log::debug!("wallet options: {self:?}"); let mut builder = Wallet::builder() - .with_alias(self.alias) + .with_address(self.address) .with_bip_path(self.bip_path) + .with_alias(self.alias) .with_client_options(self.client_options); #[cfg(feature = "storage")] From 31e04ff649527e69f77a62ede91db5cbc9a20f05 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sun, 18 Feb 2024 18:21:51 +0100 Subject: [PATCH 08/38] fix tests --- sdk/src/client/api/address.rs | 52 +++++++++++++++++++++++++- sdk/tests/wallet/address_generation.rs | 33 ++++++++-------- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index 6d5501d4d7..6d5fe3de32 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -97,7 +97,31 @@ impl Default for GetAddressesOptions { } impl SecretManager { - /// Get a vector of public bech32 addresses + /// Generates a single Ed25519 backed Bech32 address. + pub async fn generate_ed25519_address( + &self, + coin_type: u32, + account_index: u32, + address_index: u32, + bech32_hrp: impl ConvertTo, + options: impl Into> + Send, + ) -> Result { + let hrp = bech32_hrp.convert()?; + Ok(SecretManage::generate_ed25519_addresses( + self, + coin_type, + account_index, + address_index..address_index + 1, + options, + ) + .await? + .pop() + // Panic: if the secret manager hasn't failed then there must be an address. + .unwrap() + .to_bech32(hrp)) + } + + /// Generates a vector of Ed25519 backed Bech32 addresses. pub async fn generate_ed25519_addresses( &self, GetAddressesOptions { @@ -117,7 +141,31 @@ impl SecretManager { ) } - /// Get a vector of EVM address strings + /// Generates a single EVM address hex string. + pub async fn generate_evm_address( + &self, + coin_type: u32, + account_index: u32, + address_index: u32, + options: impl Into> + Send, + ) -> Result { + Ok(prefix_hex::encode( + SecretManage::generate_evm_addresses( + self, + coin_type, + account_index, + address_index..address_index + 1, + options, + ) + .await? + .pop() + // Panic: if the secret manager hasn't failed then there must be an address. + .unwrap() + .as_ref(), + )) + } + + /// Generates a vector of EVM address hex strings. pub async fn generate_evm_addresses( &self, GetAddressesOptions { diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index 304b814c15..4a0b3ca425 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -17,7 +17,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, SecretManager}, Error as ClientError, }, - types::block::address::ToBech32Ext, + types::block::address::{Hrp, ToBech32Ext}, wallet::{ClientOptions, Error, Result, Wallet}, }; use pretty_assertions::assert_eq; @@ -30,13 +30,11 @@ async fn address_generation_mnemonic() -> Result<()> { SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?); let address = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) - .await? - .pop() - .unwrap(); + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .await?; assert_eq!( - address.to_bech32_unchecked("smr"), + address, // Address generated with bip32 path: [44, 4218, 0, 0, 0]. "smr1qrpwecegav7eh0z363ca69laxej64rrt4e3u0rtycyuh0mam3vq3ulygj9p" ); @@ -47,11 +45,15 @@ async fn address_generation_mnemonic() -> Result<()> { #[cfg(feature = "stronghold")] #[tokio::test] async fn address_generation_stronghold() -> Result<()> { + let storage_path = "test-storage/address_generation_stronghold"; + setup(storage_path)?; + iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); let secret_manager = StrongholdSecretManager::builder() .password("some_hopefully_secure_password".to_owned()) - .build("test-storage/wallet_address_generation_stronghold/test.stronghold")?; + .build(format!("{}/test.stronghold", storage_path))?; + secret_manager .store_mnemonic(Mnemonic::from(DEFAULT_MNEMONIC.to_string())) .await?; @@ -59,17 +61,16 @@ async fn address_generation_stronghold() -> Result<()> { let secret_manager = SecretManager::Stronghold(secret_manager); let address = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) - .await? - .pop() - .unwrap(); + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .await?; assert_eq!( - address.to_bech32_unchecked("smr"), + address, // Address generated with bip32 path: [44, 4218, 0, 0, 0]. "smr1qrpwecegav7eh0z363ca69laxej64rrt4e3u0rtycyuh0mam3vq3ulygj9p" ); + tear_down(storage_path)?; Ok(()) } @@ -83,10 +84,8 @@ async fn address_generation_ledger() -> Result<()> { let secret_manager = SecretManager::LedgerNano(secret_manager); let address = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::default().with_coin_type(IOTA_COIN_TYPE)) - .await? - .pop() - .unwrap(); + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .await?; assert_eq!( address.to_bech32_unchecked("smr"), @@ -109,7 +108,7 @@ async fn address_generation_ledger() -> Result<()> { // #[allow(unused_mut)] // let mut wallet_builder = Wallet::builder() -// .with_secret_manager(SecretManager::Placeholder) +// .with_secret_manager(Secress_generation_stronghold ... FAILEDetManager::Placeholder) // .with_client_options(client_options) // .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); From 1d2323073bcff723869041b1a4310ca81102b65d Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sun, 18 Feb 2024 18:33:13 +0100 Subject: [PATCH 09/38] re-enable placeholder test --- sdk/tests/wallet/address_generation.rs | 43 +++++++++----------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index 4a0b3ca425..77f2add518 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -70,8 +70,7 @@ async fn address_generation_stronghold() -> Result<()> { "smr1qrpwecegav7eh0z363ca69laxej64rrt4e3u0rtycyuh0mam3vq3ulygj9p" ); - tear_down(storage_path)?; - Ok(()) + tear_down(storage_path) } #[tokio::test] @@ -99,30 +98,16 @@ async fn address_generation_ledger() -> Result<()> { Ok(()) } -// #[tokio::test] -// async fn address_generation_placeholder() -> Result<()> { -// let storage_path = "test-storage/wallet_address_generation_placeholder"; -// setup(storage_path)?; - -// let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; - -// #[allow(unused_mut)] -// let mut wallet_builder = Wallet::builder() -// .with_secret_manager(Secress_generation_stronghold ... FAILEDetManager::Placeholder) -// .with_client_options(client_options) -// .with_bip_path(Bip44::new(IOTA_COIN_TYPE)); - -// #[cfg(feature = "storage")] -// { -// wallet_builder = wallet_builder.with_storage_path(storage_path); -// } -// let wallet = wallet_builder.finish().await?; - -// if let Err(Error::Client(error)) = wallet.generate_ed25519_address(0, 0, None).await { -// assert!(matches!(*error, ClientError::PlaceholderSecretManager)) -// } else { -// panic!("expected PlaceholderSecretManager") -// } - -// tear_down(storage_path) -// } +#[tokio::test] +async fn address_generation_placeholder() -> Result<()> { + let secret_manager = SecretManager::Placeholder; + + assert!(matches!( + secret_manager + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .await, + Err(iota_sdk::client::Error::PlaceholderSecretManager) + )); + + Ok(()) +} From f70739700909bc94ca6a34d9d85b31a55b353487 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sun, 18 Feb 2024 18:44:48 +0100 Subject: [PATCH 10/38] move tests --- sdk/tests/client/common/constants.rs | 2 ++ sdk/tests/client/common/mod.rs | 16 ++++++++++++++-- .../secret_manager}/address_generation.rs | 6 +++--- sdk/tests/client/secret_manager/mod.rs | 1 + sdk/tests/wallet/mod.rs | 1 - 5 files changed, 20 insertions(+), 6 deletions(-) rename sdk/tests/{wallet => client/secret_manager}/address_generation.rs (96%) diff --git a/sdk/tests/client/common/constants.rs b/sdk/tests/client/common/constants.rs index 7f7a02fb2b..c06eb0d4e6 100644 --- a/sdk/tests/client/common/constants.rs +++ b/sdk/tests/client/common/constants.rs @@ -4,3 +4,5 @@ pub static NODE_LOCAL: &str = "http://localhost:8050"; pub static FAUCET_URL: &str = "http://localhost:8091/api/enqueue"; + +pub static DEFAULT_MNEMONIC: &str = "inhale gorilla deny three celery song category owner lottery rent author wealth penalty crawl hobby obtain glad warm early rain clutch slab august bleak"; diff --git a/sdk/tests/client/common/mod.rs b/sdk/tests/client/common/mod.rs index ef018ba902..7acff3ecaa 100644 --- a/sdk/tests/client/common/mod.rs +++ b/sdk/tests/client/common/mod.rs @@ -8,9 +8,9 @@ mod constants; // api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, node_api::indexer::query_parameters::QueryParameter, // request_funds_from_faucet, secret::SecretManager, Client, Result, // }; -use iota_sdk::client::Client; +use iota_sdk::client::{Client, Result}; -pub use self::constants::{FAUCET_URL, NODE_LOCAL}; +pub use self::constants::*; /// Sets up a Client with node health ignored. pub async fn setup_client_with_node_health_ignored() -> Client { @@ -62,3 +62,15 @@ pub async fn setup_client_with_node_health_ignored() -> Client { // } // panic!("Faucet no longer wants to hand over coins"); // } + +#[allow(dead_code)] +pub(crate) fn setup(path: &str) -> Result<()> { + std::fs::remove_dir_all(path).ok(); + Ok(()) +} + +#[allow(dead_code)] +pub(crate) fn tear_down(path: &str) -> Result<()> { + std::fs::remove_dir_all(path).ok(); + Ok(()) +} diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/client/secret_manager/address_generation.rs similarity index 96% rename from sdk/tests/wallet/address_generation.rs rename to sdk/tests/client/secret_manager/address_generation.rs index 77f2add518..6547aba33b 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/client/secret_manager/address_generation.rs @@ -15,14 +15,14 @@ use iota_sdk::{ api::GetAddressesOptions, constants::IOTA_COIN_TYPE, secret::{mnemonic::MnemonicSecretManager, SecretManager}, - Error as ClientError, + Error, Result, }, types::block::address::{Hrp, ToBech32Ext}, - wallet::{ClientOptions, Error, Result, Wallet}, + wallet::{ClientOptions, Wallet}, }; use pretty_assertions::assert_eq; -use crate::wallet::common::{setup, tear_down, DEFAULT_MNEMONIC, NODE_LOCAL}; +use crate::client::common::{setup, tear_down, DEFAULT_MNEMONIC, NODE_LOCAL}; #[tokio::test] async fn address_generation_mnemonic() -> Result<()> { diff --git a/sdk/tests/client/secret_manager/mod.rs b/sdk/tests/client/secret_manager/mod.rs index 4e2a7988d5..4ed72f4a0b 100644 --- a/sdk/tests/client/secret_manager/mod.rs +++ b/sdk/tests/client/secret_manager/mod.rs @@ -1,6 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +mod address_generation; mod mnemonic; #[cfg(feature = "private_key_secret_manager")] mod private_key; diff --git a/sdk/tests/wallet/mod.rs b/sdk/tests/wallet/mod.rs index 0cb359191e..4ef0f24d96 100644 --- a/sdk/tests/wallet/mod.rs +++ b/sdk/tests/wallet/mod.rs @@ -1,7 +1,6 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -mod address_generation; #[cfg(all(feature = "stronghold", feature = "storage"))] mod backup_restore; mod balance; From 35da3bb32675c318cdfec1537ba3159723ba2c4e Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 19 Feb 2024 09:49:49 +0100 Subject: [PATCH 11/38] nodejs: address to wallet options --- bindings/nodejs/lib/types/wallet/wallet.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/nodejs/lib/types/wallet/wallet.ts b/bindings/nodejs/lib/types/wallet/wallet.ts index a0c2d350be..31de56761b 100644 --- a/bindings/nodejs/lib/types/wallet/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/wallet.ts @@ -11,9 +11,12 @@ import { import { DecayedMana, HexEncodedString, u256, u64 } from '../utils'; import { IClientOptions } from '../client'; import { Bip44, SecretManagerType } from '../secret_manager/secret-manager'; +import { Bech32Address } from '../block'; /** Options for the Wallet builder. */ export interface WalletOptions { + /** The wallet address. */ + address?: Bech32Address; /** The alias of the wallet. */ alias?: string; /** The the BIP44 path of the wallet. */ From 916306aebbd7a7d637a2e353d6f6beb3875de344 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Tue, 20 Feb 2024 17:30:51 +0100 Subject: [PATCH 12/38] revert going through json file for address --- .../offline_signing/0_generate_address.rs | 17 +++++++++++++++-- .../offline_signing/1_prepare_transaction.rs | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/sdk/examples/wallet/offline_signing/0_generate_address.rs b/sdk/examples/wallet/offline_signing/0_generate_address.rs index 2aceb68480..f1f776de60 100644 --- a/sdk/examples/wallet/offline_signing/0_generate_address.rs +++ b/sdk/examples/wallet/offline_signing/0_generate_address.rs @@ -19,6 +19,7 @@ use iota_sdk::{ const OFFLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-offline-walletdb"; const STRONGHOLD_SNAPSHOT_PATH: &str = "./examples/wallet/offline_signing/example.stronghold"; +const ADDRESS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.address.json"; #[tokio::main] async fn main() -> Result<()> { @@ -42,15 +43,27 @@ async fn main() -> Result<()> { secret_manager.store_mnemonic(mnemonic).await?; // Create the wallet with the secret_manager and client options - Wallet::builder() + let wallet = Wallet::builder() .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)) .finish() .await?; - println!("Generated a new wallet"); + write_wallet_address_to_file(&wallet).await?; + Ok(()) +} + +async fn write_wallet_address_to_file(wallet: &Wallet) -> Result<()> { + use tokio::io::AsyncWriteExt; + + let wallet_address = wallet.address().await; + let json = serde_json::to_string_pretty(&wallet_address)?; + let mut file = tokio::io::BufWriter::new(tokio::fs::File::create(ADDRESS_FILE_PATH).await?); + println!("example.address.json:\n{json}"); + file.write_all(json.as_bytes()).await?; + file.flush().await?; Ok(()) } diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index a55630d6e3..79afb6640e 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -9,14 +9,19 @@ //! ``` use iota_sdk::{ - client::{api::PreparedTransactionDataDto, constants::SHIMMER_COIN_TYPE, secret::SecretManager}, + client::{ + api::PreparedTransactionDataDto, constants::SHIMMER_COIN_TYPE, secret::SecretManager, + stronghold::StrongholdAdapter, + }, crypto::keys::bip44::Bip44, + types::block::address::Bech32Address, wallet::{ClientOptions, Result, SendParams, Wallet}, }; const ONLINE_WALLET_DB_PATH: &str = "./examples/wallet/offline_signing/example-online-walletdb"; const PREPARED_TRANSACTION_FILE_PATH: &str = "./examples/wallet/offline_signing/example.prepared_transaction.json"; const PROTOCOL_PARAMETERS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.protocol_parameters.json"; +const ADDRESS_FILE_PATH: &str = "./examples/wallet/offline_signing/example.address.json"; // Address to which we want to send the amount. const RECV_ADDRESS: &str = "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu"; // The amount to send. @@ -40,6 +45,7 @@ async fn main() -> Result<()> { .with_secret_manager(SecretManager::Placeholder) .with_storage_path(ONLINE_WALLET_DB_PATH) .with_client_options(client_options.clone()) + .with_address(read_address_from_file().await?) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; @@ -66,6 +72,16 @@ async fn main() -> Result<()> { Ok(()) } +async fn read_address_from_file() -> Result { + use tokio::io::AsyncReadExt; + + let mut file = tokio::io::BufReader::new(tokio::fs::File::open(ADDRESS_FILE_PATH).await?); + let mut json = String::new(); + file.read_to_string(&mut json).await?; + + Ok(serde_json::from_str(&json)?) +} + async fn write_data_to_file(data: impl serde::Serialize, path: &str) -> Result<()> { use tokio::io::AsyncWriteExt; From 137edebd70d6d35b2f94bdc4ea7e89226844cf56 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 21 Feb 2024 14:38:05 +0100 Subject: [PATCH 13/38] revert unrelated change --- bindings/core/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/core/src/lib.rs b/bindings/core/src/lib.rs index 45e1e13a4b..d7dc366cfa 100644 --- a/bindings/core/src/lib.rs +++ b/bindings/core/src/lib.rs @@ -60,13 +60,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_alias(mut self, alias: impl Into>) -> Self { + self.alias = alias.into(); self } - pub fn with_alias(mut self, alias: impl Into>) -> Self { - self.alias = alias.into(); + pub fn with_bip_path(mut self, bip_path: impl Into>) -> Self { + self.bip_path = bip_path.into(); self } @@ -90,8 +90,8 @@ impl WalletOptions { log::debug!("wallet options: {self:?}"); let mut builder = Wallet::builder() .with_address(self.address) - .with_bip_path(self.bip_path) .with_alias(self.alias) + .with_bip_path(self.bip_path) .with_client_options(self.client_options); #[cfg(feature = "storage")] From 2a61956ef9109978e4caedfde71e92d9775d2dcc Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 27 Feb 2024 13:31:25 +0100 Subject: [PATCH 14/38] Update sdk/tests/client/secret_manager/address_generation.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- sdk/tests/client/secret_manager/address_generation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/tests/client/secret_manager/address_generation.rs b/sdk/tests/client/secret_manager/address_generation.rs index 6547aba33b..a21bcc8bf7 100644 --- a/sdk/tests/client/secret_manager/address_generation.rs +++ b/sdk/tests/client/secret_manager/address_generation.rs @@ -1,4 +1,4 @@ -// Copyright 2023 IOTA Stiftung +// Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #[cfg(feature = "stronghold")] From 1f0da78448d1c797b23e90e61a7f7b92d2de9dea Mon Sep 17 00:00:00 2001 From: /alex/ Date: Fri, 1 Mar 2024 16:26:12 +0100 Subject: [PATCH 15/38] recipient Co-authored-by: DaughterOfMars --- sdk/examples/wallet/ledger_nano.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/examples/wallet/ledger_nano.rs b/sdk/examples/wallet/ledger_nano.rs index fd7599749b..3a99e602bf 100644 --- a/sdk/examples/wallet/ledger_nano.rs +++ b/sdk/examples/wallet/ledger_nano.rs @@ -47,7 +47,7 @@ async fn main() -> Result<(), Box> { .await?; let recv_address = wallet.address().await; - println!("receive address: {recv_address}"); + println!("recipient address: {recv_address}"); println!("{:?}", wallet.get_ledger_nano_status().await?); let now = tokio::time::Instant::now(); From 1c02b2ac2e46e392c26ccf9895c257e5f5b96d34 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 4 Mar 2024 15:50:46 +0100 Subject: [PATCH 16/38] bad wildcards --- sdk/tests/client/common/mod.rs | 2 +- sdk/tests/wallet/common/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/tests/client/common/mod.rs b/sdk/tests/client/common/mod.rs index 7acff3ecaa..75fee9647d 100644 --- a/sdk/tests/client/common/mod.rs +++ b/sdk/tests/client/common/mod.rs @@ -10,7 +10,7 @@ mod constants; // }; use iota_sdk::client::{Client, Result}; -pub use self::constants::*; +pub use self::constants::{DEFAULT_MNEMONIC, FAUCET_URL, NODE_LOCAL}; /// Sets up a Client with node health ignored. pub async fn setup_client_with_node_health_ignored() -> Client { diff --git a/sdk/tests/wallet/common/mod.rs b/sdk/tests/wallet/common/mod.rs index 82a48d1679..045ca06ce3 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -15,7 +15,7 @@ use iota_sdk::{ wallet::{ClientOptions, Wallet}, }; -pub use self::constants::*; +pub use self::constants::{DEFAULT_MNEMONIC, FAUCET_URL, NODE_LOCAL, NODE_OTHER}; /// It creates a new wallet with a mnemonic secret manager, a client options object, /// SHIMMER_COIN_TYPE, and a storage path From ad693241cd73611cd8c1e3b74365d7948b1d1de7 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 4 Mar 2024 15:57:15 +0100 Subject: [PATCH 17/38] PR suggestion --- sdk/src/wallet/core/builder.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 46f38559a6..5c0e746f9e 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -170,12 +170,12 @@ where // May use a previously stored secret manager if it wasn't provided if self.secret_manager.is_none() { - self.secret_manager = loaded_wallet_builder - .as_ref() - .and_then(|builder| builder.secret_manager.clone()); - if self.secret_manager.is_none() { - return Err(crate::wallet::Error::MissingParameter("secret_manager")); - } + self.secret_manager.replace( + loaded_wallet_builder + .as_ref() + .and_then(|builder| builder.secret_manager.clone()) + .ok_or(crate::wallet::Error::MissingParameter("secret_manager"))?, + ); } let mut verify_address = false; From ec1915f269bf027a7255e00322e5c131255c82e0 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Mon, 4 Mar 2024 15:59:20 +0100 Subject: [PATCH 18/38] import --- cli/src/cli.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index d42fd3748b..d6f247346c 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,8 +1,7 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use core::str::FromStr; -use std::path::Path; +use std::{path::Path, str::FromStr}; use clap::{builder::BoolishValueParser, Args, CommandFactory, Parser, Subcommand}; use eyre::{bail, Error}; From 0d957c1902fa92b72115ca6021046729c0727e17 Mon Sep 17 00:00:00 2001 From: /alex/ Date: Mon, 4 Mar 2024 16:11:40 +0100 Subject: [PATCH 19/38] example doc Co-authored-by: DaughterOfMars --- sdk/examples/wallet/offline_signing/1_prepare_transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs index 79739bdae4..93c374fc96 100644 --- a/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs +++ b/sdk/examples/wallet/offline_signing/1_prepare_transaction.rs @@ -38,7 +38,7 @@ async fn main() -> Result<(), Box> { let params = [SendParams::new(SEND_AMOUNT, RECV_ADDRESS)?]; - // Recovers the address from example `0_generate_address.rs`. + // Recovers the address generated by the example `0_generate_address.rs`. let address = read_address_from_file().await?; let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?; From 623cd8ba000625eff77e544360010d7af6ec1fac Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Tue, 5 Mar 2024 16:29:29 +0100 Subject: [PATCH 20/38] fix example --- sdk/examples/wallet/logger.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/examples/wallet/logger.rs b/sdk/examples/wallet/logger.rs index 8abfc0ed0c..907a75120d 100644 --- a/sdk/examples/wallet/logger.rs +++ b/sdk/examples/wallet/logger.rs @@ -43,9 +43,12 @@ async fn main() -> Result<(), Box> { std::env::var("MNEMONIC").unwrap(), )?); + let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?; + let wallet = Wallet::::builder() .with_storage_path(&std::env::var("WALLET_DB_PATH").unwrap()) .with_client_options(client_options) + .with_secret_manager(secret_manager) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) .finish() .await?; From 2fb4b53d3c473cc3b08e4ff83b2151d6bce30bdd Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 11:21:08 +0100 Subject: [PATCH 21/38] rename generate methods --- sdk/src/client/api/address.rs | 19 +++++++++++++------ sdk/src/client/secret/ledger_nano.rs | 2 +- sdk/src/wallet/core/builder.rs | 5 ----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index e8a809223f..50b2ce73d9 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -33,6 +33,9 @@ pub struct GetAddressesOptions { } impl GetAddressesOptions { + // TODO: can we remove this function? It's not clear from the outside that it's just the default + // with a requested HRP. I think the caller can just do what this function does. Also ... this + // we do several API requests unnecessarily because oftentimes we could just re-use the HRP. pub async fn from_client(client: &Client) -> Result { Ok(Self::default().with_bech32_hrp(client.get_bech32_hrp().await?)) } @@ -97,8 +100,8 @@ impl Default for GetAddressesOptions { } impl SecretManager { - /// Generates a single Ed25519 backed Bech32 address. - pub async fn generate_ed25519_address( + /// Generates a Bech32 formatted Ed25519 address. + pub async fn generate_ed25519_address_as_bech32( &self, coin_type: u32, account_index: u32, @@ -119,8 +122,8 @@ impl SecretManager { .to_bech32(hrp)) } - /// Generates a vector of Ed25519 backed Bech32 addresses. - pub async fn generate_ed25519_addresses( + /// Generates a vector of Bech32 formatted Ed25519 addresses. + pub async fn generate_ed25519_addresses_as_bech32( &self, GetAddressesOptions { coin_type, @@ -195,8 +198,12 @@ pub async fn search_address( .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?; + let public = secret_manager + .generate_ed25519_addresses_as_bech32(opts.clone()) + .await?; + let internal = secret_manager + .generate_ed25519_addresses_as_bech32(opts.internal()) + .await?; for index in 0..public.len() { if public[index].inner == *address { return Ok((range.start + index as u32, false)); diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index 2792ab8cfb..0f61c6cd2a 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -626,7 +626,7 @@ mod tests { secret_manager.non_interactive = true; let addresses = SecretManager::LedgerNano(secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(IOTA_COIN_TYPE) .with_account_index(0) diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index fcda7a46cb..7848733294 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -168,9 +168,6 @@ where true }; - // Panic: client options must exist at this point - let client_options = self.client_options.as_ref().unwrap(); - // May use a previously stored secret manager if it wasn't provided if self.secret_manager.is_none() { self.secret_manager.replace( @@ -216,8 +213,6 @@ where } else { self.bip_path = loaded_bip_path; } - // Panic: a bip path must exist at this point - let bip_path = self.bip_path.as_ref().unwrap(); // Create the node client. let client = self From beb50b4ddd99922a16d7148460b044c54a16e943 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 11:24:40 +0100 Subject: [PATCH 22/38] Core: add SecretManager:GenerateEd25519AddressAsBech32 method --- bindings/core/src/method/secret_manager.rs | 15 ++++++++++++-- .../core/src/method_handler/secret_manager.rs | 20 +++++++++++++++++++ bindings/core/src/method_handler/wallet.rs | 5 +---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 2a13acbca0..659cf8bd0a 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -4,8 +4,11 @@ use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::{ - client::api::{GetAddressesOptions, PreparedTransactionDataDto}, - types::block::{protocol::ProtocolParameters, UnsignedBlockDto}, + client::{ + api::{GetAddressesOptions, PreparedTransactionDataDto}, + secret::GenerateAddressOptions, + }, + types::block::{address::Hrp, protocol::ProtocolParameters, UnsignedBlockDto}, utils::serde::bip44::Bip44Def, }; use serde::{Deserialize, Serialize}; @@ -19,6 +22,14 @@ use crate::OmittedDebug; #[serde(tag = "name", content = "data", rename_all = "camelCase")] #[non_exhaustive] pub enum SecretManagerMethod { + /// Generate a Bech32 formatted Ed25519 address. + GenerateEd25519AddressAsBech32 { + coin_type: u32, + account_index: u32, + address_index: u32, + options: GenerateAddressOptions, + bech32_hrp: Hrp, + }, /// Generate Ed25519 addresses. GenerateEd25519Addresses { /// Addresses generation options diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index ca01227830..5993ac52ac 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -28,6 +28,26 @@ where ClientError: From, { let response = match method { + SecretManagerMethod::GenerateEd25519AddressAsBech32 { + coin_type, + account_index, + address_index, + options, + bech32_hrp, + } => { + let address_indexes = address_index..address_index + 1; + let address = secret_manager + .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .await + .map_err(ClientError::from)? + .into_iter() + .map(|a| a.to_bech32(bech32_hrp)) + .collect::>() + .pop() + // Panic: at this point there must be at least one address + .unwrap(); + Response::Bech32Address(address) + } SecretManagerMethod::GenerateEd25519Addresses { options: GetAddressesOptions { diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index ba0162a1d7..91e9beb0de 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -6,10 +6,7 @@ use std::time::Duration; use crypto::signatures::ed25519::PublicKey; use iota_sdk::{ client::api::{PreparedTransactionData, SignedTransactionData, SignedTransactionDataDto}, - types::{ - block::{address::ToBech32Ext, output::feature::BlockIssuerKeySource}, - TryFromDto, - }, + types::{block::output::feature::BlockIssuerKeySource, TryFromDto}, wallet::{types::TransactionWithMetadataDto, Wallet}, }; From f056d0ad06e23bfdfb24eaf1d7b6284f6555a902 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 11:26:57 +0100 Subject: [PATCH 23/38] update examples and tests --- sdk/examples/client/01_generate_addresses.rs | 6 ++--- sdk/examples/client/02_address_balance.rs | 14 +++------- .../client/high_level/search_address.rs | 2 +- sdk/examples/client/ledger_nano.rs | 2 +- .../client/ledger_nano_transaction.rs | 2 +- sdk/examples/client/quorum.rs | 2 +- sdk/examples/client/send_all.rs | 4 +-- sdk/examples/client/stronghold.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 2 +- sdk/tests/client/addresses.rs | 23 +++++++++------- sdk/tests/client/node_api/core.rs | 2 +- sdk/tests/client/node_api/mod.rs | 2 +- .../secret_manager/address_generation.rs | 10 +++---- sdk/tests/client/secret_manager/mnemonic.rs | 16 +++++------- .../client/secret_manager/private_key.rs | 8 +++--- sdk/tests/client/secret_manager/stronghold.rs | 4 +-- sdk/tests/client/signing/account.rs | 4 +-- sdk/tests/client/signing/basic.rs | 8 +++--- sdk/tests/client/signing/delegation.rs | 26 +++++++++---------- sdk/tests/client/signing/mod.rs | 2 +- sdk/tests/client/signing/nft.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 4 +-- 22 files changed, 71 insertions(+), 76 deletions(-) diff --git a/sdk/examples/client/01_generate_addresses.rs b/sdk/examples/client/01_generate_addresses.rs index d3ab4f6dcd..06f2cabfbd 100644 --- a/sdk/examples/client/01_generate_addresses.rs +++ b/sdk/examples/client/01_generate_addresses.rs @@ -33,7 +33,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with default account index and range let addresses = secret_manager - .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?) + .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?) .await?; println!("List of generated public addresses (default):"); @@ -41,7 +41,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) @@ -54,7 +54,7 @@ async fn main() -> Result<(), Box> { // Generate internal addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/02_address_balance.rs b/sdk/examples/client/02_address_balance.rs index 148ba7eefb..45abb91e89 100644 --- a/sdk/examples/client/02_address_balance.rs +++ b/sdk/examples/client/02_address_balance.rs @@ -11,8 +11,8 @@ use iota_sdk::{ client::{ - api::GetAddressesOptions, node_api::indexer::query_parameters::BasicOutputQueryParameters, - secret::SecretManager, Client, + api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, + node_api::indexer::query_parameters::BasicOutputQueryParameters, secret::SecretManager, Client, }, types::block::output::NativeTokensBuilder, }; @@ -36,14 +36,8 @@ async fn main() -> Result<(), Box> { // 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_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, client.get_bech32_hrp().await?, None) + .await?; // 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/high_level/search_address.rs b/sdk/examples/client/high_level/search_address.rs index 7b8f066402..0540adde02 100644 --- a/sdk/examples/client/high_level/search_address.rs +++ b/sdk/examples/client/high_level/search_address.rs @@ -38,7 +38,7 @@ async fn main() -> Result<(), Box> { addr } else { secret_manager - .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) + .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) .await?[0] .clone() }; diff --git a/sdk/examples/client/ledger_nano.rs b/sdk/examples/client/ledger_nano.rs index c9c07e33a2..93d88b4f33 100644 --- a/sdk/examples/client/ledger_nano.rs +++ b/sdk/examples/client/ledger_nano.rs @@ -35,7 +35,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) diff --git a/sdk/examples/client/ledger_nano_transaction.rs b/sdk/examples/client/ledger_nano_transaction.rs index 790fd060bd..29e4e69017 100644 --- a/sdk/examples/client/ledger_nano_transaction.rs +++ b/sdk/examples/client/ledger_nano_transaction.rs @@ -44,7 +44,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/quorum.rs b/sdk/examples/client/quorum.rs index 6e211c3c0e..0da23a14f0 100644 --- a/sdk/examples/client/quorum.rs +++ b/sdk/examples/client/quorum.rs @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { // Generate the first address let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/send_all.rs b/sdk/examples/client/send_all.rs index a975f652b1..7360a8d89f 100644 --- a/sdk/examples/client/send_all.rs +++ b/sdk/examples/client/send_all.rs @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { let issuer_id = std::env::var("ISSUER_ID").unwrap().parse::().unwrap(); let from_address = secret_manager_1 - .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) + .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) .await?[0] .clone(); @@ -90,7 +90,7 @@ async fn main() -> Result<(), Box> { println!("Total amount: {total_amount}"); let to_address = secret_manager_2 - .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) + .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) .await?[0] .clone(); diff --git a/sdk/examples/client/stronghold.rs b/sdk/examples/client/stronghold.rs index e328b6a947..496d319626 100644 --- a/sdk/examples/client/stronghold.rs +++ b/sdk/examples/client/stronghold.rs @@ -37,7 +37,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) 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 8b47726162..76f997491c 100644 --- a/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -48,7 +48,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index a4a180ac01..82d5277139 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -29,9 +29,12 @@ async fn ed25519_addresses() { .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_ed25519_addresses_as_bech32(opts.clone()) + .await + .unwrap(); let internal = secret_manager - .generate_ed25519_addresses(opts.internal()) + .generate_ed25519_addresses_as_bech32(opts.internal()) .await .unwrap(); @@ -90,7 +93,7 @@ async fn mnemonic_address_generation_iota() { // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(IOTA_BECH32_HRP) .with_coin_type(IOTA_COIN_TYPE) @@ -111,7 +114,7 @@ async fn mnemonic_address_generation_iota() { // account 1 let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(IOTA_BECH32_HRP) .with_coin_type(IOTA_COIN_TYPE) @@ -134,7 +137,7 @@ async fn mnemonic_address_generation_shimmer() { // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -155,7 +158,7 @@ async fn mnemonic_address_generation_shimmer() { // account 1 let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -194,7 +197,7 @@ async fn address_generation() { for address in &addresses_data { let secret_manager = SecretManager::try_from_mnemonic(address.mnemonic.clone()).unwrap(); let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(address.bech32_hrp) .with_coin_type(address.coin_type) @@ -232,7 +235,7 @@ async fn address_generation() { .unwrap(); let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(address.bech32_hrp) .with_coin_type(address.coin_type) @@ -269,7 +272,7 @@ async fn search_address() -> Result<(), ClientError> { // Public let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .with_coin_type(IOTA_COIN_TYPE) @@ -293,7 +296,7 @@ async fn search_address() -> Result<(), ClientError> { // Internal let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await? .internal() diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index e0fc8d7b07..cccc00861a 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -117,7 +117,7 @@ async fn test_get_address_outputs() { let secret_manager = setup_secret_manager(); let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::from_client(&client) .await .unwrap() diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index 1d5a9edb0c..ee75feea19 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -58,7 +58,7 @@ 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)) + .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(client).await.unwrap().with_range(0..2)) .await .unwrap(); println!( diff --git a/sdk/tests/client/secret_manager/address_generation.rs b/sdk/tests/client/secret_manager/address_generation.rs index 6cb9235766..2c192b90fe 100644 --- a/sdk/tests/client/secret_manager/address_generation.rs +++ b/sdk/tests/client/secret_manager/address_generation.rs @@ -13,7 +13,7 @@ use iota_sdk::wallet::events::{WalletEvent, WalletEventType}; use iota_sdk::{ client::{ api::GetAddressesOptions, - constants::IOTA_COIN_TYPE, + constants::{IOTA_COIN_TYPE, SHIMMER_COIN_TYPE}, secret::{mnemonic::MnemonicSecretManager, SecretManager}, ClientError, }, @@ -30,7 +30,7 @@ async fn address_generation_mnemonic() -> Result<(), Box> SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?); let address = secret_manager - .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address_as_bech32(IOTA_COIN_TYPE, 0, 0, "smr", None) .await?; assert_eq!( @@ -61,7 +61,7 @@ async fn address_generation_stronghold() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::LedgerNano(secret_manager); let address = secret_manager - .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address_as_bech32(IOTA_COIN_TYPE, 0, 0, "smr", None) .await?; assert_eq!( @@ -104,7 +104,7 @@ async fn address_generation_placeholder() { assert!(matches!( secret_manager - .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, "smr", None) .await, Err(ClientError::PlaceholderSecretManager) )); diff --git a/sdk/tests/client/secret_manager/mnemonic.rs b/sdk/tests/client/secret_manager/mnemonic.rs index faca1dc980..ab7bda8e47 100644 --- a/sdk/tests/client/secret_manager/mnemonic.rs +++ b/sdk/tests/client/secret_manager/mnemonic.rs @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::client::{ - api::GetAddressesOptions, constants::SHIMMER_TESTNET_BECH32_HRP, secret::SecretManager, ClientError, + api::GetAddressesOptions, + constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, + secret::SecretManager, + ClientError, }; use pretty_assertions::assert_eq; @@ -11,18 +14,13 @@ async fn mnemonic_secret_manager() -> Result<(), ClientError> { 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 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_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, SHIMMER_TESTNET_BECH32_HRP, None) .await .unwrap(); 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 1ec0b8bc98..86923ba9fe 100644 --- a/sdk/tests/client/secret_manager/private_key.rs +++ b/sdk/tests/client/secret_manager/private_key.rs @@ -15,7 +15,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { let secret_manager: SecretManager = dto.parse()?; let address_0 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -26,7 +26,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { .clone(); // Changing range generates the same address. let address_1 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -37,7 +37,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { .clone(); // Changing account generates the same address. let address_2 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(1) @@ -70,7 +70,7 @@ async fn private_key_secret_manager_bs58() -> Result<(), ClientError> { )?); let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) diff --git a/sdk/tests/client/secret_manager/stronghold.rs b/sdk/tests/client/secret_manager/stronghold.rs index 84b5f55a8c..f778a2f7dd 100644 --- a/sdk/tests/client/secret_manager/stronghold.rs +++ b/sdk/tests/client/secret_manager/stronghold.rs @@ -25,7 +25,7 @@ async fn stronghold_secret_manager() -> Result<(), ClientError> { } let addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -64,7 +64,7 @@ async fn stronghold_mnemonic_missing() -> Result<(), ClientError> { // Generating addresses will fail because no mnemonic has been stored let error = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default(), // .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) // .with_coin_type(iota_sdk::client::constants::SHIMMER_COIN_TYPE) diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index 37aebc578e..0a44bf1e20 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -40,7 +40,7 @@ async fn sign_account_state_transition() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index 04093f6455..937ab33bb3 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -32,7 +32,7 @@ async fn single_ed25519_unlock() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -115,7 +115,7 @@ async fn ed25519_reference_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -236,7 +236,7 @@ async fn two_signature_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -245,7 +245,7 @@ async fn two_signature_unlocks() -> Result<(), Box> { .clone() .into_inner(); let address_1 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(1..2), diff --git a/sdk/tests/client/signing/delegation.rs b/sdk/tests/client/signing/delegation.rs index 1a44d93a26..30b8f3092f 100644 --- a/sdk/tests/client/signing/delegation.rs +++ b/sdk/tests/client/signing/delegation.rs @@ -40,7 +40,7 @@ async fn valid_creation() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -125,7 +125,7 @@ async fn creation_missing_commitment_input() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -300,7 +300,7 @@ async fn mismatch_amount_creation() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -386,7 +386,7 @@ async fn non_zero_end_epoch_creation() -> Result<(), Box> let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -472,7 +472,7 @@ async fn invalid_start_epoch_creation() -> Result<(), Box let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -559,7 +559,7 @@ async fn delay_not_null_id() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -660,7 +660,7 @@ async fn delay_modified_amount() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -758,7 +758,7 @@ async fn delay_modified_validator() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -856,7 +856,7 @@ async fn delay_modified_start_epoch() -> Result<(), Box> let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -954,7 +954,7 @@ async fn delay_pre_registration_slot_end_epoch() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -1149,7 +1149,7 @@ async fn destroy_reward_missing() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index 4f01bd34bf..ce8f36cd15 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -47,7 +47,7 @@ async fn all_combined() -> Result<(), Box> { let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let ed25519_bech32_addresses = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..3), diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index c714c178d4..6873b8dd4a 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -40,7 +40,7 @@ async fn nft_reference_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), 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 ae11b2cd07..dfd28eec2a 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -58,7 +58,7 @@ async fn stronghold_snapshot_v2_v3_migration() { ); let addresses = stronghold_secret_manager - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -196,7 +196,7 @@ async fn stronghold_snapshot_v2_v3_migration_with_backup() { assert_eq!(coin_type, SHIMMER_COIN_TYPE); let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses( + .generate_ed25519_addresses_as_bech32( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) From d015eacc3721e2b77c948d2b75863a5a9a3b10ad Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 12:42:14 +0100 Subject: [PATCH 24/38] Core: simplify SecretManager:GenerateEd25519AddressAsBech32 method --- bindings/core/src/method/secret_manager.rs | 8 +++++++- .../core/src/method_handler/secret_manager.rs | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 659cf8bd0a..ca5c46886b 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -23,11 +23,17 @@ use crate::OmittedDebug; #[non_exhaustive] pub enum SecretManagerMethod { /// Generate a Bech32 formatted Ed25519 address. + #[serde(rename_all = "camelCase")] GenerateEd25519AddressAsBech32 { coin_type: u32, + #[serde(default)] account_index: u32, + #[serde(default)] address_index: u32, - options: GenerateAddressOptions, + #[serde(default)] + internal: bool, + #[serde(default)] + ledger_nano_prompt: bool, bech32_hrp: Hrp, }, /// Generate Ed25519 addresses. diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 5993ac52ac..72b31fe151 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -8,7 +8,7 @@ use iota_sdk::client::secret::{stronghold::StrongholdSecretManager, SecretManage use iota_sdk::{ client::{ api::{GetAddressesOptions, PreparedTransactionData}, - secret::{DowncastSecretManager, SecretManage, SignBlock}, + secret::{DowncastSecretManager, GenerateAddressOptions, SecretManage, SignBlock}, ClientError, }, types::{ @@ -32,12 +32,21 @@ where coin_type, account_index, address_index, - options, + internal, + ledger_nano_prompt, bech32_hrp, } => { let address_indexes = address_index..address_index + 1; let address = secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_addresses( + coin_type, + account_index, + address_indexes, + GenerateAddressOptions { + internal, + ledger_nano_prompt, + }, + ) .await .map_err(ClientError::from)? .into_iter() From 89e6ac314a58a180eda6d23900aaf3f5a184ce8a Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 12:48:13 +0100 Subject: [PATCH 25/38] Python: update binding --- .../iota_sdk/secret_manager/secret_manager.py | 38 +++++++++++++++++++ bindings/python/tests/test_secret_manager.py | 24 ++++++++++++ ...eration_test.py => test_wallet_address.py} | 8 ++-- 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 bindings/python/tests/test_secret_manager.py rename bindings/python/tests/{address_generation_test.py => test_wallet_address.py} (91%) diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index d78b807206..259c63ed67 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -125,7 +125,45 @@ def _call_method(self, name, data=None): return json_response['payload'] return response + def generate_ed25519_address_as_bech32(self, + coin_type: int, + bech32_hrp: str, + account_index: Optional[int] = None, + address_index: Optional[int] = None, + internal: Optional[bool] = None, + legder_nano_prompt: Optional[bool] = None): + """Generate a Bech32 formatted Ed25519 address. + + Args: + coin_type: The coin type to generate addresses for. + bech32_hrp: The bech32 HRP (human readable part) to use. + account_index: An account index. + address_index: An address index. + internal: Whether the generated address should be internal. + ledger_nano_prompt: Whether to display the address on Ledger Nano devices. + + Returns: + The generated Bech32 address. + """ + + args = {} + args['coinType'] = coin_type + args['bech32Hrp'] = bech32_hrp + if account_index is not None: + args['accountIndex'] = account_index + if address_index is not None: + args['addressIndex'] = address_index + if internal is not None: + args['internal'] = internal + if legder_nano_prompt is not None: + args['ledgerNanoPrompot'] = legder_nano_prompt + + return self._call_method('generateEd25519AddressAsBech32', args) + # pylint: disable=unused-argument + + # TODO: `coin_type` should probably not be optional; + # TODO: arg list should probably be re-ordered to match the expected order as close as possible; def generate_ed25519_addresses(self, account_index: Optional[int] = None, start: Optional[int] = None, diff --git a/bindings/python/tests/test_secret_manager.py b/bindings/python/tests/test_secret_manager.py new file mode 100644 index 0000000000..da1931e0ba --- /dev/null +++ b/bindings/python/tests/test_secret_manager.py @@ -0,0 +1,24 @@ +# Copyright 2023 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +from iota_sdk import MnemonicSecretManager, SecretManager, CoinType, Utils + + +def test_secret_manager_address_generation_iota(): + secret_manager = SecretManager(MnemonicSecretManager( + "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) + + bech32_hrp = Utils.iota_mainnet_protocol_parameters().bech32_hrp + address = secret_manager.generate_ed25519_address_as_bech32(CoinType.IOTA, bech32_hrp) + + assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address + + +def test_secret_manager_address_generation_shimmer(): + secret_manager = SecretManager(MnemonicSecretManager( + "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) + + bech32_hrp = Utils.shimmer_mainnet_protocol_parameters().bech32_hrp + address = secret_manager.generate_ed25519_address_as_bech32(CoinType.SHIMMER, bech32_hrp) + + assert 'smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y' == address diff --git a/bindings/python/tests/address_generation_test.py b/bindings/python/tests/test_wallet_address.py similarity index 91% rename from bindings/python/tests/address_generation_test.py rename to bindings/python/tests/test_wallet_address.py index 0674245a92..847e4c1055 100644 --- a/bindings/python/tests/address_generation_test.py +++ b/bindings/python/tests/test_wallet_address.py @@ -5,8 +5,8 @@ from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletOptions, Bip44, Utils -def test_address_generation_iota(): - db_path = './test_address_generation_iota' +def test_wallet_address_iota(): + db_path = './test_wallet_address_iota' shutil.rmtree(db_path, ignore_errors=True) client_options = ClientOptions( @@ -33,8 +33,8 @@ def test_address_generation_iota(): shutil.rmtree(db_path, ignore_errors=True) -def test_address_generation_shimmer(): - db_path = './test_address_generation_shimmer' +def test_wallet_address_shimmer(): + db_path = './test_wallet_address_shimmer' shutil.rmtree(db_path, ignore_errors=True) client_options = ClientOptions( From c20b755c126951e70a38e4d6f0cbbb7660aea98b Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 6 Mar 2024 13:06:45 +0100 Subject: [PATCH 26/38] nit --- bindings/core/src/method/secret_manager.rs | 5 +---- bindings/core/src/method_handler/secret_manager.rs | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index ca5c46886b..3372033788 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -4,10 +4,7 @@ use crypto::keys::bip44::Bip44; use derivative::Derivative; use iota_sdk::{ - client::{ - api::{GetAddressesOptions, PreparedTransactionDataDto}, - secret::GenerateAddressOptions, - }, + client::api::{GetAddressesOptions, PreparedTransactionDataDto}, types::block::{address::Hrp, protocol::ProtocolParameters, UnsignedBlockDto}, utils::serde::bip44::Bip44Def, }; diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 72b31fe151..88f4d62241 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -36,12 +36,11 @@ where ledger_nano_prompt, bech32_hrp, } => { - let address_indexes = address_index..address_index + 1; let address = secret_manager .generate_ed25519_addresses( coin_type, account_index, - address_indexes, + address_index..address_index + 1, GenerateAddressOptions { internal, ledger_nano_prompt, @@ -53,7 +52,7 @@ where .map(|a| a.to_bech32(bech32_hrp)) .collect::>() .pop() - // Panic: at this point there must be at least one address + // Panic: if the secret manager method didn't fail then there must be at least one address .unwrap(); Response::Bech32Address(address) } From da0a295b9b2b299187dbea640ca2fda72f73011d Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 09:55:10 +0100 Subject: [PATCH 27/38] core: undo rename; update docs --- bindings/core/src/method/secret_manager.rs | 7 ++++--- bindings/core/src/method_handler/secret_manager.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 3372033788..961d25b06d 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -19,9 +19,10 @@ use crate::OmittedDebug; #[serde(tag = "name", content = "data", rename_all = "camelCase")] #[non_exhaustive] pub enum SecretManagerMethod { - /// Generate a Bech32 formatted Ed25519 address. + // TODO: Should we refactor `GetAddressesOptions` so we can use it for this method as well? + /// Generate a single Ed25519 address. #[serde(rename_all = "camelCase")] - GenerateEd25519AddressAsBech32 { + GenerateEd25519Address { coin_type: u32, #[serde(default)] account_index: u32, @@ -33,7 +34,7 @@ pub enum SecretManagerMethod { ledger_nano_prompt: bool, bech32_hrp: Hrp, }, - /// Generate Ed25519 addresses. + /// Generate multiple Ed25519 addresses at once. GenerateEd25519Addresses { /// Addresses generation options options: GetAddressesOptions, diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index 88f4d62241..cb98810fd5 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -28,7 +28,7 @@ where ClientError: From, { let response = match method { - SecretManagerMethod::GenerateEd25519AddressAsBech32 { + SecretManagerMethod::GenerateEd25519Address { coin_type, account_index, address_index, From 80dd4f431cbfee29c7b9adaadabc028b6f7dacac Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 10:01:49 +0100 Subject: [PATCH 28/38] add todo --- sdk/src/client/api/address.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index 50b2ce73d9..06fa94050a 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -16,6 +16,9 @@ use crate::{ utils::ConvertTo, }; +// TODO: Should we rename ths struct to `GetAddressOptions`, thereby moving out the `range` field, so +// it can be used by `GenerateEd25519Address` and `GenerateEd25519Addresses`? Do we even still need +// the latter? #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(default)] From 0348aa6537ba3f72293385581a67def1392fbf52 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 10:16:54 +0100 Subject: [PATCH 29/38] Python: nits --- .../iota_sdk/secret_manager/secret_manager.py | 37 ++++++++++--------- bindings/python/tests/test_secret_manager.py | 4 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index 259c63ed67..f9fb454eda 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -125,17 +125,18 @@ def _call_method(self, name, data=None): return json_response['payload'] return response - def generate_ed25519_address_as_bech32(self, - coin_type: int, - bech32_hrp: str, - account_index: Optional[int] = None, - address_index: Optional[int] = None, - internal: Optional[bool] = None, - legder_nano_prompt: Optional[bool] = None): - """Generate a Bech32 formatted Ed25519 address. + # TODO: Should we include `bech32` in the method name? + def generate_ed25519_address(self, + coin_type: int, + bech32_hrp: str, + account_index: Optional[int] = None, + address_index: Optional[int] = None, + internal: Optional[bool] = None, + legder_nano_prompt: Optional[bool] = None): + """Generate a single Ed25519 address. Args: - coin_type: The coin type to generate addresses for. + coin_type: The coin type to generate the address for. bech32_hrp: The bech32 HRP (human readable part) to use. account_index: An account index. address_index: An address index. @@ -143,7 +144,7 @@ def generate_ed25519_address_as_bech32(self, ledger_nano_prompt: Whether to display the address on Ledger Nano devices. Returns: - The generated Bech32 address. + The generated Ed25519 address. """ args = {} @@ -158,29 +159,29 @@ def generate_ed25519_address_as_bech32(self, if legder_nano_prompt is not None: args['ledgerNanoPrompot'] = legder_nano_prompt - return self._call_method('generateEd25519AddressAsBech32', args) + return self._call_method('generateEd25519Address', args) # pylint: disable=unused-argument - # TODO: `coin_type` should probably not be optional; - # TODO: arg list should probably be re-ordered to match the expected order as close as possible; + # TODO: Should `coin_type` and `bech32_hrp` be mandatory to provide? + # TODO: Should we include `bech32` in the method name? def generate_ed25519_addresses(self, + coin_type: Optional[int] = None, + bech32_hrp: Optional[str] = None, account_index: Optional[int] = None, start: Optional[int] = None, end: Optional[int] = None, internal: Optional[bool] = None, - coin_type: Optional[int] = None, - bech32_hrp: Optional[str] = None, ledger_nano_prompt: Optional[bool] = None): - """Generate Ed25519 addresses. + """Generate multiple Ed25519 addresses at once. Args: + coin_type: The coin type to generate addresses for. + bech32_hrp: The bech32 HRP (human readable part) to use. account_index: An account index. start: The start index of the addresses to generate. end: The end index of the addresses to generate. internal: Whether the generated addresses should be internal. - coin_type: The coin type to generate addresses for. - bech32_hrp: The bech32 HRP (human readable part) to use. ledger_nano_prompt: Whether to display the address on Ledger Nano devices. Returns: diff --git a/bindings/python/tests/test_secret_manager.py b/bindings/python/tests/test_secret_manager.py index da1931e0ba..624430275e 100644 --- a/bindings/python/tests/test_secret_manager.py +++ b/bindings/python/tests/test_secret_manager.py @@ -9,7 +9,7 @@ def test_secret_manager_address_generation_iota(): "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) bech32_hrp = Utils.iota_mainnet_protocol_parameters().bech32_hrp - address = secret_manager.generate_ed25519_address_as_bech32(CoinType.IOTA, bech32_hrp) + address = secret_manager.generate_ed25519_address(CoinType.IOTA, bech32_hrp) assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address @@ -19,6 +19,6 @@ def test_secret_manager_address_generation_shimmer(): "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast")) bech32_hrp = Utils.shimmer_mainnet_protocol_parameters().bech32_hrp - address = secret_manager.generate_ed25519_address_as_bech32(CoinType.SHIMMER, bech32_hrp) + address = secret_manager.generate_ed25519_address(CoinType.SHIMMER, bech32_hrp) assert 'smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y' == address From eb70061bd558a86afea23ce4b2ef79dae2f7d01b Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 10:49:13 +0100 Subject: [PATCH 30/38] NodeJs: add binding method --- .../lib/secret_manager/secret-manager.ts | 34 ++++++++++++++- .../client/generate-addresses-options.ts | 2 + .../lib/types/secret_manager/bridge/index.ts | 2 + .../secret_manager/bridge/secret-manager.ts | 13 ++++++ .../secret_manager/secret_manager.spec.ts | 41 +++++++++++++++++++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 bindings/nodejs/tests/secret_manager/secret_manager.spec.ts diff --git a/bindings/nodejs/lib/secret_manager/secret-manager.ts b/bindings/nodejs/lib/secret_manager/secret-manager.ts index 76747845b8..b2a5b9ca4f 100644 --- a/bindings/nodejs/lib/secret_manager/secret-manager.ts +++ b/bindings/nodejs/lib/secret_manager/secret-manager.ts @@ -6,6 +6,8 @@ import type { GenerateAddressesOptions, PreparedTransactionData, LedgerNanoStatus, + CoinType, + GenerateAddressOptions, } from '../types/client'; import { Bip44, @@ -21,6 +23,7 @@ import { UnsignedBlock, Block, parseBlock, + Bech32Address, } from '../types'; import { plainToInstance } from 'class-transformer'; @@ -44,14 +47,41 @@ export class SecretManager { } /** - * Generate Ed25519 addresses. + * Generate a single Ed25519 address. + * + * @returns The generated Bech32 address. + */ + async generateEd25519Address( + coinType: CoinType, + bech32Hrp: string, + accountIndex?: number, + addressIndex?: number, + options?: GenerateAddressOptions, + ): Promise { + const response = await this.methodHandler.callMethod({ + name: 'generateEd25519Address', + data: { + coinType, + bech32Hrp, + accountIndex, + addressIndex, + internal: options?.internal, + ledgerNanoPrompt: options?.ledgerNanoPrompt, + }, + }); + + return JSON.parse(response).payload; + } + + /** + * Generate multiple Ed25519 addresses at once. * * @param generateAddressesOptions Options to generate addresses. * @returns An array of generated addresses. */ async generateEd25519Addresses( generateAddressesOptions: GenerateAddressesOptions, - ): Promise { + ): Promise { const response = await this.methodHandler.callMethod({ name: 'generateEd25519Addresses', data: { diff --git a/bindings/nodejs/lib/types/client/generate-addresses-options.ts b/bindings/nodejs/lib/types/client/generate-addresses-options.ts index a66e7ec431..342baf257e 100644 --- a/bindings/nodejs/lib/types/client/generate-addresses-options.ts +++ b/bindings/nodejs/lib/types/client/generate-addresses-options.ts @@ -3,6 +3,8 @@ import type { CoinType } from './constants'; import type { Range } from './range'; +// TODO: Rename (to GetAddressOptions) and refactor (move out range field), +// so we can use it for the single address generation method as well? /** * Input options for GenerateAddresses */ diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts index c7027781ae..42a1eba497 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts @@ -1,4 +1,5 @@ import type { + __GenerateEd25519Address__, __GenerateEd25519AddressesMethod__, __GenerateEvmAddressesMethod__, __GetLedgerNanoStatusMethod__, @@ -14,6 +15,7 @@ import type { } from './secret-manager'; export type __SecretManagerMethods__ = + | __GenerateEd25519Address__ | __GenerateEd25519AddressesMethod__ | __GenerateEvmAddressesMethod__ | __GetLedgerNanoStatusMethod__ diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts index e3e5d504c5..7f1077a07c 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts @@ -2,11 +2,24 @@ // SPDX-License-Identifier: Apache-2.0 import { UnsignedBlock } from '../../block'; +import { CoinType } from '../../client'; import type { GenerateAddressesOptions } from '../../client/generate-addresses-options'; import type { PreparedTransactionData } from '../../client/prepared-transaction-data'; import { HexEncodedString } from '../../utils'; import { Bip44 } from '../secret-manager'; +export interface __GenerateEd25519Address__ { + name: 'generateEd25519Address'; + data: { + coinType: CoinType; + bech32Hrp: string; + accountIndex?: number; + addressIndex?: number; + internal?: boolean; + ledgerNanoPrompt?: boolean; + }; +} + export interface __GenerateEd25519AddressesMethod__ { name: 'generateEd25519Addresses'; data: { diff --git a/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts b/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts new file mode 100644 index 0000000000..5071f0ff15 --- /dev/null +++ b/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts @@ -0,0 +1,41 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import 'reflect-metadata'; + +import { describe, it, expect } from '@jest/globals'; +import { + CoinType, + SecretManager, + Utils, +} from '../../lib/'; + +describe('SecretManager', () => { + it('generate IOTA Ed25519 address', async () => { + const mnemonicSecretManager = { + 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 bech32_hrp = Utils.iotaMainnetProtocolParameters().bech32Hrp; + + const secretManager = SecretManager.create(mnemonicSecretManager); + const address = await secretManager.generateEd25519Address(CoinType.IOTA, bech32_hrp); + + expect(address).toEqual('iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg'); + + }, 20000); + + it('generate Shimmer Ed25519 address', async () => { + const mnemonicSecretManager = { + 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 bech32_hrp = Utils.shimmerMainnetProtocolParameters().bech32Hrp; + + const secretManager = SecretManager.create(mnemonicSecretManager); + const address = await secretManager.generateEd25519Address(CoinType.Shimmer, bech32_hrp); + + expect(address).toEqual('smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y'); + + }, 20000); +}); From 602457a3508ac3c3e1658521f5ee0f0261461ec8 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 10:49:47 +0100 Subject: [PATCH 31/38] nit --- bindings/core/src/method/secret_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index 961d25b06d..ab99a95d33 100644 --- a/bindings/core/src/method/secret_manager.rs +++ b/bindings/core/src/method/secret_manager.rs @@ -24,6 +24,7 @@ pub enum SecretManagerMethod { #[serde(rename_all = "camelCase")] GenerateEd25519Address { coin_type: u32, + bech32_hrp: Hrp, #[serde(default)] account_index: u32, #[serde(default)] @@ -32,7 +33,6 @@ pub enum SecretManagerMethod { internal: bool, #[serde(default)] ledger_nano_prompt: bool, - bech32_hrp: Hrp, }, /// Generate multiple Ed25519 addresses at once. GenerateEd25519Addresses { From 08041011e6fc52e0cf5ba84be97e810f983b7dcb Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 11:05:38 +0100 Subject: [PATCH 32/38] sdk: undo rename; format --- sdk/examples/client/01_generate_addresses.rs | 6 ++--- sdk/examples/client/02_address_balance.rs | 2 +- .../client/high_level/search_address.rs | 2 +- sdk/examples/client/ledger_nano.rs | 2 +- .../client/ledger_nano_transaction.rs | 2 +- sdk/examples/client/quorum.rs | 2 +- sdk/examples/client/send_all.rs | 2 +- sdk/examples/client/stronghold.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 2 +- sdk/src/client/api/address.rs | 16 ++++++------ sdk/src/client/secret/ledger_nano.rs | 2 +- sdk/tests/client/addresses.rs | 23 +++++++--------- sdk/tests/client/node_api/core.rs | 2 +- sdk/tests/client/node_api/mod.rs | 2 +- .../secret_manager/address_generation.rs | 8 +++--- sdk/tests/client/secret_manager/mnemonic.rs | 2 +- .../client/secret_manager/private_key.rs | 8 +++--- sdk/tests/client/secret_manager/stronghold.rs | 4 +-- sdk/tests/client/signing/account.rs | 4 +-- sdk/tests/client/signing/basic.rs | 8 +++--- sdk/tests/client/signing/delegation.rs | 26 +++++++++---------- sdk/tests/client/signing/mod.rs | 2 +- sdk/tests/client/signing/nft.rs | 2 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 4 +-- 24 files changed, 66 insertions(+), 69 deletions(-) diff --git a/sdk/examples/client/01_generate_addresses.rs b/sdk/examples/client/01_generate_addresses.rs index 06f2cabfbd..d3ab4f6dcd 100644 --- a/sdk/examples/client/01_generate_addresses.rs +++ b/sdk/examples/client/01_generate_addresses.rs @@ -33,7 +33,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with default account index and range let addresses = secret_manager - .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?) + .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?) .await?; println!("List of generated public addresses (default):"); @@ -41,7 +41,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) @@ -54,7 +54,7 @@ async fn main() -> Result<(), Box> { // Generate internal addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/02_address_balance.rs b/sdk/examples/client/02_address_balance.rs index 45abb91e89..b9e027b50f 100644 --- a/sdk/examples/client/02_address_balance.rs +++ b/sdk/examples/client/02_address_balance.rs @@ -36,7 +36,7 @@ async fn main() -> Result<(), Box> { // Generate the first address let first_address = secret_manager - .generate_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, client.get_bech32_hrp().await?, None) + .generate_ed25519_address(SHIMMER_COIN_TYPE, 0, 0, client.get_bech32_hrp().await?, None) .await?; // Get output ids of outputs that can be controlled by this address without further unlock constraints diff --git a/sdk/examples/client/high_level/search_address.rs b/sdk/examples/client/high_level/search_address.rs index 0540adde02..7b8f066402 100644 --- a/sdk/examples/client/high_level/search_address.rs +++ b/sdk/examples/client/high_level/search_address.rs @@ -38,7 +38,7 @@ async fn main() -> Result<(), Box> { addr } else { secret_manager - .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) + .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) .await?[0] .clone() }; diff --git a/sdk/examples/client/ledger_nano.rs b/sdk/examples/client/ledger_nano.rs index 93d88b4f33..c9c07e33a2 100644 --- a/sdk/examples/client/ledger_nano.rs +++ b/sdk/examples/client/ledger_nano.rs @@ -35,7 +35,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) diff --git a/sdk/examples/client/ledger_nano_transaction.rs b/sdk/examples/client/ledger_nano_transaction.rs index 29e4e69017..790fd060bd 100644 --- a/sdk/examples/client/ledger_nano_transaction.rs +++ b/sdk/examples/client/ledger_nano_transaction.rs @@ -44,7 +44,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/quorum.rs b/sdk/examples/client/quorum.rs index 0da23a14f0..6e211c3c0e 100644 --- a/sdk/examples/client/quorum.rs +++ b/sdk/examples/client/quorum.rs @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { // Generate the first address let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .with_account_index(0) diff --git a/sdk/examples/client/send_all.rs b/sdk/examples/client/send_all.rs index 9436253d49..0418a151be 100644 --- a/sdk/examples/client/send_all.rs +++ b/sdk/examples/client/send_all.rs @@ -99,7 +99,7 @@ async fn main() -> Result<(), Box> { println!("Total amount: {total_amount}"); let to_address = secret_manager_2 - .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) + .generate_ed25519_addresses(GetAddressesOptions::from_client(&client).await?.with_range(0..1)) .await?[0] .clone(); diff --git a/sdk/examples/client/stronghold.rs b/sdk/examples/client/stronghold.rs index 496d319626..e328b6a947 100644 --- a/sdk/examples/client/stronghold.rs +++ b/sdk/examples/client/stronghold.rs @@ -37,7 +37,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) 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 76f997491c..8b47726162 100644 --- a/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/examples/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -48,7 +48,7 @@ async fn main() -> Result<(), Box> { // Generate addresses with custom account index and range let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index 06fa94050a..8ae7d44b49 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -103,8 +103,11 @@ impl Default for GetAddressesOptions { } impl SecretManager { + // TODO: while `SecretManage::generate...` returns `Ed25519Address`, `SecretManager` + // converts those to `Bech32Address`es, hence, should we add `bech32` to its method name + // to make that the difference clear? /// Generates a Bech32 formatted Ed25519 address. - pub async fn generate_ed25519_address_as_bech32( + pub async fn generate_ed25519_address( &self, coin_type: u32, account_index: u32, @@ -125,8 +128,9 @@ impl SecretManager { .to_bech32(hrp)) } + // TODO: Same as for `generate_ed25519_address`. /// Generates a vector of Bech32 formatted Ed25519 addresses. - pub async fn generate_ed25519_addresses_as_bech32( + pub async fn generate_ed25519_addresses( &self, GetAddressesOptions { coin_type, @@ -201,12 +205,8 @@ pub async fn search_address( .with_coin_type(coin_type) .with_account_index(account_index) .with_range(range.clone()); - let public = secret_manager - .generate_ed25519_addresses_as_bech32(opts.clone()) - .await?; - let internal = secret_manager - .generate_ed25519_addresses_as_bech32(opts.internal()) - .await?; + 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)); diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index 0f61c6cd2a..2792ab8cfb 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -626,7 +626,7 @@ mod tests { secret_manager.non_interactive = true; let addresses = SecretManager::LedgerNano(secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(IOTA_COIN_TYPE) .with_account_index(0) diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index 82d5277139..a4a180ac01 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -29,12 +29,9 @@ async fn ed25519_addresses() { .with_bech32_hrp(IOTA_TESTNET_BECH32_HRP) .with_coin_type(IOTA_COIN_TYPE) .with_range(0..1); - let public = secret_manager - .generate_ed25519_addresses_as_bech32(opts.clone()) - .await - .unwrap(); + let public = secret_manager.generate_ed25519_addresses(opts.clone()).await.unwrap(); let internal = secret_manager - .generate_ed25519_addresses_as_bech32(opts.internal()) + .generate_ed25519_addresses(opts.internal()) .await .unwrap(); @@ -93,7 +90,7 @@ async fn mnemonic_address_generation_iota() { // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(IOTA_BECH32_HRP) .with_coin_type(IOTA_COIN_TYPE) @@ -114,7 +111,7 @@ async fn mnemonic_address_generation_iota() { // account 1 let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(IOTA_BECH32_HRP) .with_coin_type(IOTA_COIN_TYPE) @@ -137,7 +134,7 @@ async fn mnemonic_address_generation_shimmer() { // account 0, address 0 and 1 let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -158,7 +155,7 @@ async fn mnemonic_address_generation_shimmer() { // account 1 let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -197,7 +194,7 @@ async fn address_generation() { for address in &addresses_data { let secret_manager = SecretManager::try_from_mnemonic(address.mnemonic.clone()).unwrap(); let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(address.bech32_hrp) .with_coin_type(address.coin_type) @@ -235,7 +232,7 @@ async fn address_generation() { .unwrap(); let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(address.bech32_hrp) .with_coin_type(address.coin_type) @@ -272,7 +269,7 @@ async fn search_address() -> Result<(), ClientError> { // Public let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .with_coin_type(IOTA_COIN_TYPE) @@ -296,7 +293,7 @@ async fn search_address() -> Result<(), ClientError> { // Internal let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await? .internal() diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index cccc00861a..e0fc8d7b07 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -117,7 +117,7 @@ async fn test_get_address_outputs() { let secret_manager = setup_secret_manager(); let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::from_client(&client) .await .unwrap() diff --git a/sdk/tests/client/node_api/mod.rs b/sdk/tests/client/node_api/mod.rs index ee75feea19..1d5a9edb0c 100644 --- a/sdk/tests/client/node_api/mod.rs +++ b/sdk/tests/client/node_api/mod.rs @@ -58,7 +58,7 @@ pub async fn setup_transaction_block(client: &Client) -> (BlockId, TransactionId let secret_manager = setup_secret_manager(); let addresses = secret_manager - .generate_ed25519_addresses_as_bech32(GetAddressesOptions::from_client(client).await.unwrap().with_range(0..2)) + .generate_ed25519_addresses(GetAddressesOptions::from_client(client).await.unwrap().with_range(0..2)) .await .unwrap(); println!( diff --git a/sdk/tests/client/secret_manager/address_generation.rs b/sdk/tests/client/secret_manager/address_generation.rs index 2c192b90fe..7ff9584cce 100644 --- a/sdk/tests/client/secret_manager/address_generation.rs +++ b/sdk/tests/client/secret_manager/address_generation.rs @@ -30,7 +30,7 @@ async fn address_generation_mnemonic() -> Result<(), Box> SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?); let address = secret_manager - .generate_ed25519_address_as_bech32(IOTA_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) .await?; assert_eq!( @@ -61,7 +61,7 @@ async fn address_generation_stronghold() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::LedgerNano(secret_manager); let address = secret_manager - .generate_ed25519_address_as_bech32(IOTA_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address(IOTA_COIN_TYPE, 0, 0, "smr", None) .await?; assert_eq!( @@ -104,7 +104,7 @@ async fn address_generation_placeholder() { assert!(matches!( secret_manager - .generate_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, "smr", None) + .generate_ed25519_address(SHIMMER_COIN_TYPE, 0, 0, "smr", None) .await, Err(ClientError::PlaceholderSecretManager) )); diff --git a/sdk/tests/client/secret_manager/mnemonic.rs b/sdk/tests/client/secret_manager/mnemonic.rs index ab7bda8e47..84cf4e6cbe 100644 --- a/sdk/tests/client/secret_manager/mnemonic.rs +++ b/sdk/tests/client/secret_manager/mnemonic.rs @@ -15,7 +15,7 @@ async fn mnemonic_secret_manager() -> Result<(), ClientError> { let secret_manager: SecretManager = dto.parse()?; let address = secret_manager - .generate_ed25519_address_as_bech32(SHIMMER_COIN_TYPE, 0, 0, SHIMMER_TESTNET_BECH32_HRP, None) + .generate_ed25519_address(SHIMMER_COIN_TYPE, 0, 0, SHIMMER_TESTNET_BECH32_HRP, None) .await .unwrap(); diff --git a/sdk/tests/client/secret_manager/private_key.rs b/sdk/tests/client/secret_manager/private_key.rs index 86923ba9fe..1ec0b8bc98 100644 --- a/sdk/tests/client/secret_manager/private_key.rs +++ b/sdk/tests/client/secret_manager/private_key.rs @@ -15,7 +15,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { let secret_manager: SecretManager = dto.parse()?; let address_0 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -26,7 +26,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { .clone(); // Changing range generates the same address. let address_1 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -37,7 +37,7 @@ async fn private_key_secret_manager_hex() -> Result<(), ClientError> { .clone(); // Changing account generates the same address. let address_2 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(1) @@ -70,7 +70,7 @@ async fn private_key_secret_manager_bs58() -> Result<(), ClientError> { )?); let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) diff --git a/sdk/tests/client/secret_manager/stronghold.rs b/sdk/tests/client/secret_manager/stronghold.rs index f778a2f7dd..84b5f55a8c 100644 --- a/sdk/tests/client/secret_manager/stronghold.rs +++ b/sdk/tests/client/secret_manager/stronghold.rs @@ -25,7 +25,7 @@ async fn stronghold_secret_manager() -> Result<(), ClientError> { } let addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_account_index(0) @@ -64,7 +64,7 @@ async fn stronghold_mnemonic_missing() -> Result<(), ClientError> { // Generating addresses will fail because no mnemonic has been stored let error = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default(), // .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) // .with_coin_type(iota_sdk::client::constants::SHIMMER_COIN_TYPE) diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index d634b76fe8..dcf647039c 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -37,7 +37,7 @@ async fn sign_account_state_transition() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index 2b6457517b..39a60ea051 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -29,7 +29,7 @@ async fn single_ed25519_unlock() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -109,7 +109,7 @@ async fn ed25519_reference_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -229,7 +229,7 @@ async fn two_signature_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -238,7 +238,7 @@ async fn two_signature_unlocks() -> Result<(), Box> { .clone() .into_inner(); let address_1 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(1..2), diff --git a/sdk/tests/client/signing/delegation.rs b/sdk/tests/client/signing/delegation.rs index 707e1dba86..7b7625b97c 100644 --- a/sdk/tests/client/signing/delegation.rs +++ b/sdk/tests/client/signing/delegation.rs @@ -38,7 +38,7 @@ async fn valid_creation() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -119,7 +119,7 @@ async fn creation_missing_commitment_input() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -267,7 +267,7 @@ async fn mismatch_amount_creation() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -352,7 +352,7 @@ async fn non_zero_end_epoch_creation() -> Result<(), Box> let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -437,7 +437,7 @@ async fn invalid_start_epoch_creation() -> Result<(), Box let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -520,7 +520,7 @@ async fn delay_not_null_id() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -616,7 +616,7 @@ async fn delay_modified_amount() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -709,7 +709,7 @@ async fn delay_modified_validator() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -802,7 +802,7 @@ async fn delay_modified_start_epoch() -> Result<(), Box> let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -895,7 +895,7 @@ async fn delay_pre_registration_slot_end_epoch() -> Result<(), Box Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), @@ -1081,7 +1081,7 @@ async fn destroy_reward_missing() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index e44de1f43b..99562cd7a5 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -43,7 +43,7 @@ async fn all_combined() -> Result<(), Box> { let protocol_parameters = iota_mainnet_protocol_parameters(); let ed25519_bech32_addresses = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..3), diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index 04a2c09644..b52efa6395 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -37,7 +37,7 @@ async fn nft_reference_unlocks() -> Result<(), Box> { let secret_manager = SecretManager::try_from_mnemonic(Client::generate_mnemonic()?)?; let address_0 = secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_coin_type(SHIMMER_COIN_TYPE) .with_range(0..1), 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 dfd28eec2a..ae11b2cd07 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -58,7 +58,7 @@ async fn stronghold_snapshot_v2_v3_migration() { ); let addresses = stronghold_secret_manager - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) @@ -196,7 +196,7 @@ async fn stronghold_snapshot_v2_v3_migration_with_backup() { assert_eq!(coin_type, SHIMMER_COIN_TYPE); let addresses = SecretManager::Stronghold(stronghold_secret_manager) - .generate_ed25519_addresses_as_bech32( + .generate_ed25519_addresses( GetAddressesOptions::default() .with_bech32_hrp(SHIMMER_TESTNET_BECH32_HRP) .with_coin_type(SHIMMER_COIN_TYPE) From b53e401f074eca00b645c7604958a6d9a1862b06 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 11:06:23 +0100 Subject: [PATCH 33/38] core: import --- bindings/core/src/method/wallet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index 861228571e..1522beb9a8 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -6,9 +6,9 @@ use std::path::PathBuf; use crypto::keys::bip44::Bip44; use derivative::Derivative; +use iota_sdk::client::api::options::TransactionOptions; #[cfg(feature = "events")] use iota_sdk::wallet::events::types::{WalletEvent, WalletEventType}; -use iota_sdk::{client::api::options::TransactionOptions, utils::serde::string}; // #[cfg(feature = "participation")] // use iota_sdk::{ // client::node_manager::node::Node, @@ -21,7 +21,7 @@ use iota_sdk::{ node_manager::node::NodeAuth, }, types::block::{ - address::{Bech32Address, Hrp}, + address::Hrp, output::{AccountId, DelegationId, Output, OutputId, TokenId}, payload::signed_transaction::TransactionId, }, From cce3be48595d916e4e4cc7f3b14a3b3849e25fec Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 11:07:09 +0100 Subject: [PATCH 34/38] NodeJs: method suffix --- bindings/nodejs/lib/types/secret_manager/bridge/index.ts | 4 ++-- .../nodejs/lib/types/secret_manager/bridge/secret-manager.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts index 42a1eba497..119935dd08 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts @@ -1,5 +1,5 @@ import type { - __GenerateEd25519Address__, + __GenerateEd25519AddressMethod__, __GenerateEd25519AddressesMethod__, __GenerateEvmAddressesMethod__, __GetLedgerNanoStatusMethod__, @@ -15,7 +15,7 @@ import type { } from './secret-manager'; export type __SecretManagerMethods__ = - | __GenerateEd25519Address__ + | __GenerateEd25519AddressMethod__ | __GenerateEd25519AddressesMethod__ | __GenerateEvmAddressesMethod__ | __GetLedgerNanoStatusMethod__ diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts index 7f1077a07c..4d804b7a99 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts @@ -8,7 +8,7 @@ import type { PreparedTransactionData } from '../../client/prepared-transaction- import { HexEncodedString } from '../../utils'; import { Bip44 } from '../secret-manager'; -export interface __GenerateEd25519Address__ { +export interface __GenerateEd25519AddressMethod__ { name: 'generateEd25519Address'; data: { coinType: CoinType; From 4170fa6ce30c0ac136985e5abc086ab4e6d7676c Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 11:57:44 +0100 Subject: [PATCH 35/38] fix test --- sdk/src/client/api/address.rs | 3 ++- sdk/tests/client/common/mod.rs | 4 +++- sdk/tests/client/secret_manager/stronghold.rs | 22 +++++++------------ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index 8ae7d44b49..9a5b2fbd08 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -106,6 +106,7 @@ impl SecretManager { // TODO: while `SecretManage::generate...` returns `Ed25519Address`, `SecretManager` // converts those to `Bech32Address`es, hence, should we add `bech32` to its method name // to make that the difference clear? + // TODO: make `account_index` and `address_index` impl Into>? /// Generates a Bech32 formatted Ed25519 address. pub async fn generate_ed25519_address( &self, @@ -115,7 +116,7 @@ impl SecretManager { bech32_hrp: impl ConvertTo, options: impl Into> + Send, ) -> Result { - let hrp = bech32_hrp.convert()?; + let hrp: Hrp = bech32_hrp.convert()?; Ok(SecretManage::generate_ed25519_addresses( self, coin_type, diff --git a/sdk/tests/client/common/mod.rs b/sdk/tests/client/common/mod.rs index 4ca8a5f26d..5e249dca6c 100644 --- a/sdk/tests/client/common/mod.rs +++ b/sdk/tests/client/common/mod.rs @@ -65,7 +65,9 @@ pub async fn setup_client_with_node_health_ignored() -> Client { #[allow(dead_code)] pub(crate) fn setup(path: &str) -> Result<(), Box> { - Ok(std::fs::remove_dir_all(path)?) + // Ignore error in case the path didn't exist yet. + std::fs::remove_dir_all(path).ok(); + Ok(()) } #[allow(dead_code)] diff --git a/sdk/tests/client/secret_manager/stronghold.rs b/sdk/tests/client/secret_manager/stronghold.rs index 84b5f55a8c..bb087859ee 100644 --- a/sdk/tests/client/secret_manager/stronghold.rs +++ b/sdk/tests/client/secret_manager/stronghold.rs @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::client::{ - api::GetAddressesOptions, constants::SHIMMER_TESTNET_BECH32_HRP, secret::SecretManager, ClientError, + api::GetAddressesOptions, + constants::{SHIMMER_COIN_TYPE, SHIMMER_TESTNET_BECH32_HRP}, + secret::SecretManager, + ClientError, }; use pretty_assertions::assert_eq; @@ -24,18 +27,13 @@ async fn stronghold_secret_manager() -> Result<(), ClientError> { panic!("expect a Stronghold secret manager, but it's not the case!"); } - 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_ed25519_address(SHIMMER_COIN_TYPE, 0, 0, SHIMMER_TESTNET_BECH32_HRP, None) .await .unwrap(); assert_eq!( - addresses[0], + address, "rms1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6v3ea5a" ); @@ -64,11 +62,7 @@ async fn stronghold_mnemonic_missing() -> Result<(), ClientError> { // 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) - ) + .generate_ed25519_address(SHIMMER_COIN_TYPE, 0, 0, SHIMMER_TESTNET_BECH32_HRP, None) .await .unwrap_err(); From 20fb18fbcc8d48b6482e87d3288c18dc8ed03f80 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 12:01:57 +0100 Subject: [PATCH 36/38] nit --- sdk/src/client/api/address.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/client/api/address.rs b/sdk/src/client/api/address.rs index 9a5b2fbd08..d8a70a96b4 100644 --- a/sdk/src/client/api/address.rs +++ b/sdk/src/client/api/address.rs @@ -37,8 +37,8 @@ pub struct GetAddressesOptions { impl GetAddressesOptions { // TODO: can we remove this function? It's not clear from the outside that it's just the default - // with a requested HRP. I think the caller can just do what this function does. Also ... this - // we do several API requests unnecessarily because oftentimes we could just re-use the HRP. + // with a requested HRP. I think the caller can just do what this function does. Also ... with this + // we do several API requests unnecessarily since oftentimes we could just re-use the HRP. pub async fn from_client(client: &Client) -> Result { Ok(Self::default().with_bech32_hrp(client.get_bech32_hrp().await?)) } From fbad5914a564e8f9f175ed36d2054973eb962417 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 15:06:50 +0100 Subject: [PATCH 37/38] remove single address generation binding --- bindings/core/src/method/secret_manager.rs | 17 +---------- .../core/src/method_handler/secret_manager.rs | 30 +------------------ .../lib/secret_manager/secret-manager.ts | 29 ------------------ .../lib/types/secret_manager/bridge/index.ts | 2 -- .../secret_manager/bridge/secret-manager.ts | 13 -------- .../secret_manager/secret_manager.spec.ts | 15 +++++++--- .../iota_sdk/secret_manager/secret_manager.py | 23 ++++++++------ 7 files changed, 27 insertions(+), 102 deletions(-) diff --git a/bindings/core/src/method/secret_manager.rs b/bindings/core/src/method/secret_manager.rs index ab99a95d33..4cb40cf985 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::{address::Hrp, protocol::ProtocolParameters, UnsignedBlockDto}, + types::block::{protocol::ProtocolParameters, UnsignedBlockDto}, utils::serde::bip44::Bip44Def, }; use serde::{Deserialize, Serialize}; @@ -19,21 +19,6 @@ use crate::OmittedDebug; #[serde(tag = "name", content = "data", rename_all = "camelCase")] #[non_exhaustive] pub enum SecretManagerMethod { - // TODO: Should we refactor `GetAddressesOptions` so we can use it for this method as well? - /// Generate a single Ed25519 address. - #[serde(rename_all = "camelCase")] - GenerateEd25519Address { - coin_type: u32, - bech32_hrp: Hrp, - #[serde(default)] - account_index: u32, - #[serde(default)] - address_index: u32, - #[serde(default)] - internal: bool, - #[serde(default)] - ledger_nano_prompt: bool, - }, /// Generate multiple Ed25519 addresses at once. GenerateEd25519Addresses { /// Addresses generation options diff --git a/bindings/core/src/method_handler/secret_manager.rs b/bindings/core/src/method_handler/secret_manager.rs index cb98810fd5..ca01227830 100644 --- a/bindings/core/src/method_handler/secret_manager.rs +++ b/bindings/core/src/method_handler/secret_manager.rs @@ -8,7 +8,7 @@ use iota_sdk::client::secret::{stronghold::StrongholdSecretManager, SecretManage use iota_sdk::{ client::{ api::{GetAddressesOptions, PreparedTransactionData}, - secret::{DowncastSecretManager, GenerateAddressOptions, SecretManage, SignBlock}, + secret::{DowncastSecretManager, SecretManage, SignBlock}, ClientError, }, types::{ @@ -28,34 +28,6 @@ where ClientError: From, { let response = match method { - SecretManagerMethod::GenerateEd25519Address { - coin_type, - account_index, - address_index, - internal, - ledger_nano_prompt, - bech32_hrp, - } => { - let address = secret_manager - .generate_ed25519_addresses( - coin_type, - account_index, - address_index..address_index + 1, - GenerateAddressOptions { - internal, - ledger_nano_prompt, - }, - ) - .await - .map_err(ClientError::from)? - .into_iter() - .map(|a| a.to_bech32(bech32_hrp)) - .collect::>() - .pop() - // Panic: if the secret manager method didn't fail then there must be at least one address - .unwrap(); - Response::Bech32Address(address) - } SecretManagerMethod::GenerateEd25519Addresses { options: GetAddressesOptions { diff --git a/bindings/nodejs/lib/secret_manager/secret-manager.ts b/bindings/nodejs/lib/secret_manager/secret-manager.ts index b2a5b9ca4f..3f65aa864d 100644 --- a/bindings/nodejs/lib/secret_manager/secret-manager.ts +++ b/bindings/nodejs/lib/secret_manager/secret-manager.ts @@ -6,8 +6,6 @@ import type { GenerateAddressesOptions, PreparedTransactionData, LedgerNanoStatus, - CoinType, - GenerateAddressOptions, } from '../types/client'; import { Bip44, @@ -46,33 +44,6 @@ export class SecretManager { return new SecretManager(SecretManagerMethodHandler.create(options)); } - /** - * Generate a single Ed25519 address. - * - * @returns The generated Bech32 address. - */ - async generateEd25519Address( - coinType: CoinType, - bech32Hrp: string, - accountIndex?: number, - addressIndex?: number, - options?: GenerateAddressOptions, - ): Promise { - const response = await this.methodHandler.callMethod({ - name: 'generateEd25519Address', - data: { - coinType, - bech32Hrp, - accountIndex, - addressIndex, - internal: options?.internal, - ledgerNanoPrompt: options?.ledgerNanoPrompt, - }, - }); - - return JSON.parse(response).payload; - } - /** * Generate multiple Ed25519 addresses at once. * diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts index 119935dd08..c7027781ae 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/index.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/index.ts @@ -1,5 +1,4 @@ import type { - __GenerateEd25519AddressMethod__, __GenerateEd25519AddressesMethod__, __GenerateEvmAddressesMethod__, __GetLedgerNanoStatusMethod__, @@ -15,7 +14,6 @@ import type { } from './secret-manager'; export type __SecretManagerMethods__ = - | __GenerateEd25519AddressMethod__ | __GenerateEd25519AddressesMethod__ | __GenerateEvmAddressesMethod__ | __GetLedgerNanoStatusMethod__ diff --git a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts index 4d804b7a99..e3e5d504c5 100644 --- a/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts +++ b/bindings/nodejs/lib/types/secret_manager/bridge/secret-manager.ts @@ -2,24 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { UnsignedBlock } from '../../block'; -import { CoinType } from '../../client'; import type { GenerateAddressesOptions } from '../../client/generate-addresses-options'; import type { PreparedTransactionData } from '../../client/prepared-transaction-data'; import { HexEncodedString } from '../../utils'; import { Bip44 } from '../secret-manager'; -export interface __GenerateEd25519AddressMethod__ { - name: 'generateEd25519Address'; - data: { - coinType: CoinType; - bech32Hrp: string; - accountIndex?: number; - addressIndex?: number; - internal?: boolean; - ledgerNanoPrompt?: boolean; - }; -} - export interface __GenerateEd25519AddressesMethod__ { name: 'generateEd25519Addresses'; data: { diff --git a/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts b/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts index 5071f0ff15..98a4a00336 100644 --- a/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts +++ b/bindings/nodejs/tests/secret_manager/secret_manager.spec.ts @@ -19,9 +19,12 @@ describe('SecretManager', () => { let bech32_hrp = Utils.iotaMainnetProtocolParameters().bech32Hrp; const secretManager = SecretManager.create(mnemonicSecretManager); - const address = await secretManager.generateEd25519Address(CoinType.IOTA, bech32_hrp); + const addresses = await secretManager.generateEd25519Addresses({ + coinType: CoinType.IOTA, + bech32Hrp: bech32_hrp, + }); - expect(address).toEqual('iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg'); + expect(addresses[0]).toEqual('iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg'); }, 20000); @@ -33,9 +36,13 @@ describe('SecretManager', () => { let bech32_hrp = Utils.shimmerMainnetProtocolParameters().bech32Hrp; const secretManager = SecretManager.create(mnemonicSecretManager); - const address = await secretManager.generateEd25519Address(CoinType.Shimmer, bech32_hrp); + const addresses = await secretManager.generateEd25519Addresses({ + coinType: CoinType.Shimmer, + bech32Hrp: bech32_hrp, + range: { start: 0, end: 1 }, + }); - expect(address).toEqual('smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y'); + expect(addresses[0]).toEqual('smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y'); }, 20000); }); diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index f9fb454eda..9b92baca25 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -147,19 +147,24 @@ def generate_ed25519_address(self, The generated Ed25519 address. """ - args = {} - args['coinType'] = coin_type - args['bech32Hrp'] = bech32_hrp - if account_index is not None: - args['accountIndex'] = account_index + options = {} + options['coinType'] = coin_type + options['bech32Hrp'] = bech32_hrp if address_index is not None: - args['addressIndex'] = address_index + options['range'] = {} + options['range']['start'] = address_index + options['range']['end'] = address_index + 1 + if account_index is not None: + options['accountIndex'] = account_index + options['options'] = {} if internal is not None: - args['internal'] = internal + options['options']['internal'] = internal if legder_nano_prompt is not None: - args['ledgerNanoPrompot'] = legder_nano_prompt + options['options']['ledgerNanoPrompot'] = legder_nano_prompt - return self._call_method('generateEd25519Address', args) + return self._call_method('generateEd25519Addresses', { + 'options': options + })[0] # pylint: disable=unused-argument From 853bcb0896d26ade057b5ef1802437f8e995317f Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Thu, 7 Mar 2024 15:12:54 +0100 Subject: [PATCH 38/38] Python: small fix --- .../python/iota_sdk/secret_manager/secret_manager.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bindings/python/iota_sdk/secret_manager/secret_manager.py b/bindings/python/iota_sdk/secret_manager/secret_manager.py index 9b92baca25..36c0b5901b 100644 --- a/bindings/python/iota_sdk/secret_manager/secret_manager.py +++ b/bindings/python/iota_sdk/secret_manager/secret_manager.py @@ -156,11 +156,12 @@ def generate_ed25519_address(self, options['range']['end'] = address_index + 1 if account_index is not None: options['accountIndex'] = account_index - options['options'] = {} - if internal is not None: - options['options']['internal'] = internal - if legder_nano_prompt is not None: - options['options']['ledgerNanoPrompot'] = legder_nano_prompt + if internal is not None or legder_nano_prompt is not None: + options['options'] = {} + if internal is not None: + options['options']['internal'] = internal + if legder_nano_prompt is not None: + options['options']['ledgerNanoPrompot'] = legder_nano_prompt return self._call_method('generateEd25519Addresses', { 'options': options