From 78bdad3addd979832b7615a2319b9e7f8ebf4336 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 8 Nov 2023 13:05:37 +0100 Subject: [PATCH 01/26] First draft --- sdk/src/types/block/output/account.rs | 41 ++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/sdk/src/types/block/output/account.rs b/sdk/src/types/block/output/account.rs index de27285b41..24eaa663ec 100644 --- a/sdk/src/types/block/output/account.rs +++ b/sdk/src/types/block/output/account.rs @@ -15,13 +15,17 @@ use crate::types::{ block::{ address::{AccountAddress, Address}, output::{ - feature::{verify_allowed_features, Feature, FeatureFlags, Features}, + feature::{ + verify_allowed_features, BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey, + Feature, FeatureFlags, Features, + }, unlock_condition::{ - verify_allowed_unlock_conditions, UnlockCondition, UnlockConditionFlags, UnlockConditions, + verify_allowed_unlock_conditions, AddressUnlockCondition, UnlockCondition, UnlockConditionFlags, + UnlockConditions, }, - verify_output_amount_min, verify_output_amount_packable, verify_output_amount_supply, ChainId, NativeToken, - NativeTokens, Output, OutputBuilderAmount, OutputId, Rent, RentStructure, StateTransitionError, - StateTransitionVerifier, + verify_output_amount_min, verify_output_amount_packable, verify_output_amount_supply, BasicOutput, ChainId, + NativeToken, NativeTokens, Output, OutputBuilderAmount, OutputId, Rent, RentStructure, + StateTransitionError, StateTransitionVerifier, }, payload::signed_transaction::TransactionCapabilityFlag, protocol::ProtocolParameters, @@ -48,7 +52,11 @@ impl From<&OutputId> for AccountId { impl AccountId { /// pub fn or_from_output_id(self, output_id: &OutputId) -> Self { - if self.is_null() { Self::from(output_id) } else { self } + if self.is_null() { + Self::from(output_id) + } else { + self + } } } @@ -97,6 +105,22 @@ impl AccountOutputBuilder { } } + pub fn from_implicit_account(output: &BasicOutput, output_id: &OutputId) -> Result { + if !output.is_implicit_account() { + panic!() + } + + Ok(Self::new_with_amount(output.amount(), AccountId::from(output_id)) + .with_mana(output.mana()) + .with_unlock_conditions([AddressUnlockCondition::from(output.address().clone())]) + .with_features([BlockIssuerFeature::new( + 0, + BlockIssuerKeys::from_vec([BlockIssuerKey::from(Ed25519BlockIssuerKey::from( + output.address().as_implicit_account_creation(), + ))])?, + )])) + } + /// Sets the amount to the provided value. #[inline(always)] pub fn with_amount(mut self, amount: u64) -> Self { @@ -331,7 +355,10 @@ impl AccountOutput { /// The set of allowed [`UnlockCondition`]s for an [`AccountOutput`]. pub const ALLOWED_UNLOCK_CONDITIONS: UnlockConditionFlags = UnlockConditionFlags::ADDRESS; /// The set of allowed [`Feature`]s for an [`AccountOutput`]. - pub const ALLOWED_FEATURES: FeatureFlags = FeatureFlags::SENDER.union(FeatureFlags::METADATA); + pub const ALLOWED_FEATURES: FeatureFlags = FeatureFlags::SENDER + .union(FeatureFlags::METADATA) + .union(FeatureFlags::BLOCK_ISSUER) + .union(FeatureFlags::STAKING); /// The set of allowed immutable [`Feature`]s for an [`AccountOutput`]. pub const ALLOWED_IMMUTABLE_FEATURES: FeatureFlags = FeatureFlags::ISSUER.union(FeatureFlags::METADATA); From 8b5c2d1ba66f982b971fddc428fcf158ce5e3884 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 12:24:29 +0100 Subject: [PATCH 02/26] Wallet implicit_account_transition method --- sdk/src/types/block/output/account.rs | 28 +-------- .../wallet/operations/transaction/account.rs | 59 +++++++++++++++++++ sdk/src/wallet/operations/transaction/mod.rs | 1 + 3 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 sdk/src/wallet/operations/transaction/account.rs diff --git a/sdk/src/types/block/output/account.rs b/sdk/src/types/block/output/account.rs index 822df0f2c7..b9b1555725 100644 --- a/sdk/src/types/block/output/account.rs +++ b/sdk/src/types/block/output/account.rs @@ -14,15 +14,9 @@ use packable::{ use crate::types::block::{ address::{AccountAddress, Address}, output::{ - feature::{ - verify_allowed_features, BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey, - Feature, FeatureFlags, Features, - }, - unlock_condition::{ - verify_allowed_unlock_conditions, AddressUnlockCondition, UnlockCondition, UnlockConditionFlags, - UnlockConditions, - }, - BasicOutput, ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StateTransitionError, + feature::{verify_allowed_features, Feature, FeatureFlags, Features}, + unlock_condition::{verify_allowed_unlock_conditions, UnlockCondition, UnlockConditionFlags, UnlockConditions}, + ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StateTransitionError, StateTransitionVerifier, StorageScore, StorageScoreParameters, }, payload::signed_transaction::TransactionCapabilityFlag, @@ -99,22 +93,6 @@ impl AccountOutputBuilder { } } - pub fn from_implicit_account(output: &BasicOutput, output_id: &OutputId) -> Result { - if !output.is_implicit_account() { - panic!() - } - - Ok(Self::new_with_amount(output.amount(), AccountId::from(output_id)) - .with_mana(output.mana()) - .with_unlock_conditions([AddressUnlockCondition::from(output.address().clone())]) - .with_features([BlockIssuerFeature::new( - 0, - BlockIssuerKeys::from_vec([BlockIssuerKey::from(Ed25519BlockIssuerKey::from( - output.address().as_implicit_account_creation(), - ))])?, - )])) - } - /// Sets the amount to the provided value. #[inline(always)] pub fn with_amount(mut self, amount: u64) -> Self { diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs new file mode 100644 index 0000000000..ab0a9d7055 --- /dev/null +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -0,0 +1,59 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + client::secret::SecretManage, + types::block::output::{ + feature::{BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey}, + unlock_condition::{AddressUnlockCondition, UnlockCondition}, + AccountId, AccountOutput, BasicOutput, FoundryId, MinimumOutputAmount, NativeTokensBuilder, Output, OutputId, + }, + wallet::{ + operations::transaction::{TransactionOptions, TransactionWithMetadata}, + Result, Wallet, + }, +}; + +impl Wallet +where + crate::wallet::Error: From, + crate::client::Error: From, +{ + async fn implicit_account_transition(&self, output_id: &OutputId) -> Result { + let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); + + let implicit_account = if let Some(implicit_account_data) = &implicit_account_data { + if implicit_account_data.output.is_implicit_account() { + implicit_account_data.output.as_basic() + } else { + todo!() + } + } else { + todo!() + }; + + // [BlockIssuerFeature::new( + // 0, + // BlockIssuerKeys::from_vec([BlockIssuerKey::from(Ed25519BlockIssuerKey::from( + // implicit_account.address().as_implicit_account_creation(), + // ))] + + let account = AccountOutput::build_with_amount(implicit_account.amount(), AccountId::from(output_id)) + .with_mana(implicit_account.mana()) + .with_unlock_conditions([AddressUnlockCondition::from(implicit_account.address().clone())]) + .finish_output()?; + // .with_features()?, + + let transaction_options = TransactionOptions { + custom_inputs: Some(vec![*output_id]), + ..Default::default() + }; + + let prepared_transaction = self + .prepare_transaction(vec![account], transaction_options.clone()) + .await?; + + self.sign_and_submit_transaction(prepared_transaction, transaction_options) + .await + } +} diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 78cfcdfbf7..64b163b6a2 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -1,6 +1,7 @@ // Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +pub(crate) mod account; mod build_transaction; pub(crate) mod high_level; mod input_selection; From f0ed6402e3f0a812c4c4a23ed00c421e212b1909 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 12:30:22 +0100 Subject: [PATCH 03/26] Add to CLI --- cli/src/wallet_cli/completer.rs | 1 + cli/src/wallet_cli/mod.rs | 15 +++++++++++++++ sdk/src/wallet/operations/transaction/account.rs | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cli/src/wallet_cli/completer.rs b/cli/src/wallet_cli/completer.rs index 140183b0b6..af3bc3a843 100644 --- a/cli/src/wallet_cli/completer.rs +++ b/cli/src/wallet_cli/completer.rs @@ -25,6 +25,7 @@ const WALLET_COMMANDS: &[&str] = &[ "exit", "faucet", "implicit-account-creation-address", + "implicit-account-transition", "implicit-accounts", "melt-native-token", "mint-native-token", diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 5715f0dabe..18a0e810e5 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -120,6 +120,11 @@ pub enum WalletCommand { }, /// Returns the implicit account creation address of the wallet if it is Ed25519 based. ImplicitAccountCreationAddress, + /// Transitions an implicit account to an account. + ImplicitAccountTransition { + /// Identifier of the implicit account output. + output_id: OutputId, + }, /// Lists the implicit accounts of the wallet. ImplicitAccounts, /// Mint additional native tokens. @@ -578,6 +583,13 @@ pub async fn implicit_account_creation_address_command(wallet: &Wallet) -> Resul Ok(()) } +// `implicit-account-transition` command +pub async fn implicit_account_transition_command(wallet: &Wallet, output_id: OutputId) -> Result<(), Error> { + wallet.implicit_account_transition(&output_id).await?; + + Ok(()) +} + // `implicit-accounts` command pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> { print_outputs(wallet.implicit_accounts().await, "Implicit accounts:").await @@ -1103,6 +1115,9 @@ pub async fn prompt_internal( WalletCommand::ImplicitAccountCreationAddress => { implicit_account_creation_address_command(wallet).await } + WalletCommand::ImplicitAccountTransition { output_id } => { + implicit_account_transition_command(wallet, output_id).await + } WalletCommand::ImplicitAccounts => implicit_accounts_command(wallet).await, WalletCommand::MeltNativeToken { token_id, amount } => { melt_native_token_command(wallet, token_id, amount).await diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index ab0a9d7055..b28bff853f 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -19,7 +19,7 @@ where crate::wallet::Error: From, crate::client::Error: From, { - async fn implicit_account_transition(&self, output_id: &OutputId) -> Result { + pub async fn implicit_account_transition(&self, output_id: &OutputId) -> Result { let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); let implicit_account = if let Some(implicit_account_data) = &implicit_account_data { From 83d7e1d3fb04d1f22eb41d3f5655b5d290272184 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 12:54:34 +0100 Subject: [PATCH 04/26] Support for ImplicitAccountCreation in ISA filter --- .../client/api/block_builder/input_selection/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index e9efec2740..35643ac6c7 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -235,10 +235,12 @@ impl InputSelection { .unwrap() .0; - if let Address::Restricted(restricted_address) = required_address { - self.addresses.contains(restricted_address.address()) - } else { - self.addresses.contains(&required_address) + match required_address { + Address::ImplicitAccountCreation(implicit_account_creation) => self + .addresses + .contains(&Address::from(*implicit_account_creation.ed25519_address())), + Address::Restricted(restricted) => self.addresses.contains(restricted.address()), + _ => self.addresses.contains(&required_address), } }) } From 5705c382b63d0bc19ceb32d6b0551bff4666fa0d Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 12:58:19 +0100 Subject: [PATCH 05/26] Support for ImplicitAccountCreation in ISA required_account_nft_addresses --- sdk/src/client/api/block_builder/input_selection/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 35643ac6c7..3d41fed518 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -68,6 +68,7 @@ impl InputSelection { Address::Account(account_address) => Ok(Some(Requirement::Account(*account_address.account_id()))), Address::Nft(nft_address) => Ok(Some(Requirement::Nft(*nft_address.nft_id()))), Address::Anchor(_) => Err(Error::UnsupportedAddressType(AnchorAddress::KIND)), + Address::ImplicitAccountCreation(_) => Ok(None), Address::Restricted(_) => Ok(None), _ => todo!("What do we do here?"), } From 565fdd6c02aa66f3435969d4b141b1d6ef6dfa8f Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 13:16:12 +0100 Subject: [PATCH 06/26] Support for implicit accounts in ISA is_account_with_id --- sdk/src/client/api/block_builder/input_selection/mod.rs | 9 ++------- .../block_builder/input_selection/requirement/account.rs | 8 ++++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 3d41fed518..65adc9a9e4 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -14,6 +14,7 @@ use std::collections::HashSet; use packable::PackableExt; +use self::requirement::account::is_account_with_id; pub use self::{burn::Burn, error::Error, requirement::Requirement}; use crate::{ client::{api::types::RemainderData, secret::types::InputSigningData}, @@ -435,13 +436,7 @@ impl InputSelection { let account_input = input_accounts .iter() - .find(|i| { - if let Output::Account(account_input) = &i.output { - *account_output.account_id() == account_input.account_id_non_null(i.output_id()) - } else { - false - } - }) + .find(|i| is_account_with_id(&i.output, account_output.account_id(), i.output_id())) .expect("ISA is broken because there is no account input"); if let Err(err) = AccountOutput::transition_inner( diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs index cc1cf01fe9..87f8cd20cd 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/account.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/account.rs @@ -9,10 +9,10 @@ use crate::{ /// Checks if an output is an account with output ID that matches the given account ID. pub(crate) fn is_account_with_id(output: &Output, account_id: &AccountId, output_id: &OutputId) -> bool { - if let Output::Account(account) = output { - &account.account_id_non_null(output_id) == account_id - } else { - false + match output { + Output::Basic(basic) => basic.is_implicit_account() && &AccountId::from(output_id) == account_id, + Output::Account(account) => &account.account_id_non_null(output_id) == account_id, + _ => false, } } From 1888c186f8f469b217fb4c9bfd982c547517824e Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 15:22:10 +0100 Subject: [PATCH 07/26] Support implicit accounts in ISA validate_transitions --- .../api/block_builder/input_selection/mod.rs | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 65adc9a9e4..00c3da64f0 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -405,6 +405,11 @@ impl InputSelection { input_native_tokens_builder.add_native_token(*native_token)?; } match &input.output { + Output::Basic(basic) => { + if basic.is_implicit_account() { + input_accounts.push(input); + } + } Output::Account(_) => { input_accounts.push(input); } @@ -439,16 +444,24 @@ impl InputSelection { .find(|i| is_account_with_id(&i.output, account_output.account_id(), i.output_id())) .expect("ISA is broken because there is no account input"); - if let Err(err) = AccountOutput::transition_inner( - account_input.output.as_account(), - account_output, - &input_chains_foundries, - &self.outputs, - ) { - log::debug!("validate_transitions error {err:?}"); - return Err(Error::UnfulfillableRequirement(Requirement::Account( - *account_output.account_id(), - ))); + match &account_input.output { + Output::Account(account) => { + if let Err(err) = AccountOutput::transition_inner( + account, + account_output, + &input_chains_foundries, + &self.outputs, + ) { + log::debug!("validate_transitions error {err:?}"); + return Err(Error::UnfulfillableRequirement(Requirement::Account( + *account_output.account_id(), + ))); + } + } + Output::Basic(_) => { + // TODO + } + _ => unreachable!(), } } Output::Foundry(foundry_output) => { From ed565bf270c12cc0c295dbf88ba7afd82d614697 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 16:32:19 +0100 Subject: [PATCH 08/26] Fix default_transaction_unlocks --- sdk/src/client/secret/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 7293ccfd24..1284c5bc9f 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -553,7 +553,7 @@ where // We can only sign ed25519 addresses and block_indexes needs to contain the account or nft // address already at this point, because the reference index needs to be lower // than the current block index - if !input_address.is_ed25519() { + if !input_address.is_ed25519() && !input_address.is_implicit_account_creation() { Err(InputSelectionError::MissingInputWithEd25519Address)?; } From e450a2e59a9761a69cd0cad16b399867e437adac Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 17:29:24 +0100 Subject: [PATCH 09/26] Add implicit accounts to input chains --- sdk/src/types/block/semantic.rs | 51 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/sdk/src/types/block/semantic.rs b/sdk/src/types/block/semantic.rs index 6f2b7f726b..c22695ac45 100644 --- a/sdk/src/types/block/semantic.rs +++ b/sdk/src/types/block/semantic.rs @@ -10,7 +10,7 @@ use primitive_types::U256; use crate::types::block::{ address::{Address, AddressCapabilityFlag}, output::{ - AnchorOutput, ChainId, FoundryId, NativeTokens, Output, OutputId, StateTransitionError, TokenId, + AccountId, AnchorOutput, ChainId, FoundryId, NativeTokens, Output, OutputId, StateTransitionError, TokenId, UnlockCondition, }, payload::signed_transaction::{Transaction, TransactionCapabilityFlag, TransactionId, TransactionSigningHash}, @@ -216,6 +216,32 @@ impl<'a> SemanticValidationContext<'a> { inputs: &'a [(&'a OutputId, &'a Output)], unlocks: &'a Unlocks, ) -> Self { + let input_chains = inputs + .iter() + .filter_map(|(output_id, input)| { + if input.is_implicit_account() { + Some((ChainId::from(AccountId::from(*output_id)), *input)) + } else { + input + .chain_id() + .map(|chain_id| (chain_id.or_from_output_id(output_id), *input)) + } + }) + .collect(); + let output_chains = transaction + .outputs() + .iter() + .enumerate() + .filter_map(|(index, output)| { + output.chain_id().map(|chain_id| { + ( + chain_id.or_from_output_id(&OutputId::new(*transaction_id, index as u16).unwrap()), + output, + ) + }) + }) + .collect(); + Self { transaction, transaction_signing_hash: transaction.signing_hash(), @@ -224,30 +250,11 @@ impl<'a> SemanticValidationContext<'a> { input_amount: 0, input_mana: 0, input_native_tokens: BTreeMap::::new(), - input_chains: inputs - .iter() - .filter_map(|(output_id, input)| { - input - .chain_id() - .map(|chain_id| (chain_id.or_from_output_id(output_id), *input)) - }) - .collect(), + input_chains, output_amount: 0, output_mana: 0, output_native_tokens: BTreeMap::::new(), - output_chains: transaction - .outputs() - .iter() - .enumerate() - .filter_map(|(index, output)| { - output.chain_id().map(|chain_id| { - ( - chain_id.or_from_output_id(&OutputId::new(*transaction_id, index as u16).unwrap()), - output, - ) - }) - }) - .collect(), + output_chains, unlocked_addresses: HashSet::new(), storage_deposit_returns: HashMap::new(), simple_deposits: HashMap::new(), From 50554a62078fe0c6d821daa5a952e7be4b392f22 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 17:51:05 +0100 Subject: [PATCH 10/26] Allow implicit accounts in verify_state_transition --- sdk/src/types/block/output/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index 0f13e5bed2..8352744531 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -319,6 +319,14 @@ impl Output { (None, Some(Self::Delegation(next_state))) => DelegationOutput::creation(next_state, context), // Transitions. + (Some(Self::Basic(current_state)), Some(Self::Account(_next_state))) => { + if !current_state.is_implicit_account() { + Err(StateTransitionError::UnsupportedStateTransition) + } else { + // TODO + Ok(()) + } + } (Some(Self::Account(current_state)), Some(Self::Account(next_state))) => { AccountOutput::transition(current_state, next_state, context) } From ce09c833ade4409caacf0ad11944e505f86348e5 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 18:06:03 +0100 Subject: [PATCH 11/26] Tmp null IssuerId --- .../wallet/operations/transaction/submit_transaction.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sdk/src/wallet/operations/transaction/submit_transaction.rs b/sdk/src/wallet/operations/transaction/submit_transaction.rs index 4ce30c6a8f..63d4364b6a 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -5,7 +5,7 @@ use crate::wallet::events::types::{TransactionProgressEvent, WalletEvent}; use crate::{ client::secret::{SecretManage, SignBlock}, - types::block::{payload::Payload, BlockId}, + types::block::{payload::Payload, BlockId, IssuerId}, wallet::{operations::transaction::SignedTransactionPayload, Error, Wallet}, }; @@ -23,7 +23,8 @@ where let block = self .client() - .build_basic_block(todo!("issuer id"), Some(Payload::from(transaction_payload))) + // TODO IssuerID + .build_basic_block(IssuerId::null(), Some(Payload::from(transaction_payload))) .await? .sign_ed25519( &*self.get_secret_manager().read().await, @@ -35,7 +36,9 @@ where self.emit(WalletEvent::TransactionProgress(TransactionProgressEvent::Broadcasting)) .await; let block_id = self.client().post_block(&block).await?; + log::debug!("[TRANSACTION] submitted block {}", block_id); + Ok(block_id) } } From 605280792c9b156182eaa25e30f2cf44e4c59bb4 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 19:24:58 +0100 Subject: [PATCH 12/26] Set public key --- .../wallet/operations/transaction/account.rs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index b28bff853f..dc0d35d4a0 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -5,8 +5,8 @@ use crate::{ client::secret::SecretManage, types::block::output::{ feature::{BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey}, - unlock_condition::{AddressUnlockCondition, UnlockCondition}, - AccountId, AccountOutput, BasicOutput, FoundryId, MinimumOutputAmount, NativeTokensBuilder, Output, OutputId, + unlock_condition::AddressUnlockCondition, + AccountId, AccountOutput, OutputId, }, wallet::{ operations::transaction::{TransactionOptions, TransactionWithMetadata}, @@ -32,17 +32,29 @@ where todo!() }; - // [BlockIssuerFeature::new( - // 0, - // BlockIssuerKeys::from_vec([BlockIssuerKey::from(Ed25519BlockIssuerKey::from( - // implicit_account.address().as_implicit_account_creation(), - // ))] + let public_key = if let Some(bip_path) = self.bip_path().await { + self.secret_manager + .read() + .await + .generate_ed25519_public_keys( + bip_path.coin_type, + bip_path.account, + bip_path.address_index..bip_path.address_index + 1, + None, + ) + .await?[0] + } else { + todo!() + }; let account = AccountOutput::build_with_amount(implicit_account.amount(), AccountId::from(output_id)) .with_mana(implicit_account.mana()) .with_unlock_conditions([AddressUnlockCondition::from(implicit_account.address().clone())]) + .with_features([BlockIssuerFeature::new( + 0, + BlockIssuerKeys::from_vec(vec![BlockIssuerKey::from(Ed25519BlockIssuerKey::from(public_key))])?, + )?]) .finish_output()?; - // .with_features()?, let transaction_options = TransactionOptions { custom_inputs: Some(vec![*output_id]), From 8146d5e424f729450eff2e4dcbfdf3e0508eb7d2 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 11:35:56 +0100 Subject: [PATCH 13/26] Add TODOs --- sdk/src/client/api/block_builder/input_selection/mod.rs | 2 +- sdk/src/types/block/output/mod.rs | 2 +- sdk/src/wallet/operations/transaction/submit_transaction.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 00c3da64f0..ce7757aaaa 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -459,7 +459,7 @@ impl InputSelection { } } Output::Basic(_) => { - // TODO + // TODO https://github.com/iotaledger/iota-sdk/issues/1664 } _ => unreachable!(), } diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index 8352744531..1a43ccc664 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -323,7 +323,7 @@ impl Output { if !current_state.is_implicit_account() { Err(StateTransitionError::UnsupportedStateTransition) } else { - // TODO + // TODO https://github.com/iotaledger/iota-sdk/issues/1664 Ok(()) } } diff --git a/sdk/src/wallet/operations/transaction/submit_transaction.rs b/sdk/src/wallet/operations/transaction/submit_transaction.rs index 63d4364b6a..5c36dcfb1b 100644 --- a/sdk/src/wallet/operations/transaction/submit_transaction.rs +++ b/sdk/src/wallet/operations/transaction/submit_transaction.rs @@ -23,7 +23,7 @@ where let block = self .client() - // TODO IssuerID + // TODO https://github.com/iotaledger/iota-sdk/issues/1665 to set IssuerId .build_basic_block(IssuerId::null(), Some(Payload::from(transaction_payload))) .await? .sign_ed25519( From 2966963dc3b037a6e184dac6fb73449e4a4676c8 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 11:56:12 +0100 Subject: [PATCH 14/26] Add to bindings core --- bindings/core/src/method/wallet.rs | 4 ++++ bindings/core/src/method_handler/wallet.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index 36f280a558..06d1e5d729 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -191,6 +191,10 @@ pub enum WalletMethod { /// Returns the implicit account creation address of the wallet if it is Ed25519 based. /// Expected response: [`Bech32Address`](crate::Response::Bech32Address) ImplicitAccountCreationAddress, + /// Transitions an implicit account to an account. + /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) + #[serde(rename_all = "camelCase")] + ImplicitAccountTransition { output_id: OutputId }, /// Returns the implicit accounts of the wallet. /// Expected response: [`OutputsData`](crate::Response::OutputsData) ImplicitAccounts, diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index d7dc3d1121..9ee0c4cd10 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -210,6 +210,10 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM let implicit_account_creation_address = wallet.implicit_account_creation_address().await?; Response::Bech32Address(implicit_account_creation_address) } + WalletMethod::ImplicitAccountTransition { output_id } => { + let transaction = wallet.implicit_account_transition(&output_id).await?; + Response::SentTransaction(TransactionWithMetadataDto::from(&transaction)) + } WalletMethod::ImplicitAccounts => { let implicit_accounts = wallet.implicit_accounts().await; Response::OutputsData(implicit_accounts.iter().map(OutputDataDto::from).collect()) From 59844cd80c6f5eda2fa196b1e76f7508c156180f Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:04:26 +0100 Subject: [PATCH 15/26] Nodejs bindings --- .../nodejs/lib/types/wallet/bridge/account.ts | 4 ++++ .../nodejs/lib/types/wallet/bridge/index.ts | 2 ++ .../nodejs/lib/types/wallet/bridge/wallet.ts | 7 +++++++ bindings/nodejs/lib/wallet/wallet.ts | 17 +++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/bindings/nodejs/lib/types/wallet/bridge/account.ts b/bindings/nodejs/lib/types/wallet/bridge/account.ts index 26c33803ac..5e277a98cf 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/account.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/account.ts @@ -150,6 +150,10 @@ export type __ImplicitAccountCreationAddressMethod__ = { name: 'implicitAccountCreationAddress'; }; +export type __ImplicitAccountTransitionMethod__ = { + name: 'implicitAccountTransition'; +}; + export type __AccountsMethod__ = { name: 'accounts'; }; diff --git a/bindings/nodejs/lib/types/wallet/bridge/index.ts b/bindings/nodejs/lib/types/wallet/bridge/index.ts index 2869168102..94d2ca9c7a 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/index.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/index.ts @@ -12,6 +12,7 @@ import type { __OutputsMethod__, __PendingTransactionsMethod__, __ImplicitAccountCreationAddressMethod__, + __ImplicitAccountTransitionMethod__, __AccountsMethod__, __ImplicitAccountsMethod__, __IncomingTransactionsMethod__, @@ -85,6 +86,7 @@ export type __WalletMethod__ = | __OutputsMethod__ | __PendingTransactionsMethod__ | __ImplicitAccountCreationAddressMethod__ + | __ImplicitAccountTransitionMethod__ | __AccountsMethod__ | __ImplicitAccountsMethod__ | __IncomingTransactionsMethod__ diff --git a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts index 895a9aeeaf..053f971825 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts @@ -233,6 +233,13 @@ export type __ImplicitAccountCreationAddressMethod__ = { name: 'implicitAccountCreationAddress'; }; +export type __ImplicitAccountTransitionMethod__ = { + name: 'implicitAccountTransition'; + data: { + outputId: OutputId; + }; +}; + export type __ImplicitAccountsMethod__ = { name: 'implicitAccounts'; }; diff --git a/bindings/nodejs/lib/wallet/wallet.ts b/bindings/nodejs/lib/wallet/wallet.ts index 071d0b3667..ef7509dd14 100644 --- a/bindings/nodejs/lib/wallet/wallet.ts +++ b/bindings/nodejs/lib/wallet/wallet.ts @@ -895,6 +895,23 @@ export class Wallet { return JSON.parse(response).payload; } + /** + * Transitions an implicit account to an account. + * + * @param outputId Identifier of the implicit account output. + * @returns The created transaction. + */ + async implicitAccountTransition( + outputId: OutputId, + ): Promise { + const response = await this.methodHandler.callMethod({ + name: 'implicitAccountTransition', + data: { outputId }, + }); + + return JSON.parse(response).payload; + } + /** * Returns the implicit accounts of the wallet. * From fce4e5bb80e8462e4d04624ecd5801d59e597516 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:06:59 +0100 Subject: [PATCH 16/26] fix --- bindings/nodejs/lib/wallet/wallet.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/nodejs/lib/wallet/wallet.ts b/bindings/nodejs/lib/wallet/wallet.ts index ef7509dd14..7bf9ed64e8 100644 --- a/bindings/nodejs/lib/wallet/wallet.ts +++ b/bindings/nodejs/lib/wallet/wallet.ts @@ -909,7 +909,10 @@ export class Wallet { data: { outputId }, }); - return JSON.parse(response).payload; + const parsed = JSON.parse( + response, + ) as Response; + return plainToInstance(TransactionWithMetadata, parsed.payload); } /** From f664acb1eab01711d8144691cd521c0e45ab9c36 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:10:32 +0100 Subject: [PATCH 17/26] Python bindings --- bindings/python/iota_sdk/wallet/account.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bindings/python/iota_sdk/wallet/account.py b/bindings/python/iota_sdk/wallet/account.py index 3bc91c0181..18dc959b02 100644 --- a/bindings/python/iota_sdk/wallet/account.py +++ b/bindings/python/iota_sdk/wallet/account.py @@ -278,6 +278,16 @@ def implicit_account_creation_address(self) -> str: 'implicitAccountCreationAddress' ) + def implicit_account_transition( + self, output_id: OutputId) -> TransactionWithMetadata: + """Transitions an implicit account to an account. + """ + return TransactionWithMetadata.from_dict(self._call_account_method( + 'implicitAccountTransition', { + 'outputId': output_id + } + )) + def accounts(self) -> List[OutputData]: """Returns the accounts of the wallet. """ From 02d953da11c0528e936243547fece3d69d734ad7 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:22:50 +0100 Subject: [PATCH 18/26] TODO and errors --- sdk/src/wallet/error.rs | 3 +++ sdk/src/wallet/operations/transaction/account.rs | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sdk/src/wallet/error.rs b/sdk/src/wallet/error.rs index e16408b6e7..a23cb78d59 100644 --- a/sdk/src/wallet/error.rs +++ b/sdk/src/wallet/error.rs @@ -124,6 +124,9 @@ pub enum Error { /// Action requires the wallet to be Ed25519 address based #[error("tried to perform an action that requires the wallet to be Ed25519 address based")] NonEd25519Address, + /// Implicit account not found. + #[error("implicit account not found")] + ImplicitAccountNotFound, } // Serialize type with Display error diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index dc0d35d4a0..6c358049ec 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -10,7 +10,7 @@ use crate::{ }, wallet::{ operations::transaction::{TransactionOptions, TransactionWithMetadata}, - Result, Wallet, + Error, Result, Wallet, }, }; @@ -19,6 +19,7 @@ where crate::wallet::Error: From, crate::client::Error: From, { + /// Transitions an implicit account to an account. pub async fn implicit_account_transition(&self, output_id: &OutputId) -> Result { let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); @@ -26,10 +27,10 @@ where if implicit_account_data.output.is_implicit_account() { implicit_account_data.output.as_basic() } else { - todo!() + return Err(Error::ImplicitAccountNotFound); } } else { - todo!() + return Err(Error::ImplicitAccountNotFound); }; let public_key = if let Some(bip_path) = self.bip_path().await { @@ -44,6 +45,7 @@ where ) .await?[0] } else { + // TODO https://github.com/iotaledger/iota-sdk/issues/1666 todo!() }; From f154e1d156c8f4647f62b915d516b3b6a947447d Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:23:48 +0100 Subject: [PATCH 19/26] Use u32::MAX --- sdk/src/wallet/operations/transaction/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 6c358049ec..910e4e2815 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -53,7 +53,7 @@ where .with_mana(implicit_account.mana()) .with_unlock_conditions([AddressUnlockCondition::from(implicit_account.address().clone())]) .with_features([BlockIssuerFeature::new( - 0, + u32::MAX, BlockIssuerKeys::from_vec(vec![BlockIssuerKey::from(Ed25519BlockIssuerKey::from(public_key))])?, )?]) .finish_output()?; From d952349a982e7126beafb901cd3283860a08105a Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 12:27:10 +0100 Subject: [PATCH 20/26] Fix address --- .../wallet/operations/transaction/account.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 910e4e2815..5ea9914832 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -3,10 +3,13 @@ use crate::{ client::secret::SecretManage, - types::block::output::{ - feature::{BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey}, - unlock_condition::AddressUnlockCondition, - AccountId, AccountOutput, OutputId, + types::block::{ + address::Address, + output::{ + feature::{BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey}, + unlock_condition::AddressUnlockCondition, + AccountId, AccountOutput, OutputId, + }, }, wallet::{ operations::transaction::{TransactionOptions, TransactionWithMetadata}, @@ -51,7 +54,12 @@ where let account = AccountOutput::build_with_amount(implicit_account.amount(), AccountId::from(output_id)) .with_mana(implicit_account.mana()) - .with_unlock_conditions([AddressUnlockCondition::from(implicit_account.address().clone())]) + .with_unlock_conditions([AddressUnlockCondition::from(Address::from( + *implicit_account + .address() + .as_implicit_account_creation() + .ed25519_address(), + ))]) .with_features([BlockIssuerFeature::new( u32::MAX, BlockIssuerKeys::from_vec(vec![BlockIssuerKey::from(Ed25519BlockIssuerKey::from(public_key))])?, From 726c7e53721f05d0e3a312903f7fff952e954a1c Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 13:28:42 +0100 Subject: [PATCH 21/26] Remove account file --- .../nodejs/lib/types/wallet/bridge/account.ts | 388 ------------------ 1 file changed, 388 deletions(-) delete mode 100644 bindings/nodejs/lib/types/wallet/bridge/account.ts diff --git a/bindings/nodejs/lib/types/wallet/bridge/account.ts b/bindings/nodejs/lib/types/wallet/bridge/account.ts deleted file mode 100644 index 5e277a98cf..0000000000 --- a/bindings/nodejs/lib/types/wallet/bridge/account.ts +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright 2023 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import type { - SendParams, - SendNativeTokenParams, - SendNftParams, - GenerateAddressOptions, -} from '../address'; -import type { Burn, INode, PreparedTransactionData } from '../../client'; -import type { OutputParams } from '../output-params'; -import type { OutputsToClaim } from '../output'; -import type { SignedTransactionData } from '../signed-transaction-data'; -import type { - AccountOutputParams, - CreateNativeTokenParams, - TransactionOptions, - MintNftParams, -} from '../transaction-options'; -import type { - ParticipationEventId, - ParticipationEventRegistrationOptions, - ParticipationEventType, -} from '../participation'; -import type { ConsolidationParams } from '../consolidation-params'; -import { - FilterOptions, - HexEncodedAmount, - NumericString, - Output, - OutputId, - SyncOptions, - TokenId, - TransactionId, -} from '../../'; - -export type __PrepareBurnMethod__ = { - name: 'prepareBurn'; - data: { - burn: Burn; - options?: TransactionOptions; - }; -}; - -export type __ClaimOutputsMethod__ = { - name: 'claimOutputs'; - data: { - outputIdsToClaim: OutputId[]; - }; -}; - -export type __PrepareConsolidateOutputsMethod__ = { - name: 'prepareConsolidateOutputs'; - data: { - params: ConsolidationParams; - }; -}; - -export type __PrepareCreateAccountOutputMethod__ = { - name: 'prepareCreateAccountOutput'; - data: { - params?: AccountOutputParams; - options?: TransactionOptions; - }; -}; - -export type __PrepareMeltNativeTokenMethod__ = { - name: 'prepareMeltNativeToken'; - data: { - tokenId: TokenId; - meltAmount: HexEncodedAmount; - options?: TransactionOptions; - }; -}; - -export type __DeregisterParticipationEventMethod__ = { - name: 'deregisterParticipationEvent'; - data: { - eventId: ParticipationEventId; - }; -}; - -export type __GenerateEd25519AddressesMethod__ = { - name: 'generateEd25519Addresses'; - data: { - amount: number; - options?: GenerateAddressOptions; - }; -}; - -export type __GetBalanceMethod__ = { - name: 'getBalance'; -}; - -export type __GetIncomingTransactionMethod__ = { - name: 'getIncomingTransaction'; - data: { - transactionId: TransactionId; - }; -}; - -export type __GetOutputMethod__ = { - name: 'getOutput'; - data: { - outputId: OutputId; - }; -}; - -export type __GetFoundryOutputMethod__ = { - name: 'getFoundryOutput'; - data: { - tokenId: TokenId; - }; -}; - -export type __ClaimableOutputsMethod__ = { - name: 'claimableOutputs'; - data: { - outputsToClaim: OutputsToClaim; - }; -}; - -export type __GetTransactionMethod__ = { - name: 'getTransaction'; - data: { - transactionId: TransactionId; - }; -}; - -export type __AddressesMethod__ = { - name: 'addresses'; -}; - -export type __AddressesWithUnspentOutputsMethod__ = { - name: 'addressesWithUnspentOutputs'; -}; - -export type __OutputsMethod__ = { - name: 'outputs'; - data: { - filterOptions?: FilterOptions; - }; -}; - -export type __PendingTransactionsMethod__ = { - name: 'pendingTransactions'; -}; - -export type __ImplicitAccountCreationAddressMethod__ = { - name: 'implicitAccountCreationAddress'; -}; - -export type __ImplicitAccountTransitionMethod__ = { - name: 'implicitAccountTransition'; -}; - -export type __AccountsMethod__ = { - name: 'accounts'; -}; - -export type __ImplicitAccountsMethod__ = { - name: 'implicitAccounts'; -}; - -export type __IncomingTransactionsMethod__ = { - name: 'incomingTransactions'; -}; - -export type __TransactionsMethod__ = { - name: 'transactions'; -}; - -export type __UnspentOutputsMethod__ = { - name: 'unspentOutputs'; - data: { - filterOptions?: FilterOptions; - }; -}; - -export type __PrepareMintNativeTokenMethod__ = { - name: 'prepareMintNativeToken'; - data: { - tokenId: TokenId; - mintAmount: HexEncodedAmount; - options?: TransactionOptions; - }; -}; - -export type __PrepareCreateNativeTokenMethod__ = { - name: 'prepareCreateNativeToken'; - data: { - params: CreateNativeTokenParams; - options?: TransactionOptions; - }; -}; - -export type __PrepareMintNftsMethod__ = { - name: 'prepareMintNfts'; - data: { - params: MintNftParams[]; - options?: TransactionOptions; - }; -}; - -export type __PrepareOutputMethod__ = { - name: 'prepareOutput'; - data: { - params: OutputParams; - transactionOptions?: TransactionOptions; - }; -}; - -export type __PrepareSendMethod__ = { - name: 'prepareSend'; - data: { - params: SendParams[]; - options?: TransactionOptions; - }; -}; - -export type __PrepareTransactionMethod__ = { - name: 'prepareTransaction'; - data: { - outputs: Output[]; - options?: TransactionOptions; - }; -}; - -export type __RegisterParticipationEventsMethod__ = { - name: 'registerParticipationEvents'; - data: { - options: ParticipationEventRegistrationOptions; - }; -}; - -export type __ReissueTransactionUntilIncludedMethod__ = { - name: 'reissueTransactionUntilIncluded'; - data: { - transactionId: TransactionId; - interval?: number; - maxAttempts?: number; - }; -}; - -export type __SendMethod__ = { - name: 'send'; - data: { - amount: NumericString; - address: string; - options?: TransactionOptions; - }; -}; - -export type __SendWithParamsMethod__ = { - name: 'sendWithParams'; - data: { - params: SendParams[]; - options?: TransactionOptions; - }; -}; - -export type __PrepareSendNativeTokensMethod__ = { - name: 'prepareSendNativeTokens'; - data: { - params: SendNativeTokenParams[]; - options?: TransactionOptions; - }; -}; - -export type __PrepareSendNftMethod__ = { - name: 'prepareSendNft'; - data: { - params: SendNftParams[]; - options?: TransactionOptions; - }; -}; - -export type __SendOutputsMethod__ = { - name: 'sendOutputs'; - data: { - outputs: Output[]; - options?: TransactionOptions; - }; -}; - -export type __SetAliasMethod__ = { - name: 'setAlias'; - data: { - alias: string; - }; -}; - -export type __SetDefaultSyncOptionsMethod__ = { - name: 'setDefaultSyncOptions'; - data: { - options: SyncOptions; - }; -}; - -export type __SignTransactionMethod__ = { - name: 'signTransaction'; - data: { - preparedTransactionData: PreparedTransactionData; - }; -}; - -export type __SignAndSubmitTransactionMethod__ = { - name: 'signAndSubmitTransaction'; - data: { - preparedTransactionData: PreparedTransactionData; - }; -}; - -export type __SubmitAndStoreTransactionMethod__ = { - name: 'submitAndStoreTransaction'; - data: { - signedTransactionData: SignedTransactionData; - }; -}; - -export type __SyncAccountMethod__ = { - name: 'sync'; - data: { - options?: SyncOptions; - }; -}; - -export type __PrepareVoteMethod__ = { - name: 'prepareVote'; - data: { - eventId?: ParticipationEventId; - answers?: number[]; - }; -}; - -export type __PrepareStopParticipatingMethod__ = { - name: 'prepareStopParticipating'; - data: { - eventId: ParticipationEventId; - }; -}; - -export type __GetParticipationOverviewMethod__ = { - name: 'getParticipationOverview'; - data: { - eventIds?: ParticipationEventId[]; - }; -}; - -export type __PrepareIncreaseVotingPowerMethod__ = { - name: 'prepareIncreaseVotingPower'; - data: { - amount: NumericString; - }; -}; - -export type __GetParticipationEventMethod__ = { - name: 'getParticipationEvent'; - data: { - eventId: ParticipationEventId; - }; -}; - -export type __GetParticipationEventIdsMethod__ = { - name: 'getParticipationEventIds'; - data: { - node: INode; - eventType?: ParticipationEventType; - }; -}; - -export type __GetParticipationEventsMethod__ = { - name: 'getParticipationEvents'; -}; - -export type __GetParticipationEventStatusMethod__ = { - name: 'getParticipationEventStatus'; - data: { - eventId: ParticipationEventId; - }; -}; - -export type __PrepareDecreaseVotingPowerMethod__ = { - name: 'prepareDecreaseVotingPower'; - data: { - amount: NumericString; - }; -}; From 03e662c7fa0b023a6b46d5d6c47d0871437af299 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 13:56:33 +0100 Subject: [PATCH 22/26] Add prepare versions --- bindings/core/src/method/wallet.rs | 6 +++--- bindings/core/src/method_handler/wallet.rs | 6 +++--- bindings/core/src/response.rs | 1 + .../nodejs/lib/types/wallet/bridge/index.ts | 4 ++-- .../nodejs/lib/types/wallet/bridge/wallet.ts | 4 ++-- bindings/nodejs/lib/wallet/wallet.ts | 21 ++++++++++++++++--- bindings/python/iota_sdk/wallet/account.py | 16 ++++++++++---- .../wallet/operations/transaction/account.rs | 14 +++++++------ 8 files changed, 49 insertions(+), 23 deletions(-) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index 06d1e5d729..59be946bda 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -191,10 +191,10 @@ pub enum WalletMethod { /// Returns the implicit account creation address of the wallet if it is Ed25519 based. /// Expected response: [`Bech32Address`](crate::Response::Bech32Address) ImplicitAccountCreationAddress, - /// Transitions an implicit account to an account. - /// Expected response: [`SentTransaction`](crate::Response::SentTransaction) + /// Prepares to transition an implicit account to an account. + /// Expected response: [`PreparedTransaction`](crate::Response::PreparedTransaction) #[serde(rename_all = "camelCase")] - ImplicitAccountTransition { output_id: OutputId }, + PrepareImplicitAccountTransition { output_id: OutputId }, /// Returns the implicit accounts of the wallet. /// Expected response: [`OutputsData`](crate::Response::OutputsData) ImplicitAccounts, diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index 9ee0c4cd10..b70d2e6862 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -210,9 +210,9 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM let implicit_account_creation_address = wallet.implicit_account_creation_address().await?; Response::Bech32Address(implicit_account_creation_address) } - WalletMethod::ImplicitAccountTransition { output_id } => { - let transaction = wallet.implicit_account_transition(&output_id).await?; - Response::SentTransaction(TransactionWithMetadataDto::from(&transaction)) + WalletMethod::PrepareImplicitAccountTransition { output_id } => { + let data = wallet.prepare_implicit_account_transition(&output_id).await?; + Response::PreparedTransaction(PreparedTransactionDataDto::from(&data)) } WalletMethod::ImplicitAccounts => { let implicit_accounts = wallet.implicit_accounts().await; diff --git a/bindings/core/src/response.rs b/bindings/core/src/response.rs index 365b629b09..da71cecd3d 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -284,6 +284,7 @@ pub enum Response { /// - [`PrepareStopParticipating`](crate::method::WalletMethod::PrepareStopParticipating) /// - [`PrepareTransaction`](crate::method::WalletMethod::PrepareTransaction) /// - [`PrepareVote`](crate::method::WalletMethod::PrepareVote) + /// - [`PrepareImplicitAccountTransition`](crate::method::WalletMethod::PrepareImplicitAccountTransition) PreparedTransaction(PreparedTransactionDataDto), /// Response for: /// - [`PrepareCreateNativeToken`](crate::method::WalletMethod::PrepareCreateNativeToken), diff --git a/bindings/nodejs/lib/types/wallet/bridge/index.ts b/bindings/nodejs/lib/types/wallet/bridge/index.ts index 94d2ca9c7a..e5d818dbb6 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/index.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/index.ts @@ -12,7 +12,7 @@ import type { __OutputsMethod__, __PendingTransactionsMethod__, __ImplicitAccountCreationAddressMethod__, - __ImplicitAccountTransitionMethod__, + __PrepareImplicitAccountTransitionMethod__, __AccountsMethod__, __ImplicitAccountsMethod__, __IncomingTransactionsMethod__, @@ -86,7 +86,7 @@ export type __WalletMethod__ = | __OutputsMethod__ | __PendingTransactionsMethod__ | __ImplicitAccountCreationAddressMethod__ - | __ImplicitAccountTransitionMethod__ + | __PrepareImplicitAccountTransitionMethod__ | __AccountsMethod__ | __ImplicitAccountsMethod__ | __IncomingTransactionsMethod__ diff --git a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts index 053f971825..945086d9fd 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts @@ -233,8 +233,8 @@ export type __ImplicitAccountCreationAddressMethod__ = { name: 'implicitAccountCreationAddress'; }; -export type __ImplicitAccountTransitionMethod__ = { - name: 'implicitAccountTransition'; +export type __PrepareImplicitAccountTransitionMethod__ = { + name: 'prepareImplicitAccountTransition'; data: { outputId: OutputId; }; diff --git a/bindings/nodejs/lib/wallet/wallet.ts b/bindings/nodejs/lib/wallet/wallet.ts index 7bf9ed64e8..1b8e547a56 100644 --- a/bindings/nodejs/lib/wallet/wallet.ts +++ b/bindings/nodejs/lib/wallet/wallet.ts @@ -904,15 +904,30 @@ export class Wallet { async implicitAccountTransition( outputId: OutputId, ): Promise { + return (await this.prepareImplicitAccountTransition(outputId)).send(); + } + + /** + * Prepares to transition an implicit account to an account. + * + * @param outputId Identifier of the implicit account output. + * @returns The prepared transaction. + */ + async prepareImplicitAccountTransition( + outputId: OutputId, + ): Promise { const response = await this.methodHandler.callMethod({ - name: 'implicitAccountTransition', + name: 'prepareImplicitAccountTransition', data: { outputId }, }); const parsed = JSON.parse( response, - ) as Response; - return plainToInstance(TransactionWithMetadata, parsed.payload); + ) as Response; + return new PreparedTransaction( + plainToInstance(PreparedTransactionData, parsed.payload), + this, + ); } /** diff --git a/bindings/python/iota_sdk/wallet/account.py b/bindings/python/iota_sdk/wallet/account.py index 18dc959b02..d81f8541a2 100644 --- a/bindings/python/iota_sdk/wallet/account.py +++ b/bindings/python/iota_sdk/wallet/account.py @@ -278,15 +278,23 @@ def implicit_account_creation_address(self) -> str: 'implicitAccountCreationAddress' ) - def implicit_account_transition( - self, output_id: OutputId) -> TransactionWithMetadata: + def implicit_account_transition( + self, output_id: OutputId) -> TransactionWithMetadata: """Transitions an implicit account to an account. """ - return TransactionWithMetadata.from_dict(self._call_account_method( + return self.prepare_implicit_account_transition(output_id).send() + + def prepare_implicit_account_transition( + self, output_id: OutputId) -> PreparedTransaction: + """Prepares to transition an implicit account to an account. + """ + prepared = self._call_account_method( 'implicitAccountTransition', { 'outputId': output_id } - )) + ) + return PreparedCreateTokenTransaction( + account=self, prepared_transaction_data=prepared) def accounts(self) -> List[OutputData]: """Returns the accounts of the wallet. diff --git a/sdk/src/wallet/operations/transaction/account.rs b/sdk/src/wallet/operations/transaction/account.rs index 5ea9914832..099f9f1fcf 100644 --- a/sdk/src/wallet/operations/transaction/account.rs +++ b/sdk/src/wallet/operations/transaction/account.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - client::secret::SecretManage, + client::{api::PreparedTransactionData, secret::SecretManage}, types::block::{ address::Address, output::{ @@ -24,6 +24,12 @@ where { /// Transitions an implicit account to an account. pub async fn implicit_account_transition(&self, output_id: &OutputId) -> Result { + self.sign_and_submit_transaction(self.prepare_implicit_account_transition(output_id).await?, None) + .await + } + + /// Prepares to transition an implicit account to an account. + pub async fn prepare_implicit_account_transition(&self, output_id: &OutputId) -> Result { let implicit_account_data = self.data().await.unspent_outputs.get(output_id).cloned(); let implicit_account = if let Some(implicit_account_data) = &implicit_account_data { @@ -71,11 +77,7 @@ where ..Default::default() }; - let prepared_transaction = self - .prepare_transaction(vec![account], transaction_options.clone()) - .await?; - - self.sign_and_submit_transaction(prepared_transaction, transaction_options) + self.prepare_transaction(vec![account], transaction_options.clone()) .await } } From d65159687ebd4efee83e3e9b81a2b34310ecdf8b Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 14:23:37 +0100 Subject: [PATCH 23/26] Add Restricted in match --- sdk/src/client/secret/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 1284c5bc9f..c9af7bc968 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -553,8 +553,10 @@ where // We can only sign ed25519 addresses and block_indexes needs to contain the account or nft // address already at this point, because the reference index needs to be lower // than the current block index - if !input_address.is_ed25519() && !input_address.is_implicit_account_creation() { - Err(InputSelectionError::MissingInputWithEd25519Address)?; + match &input_address { + Address::Ed25519(_) | Address::ImplicitAccountCreation(_) => {} + Address::Restricted(restricted) if restricted.address().is_ed25519() => {} + _ => Err(InputSelectionError::MissingInputWithEd25519Address)?, } let chain = input.chain.ok_or(Error::MissingBip32Chain)?; From 333204f5a9625b5275e895baada703cf0ad47add Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 14:24:55 +0100 Subject: [PATCH 24/26] Update bindings/python/iota_sdk/wallet/account.py Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- bindings/python/iota_sdk/wallet/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/iota_sdk/wallet/account.py b/bindings/python/iota_sdk/wallet/account.py index d81f8541a2..02ce968a41 100644 --- a/bindings/python/iota_sdk/wallet/account.py +++ b/bindings/python/iota_sdk/wallet/account.py @@ -293,7 +293,7 @@ def prepare_implicit_account_transition( 'outputId': output_id } ) - return PreparedCreateTokenTransaction( + return PreparedTransaction( account=self, prepared_transaction_data=prepared) def accounts(self) -> List[OutputData]: From a2adb75c0f0c14706a25242eb07226ef9d133eee Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 22 Nov 2023 14:38:17 +0100 Subject: [PATCH 25/26] Log CLI transaction --- cli/src/wallet_cli/mod.rs | 8 +++++++- sdk/src/wallet/operations/transaction/mod.rs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 18a0e810e5..9600f81abf 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -585,7 +585,13 @@ pub async fn implicit_account_creation_address_command(wallet: &Wallet) -> Resul // `implicit-account-transition` command pub async fn implicit_account_transition_command(wallet: &Wallet, output_id: OutputId) -> Result<(), Error> { - wallet.implicit_account_transition(&output_id).await?; + let transaction = wallet.implicit_account_transition(&output_id).await?; + + println_log_info!( + "Implicit account transition transaction sent:\n{:?}\n{:?}", + transaction.transaction_id, + transaction.block_id + ); Ok(()) } diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 64b163b6a2..d3e2d5498c 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -186,7 +186,7 @@ where wallet_data.pending_transactions.insert(transaction_id); #[cfg(feature = "storage")] { - // TODO: maybe better to use the wallt address as identifier now? + // TODO: maybe better to use the wallet address as identifier now? log::debug!("[TRANSACTION] storing wallet"); self.save(Some(&wallet_data)).await?; } From bd386202872af04c9144979039682a001687e41f Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 23 Nov 2023 09:50:20 +0100 Subject: [PATCH 26/26] unreachable -> panic --- sdk/src/client/api/block_builder/input_selection/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index ce7757aaaa..da4a4014f3 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -461,7 +461,7 @@ impl InputSelection { Output::Basic(_) => { // TODO https://github.com/iotaledger/iota-sdk/issues/1664 } - _ => unreachable!(), + _ => panic!("unreachable: \"input_accounts\" only contains account outputs and implicit account (basic) outputs") } } Output::Foundry(foundry_output) => {