Skip to content

Commit

Permalink
Add body id to treasury
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidK committed Sep 27, 2024
1 parent 710e74d commit 3e2a80c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 19 deletions.
35 changes: 23 additions & 12 deletions substrate/frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ pub type ProposalIndex = u32;
/// A spending proposal.
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)]
pub struct Proposal<AccountId, Balance> {
pub struct Proposal<BodyId, AccountId, Balance> {
/// The treasury body proposal is for
body: BodyId,
/// The account proposing it.
proposer: AccountId,
/// The (total) amount that should be paid if the proposal is accepted.
Expand Down Expand Up @@ -204,6 +206,9 @@ pub mod pallet {

#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// Different bodies in treasury
type BodyId: Copy + Clone + Eq + Ord + Default + codec::FullCodec + MaxEncodedLen + TypeInfo;

/// The staking balance.
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

Expand Down Expand Up @@ -244,7 +249,10 @@ pub mod pallet {
/// The origin required for approving spends from the treasury outside of the proposal
/// process. The `Success` value is the maximum amount in a native asset that this origin
/// is allowed to spend at a time.
type SpendOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = BalanceOf<Self, I>>;
type SpendOrigin: EnsureOrigin<
Self::RuntimeOrigin,
Success = (BalanceOf<Self, I>, Self::BodyId),
>;

/// Type parameter representing the asset kinds to be spent from the treasury.
type AssetKind: Parameter + MaxEncodedLen;
Expand Down Expand Up @@ -286,7 +294,7 @@ pub mod pallet {
_,
Twox64Concat,
ProposalIndex,
Proposal<T::AccountId, BalanceOf<T, I>>,
Proposal<T::BodyId, T::AccountId, BalanceOf<T, I>>,
OptionQuery,
>;

Expand Down Expand Up @@ -444,8 +452,8 @@ pub mod pallet {
}

#[derive(Default)]
struct SpendContext<Balance> {
spend_in_context: BTreeMap<Balance, Balance>,
struct SpendContext<BodyId, Balance> {
spend_in_context: BTreeMap<(BodyId, Balance), Balance>,
}

#[pallet::call]
Expand Down Expand Up @@ -474,17 +482,17 @@ pub mod pallet {
#[pallet::compact] amount: BalanceOf<T, I>,
beneficiary: AccountIdLookupOf<T>,
) -> DispatchResult {
let max_amount = T::SpendOrigin::ensure_origin(origin)?;
let (max_amount, body) = T::SpendOrigin::ensure_origin(origin)?;
ensure!(amount <= max_amount, Error::<T, I>::InsufficientPermission);

with_context::<SpendContext<BalanceOf<T, I>>, _>(|v| {
with_context::<SpendContext<T::BodyId, BalanceOf<T, I>>, _>(|v| {
let context = v.or_default();

// We group based on `max_amount`, to distinguish between different kind of
// origins. (assumes that all origins have different `max_amount`)
//
// Worst case is that we reject some "valid" request.
let spend = context.spend_in_context.entry(max_amount).or_default();
let spend = context.spend_in_context.entry((body, max_amount)).or_default();

// Ensure that we don't overflow nor use more than `max_amount`
if spend.checked_add(&amount).map(|s| s > max_amount).unwrap_or(true) {
Expand All @@ -502,6 +510,7 @@ pub mod pallet {
Approvals::<T, I>::try_append(proposal_index)
.map_err(|_| Error::<T, I>::TooManyApprovals)?;
let proposal = Proposal {
body,
proposer: beneficiary.clone(),
value: amount,
beneficiary: beneficiary.clone(),
Expand Down Expand Up @@ -590,7 +599,7 @@ pub mod pallet {
beneficiary: Box<BeneficiaryLookupOf<T, I>>,
valid_from: Option<BlockNumberFor<T>>,
) -> DispatchResult {
let max_amount = T::SpendOrigin::ensure_origin(origin)?;
let (max_amount, body) = T::SpendOrigin::ensure_origin(origin)?;
let beneficiary = T::BeneficiaryLookup::lookup(*beneficiary)?;

let now = frame_system::Pallet::<T>::block_number();
Expand All @@ -604,13 +613,13 @@ pub mod pallet {

ensure!(native_amount <= max_amount, Error::<T, I>::InsufficientPermission);

with_context::<SpendContext<BalanceOf<T, I>>, _>(|v| {
with_context::<SpendContext<T::BodyId, BalanceOf<T, I>>, _>(|v| {
let context = v.or_default();
// We group based on `max_amount`, to distinguish between different kind of
// origins. (assumes that all origins have different `max_amount`)
//
// Worst case is that we reject some "valid" request.
let spend = context.spend_in_context.entry(max_amount).or_default();
let spend = context.spend_in_context.entry((body, max_amount)).or_default();

// Ensure that we don't overflow nor use more than `max_amount`
if spend.checked_add(&native_amount).map(|s| s > max_amount).unwrap_or(true) {
Expand Down Expand Up @@ -797,7 +806,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}

/// Public function to proposals storage.
pub fn proposals(index: ProposalIndex) -> Option<Proposal<T::AccountId, BalanceOf<T, I>>> {
pub fn proposals(
index: ProposalIndex,
) -> Option<Proposal<T::BodyId, T::AccountId, BalanceOf<T, I>>> {
Proposals::<T, I>::get(index)
}

Expand Down
15 changes: 8 additions & 7 deletions substrate/frame/treasury/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,15 @@ parameter_types! {

pub struct TestSpendOrigin;
impl frame_support::traits::EnsureOrigin<RuntimeOrigin> for TestSpendOrigin {
type Success = u64;
type Success = (u64, ());
fn try_origin(o: RuntimeOrigin) -> Result<Self::Success, RuntimeOrigin> {
Result::<frame_system::RawOrigin<_>, RuntimeOrigin>::from(o).and_then(|o| match o {
frame_system::RawOrigin::Root => Ok(u64::max_value()),
frame_system::RawOrigin::Signed(10) => Ok(5),
frame_system::RawOrigin::Signed(11) => Ok(10),
frame_system::RawOrigin::Signed(12) => Ok(20),
frame_system::RawOrigin::Signed(13) => Ok(50),
frame_system::RawOrigin::Signed(14) => Ok(500),
frame_system::RawOrigin::Root => Ok((u64::max_value(), ())),
frame_system::RawOrigin::Signed(10) => Ok((5, ())),
frame_system::RawOrigin::Signed(11) => Ok((10, ())),
frame_system::RawOrigin::Signed(12) => Ok((20, ())),
frame_system::RawOrigin::Signed(13) => Ok((50, ())),
frame_system::RawOrigin::Signed(14) => Ok((500, ())),
r => Err(RuntimeOrigin::from(r)),
})
}
Expand All @@ -170,6 +170,7 @@ impl<N: Get<u64>> ConversionFromAssetBalance<u64, u32, u64> for MulBy<N> {
}

impl Config for Test {
type BodyId = ();
type PalletId = TreasuryPalletId;
type Currency = pallet_balances::Pallet<Test>;
type RejectOrigin = frame_system::EnsureRoot<u128>;
Expand Down

0 comments on commit 3e2a80c

Please sign in to comment.