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