diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index af05b34967..dac8c0414a 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -601,6 +601,7 @@ impl pallet_treasury::Trait for Runtime { type ProposalBondMinimum = ProposalBondMinimum; type SpendPeriod = SpendPeriod; type Burn = Burn; + type BurnDestination = (); type WeightInfo = (); } diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index 684fe50437..dc54d72fc8 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -264,11 +264,12 @@ use frame_support::{decl_error, decl_module, decl_storage, decl_event, ensure, d use frame_support::weights::Weight; use frame_support::traits::{ Currency, ReservableCurrency, Randomness, Get, ChangeMembers, BalanceStatus, - ExistenceRequirement::AllowDeath, EnsureOrigin + ExistenceRequirement::AllowDeath, EnsureOrigin, OnUnbalanced, Imbalance }; use frame_system::{self as system, ensure_signed, ensure_root}; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; /// The module's configuration trait. pub trait Trait: system::Trait { @@ -1143,6 +1144,8 @@ decl_event! { NewMaxMembers(u32), /// Society is unfounded. Unfounded(AccountId), + /// Some funds were deposited into the society account. + Deposit(Balance), } } @@ -1665,3 +1668,14 @@ impl, I: Instance> Module { } } } + +impl OnUnbalanced> for Module { + fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { + let numeric_amount = amount.peek(); + + // Must resolve into existing but better to be safe. + let _ = T::Currency::resolve_creating(&Self::account_id(), amount); + + Self::deposit_event(RawEvent::Deposit(numeric_amount)); + } +} diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index ce5b7d0dea..cdb361336d 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -897,6 +897,14 @@ pub trait Currency { /// in the case of overflow. fn issue(amount: Self::Balance) -> Self::NegativeImbalance; + /// Produce a pair of imbalances that cancel each other out exactly. + /// + /// This is just the same as burning and issuing the same amount and has no effect on the + /// total issuance. + fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { + (Self::burn(amount.clone()), Self::issue(amount)) + } + /// The 'free' balance of a given account. /// /// This is the only balance that matters in terms of most operations on tokens. It alone diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 0b6f9cb7fc..05e4c3c9ef 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -184,6 +184,9 @@ pub trait Trait: frame_system::Trait { /// Percentage of spare funds (if any) that are burnt per spend period. type Burn: Get; + /// Handler for the unbalanced decrease when treasury funds are burned. + type BurnDestination: OnUnbalanced>; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -771,7 +774,10 @@ impl Module { // burn some proportion of the remaining budget if we run a surplus. let burn = (T::Burn::get() * budget_remaining).min(budget_remaining); budget_remaining -= burn; - imbalance.subsume(T::Currency::burn(burn)); + + let (debit, credit) = T::Currency::pair(burn); + imbalance.subsume(debit); + T::BurnDestination::on_unbalanced(credit); Self::deposit_event(RawEvent::Burnt(burn)) } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index 469c645643..59a41a263c 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -149,6 +149,7 @@ impl Trait for Test { type ProposalBondMinimum = ProposalBondMinimum; type SpendPeriod = SpendPeriod; type Burn = Burn; + type BurnDestination = (); // Just gets burned. type WeightInfo = (); } type System = frame_system::Module; diff --git a/substrate/primitives/arithmetic/src/per_things.rs b/substrate/primitives/arithmetic/src/per_things.rs index f809358446..cf53988b33 100644 --- a/substrate/primitives/arithmetic/src/per_things.rs +++ b/substrate/primitives/arithmetic/src/per_things.rs @@ -1170,6 +1170,51 @@ macro_rules! implement_per_thing { }; } +macro_rules! implement_per_thing_with_perthousand { + ( + $name:ident, + $test_mod:ident, + $pt_test_mod:ident, + [$($test_units:tt),+], + $max:tt, + $type:ty, + $upper_type:ty, + $title:expr $(,)? + ) => { + implement_per_thing! { + $name, $test_mod, [ $( $test_units ),+ ], $max, $type, $upper_type, $title, + } + impl $name { + /// Converts a percent into `Self`. Equal to `x / 1000`. + /// + /// This can be created at compile time. + pub const fn from_perthousand(x: $type) -> Self { + Self(([x, 1000][(x > 1000) as usize] as $upper_type * $max as $upper_type / 1000) as $type) + } + } + #[cfg(test)] + mod $pt_test_mod { + use super::$name; + use crate::traits::Zero; + + #[test] + fn from_perthousand_works() { + // some really basic stuff + assert_eq!($name::from_perthousand(00), $name::from_parts(Zero::zero())); + assert_eq!($name::from_perthousand(100), $name::from_parts($max / 10)); + assert_eq!($name::from_perthousand(1000), $name::from_parts($max)); + assert_eq!($name::from_perthousand(2000), $name::from_parts($max)); + } + + #[test] + #[allow(unused)] + fn const_fns_work() { + const C1: $name = $name::from_perthousand(500); + } + } + } +} + implement_per_thing!( Percent, test_per_cent, @@ -1179,36 +1224,40 @@ implement_per_thing!( u16, "_Percent_", ); -implement_per_thing!( +implement_per_thing_with_perthousand!( PerU16, test_peru16, + test_peru16_extra, [u32, u64, u128], 65535_u16, u16, u32, "_Parts per 65535_", ); -implement_per_thing!( +implement_per_thing_with_perthousand!( Permill, test_permill, + test_permill_extra, [u32, u64, u128], 1_000_000u32, u32, u64, "_Parts per Million_", ); -implement_per_thing!( +implement_per_thing_with_perthousand!( Perbill, test_perbill, + test_perbill_extra, [u32, u64, u128], 1_000_000_000u32, u32, u64, "_Parts per Billion_", ); -implement_per_thing!( +implement_per_thing_with_perthousand!( Perquintill, test_perquintill, + test_perquintill_extra, [u64, u128], 1_000_000_000_000_000_000u64, u64,