mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 03:21:06 +00:00
pallet-treasury: Ensure we respect max_amount for spend across batch calls (#13468)
* `pallet-treasury`: Ensure we respect `max_amount` for spend across batch calls When calling `spend` the origin defines the `max_amount` of tokens it is allowed to spend. The problem is that someone can send a `batch(spend, spend)` to circumvent this restriction as we don't check across different calls that the `max_amount` is respected. This pull request fixes this behavior by introducing a so-called dispatch context. This dispatch context is created once per outer most `dispatch` call. For more information see the docs in this pr. The treasury then uses this dispatch context to attach information about already spent funds per `max_amount` (we assume that each origin has a different `max_amount` configured). So, a `batch(spend, spend)` is now checked to stay inside the allowed spending bounds. Fixes: https://github.com/paritytech/substrate/issues/13167 * Import `Box` for wasm * FMT
This commit is contained in:
@@ -22,11 +22,11 @@
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{BadOrigin, BlakeTwo256, IdentityLookup},
|
||||
traits::{BadOrigin, BlakeTwo256, Dispatchable, IdentityLookup},
|
||||
};
|
||||
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok,
|
||||
assert_err_ignore_postinfo, assert_noop, assert_ok,
|
||||
pallet_prelude::GenesisBuild,
|
||||
parameter_types,
|
||||
traits::{ConstU32, ConstU64, OnInitialize},
|
||||
@@ -38,6 +38,8 @@ use crate as treasury;
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
type UtilityCall = pallet_utility::Call<Test>;
|
||||
type TreasuryCall = crate::Call<Test>;
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Test where
|
||||
@@ -48,6 +50,7 @@ frame_support::construct_runtime!(
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Treasury: treasury::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Utility: pallet_utility,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -88,6 +91,14 @@ impl pallet_balances::Config for Test {
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
impl pallet_utility::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type PalletsOrigin = OriginCaller;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ProposalBond: Permill = Permill::from_percent(5);
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
@@ -470,3 +481,28 @@ fn remove_already_removed_approval_fails() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spending_in_batch_respects_max_total() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Respect the `max_total` for the given origin.
|
||||
assert_ok!(RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 101 })
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)));
|
||||
|
||||
assert_err_ignore_postinfo!(
|
||||
RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 4, beneficiary: 101 })
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)),
|
||||
Error::<Test, _>::InsufficientPermission
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user