diff --git a/Cargo.lock b/Cargo.lock index cdf5207a796..06467f55336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5015,6 +5015,7 @@ dependencies = [ "pallet-balances", "pallet-base-fee", "pallet-collective", + "pallet-conviction-voting", "pallet-crowdloan-rewards", "pallet-democracy", "pallet-ethereum", @@ -5047,10 +5048,12 @@ dependencies = [ "pallet-migrations", "pallet-moonbeam-orbiters", "pallet-parachain-staking", + "pallet-preimage", "pallet-proxy", "pallet-proxy-genesis-companion", "pallet-randomness", "pallet-randomness-collective-flip", + "pallet-referenda", "pallet-scheduler", "pallet-society", "pallet-sudo", @@ -5059,6 +5062,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", "pallet-utility", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-transactor", "parachain-info", @@ -5075,6 +5079,7 @@ dependencies = [ "sha3 0.9.1", "smallvec", "sp-api", + "sp-arithmetic", "sp-block-builder", "sp-core", "sp-debug-derive", @@ -6722,6 +6727,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +source = "git+https://github.com/purestake/substrate?branch=moonbeam-polkadot-v0.9.26#c674000cb498e8d885987bde1a4490939b5fe3db" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-crowdloan-rewards" version = "0.6.0" @@ -7748,6 +7770,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-referenda" +version = "4.0.0-dev" +source = "git+https://github.com/purestake/substrate?branch=moonbeam-polkadot-v0.9.26#c674000cb498e8d885987bde1a4490939b5fe3db" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" @@ -7977,6 +8017,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-whitelist" +version = "4.0.0-dev" +source = "git+https://github.com/purestake/substrate?branch=moonbeam-polkadot-v0.9.26#c674000cb498e8d885987bde1a4490939b5fe3db" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-xcm" version = "0.9.26" diff --git a/runtime/moonbase/Cargo.toml b/runtime/moonbase/Cargo.toml index b4d1b0ab340..61f4e409dd4 100644 --- a/runtime/moonbase/Cargo.toml +++ b/runtime/moonbase/Cargo.toml @@ -70,10 +70,13 @@ frame-system-rpc-runtime-api = { git = "https://github.com/purestake/substrate", pallet-assets = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-balances = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-collective = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } +pallet-conviction-voting = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-democracy = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-identity = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } +pallet-preimage = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-proxy = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-randomness-collective-flip = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } +pallet-referenda = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-scheduler = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-society = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-sudo = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } @@ -82,9 +85,11 @@ pallet-transaction-payment = { git = "https://github.com/purestake/substrate", b pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-treasury = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } pallet-utility = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } +pallet-whitelist = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } parity-scale-codec = { version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len" ] } scale-info = { version = "2.0", default-features = false, features = [ "derive" ] } sp-api = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } +sp-arithmetic = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } sp-block-builder = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } sp-core = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } sp-debug-derive = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.26", default-features = false } @@ -190,6 +195,7 @@ std = [ "pallet-balances/std", "pallet-base-fee/std", "pallet-collective/std", + "pallet-conviction-voting/std", "pallet-crowdloan-rewards/std", "pallet-democracy/std", "pallet-ethereum-chain-id/std", @@ -213,10 +219,12 @@ std = [ "pallet-migrations/std", "pallet-moonbeam-orbiters/std", "pallet-parachain-staking/std", + "pallet-preimage/std", "pallet-proxy-genesis-companion/std", "pallet-proxy/std", "pallet-randomness-collective-flip/std", "pallet-randomness/std", + "pallet-referenda/std", "pallet-scheduler/std", "pallet-society/std", "pallet-sudo/std", @@ -225,6 +233,7 @@ std = [ "pallet-transaction-payment/std", "pallet-treasury/std", "pallet-utility/std", + "pallet-whitelist/std", "pallet-xcm-transactor/std", "pallet-xcm/std", "parachain-info/std", @@ -234,6 +243,7 @@ std = [ "serde", "session-keys-primitives/std", "sp-api/std", + "sp-arithmetic/std", "sp-block-builder/std", "sp-core/std", "sp-inherents/std", @@ -277,12 +287,14 @@ runtime-benchmarks = [ "pallet-author-slot-filter/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", "pallet-crowdloan-rewards/runtime-benchmarks", "pallet-ethereum-xcm/runtime-benchmarks", "pallet-ethereum/runtime-benchmarks", "pallet-moonbeam-orbiters/runtime-benchmarks", "pallet-parachain-staking/runtime-benchmarks", "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-xcm-transactor/runtime-benchmarks", @@ -301,11 +313,13 @@ try-runtime = [ "pallet-author-slot-filter/try-runtime", "pallet-balances/try-runtime", "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", "pallet-maintenance-mode/try-runtime", #"pallet-crowdloan-rewards/try-runtime", "pallet-maintenance-mode/try-runtime", "pallet-migrations/try-runtime", "pallet-parachain-staking/try-runtime", + "pallet-referenda/try-runtime", "pallet-scheduler/try-runtime", "pallet-society/try-runtime", "pallet-timestamp/try-runtime", diff --git a/runtime/moonbase/src/governance/mod.rs b/runtime/moonbase/src/governance/mod.rs new file mode 100644 index 00000000000..64e4fc52914 --- /dev/null +++ b/runtime/moonbase/src/governance/mod.rs @@ -0,0 +1,88 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Moonbeam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Moonbeam. If not, see . + +//! New governance configurations for the Moonbase runtime. + +use super::*; +use crate::currency::*; +use frame_support::traits::EitherOf; +use frame_system::EnsureRootWithSuccess; + +mod origins; +pub use origins::{ + pallet_custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, Spender, + WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = pallet_conviction_voting::weights::SubstrateWeight; + type Event = Event; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 100 * UNIT; + pub const UndecidingTimeout: BlockNumber = 28 * DAYS; +} + +parameter_types! { + pub const MaxBalance: Balance = Balance::max_value(); +} +pub type TreasurySpender = EitherOf, Spender>; + +impl origins::pallet_custom_origins::Config for Runtime {} + +// purpose of this pallet is to queue calls to be dispatched as root for later +impl pallet_whitelist::Config for Runtime { + type WeightInfo = pallet_whitelist::weights::SubstrateWeight; + type Event = Event; + type Call = Call; + // polkadot: EitherOf>, Fellows>; + type WhitelistOrigin = + EnsureRootWithSuccess, TODO: COLLECTIVE>; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type PreimageProvider = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = pallet_referenda::weights::SubstrateWeight; + type Call = Call; + type Event = Event; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = ReferendumCanceller; + type KillOrigin = ReferendumKiller; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; +} diff --git a/runtime/moonbase/src/governance/old.rs b/runtime/moonbase/src/governance/old.rs new file mode 100644 index 00000000000..867d58fa8d9 --- /dev/null +++ b/runtime/moonbase/src/governance/old.rs @@ -0,0 +1 @@ +//! old governance configurations \ No newline at end of file diff --git a/runtime/moonbase/src/governance/origins.rs b/runtime/moonbase/src/governance/origins.rs new file mode 100644 index 00000000000..8353de5713e --- /dev/null +++ b/runtime/moonbase/src/governance/origins.rs @@ -0,0 +1,136 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Moonbeam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +//! Custom origins for governance interventions. + +pub use pallet_custom_origins::*; + +#[frame_support::pallet] +pub mod pallet_custom_origins { + use crate::{ + currency::{KILOUNIT, UNIT}, + Balance, + }; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Origin for spending (any amount of) funds. + Treasurer, + /// Origin for managing the registrar. + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Origin able to spend up to 1 KSM from the treasury at once. + SmallTipper, + /// Origin able to spend up to 5 KSM from the treasury at once. + BigTipper, + /// Origin able to spend up to 50 KSM from the treasury at once. + SmallSpender, + /// Origin able to spend up to 500 KSM from the treasury at once. + MediumSpender, + /// Origin able to spend up to 5,000 KSM from the treasury at once. + BigSpender, + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + GeneralAdmin, + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + ); + + macro_rules! decl_ensure { + ( + $vis:vis type $name:ident: EnsureOrigin { + $( $item:ident = $success:expr, )* + } + ) => { + $vis struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + $( + Origin::$item => Ok($success), + )* + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // By convention the more privileged origins go later, so for greatest chance + // of success, we want the last one. + let _result: Result = Err(()); + $( + let _result: Result = Ok(O::from(Origin::$item)); + )* + _result + } + } + } + } + + decl_ensure! { + pub type Spender: EnsureOrigin { + SmallTipper = 250 * 100 * UNIT, + BigTipper = 1 * KILOUNIT, + SmallSpender = 10 * KILOUNIT, + MediumSpender = 100 * KILOUNIT, + BigSpender = 1_000 * KILOUNIT, + } + } +} diff --git a/runtime/moonbase/src/governance/tracks.rs b/runtime/moonbase/src/governance/tracks.rs new file mode 100644 index 00000000000..cd54b786f1e --- /dev/null +++ b/runtime/moonbase/src/governance/tracks.rs @@ -0,0 +1,250 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{KILOUNIT, UNIT}; + +const fn percent(x: i32) -> sp_arithmetic::FixedI64 { + sp_arithmetic::FixedI64::from_rational(x as u128, 100) +} +use pallet_referenda::Curve; +const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +const APP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_GENERAL_ADMIN: Curve = + Curve::make_reciprocal(7, 28, percent(10), percent(0), percent(50)); +const APP_REFERENDUM_CANCELLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_CANCELLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_REFERENDUM_KILLER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_REFERENDUM_KILLER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); +const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_SMALL_SPENDER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); +const SUP_MEDIUM_SPENDER: Curve = + Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); +const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); +const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); +const APP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); +const SUP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(1, 28, percent(20), percent(10), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 11] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 1_000 * KILOUNIT, + prepare_period: 3 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 3 * HOURS, + min_approval: APP_ROOT, + min_support: SUP_ROOT, + }, + ), + // Fastrack + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 10, + decision_deposit: 10_000 * KILOUNIT, + prepare_period: 3 * HOURS, + decision_period: 28 * DAYS, + // TODO: review + confirm_period: 10 * MINUTES, + // TODO: review + min_enactment_period: 30 * MINUTES, + min_approval: APP_WHITELISTED_CALLER, + min_support: SUP_WHITELISTED_CALLER, + }, + ), + ( + 10, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 10, + decision_deposit: 5 * KILOUNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 2 * DAYS, + min_approval: APP_TREASURER, + min_support: SUP_TREASURER, + }, + ), + ( + 11, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 5 * KILOUNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 2 * DAYS, + min_approval: APP_GENERAL_ADMIN, + min_support: SUP_GENERAL_ADMIN, + }, + ), + ( + 12, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 1_000, + decision_deposit: 50 * KILOUNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_CANCELLER, + min_support: SUP_REFERENDUM_CANCELLER, + }, + ), + ( + 13, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 1_000, + decision_deposit: 50 * KILOUNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_KILLER, + min_support: SUP_REFERENDUM_KILLER, + }, + ), + ( + 14, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 200, + decision_deposit: 5 * 100 * UNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 28 * DAYS, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 15, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 100, + decision_deposit: 50 * 100 * UNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 6 * HOURS, + min_enactment_period: 28 * DAYS, + min_approval: APP_BIG_TIPPER, + min_support: SUP_BIG_TIPPER, + }, + ), + ( + 16, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 50, + decision_deposit: 500 * 100 * UNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 12 * HOURS, + min_enactment_period: 28 * DAYS, + min_approval: APP_SMALL_SPENDER, + min_support: SUP_SMALL_SPENDER, + }, + ), + ( + 17, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 20, + decision_deposit: 1_500 * 100 * UNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 28 * DAYS, + min_approval: APP_MEDIUM_SPENDER, + min_support: SUP_MEDIUM_SPENDER, + }, + ), + ( + 18, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 10, + decision_deposit: 5 * KILOUNIT, + prepare_period: 4, + decision_period: 28 * DAYS, + confirm_period: 48 * HOURS, + min_enactment_period: 28 * DAYS, + min_approval: APP_BIG_SPENDER, + min_support: SUP_BIG_SPENDER, + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type Origin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::Origin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + _ => Err(()), + } + } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { + match custom_origin { + origins::Origin::WhitelistedCaller => Ok(1), + // General admin + origins::Origin::Treasurer => Ok(10), + origins::Origin::GeneralAdmin => Ok(11), + // Referendum admins + origins::Origin::ReferendumCanceller => Ok(12), + origins::Origin::ReferendumKiller => Ok(13), + // Limited treasury spenders + origins::Origin::SmallTipper => Ok(14), + origins::Origin::BigTipper => Ok(15), + origins::Origin::SmallSpender => Ok(16), + origins::Origin::MediumSpender => Ok(17), + origins::Origin::BigSpender => Ok(18), + } + } else { + Err(()) + } + } +} diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index 21c80ac1abf..6de3a77c469 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -111,7 +111,9 @@ pub use sp_runtime::BuildStorage; pub type Precompiles = MoonbasePrecompiles; pub mod asset_config; +pub mod governance; pub mod xcm_config; +use governance::{pallet_custom_origins, TreasurySpender}; /// UNIT, the native token, uses 18 decimals of precision. pub mod currency { @@ -478,10 +480,20 @@ impl pallet_scheduler::Config for Runtime { type MaxScheduledPerBlock = ConstU32<50>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = (); + type PreimageProvider = Preimage; type NoPreimagePostponement = (); } +impl pallet_preimage::Config for Runtime { + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = ConstU32<{ 4096 * 1024 }>; + type BaseDeposit = ConstU128<{ 5 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type ByteDeposit = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; +} + type CouncilInstance = pallet_collective::Instance1; type TechCommitteeInstance = pallet_collective::Instance2; type TreasuryCouncilInstance = pallet_collective::Instance3; @@ -619,9 +631,10 @@ impl pallet_treasury::Config for Runtime { type WeightInfo = pallet_treasury::weights::SubstrateWeight; type SpendFunds = (); type ProposalBondMaximum = (); - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type SpendOrigin = TreasurySpender; } +// TODO: name same origin to same type type IdentityForceOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, @@ -1263,6 +1276,11 @@ construct_runtime! { Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 39, TreasuryCouncilCollective: pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 40, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 41, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 42, + Origins: pallet_custom_origins::{Origin} = 43, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 44, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 45, } } diff --git a/runtime/moonbase/tests/common/mod.rs b/runtime/moonbase/tests/common/mod.rs index cd7edcfdf84..12ed0c41766 100644 --- a/runtime/moonbase/tests/common/mod.rs +++ b/runtime/moonbase/tests/common/mod.rs @@ -28,8 +28,8 @@ pub use moonbase_runtime::{ currency::{GIGAWEI, SUPPLY_FACTOR, UNIT, WEI}, AccountId, AssetId, AssetManager, Assets, AuthorInherent, Balance, Balances, Call, CrowdloanRewards, Ethereum, Event, Executive, FixedGasPrice, InflationInfo, LocalAssets, - ParachainStaking, Range, Runtime, System, TransactionConverter, UncheckedExtrinsic, HOURS, - WEEKS, + ParachainStaking, Range, Runtime, Scheduler, System, TransactionConverter, UncheckedExtrinsic, + HOURS, WEEKS, }; use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; use sp_core::{Encode, H160}; @@ -85,6 +85,7 @@ pub fn run_to_block(n: u32, author: Option) { } // Initialize the new block + Scheduler::on_initialize(System::block_number()); AuthorInherent::on_initialize(System::block_number()); ParachainStaking::on_initialize(System::block_number()); Ethereum::on_initialize(System::block_number()); diff --git a/runtime/moonbase/tests/gov_tests.rs b/runtime/moonbase/tests/gov_tests.rs new file mode 100644 index 00000000000..573492cfaf7 --- /dev/null +++ b/runtime/moonbase/tests/gov_tests.rs @@ -0,0 +1,88 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Moonbeam is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Moonbeam. If not, see . + +//! TODO: move to integration tests if any of these are worth keeping + +mod common; +use common::*; + +use frame_support::{ + assert_noop, assert_ok, + dispatch::RawOrigin, + traits::{schedule::DispatchTime, PreimageRecipient}, +}; +use moonbase_runtime::{governance::*, Preimage, Referenda}; +use nimbus_primitives::NimbusId; +use pallet_referenda::ReferendumInfo; +use sp_core::{ByteArray, Encode, H256}; +use sp_runtime::traits::{BlakeTwo256, Hash}; + +pub fn set_balance_proposal(value: u128) -> Vec { + Call::Balances(pallet_balances::Call::set_balance { + who: AccountId::from(ALICE), + new_free: value, + new_reserved: 0, + }) + .encode() +} + +pub fn set_balance_proposal_hash(value: u128) -> H256 { + let c = Call::Balances(pallet_balances::Call::set_balance { + who: AccountId::from(ALICE), + new_free: value, + new_reserved: 0, + }); + >::note_preimage(c.encode().try_into().unwrap()); + BlakeTwo256::hash_of(&c) +} + +#[test] +fn referenda_times_out_if_inaction() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + run_to_block(0, NimbusId::from_slice(&ALICE_NIMBUS).ok()); + assert_ok!(Referenda::submit( + origin_of(AccountId::from(ALICE)), + // TODO: treasury spend from fasttrack origin + Box::new(WhitelistedCaller.into()), + set_balance_proposal_hash(1), + DispatchTime::At(10), + )); + run_to_block(10, NimbusId::from_slice(&ALICE_NIMBUS).ok()); + let is_ongoing = match pallet_referenda::ReferendumInfoFor::::get(0) { + Some(ReferendumInfo::Ongoing(_)) => true, + _ => false, + }; + assert!(is_ongoing); + // TODO: bring back once scheduler fixed + // TODO: check state in scheduler to see when expected to schedule + // and try to figure out why not scheduled + // run_to_block(15, NimbusId::from_slice(&ALICE_NIMBUS).ok()); + // // Timed out - ended. + // let is_timed_out = match pallet_referenda::ReferendumInfoFor::::get(0) { + // Some(ReferendumInfo::TimedOut(11, _, None)) => true, + // _ => false, + // }; + // assert!(is_timed_out, "{:?}", pallet_referenda::ReferendumInfoFor::::get(0)); + }); +}