diff --git a/.changelog/unreleased/improvements/3154-minor-cli-fixe4s.md b/.changelog/unreleased/improvements/3154-minor-cli-fixe4s.md new file mode 100644 index 0000000000..cf8103f813 --- /dev/null +++ b/.changelog/unreleased/improvements/3154-minor-cli-fixe4s.md @@ -0,0 +1,2 @@ +- Client improvements related to valid thresholds for mutlisig accounts and PGF + steward submissions. ([\#3154](https://github.com/anoma/namada/pull/3154)) \ No newline at end of file diff --git a/crates/governance/src/pgf/cli/steward.rs b/crates/governance/src/pgf/cli/steward.rs index c6e0196187..17cf251857 100644 --- a/crates/governance/src/pgf/cli/steward.rs +++ b/crates/governance/src/pgf/cli/steward.rs @@ -29,6 +29,9 @@ impl Commission { let mut sum = Dec::zero(); for percentage in self.reward_distribution.values() { + if *percentage < Dec::zero() { + return false; + } sum = sum.add(percentage); if sum > Dec::one() { return false; diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs index c2f87b7651..39734e7349 100644 --- a/crates/sdk/src/error.rs +++ b/crates/sdk/src/error.rs @@ -287,6 +287,9 @@ pub enum TxSubmitError { /// Account threshold is not set #[error("Account threshold must be set.")] MissingAccountThreshold, + /// Account threshold is not set + #[error("Account threshold is invalid.")] + InvalidAccountThreshold, /// Not enough signature #[error("Account threshold is {0} but the valid signatures are {1}.")] MissingSigningKeys(u8, u8), diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index 66514ca6cb..f6040947f2 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -61,6 +61,7 @@ use namada_tx::data::pgf::UpdateStewardCommission; use namada_tx::data::pos::{BecomeValidator, ConsensusKeyChange}; use namada_tx::data::{pos, ResultCode, TxResult}; pub use namada_tx::{Authorization, *}; +use num_traits::Zero; use rand_core::{OsRng, RngCore}; use crate::args::{self, InputAmount}; @@ -3150,7 +3151,27 @@ pub async fn build_init_account( let vp_code_hash = query_wasm_code_hash_buf(context, vp_code_path).await?; let threshold = match threshold { - Some(threshold) => *threshold, + Some(threshold) => { + let threshold = *threshold; + if (threshold > 0 && public_keys.len() as u8 >= threshold) + || tx_args.force + { + threshold + } else { + edisplay_line!( + context.io(), + "Invalid account threshold: either the provided threshold \ + is zero or the number of public keys is less than the \ + threshold." + ); + if !tx_args.force { + return Err(Error::from( + TxSubmitError::InvalidAccountThreshold, + )); + } + threshold + } + } None => { if public_keys.len() == 1 { 1u8 @@ -3218,18 +3239,51 @@ pub async fn build_update_account( ) .await?; - let addr = if let Some(account) = + let account = if let Some(account) = rpc::get_account_info(context.client(), addr).await? { - account.address - } else if tx_args.force { - addr.clone() + account } else { return Err(Error::from(TxSubmitError::LocationDoesNotExist( addr.clone(), ))); }; + let threshold = if let Some(threshold) = threshold { + let threshold = *threshold; + + let invalid_threshold = threshold.is_zero(); + let invalid_too_few_pks: bool = (public_keys.is_empty() + && public_keys.len() < threshold as usize) + || (account.get_all_public_keys().len() < threshold as usize); + + if invalid_threshold || invalid_too_few_pks { + edisplay_line!( + context.io(), + "Invalid account threshold: either the provided threshold is \ + zero or the number of public keys is less than the threshold." + ); + if !tx_args.force { + return Err(Error::from( + TxSubmitError::InvalidAccountThreshold, + )); + } + } + + Some(threshold) + } else { + let invalid_too_few_pks = (!public_keys.is_empty() + && public_keys.len() < account.threshold as usize) + || (account.get_all_public_keys().len() + < account.threshold as usize); + + if invalid_too_few_pks { + return Err(Error::from(TxSubmitError::InvalidAccountThreshold)); + } + + None + }; + let vp_code_hash = match vp_code_path { Some(code_path) => { let vp_hash = query_wasm_code_hash_buf(context, code_path).await?; @@ -3253,10 +3307,10 @@ pub async fn build_update_account( ); let data = UpdateAccount { - addr, + addr: account.address, vp_code_hash: extra_section_hash, public_keys: public_keys.clone(), - threshold: *threshold, + threshold, }; let add_code_hash = |tx: &mut Tx, data: &mut UpdateAccount| {