From 4f8c56f4d046bc82f4c8413e764a68b7725b0389 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 25 Apr 2024 15:45:31 +0200 Subject: [PATCH 01/11] Enable adding block issuer keys in cli wallet --- cli/src/wallet_cli/mod.rs | 31 ++++++- sdk/src/wallet/mod.rs | 1 + .../high_level/account_block_issuer_keys.rs | 90 +++++++++++++++++++ .../operations/transaction/high_level/mod.rs | 1 + 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 5b81f1363b..37975cb499 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -14,7 +14,7 @@ use iota_sdk::{ address::{AccountAddress, Bech32Address, ToBech32Ext}, mana::ManaAllotment, output::{ - feature::{BlockIssuerKeySource, MetadataFeature}, + feature::{BlockIssuerKeySource, Ed25519PublicKeyHashBlockIssuerKey, MetadataFeature}, unlock_condition::AddressUnlockCondition, AccountId, BasicOutputBuilder, DelegationId, FoundryId, NativeToken, NativeTokensBuilder, NftId, Output, OutputId, TokenId, @@ -26,8 +26,8 @@ use iota_sdk::{ utils::ConvertTo, wallet::{ types::OutputData, BeginStakingParams, ConsolidationParams, CreateDelegationParams, CreateNativeTokenParams, - MintNftParams, OutputsToClaim, ReturnStrategy, SendManaParams, SendNativeTokenParams, SendNftParams, - SendParams, SyncOptions, Wallet, WalletError, + MintNftParams, ModifyAccountBlockIssuerKey, OutputsToClaim, ReturnStrategy, SendManaParams, + SendNativeTokenParams, SendNftParams, SendParams, SyncOptions, Wallet, WalletError, }, U256, }; @@ -196,6 +196,14 @@ pub enum WalletCommand { }, /// Lists the implicit accounts of the wallet. ImplicitAccounts, + /// Adds a block issuer key to an account. + AddBlockIssuerKey { + /// The account to which the key should be added. + account_id: AccountId, + /// The hex-encoded key to add. + // TODO: Use the actual type somehow? + issuer_key: String, + }, /// Mint additional native tokens. MintNativeToken { /// Token ID to be minted, e.g. 0x087d205988b733d97fb145ae340e27a8b19554d1ceee64574d7e5ff66c45f69e7a0100000000. @@ -924,6 +932,20 @@ pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> { Ok(()) } +// `add-block-issuer-key` command +pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { + let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; + let params = ModifyAccountBlockIssuerKey { + account: account_id.clone(), + keys_to_add: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], + keys_to_remove: vec![], + }; + + wallet.modify_account_output_block_issuer_keys(params, None).await?; + + Ok(()) +} + // `melt-native-token` command pub async fn melt_native_token_command(wallet: &Wallet, token_id: TokenId, amount: U256) -> Result<(), Error> { let transaction = wallet.melt_native_token(token_id, amount, None).await?; @@ -1580,6 +1602,9 @@ pub async fn prompt_internal( implicit_account_transition_command(wallet, output_id).await } WalletCommand::ImplicitAccounts => implicit_accounts_command(wallet).await, + WalletCommand::AddBlockIssuerKey { account_id, issuer_key } => { + add_block_issuer_key(wallet, &account_id, &issuer_key).await + } WalletCommand::MeltNativeToken { token_id, amount } => { ensure_password(wallet).await?; melt_native_token_command(wallet, token_id, amount).await diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 8b704305ab..6523c5d50b 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -52,6 +52,7 @@ pub use self::{ transaction::{ high_level::{ create_account::CreateAccountParams, + account_block_issuer_keys::ModifyAccountBlockIssuerKey, delegation::create::{ CreateDelegationParams, CreateDelegationTransaction, PreparedCreateDelegationTransaction, }, diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs new file mode 100644 index 0000000000..21652221b9 --- /dev/null +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -0,0 +1,90 @@ +// Copyright 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +use crate::{ + client::{api::PreparedTransactionData, secret::SecretManage, ClientError}, + types::block::output::{ + feature::{BlockIssuerFeature, BlockIssuerKey}, + AccountId, AccountOutput, AccountOutputBuilder, + }, + wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet, WalletError}, +}; + +/// Params `modify_account_block_issuer_key()` +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModifyAccountBlockIssuerKey { + pub account: AccountId, + /// The keys that will be added. + pub keys_to_add: Vec, + /// The keys that will be removed. + pub keys_to_remove: Vec, +} + +impl Wallet +where + WalletError: From, + ClientError: From, +{ + pub async fn modify_account_output_block_issuer_keys( + &self, + params: ModifyAccountBlockIssuerKey, + options: impl Into> + Send, + ) -> Result { + let options = options.into(); + let prepared_transaction = self + .prepare_modify_account_output_block_issuer_keys(params, options.clone()) + .await?; + + self.sign_and_submit_transaction(prepared_transaction, options).await + } + + /// Prepares the transaction for [Wallet::create_account_output()]. + pub async fn prepare_modify_account_output_block_issuer_keys( + &self, + params: ModifyAccountBlockIssuerKey, + options: impl Into> + Send, + ) -> Result { + log::debug!("[TRANSACTION] prepare_modify_account_output_block_issuer_keys"); + let storage_score_params = self.client().get_storage_score_parameters().await?; + + let (_, output_data) = self + .get_account_output(params.account) + .await + .ok_or(WalletError::AccountNotFound)?; + + let previous_account: &AccountOutput = output_data.output.as_account(); + + if !previous_account.is_block_issuer() { + return Err(WalletError::InvalidParameter( + "block issuer keys can only be modified on an account with an existing block issuer feature", + )); + } + + let previous_block_issuer_feature = previous_account + .features() + .block_issuer() + .expect("we should not support adding a new block issuer feature in this method for now"); + let mut block_issuer_keys = previous_block_issuer_feature.block_issuer_keys().to_vec(); + + block_issuer_keys.extend(params.keys_to_add); + params.keys_to_remove.iter().for_each(|key_to_remove| { + if let Ok(index) = block_issuer_keys.binary_search(key_to_remove) { + block_issuer_keys.remove(index); + } + }); + + let updated_block_issuer_feature = + BlockIssuerFeature::new(previous_block_issuer_feature.expiry_slot(), block_issuer_keys)?; + + let account_output_builder = AccountOutputBuilder::from(previous_account) + .with_amount_or_minimum(previous_account.amount(), storage_score_params) + .replace_feature(updated_block_issuer_feature); + + let outputs = [account_output_builder.finish_output()?]; + + self.prepare_send_outputs(outputs, options).await + } +} diff --git a/sdk/src/wallet/operations/transaction/high_level/mod.rs b/sdk/src/wallet/operations/transaction/high_level/mod.rs index 0312a91efe..5f0189596d 100644 --- a/sdk/src/wallet/operations/transaction/high_level/mod.rs +++ b/sdk/src/wallet/operations/transaction/high_level/mod.rs @@ -1,6 +1,7 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +pub(crate) mod account_block_issuer_keys; pub(crate) mod allot_mana; pub(crate) mod burning_melting; pub(crate) mod create_account; From 1e4cec9efce70d3526e5670e730c50f6feddfb21 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 10:28:49 +0200 Subject: [PATCH 02/11] Add Modify Block Issuer Keys in AccountChange Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- cli/src/wallet_cli/mod.rs | 11 ++- .../transaction_builder/error.rs | 2 + .../transaction_builder/transition.rs | 24 +++++++ sdk/src/wallet/mod.rs | 2 +- .../high_level/account_block_issuer_keys.rs | 69 +++++++++---------- .../transaction/high_level/staking/begin.rs | 8 +++ .../transaction/high_level/staking/end.rs | 8 +++ .../transaction/high_level/staking/extend.rs | 8 +++ 8 files changed, 92 insertions(+), 40 deletions(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 37975cb499..3849a93bbd 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -200,7 +200,7 @@ pub enum WalletCommand { AddBlockIssuerKey { /// The account to which the key should be added. account_id: AccountId, - /// The hex-encoded key to add. + /// The hex-encoded public key to add. // TODO: Use the actual type somehow? issuer_key: String, }, @@ -941,7 +941,13 @@ pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issue keys_to_remove: vec![], }; - wallet.modify_account_output_block_issuer_keys(params, None).await?; + let transaction = wallet.modify_account_output_block_issuer_keys(params, None).await?; + + println_log_info!( + "Block issuer key adding transaction sent:\n{:?}\n{:?}", + transaction.transaction_id, + transaction.block_id + ); Ok(()) } @@ -1603,6 +1609,7 @@ pub async fn prompt_internal( } WalletCommand::ImplicitAccounts => implicit_accounts_command(wallet).await, WalletCommand::AddBlockIssuerKey { account_id, issuer_key } => { + ensure_password(wallet).await?; add_block_issuer_key(wallet, &account_id, &issuer_key).await } WalletCommand::MeltNativeToken { token_id, amount } => { diff --git a/sdk/src/client/api/block_builder/transaction_builder/error.rs b/sdk/src/client/api/block_builder/transaction_builder/error.rs index 8c3f50e910..22f76bd746 100644 --- a/sdk/src/client/api/block_builder/transaction_builder/error.rs +++ b/sdk/src/client/api/block_builder/transaction_builder/error.rs @@ -82,6 +82,8 @@ pub enum TransactionBuilderError { NoAvailableInputsProvided, #[error("account {0} is not staking")] NotStaking(AccountId), + #[error("account {0} has no block issuer feature")] + MissingBlockIssuerFeature(AccountId), /// Required input is not available. #[error("required input {0} is not available")] RequiredInputIsNotAvailable(OutputId), diff --git a/sdk/src/client/api/block_builder/transaction_builder/transition.rs b/sdk/src/client/api/block_builder/transaction_builder/transition.rs index 8137dabb62..8889001432 100644 --- a/sdk/src/client/api/block_builder/transaction_builder/transition.rs +++ b/sdk/src/client/api/block_builder/transaction_builder/transition.rs @@ -140,6 +140,24 @@ impl TransactionBuilder { } features.retain(|f| !f.is_staking()); } + AccountChange::ModifyBlockIssuerKeys { + keys_to_add, + keys_to_remove, + } => { + if let Some(feature) = features.iter_mut().find(|f| f.is_block_issuer()) { + let block_issuer_feature = feature.as_block_issuer(); + let updated_keys = block_issuer_feature + .block_issuer_keys() + .iter() + .filter(|k| !keys_to_remove.contains(k)) + .chain(keys_to_add) + .cloned() + .collect::>(); + *feature = BlockIssuerFeature::new(block_issuer_feature.expiry_slot(), updated_keys)?.into(); + } else { + return Err(TransactionBuilderError::MissingBlockIssuerFeature(account_id)); + } + } } } @@ -308,6 +326,12 @@ pub enum AccountChange { additional_epochs: u32, }, EndStaking, + ModifyBlockIssuerKeys { + /// The keys that will be added. + keys_to_add: Vec, + /// The keys that will be removed. + keys_to_remove: Vec, + }, } /// A type to specify intended transitions. diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 6523c5d50b..746f18c39c 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -51,8 +51,8 @@ pub use self::{ }, transaction::{ high_level::{ - create_account::CreateAccountParams, account_block_issuer_keys::ModifyAccountBlockIssuerKey, + create_account::CreateAccountParams, delegation::create::{ CreateDelegationParams, CreateDelegationTransaction, PreparedCreateDelegationTransaction, }, diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs index 21652221b9..5fbb62b50e 100644 --- a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -1,14 +1,20 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use alloc::collections::BTreeSet; + use serde::{Deserialize, Serialize}; use crate::{ - client::{api::PreparedTransactionData, secret::SecretManage, ClientError}, - types::block::output::{ - feature::{BlockIssuerFeature, BlockIssuerKey}, - AccountId, AccountOutput, AccountOutputBuilder, + client::{ + api::{ + transaction_builder::{transition::AccountChange, Transitions}, + PreparedTransactionData, + }, + secret::SecretManage, + ClientError, }, + types::block::output::{feature::BlockIssuerKey, AccountId}, wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet, WalletError}, }; @@ -48,43 +54,32 @@ where options: impl Into> + Send, ) -> Result { log::debug!("[TRANSACTION] prepare_modify_account_output_block_issuer_keys"); - let storage_score_params = self.client().get_storage_score_parameters().await?; - - let (_, output_data) = self - .get_account_output(params.account) - .await - .ok_or(WalletError::AccountNotFound)?; - let previous_account: &AccountOutput = output_data.output.as_account(); - - if !previous_account.is_block_issuer() { - return Err(WalletError::InvalidParameter( - "block issuer keys can only be modified on an account with an existing block issuer feature", - )); - } + let change = AccountChange::ModifyBlockIssuerKeys { + keys_to_add: params.keys_to_add, + keys_to_remove: params.keys_to_remove, + }; - let previous_block_issuer_feature = previous_account - .features() - .block_issuer() - .expect("we should not support adding a new block issuer feature in this method for now"); - let mut block_issuer_keys = previous_block_issuer_feature.block_issuer_keys().to_vec(); + let account_id = params.account; - block_issuer_keys.extend(params.keys_to_add); - params.keys_to_remove.iter().for_each(|key_to_remove| { - if let Ok(index) = block_issuer_keys.binary_search(key_to_remove) { - block_issuer_keys.remove(index); + let mut options = options.into(); + if let Some(options) = options.as_mut() { + if let Some(transitions) = options.transitions.take() { + options.transitions = Some(transitions.add_account(account_id, change)); } - }); - - let updated_block_issuer_feature = - BlockIssuerFeature::new(previous_block_issuer_feature.expiry_slot(), block_issuer_keys)?; - - let account_output_builder = AccountOutputBuilder::from(previous_account) - .with_amount_or_minimum(previous_account.amount(), storage_score_params) - .replace_feature(updated_block_issuer_feature); - - let outputs = [account_output_builder.finish_output()?]; + } else { + options.replace(TransactionOptions { + transitions: Some(Transitions::new().add_account(account_id, change)), + required_inputs: BTreeSet::from([self + .get_account_output(account_id) + .await + .ok_or(WalletError::AccountNotFound)? + .1 + .output_id]), + ..Default::default() + }); + } - self.prepare_send_outputs(outputs, options).await + self.prepare_send_outputs(None, options).await } } diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs index e3d04154e0..96ad085c89 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs @@ -1,6 +1,8 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use alloc::collections::BTreeSet; + use serde::{Deserialize, Serialize}; use crate::{ @@ -72,6 +74,12 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(params.account_id, change)), + required_inputs: BTreeSet::from([self + .get_account_output(params.account_id) + .await + .ok_or(WalletError::AccountNotFound)? + .1 + .output_id]), ..Default::default() }); } diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs index 600fd98da0..db9a30c292 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs @@ -1,6 +1,8 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use alloc::collections::BTreeSet; + use crate::{ client::{ api::{ @@ -47,6 +49,12 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(account_id, AccountChange::EndStaking)), + required_inputs: BTreeSet::from([self + .get_account_output(account_id) + .await + .ok_or(WalletError::AccountNotFound)? + .1 + .output_id]), ..Default::default() }); } diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs index 0b1a75aff1..6a2bdd15c5 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs @@ -1,6 +1,8 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use alloc::collections::BTreeSet; + use crate::{ client::{ api::{ @@ -53,6 +55,12 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(account_id, change)), + required_inputs: BTreeSet::from([self + .get_account_output(account_id) + .await + .ok_or(WalletError::AccountNotFound)? + .1 + .output_id]), ..Default::default() }); } From ad34845b0d005d7c77013d02ddc028ba1edc2f64 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 10:34:30 +0200 Subject: [PATCH 03/11] Add remove block issuer key command --- cli/src/wallet_cli/mod.rs | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 3849a93bbd..1de2f71336 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -202,7 +202,14 @@ pub enum WalletCommand { account_id: AccountId, /// The hex-encoded public key to add. // TODO: Use the actual type somehow? - issuer_key: String, + block_issuer_key: String, + }, + RemoveBlockIssuerKey { + /// The account from which the key should be removed. + account_id: AccountId, + /// The hex-encoded public key to remove. + // TODO: Use the actual type somehow? + block_issuer_key: String, }, /// Mint additional native tokens. MintNativeToken { @@ -952,6 +959,26 @@ pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issue Ok(()) } +// `remove-block-issuer-key` command +pub async fn remove_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { + let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; + let params = ModifyAccountBlockIssuerKey { + account: account_id.clone(), + keys_to_add: vec![], + keys_to_remove: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], + }; + + let transaction = wallet.modify_account_output_block_issuer_keys(params, None).await?; + + println_log_info!( + "Block issuer key adding transaction sent:\n{:?}\n{:?}", + transaction.transaction_id, + transaction.block_id + ); + + Ok(()) +} + // `melt-native-token` command pub async fn melt_native_token_command(wallet: &Wallet, token_id: TokenId, amount: U256) -> Result<(), Error> { let transaction = wallet.melt_native_token(token_id, amount, None).await?; @@ -1608,9 +1635,19 @@ pub async fn prompt_internal( implicit_account_transition_command(wallet, output_id).await } WalletCommand::ImplicitAccounts => implicit_accounts_command(wallet).await, - WalletCommand::AddBlockIssuerKey { account_id, issuer_key } => { + WalletCommand::AddBlockIssuerKey { + account_id, + block_issuer_key, + } => { + ensure_password(wallet).await?; + add_block_issuer_key(wallet, &account_id, &block_issuer_key).await + } + WalletCommand::RemoveBlockIssuerKey { + account_id, + block_issuer_key, + } => { ensure_password(wallet).await?; - add_block_issuer_key(wallet, &account_id, &issuer_key).await + remove_block_issuer_key(wallet, &account_id, &block_issuer_key).await } WalletCommand::MeltNativeToken { token_id, amount } => { ensure_password(wallet).await?; From 3ea2afa2e7b3d319f5d67fd3d44661b974b6411d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 10:42:55 +0200 Subject: [PATCH 04/11] Fix incorrect info message --- cli/src/wallet_cli/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 1de2f71336..e3734aa1e6 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -971,7 +971,7 @@ pub async fn remove_block_issuer_key(wallet: &Wallet, account_id: &AccountId, is let transaction = wallet.modify_account_output_block_issuer_keys(params, None).await?; println_log_info!( - "Block issuer key adding transaction sent:\n{:?}\n{:?}", + "Block issuer key removing transaction sent:\n{:?}\n{:?}", transaction.transaction_id, transaction.block_id ); From 97f5bff422f960a44eba86125b5aa5ba7b1abc27 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 11:45:55 +0200 Subject: [PATCH 05/11] Add missing comment on enum variant --- cli/src/wallet_cli/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index e3734aa1e6..c1657511f1 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -204,6 +204,7 @@ pub enum WalletCommand { // TODO: Use the actual type somehow? block_issuer_key: String, }, + /// Removes a block issuer key from an account. RemoveBlockIssuerKey { /// The account from which the key should be removed. account_id: AccountId, From da9028b761f203940c6e3ff225c54586db56d77d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 13:31:52 +0200 Subject: [PATCH 06/11] Add missing "for" in doc comment --- .../transaction/high_level/account_block_issuer_keys.rs | 2 +- .../wallet/operations/transaction/high_level/create_account.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs index 5fbb62b50e..e86d1f15fe 100644 --- a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -18,7 +18,7 @@ use crate::{ wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet, WalletError}, }; -/// Params `modify_account_block_issuer_key()` +/// Params for `modify_account_block_issuer_key()` #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModifyAccountBlockIssuerKey { diff --git a/sdk/src/wallet/operations/transaction/high_level/create_account.rs b/sdk/src/wallet/operations/transaction/high_level/create_account.rs index fd9d167e72..372035a376 100644 --- a/sdk/src/wallet/operations/transaction/high_level/create_account.rs +++ b/sdk/src/wallet/operations/transaction/high_level/create_account.rs @@ -18,7 +18,7 @@ use crate::{ }, }; -/// Params `create_account_output()` +/// Params for `create_account_output()` #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreateAccountParams { From ba45c7197a699591fd75cd61640a92117585a34d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 26 Apr 2024 13:33:18 +0200 Subject: [PATCH 07/11] Rename `account` -> `account_id` --- cli/src/wallet_cli/mod.rs | 4 ++-- .../transaction/high_level/account_block_issuer_keys.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index c1657511f1..eef3e9a93d 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -944,7 +944,7 @@ pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> { pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; let params = ModifyAccountBlockIssuerKey { - account: account_id.clone(), + account_id: account_id.clone(), keys_to_add: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], keys_to_remove: vec![], }; @@ -964,7 +964,7 @@ pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issue pub async fn remove_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; let params = ModifyAccountBlockIssuerKey { - account: account_id.clone(), + account_id: account_id.clone(), keys_to_add: vec![], keys_to_remove: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], }; diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs index e86d1f15fe..f1747011f1 100644 --- a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -22,7 +22,7 @@ use crate::{ #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModifyAccountBlockIssuerKey { - pub account: AccountId, + pub account_id: AccountId, /// The keys that will be added. pub keys_to_add: Vec, /// The keys that will be removed. @@ -60,7 +60,7 @@ where keys_to_remove: params.keys_to_remove, }; - let account_id = params.account; + let account_id = params.account_id; let mut options = options.into(); if let Some(options) = options.as_mut() { From 3e0bcc084e810de913590155c42d9ae246985734 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 29 Apr 2024 09:57:22 +0200 Subject: [PATCH 08/11] Refactor account transition requirement Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- .../api/block_builder/transaction_builder/mod.rs | 12 +++++++++++- .../high_level/account_block_issuer_keys.rs | 8 -------- .../operations/transaction/high_level/staking/end.rs | 8 -------- .../transaction/high_level/staking/extend.rs | 8 -------- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/sdk/src/client/api/block_builder/transaction_builder/mod.rs b/sdk/src/client/api/block_builder/transaction_builder/mod.rs index 3e538a0960..78d32a3d13 100644 --- a/sdk/src/client/api/block_builder/transaction_builder/mod.rs +++ b/sdk/src/client/api/block_builder/transaction_builder/mod.rs @@ -321,6 +321,13 @@ impl TransactionBuilder { // Gets requirements from burn. self.burn_requirements()?; + // Add requirements from transitions. + if let Some(transitions) = &self.transitions { + for account_id in transitions.accounts().keys() { + self.requirements.push(Requirement::Account(*account_id)); + } + } + Ok(()) } @@ -331,7 +338,10 @@ impl TransactionBuilder { // If burn or mana allotments are provided, outputs will be added later, in the other cases it will just // create remainder outputs. if !self.provided_outputs.is_empty() - || (self.burn.is_none() && self.mana_allotments.is_empty() && self.required_inputs.is_empty()) + || (self.burn.is_none() + && self.mana_allotments.is_empty() + && self.required_inputs.is_empty() + && self.transitions.is_none()) { return Err(TransactionBuilderError::InvalidOutputCount(self.provided_outputs.len())); } diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs index f1747011f1..2dba91426f 100644 --- a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -1,8 +1,6 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::collections::BTreeSet; - use serde::{Deserialize, Serialize}; use crate::{ @@ -70,12 +68,6 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(account_id, change)), - required_inputs: BTreeSet::from([self - .get_account_output(account_id) - .await - .ok_or(WalletError::AccountNotFound)? - .1 - .output_id]), ..Default::default() }); } diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs index db9a30c292..600fd98da0 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs @@ -1,8 +1,6 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::collections::BTreeSet; - use crate::{ client::{ api::{ @@ -49,12 +47,6 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(account_id, AccountChange::EndStaking)), - required_inputs: BTreeSet::from([self - .get_account_output(account_id) - .await - .ok_or(WalletError::AccountNotFound)? - .1 - .output_id]), ..Default::default() }); } diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs index 6a2bdd15c5..0b1a75aff1 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs @@ -1,8 +1,6 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::collections::BTreeSet; - use crate::{ client::{ api::{ @@ -55,12 +53,6 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(account_id, change)), - required_inputs: BTreeSet::from([self - .get_account_output(account_id) - .await - .ok_or(WalletError::AccountNotFound)? - .1 - .output_id]), ..Default::default() }); } From 7afade3e516a1418d82ab42f2abae3ebf85dd86d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 29 Apr 2024 10:52:49 +0200 Subject: [PATCH 09/11] Update sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- .../transaction/high_level/account_block_issuer_keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs index 2dba91426f..e36eaa4bb7 100644 --- a/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs +++ b/sdk/src/wallet/operations/transaction/high_level/account_block_issuer_keys.rs @@ -16,7 +16,7 @@ use crate::{ wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet, WalletError}, }; -/// Params for `modify_account_block_issuer_key()` +/// Params for `modify_account_output_block_issuer_keys()` #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModifyAccountBlockIssuerKey { From 2a705b3fbf009975704fa73895c0c2c251b7fd01 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 29 Apr 2024 11:22:16 +0200 Subject: [PATCH 10/11] Avoid clone of account_id --- cli/src/wallet_cli/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index eef3e9a93d..16e7fbadd1 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -941,10 +941,10 @@ pub async fn implicit_accounts_command(wallet: &Wallet) -> Result<(), Error> { } // `add-block-issuer-key` command -pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { +pub async fn add_block_issuer_key(wallet: &Wallet, account_id: AccountId, issuer_key: &str) -> Result<(), Error> { let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; let params = ModifyAccountBlockIssuerKey { - account_id: account_id.clone(), + account_id, keys_to_add: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], keys_to_remove: vec![], }; @@ -961,10 +961,10 @@ pub async fn add_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issue } // `remove-block-issuer-key` command -pub async fn remove_block_issuer_key(wallet: &Wallet, account_id: &AccountId, issuer_key: &str) -> Result<(), Error> { +pub async fn remove_block_issuer_key(wallet: &Wallet, account_id: AccountId, issuer_key: &str) -> Result<(), Error> { let issuer_key: [u8; Ed25519PublicKeyHashBlockIssuerKey::LENGTH] = prefix_hex::decode(issuer_key)?; let params = ModifyAccountBlockIssuerKey { - account_id: account_id.clone(), + account_id, keys_to_add: vec![], keys_to_remove: vec![Ed25519PublicKeyHashBlockIssuerKey::new(issuer_key).into()], }; @@ -1641,14 +1641,14 @@ pub async fn prompt_internal( block_issuer_key, } => { ensure_password(wallet).await?; - add_block_issuer_key(wallet, &account_id, &block_issuer_key).await + add_block_issuer_key(wallet, account_id, &block_issuer_key).await } WalletCommand::RemoveBlockIssuerKey { account_id, block_issuer_key, } => { ensure_password(wallet).await?; - remove_block_issuer_key(wallet, &account_id, &block_issuer_key).await + remove_block_issuer_key(wallet, account_id, &block_issuer_key).await } WalletCommand::MeltNativeToken { token_id, amount } => { ensure_password(wallet).await?; From bb6b8fc1b3058119db967903b736369661eb3f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thoralf=20M=C3=BCller?= Date: Mon, 29 Apr 2024 12:24:58 +0200 Subject: [PATCH 11/11] Remove required_inputs from begin staking as it's handled by the transition --- .../operations/transaction/high_level/staking/begin.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs index 96ad085c89..e3d04154e0 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/begin.rs @@ -1,8 +1,6 @@ // Copyright 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::collections::BTreeSet; - use serde::{Deserialize, Serialize}; use crate::{ @@ -74,12 +72,6 @@ where } else { options.replace(TransactionOptions { transitions: Some(Transitions::new().add_account(params.account_id, change)), - required_inputs: BTreeSet::from([self - .get_account_output(params.account_id) - .await - .ok_or(WalletError::AccountNotFound)? - .1 - .output_id]), ..Default::default() }); }