From e256877eb0380f856fd4c3b45060d1122b267724 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 13 Jul 2021 15:26:58 +0800 Subject: [PATCH] Migrate `pallet-treasury` to the new pallet attribute macro (#9197) * Migrate pallet-treasury to the new pallet attribute macro Signed-off-by: koushiro * Fix bounties/tips tests Signed-off-by: koushiro * fix Signed-off-by: koushiro * Update frame/treasury/src/lib.rs Co-authored-by: Guillaume Thiolliere * Update frame/treasury/src/lib.rs Co-authored-by: Guillaume Thiolliere * use `GenesisBuild` * fix imports Co-authored-by: thiolliere Co-authored-by: Shawn Tabrizi --- substrate/bin/node/executor/tests/basic.rs | 6 +- substrate/frame/bounties/src/benchmarking.rs | 2 +- substrate/frame/bounties/src/tests.rs | 12 +- substrate/frame/tips/src/lib.rs | 2 +- substrate/frame/tips/src/tests.rs | 6 +- substrate/frame/treasury/Cargo.toml | 10 +- substrate/frame/treasury/README.md | 8 +- substrate/frame/treasury/src/benchmarking.rs | 19 +- substrate/frame/treasury/src/lib.rs | 436 ++++++++++--------- substrate/frame/treasury/src/tests.rs | 18 +- 10 files changed, 278 insertions(+), 241 deletions(-) diff --git a/substrate/bin/node/executor/tests/basic.rs b/substrate/bin/node/executor/tests/basic.rs index af9843715f..4e17366795 100644 --- a/substrate/bin/node/executor/tests/basic.rs +++ b/substrate/bin/node/executor/tests/basic.rs @@ -363,7 +363,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), topics: vec![], }, EventRecord { @@ -417,7 +417,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), topics: vec![], }, EventRecord { @@ -440,7 +440,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), + event: Event::Treasury(pallet_treasury::Event::Deposit(fees * 8 / 10)), topics: vec![], }, EventRecord { diff --git a/substrate/frame/bounties/src/benchmarking.rs b/substrate/frame/bounties/src/benchmarking.rs index b07427db28..23542e6c31 100644 --- a/substrate/frame/bounties/src/benchmarking.rs +++ b/substrate/frame/bounties/src/benchmarking.rs @@ -27,7 +27,7 @@ use frame_benchmarking::{benchmarks, account, whitelisted_caller, impl_benchmark use frame_support::traits::OnInitialize; use crate::Module as Bounties; -use pallet_treasury::Module as Treasury; +use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 54973bf9b2..2e96d8271e 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -25,7 +25,7 @@ use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, parameter_types, weights::Weight, traits::OnInitialize, - PalletId + PalletId, pallet_prelude::GenesisBuild, }; use sp_core::H256; @@ -146,7 +146,7 @@ impl Config for Test { type WeightInfo = (); } -type TreasuryError = pallet_treasury::Error::; +type TreasuryError = pallet_treasury::Error::; pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -154,7 +154,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Total issuance will be 200 with treasury account initialized at ED. balances: vec![(0, 100), (1, 98), (2, 1)], }.assimilate_storage(&mut t).unwrap(); - pallet_treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); t.into() } @@ -268,7 +268,7 @@ fn reject_already_rejected_spend_proposal_fails() { fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { assert_noop!(Treasury::reject_proposal(Origin::root(), 0), - pallet_treasury::Error::::InvalidIndex); + pallet_treasury::Error::::InvalidIndex); }); } @@ -457,7 +457,7 @@ fn close_bounty_works() { assert_eq!(Balances::free_balance(0), 100 - deposit); assert_eq!(Bounties::bounties(0), None); - assert!(!pallet_treasury::Proposals::::contains_key(0)); + assert!(!pallet_treasury::Proposals::::contains_key(0)); assert_eq!(Bounties::bounty_descriptions(0), None); }); @@ -897,7 +897,7 @@ fn genesis_funding_works() { // Total issuance will be 200 with treasury account initialized with 100. balances: vec![(0, 100), (Treasury::account_id(), initial_funding)], }.assimilate_storage(&mut t).unwrap(); - pallet_treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); let mut t: sp_io::TestExternalities = t.into(); t.execute_with(|| { diff --git a/substrate/frame/tips/src/lib.rs b/substrate/frame/tips/src/lib.rs index b31468797c..e57f0d7b8d 100644 --- a/substrate/frame/tips/src/lib.rs +++ b/substrate/frame/tips/src/lib.rs @@ -501,7 +501,7 @@ impl Module { tips.sort_by_key(|i| i.1); let treasury = Self::account_id(); - let max_payout = pallet_treasury::Module::::pot(); + let max_payout = pallet_treasury::Pallet::::pot(); let mut payout = tips[tips.len() / 2].1.min(max_payout); if !tip.deposit.is_zero() { diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index cb58ba6aab..7cf4c31a64 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -25,7 +25,7 @@ use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, parameter_types, weights::Weight, traits::SortedMembers, - PalletId + PalletId, pallet_prelude::GenesisBuild, }; use sp_runtime::Permill; use sp_core::H256; @@ -169,7 +169,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Total issuance will be 200 with treasury account initialized at ED. balances: vec![(0, 100), (1, 98), (2, 1)], }.assimilate_storage(&mut t).unwrap(); - pallet_treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); t.into() } @@ -485,7 +485,7 @@ fn genesis_funding_works() { // Total issuance will be 200 with treasury account initialized with 100. balances: vec![(0, 100), (Treasury::account_id(), initial_funding)], }.assimilate_storage(&mut t).unwrap(); - pallet_treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&pallet_treasury::GenesisConfig, &mut t).unwrap(); let mut t: sp_io::TestExternalities = t.into(); t.execute_with(|| { diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 339ce19607..95c54dafe1 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -13,16 +13,18 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.101", features = ["derive"], optional = true } +impl-trait-for-tuples = "0.2.1" + sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../balances" } -impl-trait-for-tuples = "0.2.1" -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-io ={ version = "4.0.0-dev", path = "../../primitives/io" } @@ -32,8 +34,8 @@ sp-storage = { version = "4.0.0-dev", path = "../../primitives/storage" } [features] default = ["std"] std = [ - "serde", "codec/std", + "serde", "sp-std/std", "sp-runtime/std", "frame-support/std", diff --git a/substrate/frame/treasury/README.md b/substrate/frame/treasury/README.md index 4b061359fe..4945d79d14 100644 --- a/substrate/frame/treasury/README.md +++ b/substrate/frame/treasury/README.md @@ -1,11 +1,11 @@ -# Treasury Module +# Treasury Pallet -The Treasury module provides a "pot" of funds that can be managed by stakeholders in the system and +The Treasury pallet provides a "pot" of funds that can be managed by stakeholders in the system and a structure for making spending proposals from this pot. ## Overview -The Treasury Module itself provides the pot to store funds, and a means for stakeholders to propose, +The Treasury Pallet itself provides the pot to store funds, and a means for stakeholders to propose, approve, and deny expenditures. The chain will need to provide a method (e.g.inflation, fees) for collecting funds. @@ -19,7 +19,7 @@ and use the funds to pay developers. approved. - **Deposit:** Funds that a proposer must lock when making a proposal. The deposit will be returned or slashed if the proposal is approved or rejected respectively. -- **Pot:** Unspent funds accumulated by the treasury module. +- **Pot:** Unspent funds accumulated by the treasury pallet. ## Interface diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 64ecbebe0b..cc5db8ce94 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -19,18 +19,16 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; +use super::{*, Pallet as Treasury}; +use frame_benchmarking::{benchmarks_instance_pallet, account, impl_benchmark_test_suite}; +use frame_support::{traits::OnInitialize, ensure}; use frame_system::RawOrigin; -use frame_benchmarking::{benchmarks_instance, account, impl_benchmark_test_suite}; -use frame_support::traits::OnInitialize; - -use crate::Module as Treasury; const SEED: u32 = 0; // Create the pre-requisite information needed to create a treasury `propose_spend`. -fn setup_proposal, I: Instance>(u: u32) -> ( +fn setup_proposal, I: 'static>(u: u32) -> ( T::AccountId, BalanceOf, ::Source, @@ -44,7 +42,7 @@ fn setup_proposal, I: Instance>(u: u32) -> ( } // Create proposals that are approved for use in `on_initialize`. -fn create_approved_proposals, I: Instance>(n: u32) -> Result<(), &'static str> { +fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'static str> { for i in 0 .. n { let (caller, value, lookup) = setup_proposal::(i); Treasury::::propose_spend( @@ -52,21 +50,20 @@ fn create_approved_proposals, I: Instance>(n: u32) -> Result<(), &' value, lookup )?; - let proposal_id = >::get() - 1; + let proposal_id = >::get() - 1; Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; } ensure!(>::get().len() == n as usize, "Not all approved"); Ok(()) } -fn setup_pot_account, I: Instance>() { +fn setup_pot_account, I: 'static>() { let pot_account = Treasury::::account_id(); let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); let _ = T::Currency::make_free_balance_be(&pot_account, value); } -benchmarks_instance! { - +benchmarks_instance_pallet! { propose_spend { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); // Whitelist caller account from further DB operations. diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 6028f1fbe4..3951a553ad 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Treasury Module +//! # Treasury Pallet //! -//! The Treasury module provides a "pot" of funds that can be managed by stakeholders in the system +//! The Treasury pallet provides a "pot" of funds that can be managed by stakeholders in the system //! and a structure for making spending proposals from this pot. //! //! - [`Config`] @@ -25,7 +25,7 @@ //! //! ## Overview //! -//! The Treasury Module itself provides the pot to store funds, and a means for stakeholders to +//! The Treasury Pallet itself provides the pot to store funds, and a means for stakeholders to //! propose, approve, and deny expenditures. The chain will need to provide a method (e.g. //! inflation, fees) for collecting funds. //! @@ -40,7 +40,7 @@ //! approved. //! - **Deposit:** Funds that a proposer must lock when making a proposal. The deposit will be //! returned or slashed if the proposal is approved or rejected respectively. -//! - **Pot:** Unspent funds accumulated by the treasury module. +//! - **Pot:** Unspent funds accumulated by the treasury pallet. //! //! ## Interface //! @@ -53,89 +53,42 @@ //! //! ## GenesisConfig //! -//! The Treasury module depends on the [`GenesisConfig`]. +//! The Treasury pallet depends on the [`GenesisConfig`]. #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] mod tests; mod benchmarking; - pub mod weights; +use codec::{Encode, Decode}; + use sp_std::prelude::*; -use frame_support::{ - decl_module, decl_storage, decl_event, ensure, print, decl_error, - PalletId, BoundedVec, storage::TryAppendValue, -}; -use frame_support::traits::{ - Currency, Get, Imbalance, OnUnbalanced, ExistenceRequirement::KeepAlive, - ReservableCurrency, WithdrawReasons, -}; use sp_runtime::{ Permill, RuntimeDebug, traits::{ Zero, StaticLookup, AccountIdConversion, Saturating } }; -use frame_support::weights::{Weight, DispatchClass}; -use frame_support::traits::EnsureOrigin; -use codec::{Encode, Decode}; -use frame_system::ensure_signed; + +use frame_support::{print, PalletId}; +use frame_support::traits::{ + Currency, Get, Imbalance, OnUnbalanced, ExistenceRequirement::KeepAlive, + ReservableCurrency, WithdrawReasons +}; +use frame_support::weights::Weight; + pub use weights::WeightInfo; +pub use pallet::*; -pub type BalanceOf = +pub type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -pub type PositiveImbalanceOf = +pub type PositiveImbalanceOf = <>::Currency as Currency<::AccountId>>::PositiveImbalance; -pub type NegativeImbalanceOf = +pub type NegativeImbalanceOf = <>::Currency as Currency<::AccountId>>::NegativeImbalance; -pub trait Config: frame_system::Config { - /// The treasury's module id, used for deriving its sovereign account ID. - type PalletId: Get; - - /// The staking balance. - type Currency: Currency + ReservableCurrency; - - /// Origin from which approvals must come. - type ApproveOrigin: EnsureOrigin; - - /// Origin from which rejections must come. - type RejectOrigin: EnsureOrigin; - - /// The overarching event type. - type Event: From> + Into<::Event>; - - /// Handler for the unbalanced decrease when slashing for a rejected proposal or bounty. - type OnSlash: OnUnbalanced>; - - /// Fraction of a proposal's value that should be bonded in order to place the proposal. - /// An accepted proposal gets these back. A rejected proposal does not. - type ProposalBond: Get; - - /// Minimum amount of funds that should be placed in a deposit for making a proposal. - type ProposalBondMinimum: Get>; - - /// Period between successive spends. - type SpendPeriod: Get; - - /// 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; - - /// Runtime hooks to external pallet using treasury to compute spend funds. - type SpendFunds: SpendFunds; - - /// The maximum number of approvals that can wait in the spending queue. - type MaxApprovals: Get; -} - /// A trait to allow the Treasury Pallet to spend it's funds for other purposes. /// There is an expectation that the implementer of this trait will correctly manage /// the mutable variables passed to it: @@ -149,7 +102,7 @@ pub trait Config: frame_system::Config { /// not enough funds, mark this value as `true`. This will prevent the treasury /// from burning the excess funds. #[impl_trait_for_tuples::impl_for_tuples(30)] -pub trait SpendFunds, I=DefaultInstance> { +pub trait SpendFunds, I: 'static = ()> { fn spend_funds( budget_remaining: &mut BalanceOf, imbalance: &mut PositiveImbalanceOf, @@ -175,58 +128,154 @@ pub struct Proposal { bond: Balance, } -decl_storage! { - trait Store for Module, I: Instance=DefaultInstance> as Treasury { - /// Number of proposals that have been made. - ProposalCount get(fn proposal_count): ProposalIndex; +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use super::*; - /// Proposals that have been made. - pub Proposals get(fn proposals): - map hasher(twox_64_concat) ProposalIndex - => Option>>; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData<(T, I)>); - /// Proposal indices that have been approved but not yet awarded. - pub Approvals get(fn approvals): BoundedVec; + #[pallet::config] + pub trait Config: frame_system::Config { + /// The staking balance. + type Currency: Currency + ReservableCurrency; + + /// Origin from which approvals must come. + type ApproveOrigin: EnsureOrigin; + + /// Origin from which rejections must come. + type RejectOrigin: EnsureOrigin; + + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Handler for the unbalanced decrease when slashing for a rejected proposal or bounty. + type OnSlash: OnUnbalanced>; + + /// Fraction of a proposal's value that should be bonded in order to place the proposal. + /// An accepted proposal gets these back. A rejected proposal does not. + #[pallet::constant] + type ProposalBond: Get; + + /// Minimum amount of funds that should be placed in a deposit for making a proposal. + #[pallet::constant] + type ProposalBondMinimum: Get>; + + /// Period between successive spends. + #[pallet::constant] + type SpendPeriod: Get; + + /// Percentage of spare funds (if any) that are burnt per spend period. + #[pallet::constant] + type Burn: Get; + + /// The treasury's pallet id, used for deriving its sovereign account ID. + #[pallet::constant] + type PalletId: Get; + + /// Handler for the unbalanced decrease when treasury funds are burned. + type BurnDestination: OnUnbalanced>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// Runtime hooks to external pallet using treasury to compute spend funds. + type SpendFunds: SpendFunds; + + /// The maximum number of approvals that can wait in the spending queue. + type MaxApprovals: Get; } - add_extra_genesis { - build(|_config| { + + /// Number of proposals that have been made. + #[pallet::storage] + #[pallet::getter(fn proposal_count)] + pub(crate) type ProposalCount = StorageValue<_, ProposalIndex, ValueQuery>; + + /// Proposals that have been made. + #[pallet::storage] + #[pallet::getter(fn proposals)] + pub type Proposals, I: 'static = ()> = StorageMap< + _, + Twox64Concat, + ProposalIndex, + Proposal>, + OptionQuery + >; + + /// Proposal indices that have been approved but not yet awarded. + #[pallet::storage] + #[pallet::getter(fn approvals)] + pub type Approvals, I: 'static = ()> = StorageValue< + _, + BoundedVec, + ValueQuery + >; + + #[pallet::genesis_config] + pub struct GenesisConfig; + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self + } + } + + #[cfg(feature = "std")] + impl GenesisConfig { + /// Direct implementation of `GenesisBuild::assimilate_storage`. + #[deprecated(note = "use ` as GenesisBuild>::assimilate_storage` instead")] + pub fn assimilate_storage, I: 'static>( + &self, + storage: &mut sp_runtime::Storage + ) -> Result<(), String> { + >::assimilate_storage(self, storage) + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { // Create Treasury account - let account_id = >::account_id(); + let account_id = >::account_id(); let min = T::Currency::minimum_balance(); if T::Currency::free_balance(&account_id) < min { let _ = T::Currency::make_free_balance_be(&account_id, min); } - }); + } } -} -decl_event!( - pub enum Event - where - Balance = BalanceOf, - ::AccountId, - { + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::metadata(T::AccountId = "AccountId", BalanceOf = "Balance")] + pub enum Event, I: 'static = ()> { /// New proposal. \[proposal_index\] Proposed(ProposalIndex), /// We have ended a spend period and will now allocate funds. \[budget_remaining\] - Spending(Balance), + Spending(BalanceOf), /// Some funds have been allocated. \[proposal_index, award, beneficiary\] - Awarded(ProposalIndex, Balance, AccountId), + Awarded(ProposalIndex, BalanceOf, T::AccountId), /// A proposal was rejected; funds were slashed. \[proposal_index, slashed\] - Rejected(ProposalIndex, Balance), + Rejected(ProposalIndex, BalanceOf), /// Some of our funds have been burnt. \[burn\] - Burnt(Balance), + Burnt(BalanceOf), /// Spending has finished; this is the amount that rolls over until next spend. /// \[budget_remaining\] - Rollover(Balance), + Rollover(BalanceOf), /// Some funds have been deposited. \[deposit\] - Deposit(Balance), + Deposit(BalanceOf), } -); -decl_error! { - /// Error for the treasury module. - pub enum Error for Module, I: Instance> { + /// Old name generated by `decl_event`. + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + /// Error for the treasury pallet. + #[pallet::error] + pub enum Error { /// Proposer's balance is too low. InsufficientProposersBalance, /// No proposal or bounty at that index. @@ -234,101 +283,9 @@ decl_error! { /// Too many approvals in the queue. TooManyApprovals, } -} - -decl_module! { - pub struct Module, I: Instance=DefaultInstance> - for enum Call - where origin: T::Origin - { - /// Fraction of a proposal's value that should be bonded in order to place the proposal. - /// An accepted proposal gets these back. A rejected proposal does not. - const ProposalBond: Permill = T::ProposalBond::get(); - - /// Minimum amount of funds that should be placed in a deposit for making a proposal. - const ProposalBondMinimum: BalanceOf = T::ProposalBondMinimum::get(); - - /// Period between successive spends. - const SpendPeriod: T::BlockNumber = T::SpendPeriod::get(); - - /// Percentage of spare funds (if any) that are burnt per spend period. - const Burn: Permill = T::Burn::get(); - - /// The treasury's module id, used for deriving its sovereign account ID. - const PalletId: PalletId = T::PalletId::get(); - - type Error = Error; - - fn deposit_event() = default; - - /// Put forward a suggestion for spending. A deposit proportional to the value - /// is reserved and slashed if the proposal is rejected. It is returned once the - /// proposal is awarded. - /// - /// # - /// - Complexity: O(1) - /// - DbReads: `ProposalCount`, `origin account` - /// - DbWrites: `ProposalCount`, `Proposals`, `origin account` - /// # - #[weight = T::WeightInfo::propose_spend()] - pub fn propose_spend( - origin, - #[compact] value: BalanceOf, - beneficiary: ::Source - ) { - let proposer = ensure_signed(origin)?; - let beneficiary = T::Lookup::lookup(beneficiary)?; - - let bond = Self::calculate_bond(value); - T::Currency::reserve(&proposer, bond) - .map_err(|_| Error::::InsufficientProposersBalance)?; - - let c = Self::proposal_count(); - >::put(c + 1); - >::insert(c, Proposal { proposer, value, beneficiary, bond }); - - Self::deposit_event(RawEvent::Proposed(c)); - } - - /// Reject a proposed spend. The original deposit will be slashed. - /// - /// May only be called from `T::RejectOrigin`. - /// - /// # - /// - Complexity: O(1) - /// - DbReads: `Proposals`, `rejected proposer account` - /// - DbWrites: `Proposals`, `rejected proposer account` - /// # - #[weight = (T::WeightInfo::reject_proposal(), DispatchClass::Operational)] - pub fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) { - T::RejectOrigin::ensure_origin(origin)?; - - let proposal = >::take(&proposal_id).ok_or(Error::::InvalidIndex)?; - let value = proposal.bond; - let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0; - T::OnSlash::on_unbalanced(imbalance); - - Self::deposit_event(Event::::Rejected(proposal_id, value)); - } - - /// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary - /// and the original deposit will be returned. - /// - /// May only be called from `T::ApproveOrigin`. - /// - /// # - /// - Complexity: O(1). - /// - DbReads: `Proposals`, `Approvals` - /// - DbWrite: `Approvals` - /// # - #[weight = (T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational)] - pub fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) { - T::ApproveOrigin::ensure_origin(origin)?; - - ensure!(>::contains_key(proposal_id), Error::::InvalidIndex); - Approvals::::try_append(proposal_id).map_err(|_| Error::::TooManyApprovals)?; - } + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { /// # /// - Complexity: `O(A)` where `A` is the number of approvals /// - Db reads and writes: `Approvals`, `pot account data` @@ -345,9 +302,89 @@ decl_module! { } } } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Put forward a suggestion for spending. A deposit proportional to the value + /// is reserved and slashed if the proposal is rejected. It is returned once the + /// proposal is awarded. + /// + /// # + /// - Complexity: O(1) + /// - DbReads: `ProposalCount`, `origin account` + /// - DbWrites: `ProposalCount`, `Proposals`, `origin account` + /// # + #[pallet::weight(T::WeightInfo::propose_spend())] + pub fn propose_spend( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + beneficiary: ::Source + ) -> DispatchResult { + let proposer = ensure_signed(origin)?; + let beneficiary = T::Lookup::lookup(beneficiary)?; + + let bond = Self::calculate_bond(value); + T::Currency::reserve(&proposer, bond) + .map_err(|_| Error::::InsufficientProposersBalance)?; + + let c = Self::proposal_count(); + >::put(c + 1); + >::insert(c, Proposal { proposer, value, beneficiary, bond }); + + Self::deposit_event(Event::Proposed(c)); + Ok(()) + } + + /// Reject a proposed spend. The original deposit will be slashed. + /// + /// May only be called from `T::RejectOrigin`. + /// + /// # + /// - Complexity: O(1) + /// - DbReads: `Proposals`, `rejected proposer account` + /// - DbWrites: `Proposals`, `rejected proposer account` + /// # + #[pallet::weight((T::WeightInfo::reject_proposal(), DispatchClass::Operational))] + pub fn reject_proposal( + origin: OriginFor, + #[pallet::compact] proposal_id: ProposalIndex + ) -> DispatchResult { + T::RejectOrigin::ensure_origin(origin)?; + + let proposal = >::take(&proposal_id).ok_or(Error::::InvalidIndex)?; + let value = proposal.bond; + let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0; + T::OnSlash::on_unbalanced(imbalance); + + Self::deposit_event(Event::::Rejected(proposal_id, value)); + Ok(()) + } + + /// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary + /// and the original deposit will be returned. + /// + /// May only be called from `T::ApproveOrigin`. + /// + /// # + /// - Complexity: O(1). + /// - DbReads: `Proposals`, `Approvals` + /// - DbWrite: `Approvals` + /// # + #[pallet::weight((T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational))] + pub fn approve_proposal( + origin: OriginFor, + #[pallet::compact] proposal_id: ProposalIndex + ) -> DispatchResult { + T::ApproveOrigin::ensure_origin(origin)?; + + ensure!(>::contains_key(proposal_id), Error::::InvalidIndex); + Approvals::::try_append(proposal_id).map_err(|_| Error::::TooManyApprovals)?; + Ok(()) + } + } } -impl, I: Instance> Module { +impl, I: 'static> Pallet { // Add public immutables and private mutables. /// The account ID of the treasury pot. @@ -368,7 +405,7 @@ impl, I: Instance> Module { let mut total_weight: Weight = Zero::zero(); let mut budget_remaining = Self::pot(); - Self::deposit_event(RawEvent::Spending(budget_remaining)); + Self::deposit_event(Event::Spending(budget_remaining)); let account_id = Self::account_id(); let mut missed_any = false; @@ -389,7 +426,7 @@ impl, I: Instance> Module { // provide the allocation. imbalance.subsume(T::Currency::deposit_creating(&p.beneficiary, p.value)); - Self::deposit_event(RawEvent::Awarded(index, p.value, p.beneficiary)); + Self::deposit_event(Event::Awarded(index, p.value, p.beneficiary)); false } else { missed_any = true; @@ -415,7 +452,7 @@ impl, I: Instance> Module { let (debit, credit) = T::Currency::pair(burn); imbalance.subsume(debit); T::BurnDestination::on_unbalanced(credit); - Self::deposit_event(RawEvent::Burnt(burn)) + Self::deposit_event(Event::Burnt(burn)) } // Must never be an error, but better to be safe. @@ -433,7 +470,7 @@ impl, I: Instance> Module { drop(problem); } - Self::deposit_event(RawEvent::Rollover(budget_remaining)); + Self::deposit_event(Event::Rollover(budget_remaining)); total_weight } @@ -445,16 +482,15 @@ impl, I: Instance> Module { // Must never be less than 0 but better be safe. .saturating_sub(T::Currency::minimum_balance()) } - } -impl, I: Instance> OnUnbalanced> for Module { +impl, I: 'static> OnUnbalanced> for Pallet { 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)); + Self::deposit_event(Event::Deposit(numeric_amount)); } } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index dbd5b22741..a59491e1f6 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -19,13 +19,7 @@ #![cfg(test)] -use crate as treasury; -use super::*; use std::cell::RefCell; -use frame_support::{ - assert_noop, assert_ok, parameter_types, - traits::OnInitialize, PalletId -}; use sp_core::H256; use sp_runtime::{ @@ -33,6 +27,14 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, }; +use frame_support::{ + assert_noop, assert_ok, parameter_types, + traits::OnInitialize, PalletId, pallet_prelude::GenesisBuild, +}; + +use crate as treasury; +use super::*; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -129,7 +131,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // Total issuance will be 200 with treasury account initialized at ED. balances: vec![(0, 100), (1, 98), (2, 1)], }.assimilate_storage(&mut t).unwrap(); - treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&crate::GenesisConfig, &mut t).unwrap(); t.into() } @@ -355,7 +357,7 @@ fn genesis_funding_works() { // Total issuance will be 200 with treasury account initialized with 100. balances: vec![(0, 100), (Treasury::account_id(), initial_funding)], }.assimilate_storage(&mut t).unwrap(); - treasury::GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); + GenesisBuild::::assimilate_storage(&crate::GenesisConfig, &mut t).unwrap(); let mut t: sp_io::TestExternalities = t.into(); t.execute_with(|| {