From 3175a903a6b5d427503a4dea099c10d55f020645 Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Tue, 21 Nov 2023 09:40:54 +0100 Subject: [PATCH 1/3] Nodejs: add Weighted and MultiAddress (#1645) * nodejs add Weighted and MultiAddress * Only allowed addresses in discriminator --------- Co-authored-by: Thibault Martinez --- bindings/nodejs/lib/types/block/address.ts | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/bindings/nodejs/lib/types/block/address.ts b/bindings/nodejs/lib/types/block/address.ts index b5b7c4889a..082c065632 100644 --- a/bindings/nodejs/lib/types/block/address.ts +++ b/bindings/nodejs/lib/types/block/address.ts @@ -24,6 +24,8 @@ enum AddressType { Anchor = 24, /** An implicit account creation address. */ ImplicitAccountCreation = 32, + /** A Multi address. */ + Multi = 40, /** An address with restricted capabilities. */ Restricted = 48, } @@ -78,6 +80,7 @@ abstract class Address { throw new Error('Invalid JSON'); } } + /** * An Ed25519 Address. */ @@ -256,6 +259,70 @@ class RestrictedAddress extends Address { } } +/** + * A weighted address. + */ +class WeightedAddress { + /** + * The unlocked address. + */ + @Type(() => Address, { + discriminator: { + property: 'type', + subTypes: [ + { value: Ed25519Address, name: AddressType.Ed25519 as any }, + { value: AccountAddress, name: AddressType.Account as any }, + { value: NftAddress, name: AddressType.Nft as any }, + { value: AnchorAddress, name: AddressType.Anchor as any }, + ], + }, + }) + readonly address: Address; + /** + * The weight of the unlocked address. + */ + readonly weight: number; + + /** + * @param address The unlocked address. + * @param weight The weight of the unlocked address. + */ + constructor(address: Address, weight: number) { + this.address = address; + this.weight = weight; + } +} + +/** + * An address that consists of addresses with weights and a threshold value. + * The Multi Address can be unlocked if the cumulative weight of all unlocked addresses is equal to or exceeds the + * threshold. + */ +class MultiAddress extends Address { + /** + * The weighted unlocked addresses. + */ + readonly addresses: WeightedAddress[]; + /** + * The threshold that needs to be reached by the unlocked addresses in order to unlock the multi address. + */ + readonly threshold: number; + + /** + * @param addresses The weighted unlocked addresses. + * @param threshold The threshold that needs to be reached by the unlocked addresses in order to unlock the multi address. + */ + constructor(addresses: WeightedAddress[], threshold: number) { + super(AddressType.Multi); + this.addresses = addresses; + this.threshold = threshold; + } + + toString(): string { + return JSON.stringify(this); + } +} + const AddressDiscriminator = { property: 'type', subTypes: [ @@ -267,6 +334,7 @@ const AddressDiscriminator = { value: ImplicitAccountCreationAddress, name: AddressType.ImplicitAccountCreation as any, }, + { value: MultiAddress, name: AddressType.Multi as any }, { value: RestrictedAddress, name: AddressType.Restricted as any }, ], }; @@ -281,5 +349,7 @@ export { NftAddress, AnchorAddress, ImplicitAccountCreationAddress, + WeightedAddress, + MultiAddress, RestrictedAddress, }; From 9f40b1a165d6e95614aa726d054e33bf84a5852c Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 10:09:30 +0100 Subject: [PATCH 2/3] Change *_ignore_errors to *_ignore_not_found (#1642) * Rename * Ignore not found * Missed account rename * format output list --- bindings/core/src/method_handler/client.rs | 2 +- cli/src/wallet_cli/mod.rs | 2 +- sdk/src/client/node_api/core/mod.rs | 50 ++++++++----------- .../syncing/addresses/output_ids/mod.rs | 12 ++--- sdk/src/wallet/operations/syncing/mod.rs | 2 +- sdk/src/wallet/operations/syncing/outputs.rs | 2 +- 6 files changed, 32 insertions(+), 38 deletions(-) diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index d68fea59b3..753c897297 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -251,7 +251,7 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM } ClientMethod::GetOutputsIgnoreErrors { output_ids } => { let outputs_response = client - .get_outputs_with_metadata_ignore_errors(&output_ids) + .get_outputs_with_metadata_ignore_not_found(&output_ids) .await? .iter() .map(OutputWithMetadataResponse::from) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 304b582e76..5715f0dabe 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -1210,7 +1210,7 @@ async fn print_outputs(mut outputs: Vec, title: &str) -> Result<(), }; println_log_info!( - "{:<5}{}\t{}\t{}", + "{:<5}{} {:<16}{}", i, &output_data.output_id, kind_str, diff --git a/sdk/src/client/node_api/core/mod.rs b/sdk/src/client/node_api/core/mod.rs index ade26cf22a..7f31339855 100644 --- a/sdk/src/client/node_api/core/mod.rs +++ b/sdk/src/client/node_api/core/mod.rs @@ -8,7 +8,7 @@ pub mod routes; use packable::PackableExt; use crate::{ - client::{Client, Result}, + client::{node_api::error::Error as NodeApiError, Client, Error, Result}, types::block::output::{Output, OutputId, OutputMetadata, OutputWithMetadata}, }; @@ -31,16 +31,14 @@ impl Client { futures::future::try_join_all(output_ids.iter().map(|id| self.get_output(id))).await } - /// Requests outputs by their output ID in parallel, ignoring failed requests. + /// Requests outputs by their output ID in parallel, ignoring outputs not found. /// Useful to get data about spent outputs, that might not be pruned yet. - pub async fn get_outputs_ignore_errors(&self, output_ids: &[OutputId]) -> Result> { - Ok( - futures::future::join_all(output_ids.iter().map(|id| self.get_output(id))) - .await - .into_iter() - .filter_map(Result::ok) - .collect(), - ) + pub async fn get_outputs_ignore_not_found(&self, output_ids: &[OutputId]) -> Result> { + futures::future::join_all(output_ids.iter().map(|id| self.get_output(id))) + .await + .into_iter() + .filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_))))) + .collect() } /// Requests metadata for outputs by their output ID in parallel. @@ -48,15 +46,13 @@ impl Client { futures::future::try_join_all(output_ids.iter().map(|id| self.get_output_metadata(id))).await } - /// Requests metadata for outputs by their output ID in parallel, ignoring failed requests. - pub async fn get_outputs_metadata_ignore_errors(&self, output_ids: &[OutputId]) -> Result> { - Ok( - futures::future::join_all(output_ids.iter().map(|id| self.get_output_metadata(id))) - .await - .into_iter() - .filter_map(Result::ok) - .collect(), - ) + /// Requests metadata for outputs by their output ID in parallel, ignoring outputs not found. + pub async fn get_outputs_metadata_ignore_not_found(&self, output_ids: &[OutputId]) -> Result> { + futures::future::join_all(output_ids.iter().map(|id| self.get_output_metadata(id))) + .await + .into_iter() + .filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_))))) + .collect() } /// Requests outputs and their metadata by their output ID in parallel. @@ -64,18 +60,16 @@ impl Client { futures::future::try_join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id))).await } - /// Requests outputs and their metadata by their output ID in parallel, ignoring failed requests. + /// Requests outputs and their metadata by their output ID in parallel, ignoring outputs not found. /// Useful to get data about spent outputs, that might not be pruned yet. - pub async fn get_outputs_with_metadata_ignore_errors( + pub async fn get_outputs_with_metadata_ignore_not_found( &self, output_ids: &[OutputId], ) -> Result> { - Ok( - futures::future::join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id))) - .await - .into_iter() - .filter_map(Result::ok) - .collect(), - ) + futures::future::join_all(output_ids.iter().map(|id| self.get_output_with_metadata(id))) + .await + .into_iter() + .filter(|res| !matches!(res, Err(Error::Node(NodeApiError::NotFound(_))))) + .collect() } } diff --git a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs index c9ddc7b6cb..994b036752 100644 --- a/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs +++ b/sdk/src/wallet/operations/syncing/addresses/output_ids/mod.rs @@ -80,9 +80,9 @@ where tasks.push( async { let bech32_address = address.clone(); - let account = self.clone(); + let wallet = self.clone(); tokio::spawn(async move { - account + wallet .get_basic_output_ids_with_any_unlock_condition(bech32_address) .await }) @@ -108,9 +108,9 @@ where tasks.push( async { let bech32_address = address.clone(); - let account = self.clone(); + let wallet = self.clone(); tokio::spawn(async move { - account + wallet .get_nft_output_ids_with_any_unlock_condition(bech32_address) .await }) @@ -140,9 +140,9 @@ where async { let bech32_address = address.clone(); let sync_options = sync_options.clone(); - let account = self.clone(); + let wallet = self.clone(); tokio::spawn(async move { - account + wallet .get_account_and_foundry_output_ids(bech32_address, &sync_options) .await }) diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index 4ec2ac0045..a19b66b265 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -127,7 +127,7 @@ where log::debug!("[SYNC] spent_or_not_synced_outputs: {spent_or_not_synced_output_ids:?}"); let spent_or_unsynced_output_metadata_responses = self .client() - .get_outputs_metadata_ignore_errors(&spent_or_not_synced_output_ids) + .get_outputs_metadata_ignore_not_found(&spent_or_not_synced_output_ids) .await?; // Add the output response to the output ids, the output response is optional, because an output could be diff --git a/sdk/src/wallet/operations/syncing/outputs.rs b/sdk/src/wallet/operations/syncing/outputs.rs index dfa73891c5..bc048e8350 100644 --- a/sdk/src/wallet/operations/syncing/outputs.rs +++ b/sdk/src/wallet/operations/syncing/outputs.rs @@ -220,7 +220,7 @@ pub(crate) async fn get_inputs_for_transaction_payload( .collect::>(); client - .get_outputs_with_metadata_ignore_errors(&output_ids) + .get_outputs_with_metadata_ignore_not_found(&output_ids) .await .map_err(|e| e.into()) } From 805f5df80e058162edba55a158cc12699e9e1da6 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 10:09:50 +0100 Subject: [PATCH 3/3] Add SecretManage::generate_ed25519_public_keys (#1655) * Add SecretManage::generate_ed25519_public_keys * Add doc --- sdk/src/client/secret/ledger_nano.rs | 74 +++++++++++++++------------- sdk/src/client/secret/mnemonic.rs | 16 ++---- sdk/src/client/secret/mod.rs | 38 +++++++++++--- sdk/src/client/secret/private_key.rs | 15 ++---- sdk/src/client/stronghold/secret.rs | 32 +++++------- 5 files changed, 90 insertions(+), 85 deletions(-) diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index e627293adf..7c38f03597 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -10,7 +10,10 @@ use std::{collections::HashMap, ops::Range}; use async_trait::async_trait; use crypto::{ keys::{bip44::Bip44, slip10::Segment}, - signatures::secp256k1_ecdsa::{self, EvmAddress}, + signatures::{ + ed25519, + secp256k1_ecdsa::{self, EvmAddress}, + }, }; use iota_ledger_nano::{ api::errors::APIError, get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index, @@ -26,7 +29,7 @@ use crate::{ LedgerNanoStatus, PreparedTransactionData, }, types::block::{ - address::{AccountAddress, Address, AnchorAddress, Ed25519Address, NftAddress}, + address::{AccountAddress, Address, AnchorAddress, NftAddress}, output::Output, payload::signed_transaction::SignedTransactionPayload, signature::{Ed25519Signature, Signature}, @@ -131,41 +134,44 @@ impl TryFrom for LedgerDeviceType { impl SecretManage for LedgerSecretManager { type Error = crate::client::Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, // https://github.com/satoshilabs/slips/blob/master/slip-0044.md // current ledger app only supports IOTA_COIN_TYPE, SHIMMER_COIN_TYPE and TESTNET_COIN_TYPE - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - let options = options.into().unwrap_or_default(); - let bip32_account = account_index.harden().into(); - - let bip32 = LedgerBIP32Index { - bip32_index: address_indexes.start.harden().into(), - bip32_change: u32::from(options.internal).harden().into(), - }; - - // lock the mutex to prevent multiple simultaneous requests to a ledger - let lock = self.mutex.lock().await; - - // get ledger - let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; - if ledger.is_debug_app() { - ledger - .set_non_interactive_mode(self.non_interactive) - .map_err(Error::from)?; - } - - let addresses = ledger - .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len()) - .map_err(Error::from)?; - - drop(lock); - - Ok(addresses.into_iter().map(Ed25519Address::new).collect()) + _coin_type: u32, + _account_index: u32, + _address_indexes: Range, + _options: impl Into> + Send, + ) -> Result, Self::Error> { + // need an update on the ledger C lib + todo!(); + // + // let options = options.into().unwrap_or_default(); + // let bip32_account = account_index.harden().into(); + + // let bip32 = LedgerBIP32Index { + // bip32_index: address_indexes.start.harden().into(), + // bip32_change: u32::from(options.internal).harden().into(), + // }; + + // // lock the mutex to prevent multiple simultaneous requests to a ledger + // let lock = self.mutex.lock().await; + + // // get ledger + // let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; + // if ledger.is_debug_app() { + // ledger + // .set_non_interactive_mode(self.non_interactive) + // .map_err(Error::from)?; + // } + + // let addresses = ledger + // .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len()) + // .map_err(Error::from)?; + + // drop(lock); + + // Ok(addresses.into_iter().map(Ed25519Address::new).collect()) } async fn generate_evm_addresses( diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index d955309c1e..ee705d0c8e 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -7,7 +7,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::{bip39::Mnemonic, bip44::Bip44, slip10::Seed}, signatures::{ ed25519, @@ -20,8 +19,7 @@ use super::{GenerateAddressOptions, SecretManage}; use crate::{ client::{api::PreparedTransactionData, Client, Error}, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -40,13 +38,13 @@ impl std::fmt::Debug for MnemonicSecretManager { impl SecretManage for MnemonicSecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let internal = options.into().map(|o| o.internal).unwrap_or_default(); Ok(address_indexes @@ -59,13 +57,9 @@ impl SecretManage for MnemonicSecretManager { let public_key = chain .derive(&self.0.to_master_key::()) .secret_key() - .public_key() - .to_bytes(); - - // Hash the public key to get the address - let result = Blake2b256::digest(public_key).into(); + .public_key(); - crate::client::Result::Ok(Ed25519Address::new(result)) + crate::client::Result::Ok(public_key) }) .collect::>()?) } diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 9c6af509c8..7293ccfd24 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -26,8 +26,12 @@ use std::{collections::HashMap, fmt::Debug, ops::Range, str::FromStr}; use async_trait::async_trait; use crypto::{ + hashes::{blake2b::Blake2b256, Digest}, keys::{bip39::Mnemonic, bip44::Bip44}, - signatures::secp256k1_ecdsa::{self, EvmAddress}, + signatures::{ + ed25519, + secp256k1_ecdsa::{self, EvmAddress}, + }, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use zeroize::Zeroizing; @@ -66,6 +70,17 @@ use crate::{ pub trait SecretManage: Send + Sync { type Error: std::error::Error + Send + Sync; + /// Generates public keys. + /// + /// For `coin_type`, see also . + async fn generate_ed25519_public_keys( + &self, + coin_type: u32, + account_index: u32, + address_indexes: Range, + options: impl Into> + Send, + ) -> Result, Self::Error>; + /// Generates addresses. /// /// For `coin_type`, see also . @@ -75,7 +90,14 @@ pub trait SecretManage: Send + Sync { account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error>; + ) -> Result, Self::Error> { + Ok(self + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) + .await? + .iter() + .map(|public_key| Ed25519Address::new(Blake2b256::digest(public_key.to_bytes()).into())) + .collect()) + } async fn generate_evm_addresses( &self, @@ -308,31 +330,31 @@ impl From<&SecretManager> for SecretManagerDto { impl SecretManage for SecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> crate::client::Result> { + ) -> Result, Self::Error> { match self { #[cfg(feature = "stronghold")] Self::Stronghold(secret_manager) => Ok(secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await?), #[cfg(feature = "ledger_nano")] Self::LedgerNano(secret_manager) => Ok(secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await?), Self::Mnemonic(secret_manager) => { secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await } #[cfg(feature = "private_key_secret_manager")] Self::PrivateKey(secret_manager) => { secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await } Self::Placeholder => Err(Error::PlaceholderSecretManager), diff --git a/sdk/src/client/secret/private_key.rs b/sdk/src/client/secret/private_key.rs index f1b23862b6..0be00cd7a3 100644 --- a/sdk/src/client/secret/private_key.rs +++ b/sdk/src/client/secret/private_key.rs @@ -7,7 +7,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::bip44::Bip44, signatures::{ ed25519, @@ -20,8 +19,7 @@ use super::{GenerateAddressOptions, SecretManage}; use crate::{ client::{api::PreparedTransactionData, Error}, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -38,19 +36,14 @@ impl std::fmt::Debug for PrivateKeySecretManager { impl SecretManage for PrivateKeySecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, _coin_type: u32, _account_index: u32, _address_indexes: Range, _options: impl Into> + Send, - ) -> Result, Self::Error> { - let public_key = self.0.public_key().to_bytes(); - - // Hash the public key to get the address - let result = Blake2b256::digest(public_key).into(); - - crate::client::Result::Ok(vec![Ed25519Address::new(result)]) + ) -> Result, Self::Error> { + crate::client::Result::Ok(vec![self.0.public_key()]) } async fn generate_evm_addresses( diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index bdcc3e1dd3..cc0993a522 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -8,7 +8,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::{ bip39::{Mnemonic, MnemonicRef, Passphrase}, bip44::Bip44, @@ -36,8 +35,7 @@ use crate::{ stronghold::Error, }, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -45,13 +43,13 @@ use crate::{ impl SecretManage for StrongholdAdapter { type Error = crate::client::Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -64,8 +62,8 @@ impl SecretManage for StrongholdAdapter { // Stronghold arguments. let seed_location = Slip10DeriveInput::Seed(Location::generic(SECRET_VAULT_PATH, SEED_RECORD_PATH)); - // Addresses to return. - let mut addresses = Vec::new(); + // Public keys to return. + let mut public_keys = Vec::new(); let internal = options.into().map(|o| o.internal).unwrap_or_default(); for address_index in address_indexes { @@ -104,17 +102,11 @@ impl SecretManage for StrongholdAdapter { .delete_secret(derive_location.record_path()) .map_err(Error::from)?; - // Hash the public key to get the address. - let hash = Blake2b256::digest(public_key); - - // Convert the hash into [Address]. - let address = Ed25519Address::new(hash.into()); - // Collect it. - addresses.push(address); + public_keys.push(public_key); } - Ok(addresses) + Ok(public_keys) } async fn generate_evm_addresses( @@ -589,12 +581,10 @@ mod tests { stronghold_adapter.clear_key().await; // Address generation returns an error when the key is cleared. - assert!( - stronghold_adapter - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None,) - .await - .is_err() - ); + assert!(stronghold_adapter + .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None,) + .await + .is_err()); stronghold_adapter.set_password("drowssap".to_owned()).await.unwrap();