diff --git a/bindings/nodejs/lib/types/wallet/wallet.ts b/bindings/nodejs/lib/types/wallet/wallet.ts index bcf3141e93..db1cb5b450 100644 --- a/bindings/nodejs/lib/types/wallet/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/wallet.ts @@ -105,6 +105,8 @@ export interface SyncOptions { syncOnlyMostBasicOutputs?: boolean; /** Sync native token foundries, so their metadata can be returned in the balance. Default: false. */ syncNativeTokenFoundries?: boolean; + /// Sync implicit accounts. + syncImplicitAccounts?: boolean; } /** Specifies what outputs should be synced for the ed25519 address from the wallet. */ diff --git a/bindings/nodejs/lib/utils/index.ts b/bindings/nodejs/lib/utils/index.ts index 296753ff95..6a080b7de6 100644 --- a/bindings/nodejs/lib/utils/index.ts +++ b/bindings/nodejs/lib/utils/index.ts @@ -1,6 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +export * from './units-helper'; export * from './utf8'; export * from './utils'; export * from '../types/utils'; diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 0ff7bda314..10ef4afdeb 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -323,21 +323,23 @@ impl FromStr for OutputSelector { pub async fn accounts_command(wallet: &Wallet) -> Result<(), Error> { let wallet_data = wallet.data().await; let accounts = wallet_data.accounts(); + let hrp = wallet.client().get_bech32_hrp().await?; println_log_info!("Accounts:\n"); for account in accounts { let output_id = account.output_id; let account_id = account.output.as_account().account_id_non_null(&output_id); - let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?); + let account_address = account_id.to_bech32(hrp); let bic = wallet .client() .get_account_congestion(&account_id) - .await? - .block_issuance_credits; + .await + .map(|r| r.block_issuance_credits) + .ok(); println_log_info!( - "{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n", + "{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic:?}\n", "Output ID:", "Account ID:", "Account Address:", @@ -698,21 +700,23 @@ pub async fn implicit_account_transition_command( pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> { let wallet_data = wallet.data().await; let implicit_accounts = wallet_data.implicit_accounts(); + let hrp = wallet.client().get_bech32_hrp().await?; println_log_info!("Implicit accounts:\n"); for implicit_account in implicit_accounts { let output_id = implicit_account.output_id; let account_id = AccountId::from(&output_id); - let account_address = account_id.to_bech32(wallet.client().get_bech32_hrp().await?); + let account_address = account_id.to_bech32(hrp); let bic = wallet .client() .get_account_congestion(&account_id) - .await? - .block_issuance_credits; + .await + .map(|r| r.block_issuance_credits) + .ok(); println_log_info!( - "{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic}\n", + "{:<16} {output_id}\n{:<16} {account_id}\n{:<16} {account_address}\n{:<16} {bic:?}\n", "Output ID:", "Account ID:", "Account Address:", diff --git a/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs b/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs index 936aeac41d..8554f1c1b3 100644 --- a/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs +++ b/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs @@ -4,13 +4,14 @@ use derive_more::From; use crate::types::block::{ - address::AccountAddress, + address::{AccountAddress, Address}, + error::Error, output::{StorageScore, StorageScoreParameters}, }; /// Defines the permanent [`AccountAddress`] that owns this output. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, From, packable::Packable)] -pub struct ImmutableAccountAddressUnlockCondition(AccountAddress); +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, From, packable::Packable)] +pub struct ImmutableAccountAddressUnlockCondition(#[packable(verify_with = verify_address)] Address); impl ImmutableAccountAddressUnlockCondition { /// The [`UnlockCondition`](crate::types::block::output::UnlockCondition) kind of an @@ -20,12 +21,12 @@ impl ImmutableAccountAddressUnlockCondition { /// Creates a new [`ImmutableAccountAddressUnlockCondition`]. #[inline(always)] pub fn new(address: impl Into) -> Self { - Self(address.into()) + Self(Address::from(address.into())) } /// Returns the account address of an [`ImmutableAccountAddressUnlockCondition`]. pub fn address(&self) -> &AccountAddress { - &self.0 + self.0.as_account() } } @@ -35,6 +36,15 @@ impl StorageScore for ImmutableAccountAddressUnlockCondition { } } +#[inline] +fn verify_address(address: &Address) -> Result<(), Error> { + if VERIFY && !address.is_account() { + Err(Error::InvalidAddressKind(address.kind())) + } else { + Ok(()) + } +} + #[cfg(feature = "serde")] mod dto { use serde::{Deserialize, Serialize}; @@ -45,14 +55,14 @@ mod dto { struct ImmutableAccountAddressUnlockConditionDto { #[serde(rename = "type")] kind: u8, - address: AccountAddress, + address: Address, } impl From<&ImmutableAccountAddressUnlockCondition> for ImmutableAccountAddressUnlockConditionDto { fn from(value: &ImmutableAccountAddressUnlockCondition) -> Self { Self { kind: ImmutableAccountAddressUnlockCondition::KIND, - address: value.0, + address: value.0.clone(), } } } diff --git a/sdk/tests/types/output/foundry.rs b/sdk/tests/types/output/foundry.rs index f52388bbf3..8a6b39822c 100644 --- a/sdk/tests/types/output/foundry.rs +++ b/sdk/tests/types/output/foundry.rs @@ -28,7 +28,7 @@ fn builder() { let mut builder = FoundryOutput::build_with_amount(amount, 234, rand_token_scheme()) .with_serial_number(85) .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) - .with_unlock_conditions([account_1]) + .with_unlock_conditions([account_1.clone()]) .add_feature(metadata_1.clone()) .replace_feature(metadata_2.clone()) .with_immutable_features([metadata_2.clone()]) @@ -45,7 +45,7 @@ fn builder() { .clear_unlock_conditions() .clear_features() .clear_immutable_features() - .replace_unlock_condition(account_2); + .replace_unlock_condition(account_2.clone()); let output = builder.clone().finish().unwrap(); assert_eq!(output.unlock_conditions().immutable_account_address(), Some(&account_2)); assert!(output.features().is_empty());