From 13240af738f5cade003691724f45bc2da59cfd9e Mon Sep 17 00:00:00 2001 From: Vladimir Guguiev <1524432+vovacodes@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:04:11 +0300 Subject: [PATCH] feat(spending_limit): verify members are non-empty and contain no duplicates --- .../instructions/config_transaction_execute.rs | 16 ++++++++++++---- programs/multisig/src/state/spending_limit.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/programs/multisig/src/instructions/config_transaction_execute.rs b/programs/multisig/src/instructions/config_transaction_execute.rs index d509d110..ad971124 100644 --- a/programs/multisig/src/instructions/config_transaction_execute.rs +++ b/programs/multisig/src/instructions/config_transaction_execute.rs @@ -216,8 +216,12 @@ impl<'info> ConfigTransactionExecute<'info> { ], )?; + let mut members = members.to_vec(); + // Make sure members are sorted. + members.sort(); + // Serialize the SpendingLimit data into the account info. - SpendingLimit { + let spending_limit = SpendingLimit { multisig: multisig.key().to_owned(), create_key: create_key.to_owned(), vault_index: *vault_index, @@ -227,10 +231,14 @@ impl<'info> ConfigTransactionExecute<'info> { remaining_amount: *amount, last_reset: Clock::get()?.unix_timestamp, bump: spending_limit_bump, - members: members.to_vec(), + members, destinations: destinations.to_vec(), - } - .try_serialize(&mut &mut spending_limit_info.data.borrow_mut()[..])?; + }; + + spending_limit.invariant()?; + + spending_limit + .try_serialize(&mut &mut spending_limit_info.data.borrow_mut()[..])?; } ConfigAction::RemoveSpendingLimit { diff --git a/programs/multisig/src/state/spending_limit.rs b/programs/multisig/src/state/spending_limit.rs index b17e4de0..e56f806e 100644 --- a/programs/multisig/src/state/spending_limit.rs +++ b/programs/multisig/src/state/spending_limit.rs @@ -1,5 +1,7 @@ use anchor_lang::prelude::*; +use crate::errors::*; + #[account] pub struct SpendingLimit { /// The multisig this belongs to. @@ -62,6 +64,16 @@ impl SpendingLimit { 4 + // destinations vector length destinations_length * 32 // destinations } + + pub fn invariant(&self) -> Result<()> { + require!(!self.members.is_empty(), MultisigError::EmptyMembers); + + // There must be no duplicate members, we make sure members are sorted when creating a SpendingLimit. + let has_duplicates = self.members.windows(2).any(|win| win[0] == win[1]); + require!(!has_duplicates, MultisigError::DuplicateMember); + + Ok(()) + } } /// The reset period of the spending limit.