diff --git a/CHANGELOG.md b/CHANGELOG.md index 984018153..76aa4fbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - [C,D] Updated Substrate to polkadot-v1.1.0 +- [C,D] Introduction of the OpenGov ## [5.2.0] diff --git a/Cargo.lock b/Cargo.lock index afaa652fb..ac4f35488 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,6 +453,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "async-channel" version = "1.9.0" @@ -989,6 +995,7 @@ dependencies = [ "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", + "pallet-conviction-voting", "pallet-ddc-clusters", "pallet-ddc-customers", "pallet-ddc-nodes", @@ -1016,6 +1023,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -1029,9 +1037,11 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "parity-scale-codec", "scale-info", "sp-api", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", @@ -1107,6 +1117,7 @@ dependencies = [ "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", + "pallet-conviction-voting", "pallet-ddc-clusters", "pallet-ddc-customers", "pallet-ddc-nodes", @@ -1134,6 +1145,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -1147,9 +1159,11 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "parity-scale-codec", "scale-info", "sp-api", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", @@ -5140,6 +5154,23 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-ddc-clusters" version = "5.3.0" @@ -5646,6 +5677,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-referenda" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" @@ -5882,6 +5932,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-whitelist" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + [[package]] name = "parity-db" version = "0.4.13" diff --git a/Cargo.toml b/Cargo.toml index 5f504cd2b..4bfe6aa5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,9 @@ pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/parityt pallet-treasury = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } pallet-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } pallet-vesting = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } +pallet-conviction-voting = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } +pallet-referenda = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } +pallet-whitelist = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } sc-authority-discovery = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-v1.1.0", default-features = false } sc-basic-authorship = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-v1.1.0", default-features = false } sc-chain-spec = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-v1.1.0", default-features = false } diff --git a/node/cli/src/command.rs b/node/cli/src/command.rs index 5720c980e..3abf560a7 100644 --- a/node/cli/src/command.rs +++ b/node/cli/src/command.rs @@ -1,4 +1,4 @@ -use cere_service::{self, IdentifyVariant}; +use cere_service::IdentifyVariant; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use sc_cli::{Error, SubstrateCli}; use sc_service::error::Error as ServiceError; diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 454d43cc8..05f71ff88 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -157,8 +157,6 @@ pub fn cere_dev_genesis( })) .collect::>(); - let num_endowed_accounts = endowed_accounts.len(); - const ENDOWMENT: Balance = 10_000_000_000 * TEST_UNITS; const STASH: Balance = ENDOWMENT / 1000; @@ -194,24 +192,6 @@ pub fn cere_dev_genesis( ..Default::default() }, ddc_staking: cere_dev::DdcStakingConfig::default(), - democracy: cere_dev::DemocracyConfig::default(), - elections: cere_dev::ElectionsConfig { - members: endowed_accounts - .iter() - .take((num_endowed_accounts + 1) / 2) - .cloned() - .map(|member| (member, STASH)) - .collect(), - }, - council: cere_dev::CouncilConfig::default(), - technical_committee: cere_dev::TechnicalCommitteeConfig { - members: endowed_accounts - .iter() - .take((num_endowed_accounts + 1) / 2) - .cloned() - .collect(), - phantom: Default::default(), - }, sudo: cere_dev::SudoConfig { key: Some(root_key) }, babe: cere_dev::BabeConfig { authorities: Default::default(), @@ -224,7 +204,6 @@ pub fn cere_dev_genesis( ..Default::default() }, grandpa: Default::default(), - technical_membership: Default::default(), treasury: Default::default(), vesting: Default::default(), transaction_payment: Default::default(), diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 374732ae5..27e9d89f4 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -11,7 +11,7 @@ pub use cere_dev_runtime; pub use cere_runtime; use futures::prelude::*; use sc_client_api::{Backend, BlockBackend}; -use sc_consensus_babe::{self, SlotProportion}; +use sc_consensus_babe::SlotProportion; pub use sc_executor::NativeExecutionDispatch; use sc_network::{Event, NetworkEventStream}; use sc_service::{ diff --git a/pallets/ddc-staking/src/lib.rs b/pallets/ddc-staking/src/lib.rs index 8d42e0316..65f8639e7 100644 --- a/pallets/ddc-staking/src/lib.rs +++ b/pallets/ddc-staking/src/lib.rs @@ -38,7 +38,6 @@ use frame_support::{ pallet_prelude::*, parameter_types, traits::{Currency, DefensiveSaturating, LockIdentifier, LockableCurrency, WithdrawReasons}, - BoundedVec, }; use frame_system::pallet_prelude::*; pub use pallet::*; diff --git a/runtime/cere-dev/Cargo.toml b/runtime/cere-dev/Cargo.toml index 1ad99fd27..06cbfdd15 100644 --- a/runtime/cere-dev/Cargo.toml +++ b/runtime/cere-dev/Cargo.toml @@ -39,6 +39,7 @@ pallet-child-bounties = { workspace = true } pallet-collective = { workspace = true } pallet-contracts = { workspace = true } pallet-contracts-primitives = { workspace = true } +pallet-conviction-voting = { workspace = true } pallet-democracy = { workspace = true } pallet-election-provider-multi-phase = { workspace = true } pallet-election-provider-support-benchmarking = { workspace = true, optional = true } @@ -59,6 +60,7 @@ pallet-offences-benchmarking = { workspace = true, optional = true } pallet-preimage = { workspace = true } pallet-proxy = { workspace = true } pallet-recovery = { workspace = true } +pallet-referenda = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true, features = ["historical"] } pallet-session-benchmarking = { workspace = true, optional = true } @@ -72,7 +74,9 @@ pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-treasury = { workspace = true } pallet-utility = { workspace = true } pallet-vesting = { workspace = true } +pallet-whitelist = { workspace = true } sp-api = { workspace = true } +sp-arithmetic = { workspace = true } sp-authority-discovery = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-babe = { workspace = true } @@ -182,6 +186,10 @@ std = [ "pallet-ddc-clusters/std", "pallet-ddc-payouts/std", "cere-runtime-common/std", + "sp-arithmetic/std", + "pallet-conviction-voting/std", + "pallet-referenda/std", + "pallet-whitelist/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -228,6 +236,9 @@ runtime-benchmarks = [ "pallet-chainbridge/runtime-benchmarks", "ddc-primitives/runtime-benchmarks", "hex-literal", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", ] try-runtime = [ "frame-executive/try-runtime", @@ -276,4 +287,7 @@ try-runtime = [ "pallet-ddc-staking/try-runtime", "pallet-erc20/try-runtime", "pallet-erc721/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-referenda/try-runtime", + "pallet-whitelist/try-runtime", ] diff --git a/runtime/cere-dev/src/governance/mod.rs b/runtime/cere-dev/src/governance/mod.rs new file mode 100644 index 000000000..75b25fcc8 --- /dev/null +++ b/runtime/cere-dev/src/governance/mod.rs @@ -0,0 +1,70 @@ +use frame_support::parameter_types; +use frame_system::EnsureRootWithSuccess; + +use super::*; + +mod origins; +pub use origins::{ + pallet_custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, Spender, + StakingAdmin, Treasurer, 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 RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = + frame_support::traits::tokens::currency::ActiveIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = DOLLARS; + pub const UndecidingTimeout: BlockNumber = 14 * DAYS; +} + +parameter_types! { + pub const MaxBalance: Balance = Balance::max_value(); +} + +pub type TreasurySpender = EitherOf, Spender>; + +impl origins::pallet_custom_origins::Config for Runtime {} + +impl pallet_whitelist::Config for Runtime { + type WeightInfo = pallet_whitelist::weights::SubstrateWeight; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WhitelistOrigin = EnsureRoot; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = pallet_referenda::weights::SubstrateWeight; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, 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; + type Preimages = Preimage; +} diff --git a/runtime/cere-dev/src/governance/origins.rs b/runtime/cere-dev/src/governance/origins.rs new file mode 100644 index 000000000..57e2c98cc --- /dev/null +++ b/runtime/cere-dev/src/governance/origins.rs @@ -0,0 +1,130 @@ +//! Custom origins for governance interventions. + +pub use pallet_custom_origins::*; + +#[frame_support::pallet] +pub mod pallet_custom_origins { + use frame_support::pallet_prelude::*; + + use crate::{Balance, DOLLARS, GRAND}; + + #[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 able to cancel slashes and manage minimum commission. + StakingAdmin, + /// Origin for spending up to $10,000,000 DOT from the treasury as well as generally + /// administering it. + Treasurer, + /// Origin for managing the composition of the fellowship. + FellowshipAdmin, + /// Origin for managing the registrar. + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Origin able to spend around $250 from the treasury at once. + SmallTipper, + /// Origin able to spend around $1,000 from the treasury at once. + BigTipper, + /// Origin able to spend around $10,000 from the treasury at once. + SmallSpender, + /// Origin able to spend around $100,000 from the treasury at once. + MediumSpender, + /// Origin able to spend up to $1,000,000 DOT 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!( + StakingAdmin, + Treasurer, + FellowshipAdmin, + 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 * DOLLARS, + BigTipper = GRAND, + SmallSpender = 10 * GRAND, + MediumSpender = 100 * GRAND, + BigSpender = 1_000 * GRAND, + Treasurer = 10_000 * GRAND, + } + } +} diff --git a/runtime/cere-dev/src/governance/tracks.rs b/runtime/cere-dev/src/governance/tracks.rs new file mode 100644 index 000000000..d4c813a46 --- /dev/null +++ b/runtime/cere-dev/src/governance/tracks.rs @@ -0,0 +1,267 @@ +//! Track configurations for governance. + +use super::*; + +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_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_STAKING_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), 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_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_FELLOWSHIP_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), 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(5), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 13] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 100 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_ROOT, + min_support: SUP_ROOT, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * GRAND, + prepare_period: 30 * MINUTES, + decision_period: 28 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 10 * MINUTES, + min_approval: APP_WHITELISTED_CALLER, + min_support: SUP_WHITELISTED_CALLER, + }, + ), + ( + 10, + pallet_referenda::TrackInfo { + name: "staking_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_STAKING_ADMIN, + min_support: SUP_STAKING_ADMIN, + }, + ), + ( + 11, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 10, + decision_deposit: GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_TREASURER, + min_support: SUP_TREASURER, + }, + ), + ( + 13, + pallet_referenda::TrackInfo { + name: "fellowship_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_FELLOWSHIP_ADMIN, + min_support: SUP_FELLOWSHIP_ADMIN, + }, + ), + ( + 14, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_GENERAL_ADMIN, + min_support: SUP_GENERAL_ADMIN, + }, + ), + ( + 20, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 1_000, + decision_deposit: 10 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_CANCELLER, + min_support: SUP_REFERENDUM_CANCELLER, + }, + ), + ( + 21, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 1_000, + decision_deposit: 50 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_KILLER, + min_support: SUP_REFERENDUM_KILLER, + }, + ), + ( + 30, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 200, + decision_deposit: DOLLARS, + prepare_period: MINUTES, + decision_period: 7 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: MINUTES, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 31, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 100, + decision_deposit: 10 * DOLLARS, + prepare_period: 10 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_BIG_TIPPER, + min_support: SUP_BIG_TIPPER, + }, + ), + ( + 32, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 50, + decision_deposit: 100 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 12 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_SMALL_SPENDER, + min_support: SUP_SMALL_SPENDER, + }, + ), + ( + 33, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 50, + decision_deposit: 200 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_MEDIUM_SPENDER, + min_support: SUP_MEDIUM_SPENDER, + }, + ), + ( + 34, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 50, + decision_deposit: 400 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 48 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_BIG_SPENDER, + min_support: SUP_BIG_SPENDER, + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> 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::StakingAdmin => Ok(10), + origins::Origin::Treasurer => Ok(11), + origins::Origin::FellowshipAdmin => Ok(13), + origins::Origin::GeneralAdmin => Ok(14), + // Referendum admins + origins::Origin::ReferendumCanceller => Ok(20), + origins::Origin::ReferendumKiller => Ok(21), + // Limited treasury spenders + origins::Origin::SmallTipper => Ok(30), + origins::Origin::BigTipper => Ok(31), + origins::Origin::SmallSpender => Ok(32), + origins::Origin::MediumSpender => Ok(33), + origins::Origin::BigSpender => Ok(34), + } + } else { + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/runtime/cere-dev/src/lib.rs b/runtime/cere-dev/src/lib.rs index e736bde96..54e524a65 100644 --- a/runtime/cere-dev/src/lib.rs +++ b/runtime/cere-dev/src/lib.rs @@ -33,8 +33,8 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, - Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, + ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOf, EitherOfDiverse, + EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, Nothing, OnUnbalanced, WithdrawReasons, }, weights::{ @@ -109,6 +109,10 @@ use cere_runtime_common::{ use impls::Author; use sp_runtime::generic::Era; +// Governance configurations. +pub mod governance; +use governance::{pallet_custom_origins, GeneralAdmin, StakingAdmin, Treasurer, TreasurySpender}; + /// Generated voter bag information. mod voter_bags; @@ -308,15 +312,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Balances(..) | RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) | RuntimeCall::Indices(pallet_indices::Call::transfer { .. }) | - RuntimeCall::NominationPools(..) + RuntimeCall::NominationPools(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) ), ProxyType::Governance => matches!( c, - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | - RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::Elections(..) | - RuntimeCall::Treasury(..) + RuntimeCall::Treasury(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) ), ProxyType::Staking => matches!(c, RuntimeCall::Staking(..)), } @@ -536,11 +542,6 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxValidators = ConstU32<1000>; } -type StakingAdminOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, ->; - impl pallet_staking::Config for Runtime { type Currency = Balances; type CurrencyBalance = Balance; @@ -553,7 +554,7 @@ impl pallet_staking::Config for Runtime { type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = StakingAdminOrigin; + type AdminOrigin = EitherOf, StakingAdmin>; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; @@ -573,7 +574,7 @@ impl pallet_staking::Config for Runtime { impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ControlOrigin = frame_system::EnsureRoot; + type ControlOrigin = EnsureRoot; type Deposit = ConstU128<{ DOLLARS }>; type Currency = Balances; type BatchSize = frame_support::traits::ConstU32<64>; @@ -732,7 +733,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type Fallback = onchain::OnChainExecution; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen, OffchainRandomBalancing>; - type ForceOrigin = EnsureRootOrHalfCouncil; + type ForceOrigin = EitherOf, StakingAdmin>; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type MaxWinners = MaxActiveValidators; type ElectionBounds = ElectionBounds; @@ -752,165 +753,6 @@ impl pallet_bags_list::Config for Runtime { type Score = VoteWeight; } -parameter_types! { - pub const LaunchPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const VotingPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const FastTrackVotingPeriod: BlockNumber = 3 * 60 * MINUTES; - pub const MinimumDeposit: Balance = 50_000 * DOLLARS; - pub const EnactmentPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const CooloffPeriod: BlockNumber = 7 * 24 * 60 * MINUTES; - pub const MaxProposals: u32 = 100; -} - -impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = EnactmentPeriod; // Same as EnactmentPeriod - type MinimumDeposit = MinimumDeposit; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = - pallet_collective::EnsureProportionAtLeast; - /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantAllowed = frame_support::traits::ConstBool; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = - pallet_collective::EnsureProportionAtLeast; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type BlacklistOrigin = EnsureRoot; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cool-off period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type SubmitOrigin = frame_system::EnsureSigned; - type PalletsOrigin = OriginCaller; - type MaxVotes = ConstU32<100>; - type WeightInfo = pallet_democracy::weights::SubstrateWeight; - type MaxProposals = MaxProposals; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; -} - -parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 7 * DAYS; - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; -} - -type CouncilCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type SetMembersOrigin = EnsureRoot; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type MaxProposalWeight = MaxCollectivesProposalWeight; -} - -parameter_types! { - pub const CandidacyBond: Balance = 5_000_000 * DOLLARS; - // 1 storage item created, key size is 32 bytes, value size is 16+16. - pub const VotingBondBase: Balance = deposit(1, 64); - pub const VotingBondFactor: Balance = DOLLARS; - pub const TermDuration: BlockNumber = 182 * DAYS; - pub const DesiredMembers: u32 = 13; - pub const DesiredRunnersUp: u32 = 20; - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; - pub const MaxVoters: u32 = 10 * 1000; - pub const MaxVotesPerVoter: u32 = 16; - pub const MaxCandidates: u32 = 1000; -} - -// Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. -const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); - -impl pallet_elections_phragmen::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletId = ElectionsPhragmenPalletId; - type Currency = Balances; - type ChangeMembers = Council; - // NOTE: this implies that council's genesis members cannot be set directly and must come from - // this module. - type InitializeMembers = Council; - type CurrencyToVote = CurrencyToVote; - type CandidacyBond = CandidacyBond; - type VotingBondBase = VotingBondBase; - type VotingBondFactor = VotingBondFactor; - type LoserCandidate = (); - type KickedMember = (); - type DesiredMembers = DesiredMembers; - type DesiredRunnersUp = DesiredRunnersUp; - type TermDuration = TermDuration; - type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; - type MaxVoters = MaxVoters; - type MaxVotesPerVoter = MaxVotesPerVoter; - type MaxCandidates = MaxCandidates; -} - -parameter_types! { - pub const TechnicalMotionDuration: BlockNumber = 5 * DAYS; - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; -} - -type TechnicalCollective = pallet_collective::Instance2; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type SetMembersOrigin = EnsureRoot; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type MaxProposalWeight = MaxCollectivesProposalWeight; -} - -type EnsureRootOrHalfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, ->; -impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRootOrHalfCouncil; - type RemoveOrigin = EnsureRootOrHalfCouncil; - type SwapOrigin = EnsureRootOrHalfCouncil; - type ResetOrigin = EnsureRootOrHalfCouncil; - type PrimeOrigin = EnsureRootOrHalfCouncil; - type MembershipInitialized = TechnicalCommittee; - type MembershipChanged = TechnicalCommittee; - type MaxMembers = TechnicalMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; -} - parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const ProposalBondMinimum: Balance = 50_000 * DOLLARS; @@ -928,14 +770,8 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type RejectOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, - >; + type ApproveOrigin = EitherOfDiverse, Treasurer>; + type RejectOrigin = EitherOfDiverse, Treasurer>; type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; @@ -947,7 +783,7 @@ impl pallet_treasury::Config for Runtime { type SpendFunds = Bounties; type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = TreasurySpender; } parameter_types! { @@ -987,17 +823,6 @@ impl pallet_child_bounties::Config for Runtime { type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } -impl pallet_tips::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; - type Tippers = Elections; - type TipCountdown = TipCountdown; - type TipFindersFee = TipFindersFee; - type TipReportDepositBase = TipReportDepositBase; - type WeightInfo = pallet_tips::weights::SubstrateWeight; -} - parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); @@ -1181,8 +1006,8 @@ impl pallet_identity::Config for Runtime { type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; - type ForceOrigin = EnsureRootOrHalfCouncil; - type RegistrarOrigin = EnsureRootOrHalfCouncil; + type ForceOrigin = EitherOf, GeneralAdmin>; + type RegistrarOrigin = EitherOf, GeneralAdmin>; type WeightInfo = pallet_identity::weights::SubstrateWeight; } @@ -1367,11 +1192,6 @@ construct_runtime!( ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, Session: pallet_session, - Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, - Elections: pallet_elections_phragmen, - TechnicalMembership: pallet_membership::, Grandpa: pallet_grandpa, Treasury: pallet_treasury, Contracts: pallet_contracts, @@ -1389,7 +1209,6 @@ construct_runtime!( Proxy: pallet_proxy, Multisig: pallet_multisig, Bounties: pallet_bounties, - Tips: pallet_tips, VoterList: pallet_bags_list::, ChildBounties: pallet_child_bounties, NominationPools: pallet_nomination_pools, @@ -1401,7 +1220,13 @@ construct_runtime!( DdcCustomers: pallet_ddc_customers, DdcNodes: pallet_ddc_nodes, DdcClusters: pallet_ddc_clusters, - DdcPayouts: pallet_ddc_payouts + DdcPayouts: pallet_ddc_payouts, + // Start OpenGov. + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event}, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event}, + Origins: pallet_custom_origins::{Origin}, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event}, + // End OpenGov. } ); @@ -1440,27 +1265,83 @@ pub type SignedPayload = generic::SignedPayload; pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Runtime migrations -type Migrations = ( - pallet_contracts::migration::Migration, - // TODO: Leaving this for the OpenGov PR - // Gov v1 storage migrations - // https://github.com/paritytech/polkadot/issues/6749 - // pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - // pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - // pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, - - // Delete all Gov v1 pallet storage key/values. - // frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, -); +type Migrations = migrations::Unreleased; + +/// The runtime migrations per release. +#[allow(deprecated, missing_docs)] +pub mod migrations { + use frame_support::traits::LockIdentifier; + use frame_system::pallet_prelude::BlockNumberFor; + + use super::*; + + parameter_types! { + pub const DemocracyPalletName: &'static str = "Democracy"; + pub const CouncilPalletName: &'static str = "Council"; + pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; + pub const ElectionPalletName: &'static str = "Elections"; + pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; + pub const TipsPalletName: &'static str = "Tips"; + pub const ElectionPalletId: LockIdentifier = *b"phrelect"; + } + + // Special Config for Gov V1 pallets, allowing us to run migrations for them without + // implementing their configs on [`Runtime`]. + pub struct UnlockConfig; + impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { + type Currency = Balances; + type MaxVotes = ConstU32<100>; + type MaxDeposits = ConstU32<100>; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = DemocracyPalletName; + } + impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig + for UnlockConfig + { + type Currency = Balances; + type MaxVotesPerVoter = ConstU32<16>; + type PalletId = ElectionPalletId; + type AccountId = AccountId; + type DbWeight = ::DbWeight; + type PalletName = ElectionPalletName; + } + impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { + type Currency = Balances; + type Hash = Hash; + type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = TipReportDepositBase; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = TipsPalletName; + } + + /// Unreleased migrations. Add new ones here: + pub type Unreleased = ( + pallet_contracts::migration::Migration, + // Gov v1 storage migrations + // https://github.com/paritytech/polkadot/issues/6749 + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete all Gov v1 pallet storage key/values. + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + ); +} /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -1490,18 +1371,14 @@ mod benches { [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] - [pallet_collective, Council] [pallet_contracts, Contracts] - [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] - [pallet_elections_phragmen, Elections] [pallet_fast_unstake, FastUnstake] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_im_online, ImOnline] [pallet_indices, Indices] - [pallet_membership, TechnicalMembership] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] @@ -1517,10 +1394,12 @@ mod benches { [pallet_ddc_payouts, DdcPayouts] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] - [pallet_tips, Tips] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_whitelist, Whitelist] ); } diff --git a/runtime/cere/Cargo.toml b/runtime/cere/Cargo.toml index 629071867..f9e36d6a9 100644 --- a/runtime/cere/Cargo.toml +++ b/runtime/cere/Cargo.toml @@ -73,6 +73,7 @@ pallet-treasury = { workspace = true } pallet-utility = { workspace = true } pallet-vesting = { workspace = true } sp-api = { workspace = true } +sp-arithmetic = { workspace = true } sp-authority-discovery = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-babe = { workspace = true } @@ -92,6 +93,7 @@ sp-version = { workspace = true } cere-runtime-common = { workspace = true } ddc-primitives = { workspace = true } pallet-chainbridge = { workspace = true } +pallet-conviction-voting = { workspace = true } pallet-ddc-clusters = { workspace = true } pallet-ddc-customers = { workspace = true } pallet-ddc-nodes = { workspace = true } @@ -99,6 +101,8 @@ pallet-ddc-payouts = { workspace = true } pallet-ddc-staking = { workspace = true } pallet-erc20 = { workspace = true } pallet-erc721 = { workspace = true } +pallet-referenda = { workspace = true } +pallet-whitelist = { workspace = true } [build-dependencies] substrate-wasm-builder = { workspace = true, default-features = true } @@ -143,7 +147,6 @@ std = [ "pallet-scheduler/std", "pallet-offences/std", "pallet-proxy/std", - "pallet-preimage/std", "pallet-insecure-randomness-collective-flip/std", "pallet-session/std", "pallet-staking/std", @@ -180,6 +183,10 @@ std = [ "pallet-ddc-payouts/std", "pallet-ddc-staking/std", "cere-runtime-common/std", + "sp-arithmetic/std", + "pallet-conviction-voting/std", + "pallet-referenda/std", + "pallet-whitelist/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -212,7 +219,6 @@ runtime-benchmarks = [ "pallet-nomination-pools/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", "pallet-offences-benchmarking/runtime-benchmarks", - "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", @@ -227,6 +233,9 @@ runtime-benchmarks = [ "pallet-chainbridge/runtime-benchmarks", "ddc-primitives/runtime-benchmarks", "hex-literal", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", ] try-runtime = [ "frame-executive/try-runtime", @@ -275,4 +284,7 @@ try-runtime = [ "pallet-ddc-staking/try-runtime", "pallet-erc20/try-runtime", "pallet-erc721/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-referenda/try-runtime", + "pallet-whitelist/try-runtime", ] diff --git a/runtime/cere/src/governance/mod.rs b/runtime/cere/src/governance/mod.rs new file mode 100644 index 000000000..1e2c835e6 --- /dev/null +++ b/runtime/cere/src/governance/mod.rs @@ -0,0 +1,70 @@ +use frame_support::parameter_types; +use frame_system::EnsureRootWithSuccess; + +use super::*; + +mod origins; +pub use origins::{ + pallet_custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, Spender, + StakingAdmin, Treasurer, 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 RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = + frame_support::traits::tokens::currency::ActiveIssuanceOf; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = DOLLARS; + pub const UndecidingTimeout: BlockNumber = 14 * DAYS; +} + +parameter_types! { + pub const MaxBalance: Balance = Balance::max_value(); +} +pub type TreasurySpender = EitherOf, Spender>; + +impl origins::pallet_custom_origins::Config for Runtime {} + +impl pallet_whitelist::Config for Runtime { + type WeightInfo = pallet_whitelist::weights::SubstrateWeight; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WhitelistOrigin = EnsureRoot; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = pallet_referenda::weights::SubstrateWeight; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, 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; + type Preimages = Preimage; +} diff --git a/runtime/cere/src/governance/origins.rs b/runtime/cere/src/governance/origins.rs new file mode 100644 index 000000000..dbbfebe20 --- /dev/null +++ b/runtime/cere/src/governance/origins.rs @@ -0,0 +1,129 @@ +//! Custom origins for governance interventions. +pub use pallet_custom_origins::*; + +#[frame_support::pallet] +pub mod pallet_custom_origins { + use frame_support::pallet_prelude::*; + + use crate::{Balance, DOLLARS, GRAND}; + + #[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 able to cancel slashes and manage minimum commission. + StakingAdmin, + /// Origin for spending up to $10,000,000 DOT from the treasury as well as generally + /// administering it. + Treasurer, + /// Origin for managing the composition of the fellowship. + FellowshipAdmin, + /// Origin for managing the registrar. + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Origin able to spend around $250 from the treasury at once. + SmallTipper, + /// Origin able to spend around $1,000 from the treasury at once. + BigTipper, + /// Origin able to spend around $10,000 from the treasury at once. + SmallSpender, + /// Origin able to spend around $100,000 from the treasury at once. + MediumSpender, + /// Origin able to spend up to $1,000,000 DOT 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!( + StakingAdmin, + Treasurer, + FellowshipAdmin, + 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 * DOLLARS, + BigTipper = GRAND, + SmallSpender = 10 * GRAND, + MediumSpender = 100 * GRAND, + BigSpender = 1_000 * GRAND, + Treasurer = 10_000 * GRAND, + } + } +} diff --git a/runtime/cere/src/governance/tracks.rs b/runtime/cere/src/governance/tracks.rs new file mode 100644 index 000000000..da3b0dce1 --- /dev/null +++ b/runtime/cere/src/governance/tracks.rs @@ -0,0 +1,283 @@ +// Copyright 2023 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::*; + +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_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_STAKING_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), 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_FELLOWSHIP_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_FELLOWSHIP_ADMIN: Curve = + Curve::make_reciprocal(12, 28, percent(1), 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(5), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 13] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 100 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_ROOT, + min_support: SUP_ROOT, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * GRAND, + prepare_period: 30 * MINUTES, + decision_period: 28 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 10 * MINUTES, + min_approval: APP_WHITELISTED_CALLER, + min_support: SUP_WHITELISTED_CALLER, + }, + ), + ( + 10, + pallet_referenda::TrackInfo { + name: "staking_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_STAKING_ADMIN, + min_support: SUP_STAKING_ADMIN, + }, + ), + ( + 11, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 10, + decision_deposit: GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_TREASURER, + min_support: SUP_TREASURER, + }, + ), + ( + 13, + pallet_referenda::TrackInfo { + name: "fellowship_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_FELLOWSHIP_ADMIN, + min_support: SUP_FELLOWSHIP_ADMIN, + }, + ), + ( + 14, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 5 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_GENERAL_ADMIN, + min_support: SUP_GENERAL_ADMIN, + }, + ), + ( + 20, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 1_000, + decision_deposit: 10 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 7 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_CANCELLER, + min_support: SUP_REFERENDUM_CANCELLER, + }, + ), + ( + 21, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 1_000, + decision_deposit: 50 * GRAND, + prepare_period: 2 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_REFERENDUM_KILLER, + min_support: SUP_REFERENDUM_KILLER, + }, + ), + ( + 30, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 200, + decision_deposit: DOLLARS, + prepare_period: MINUTES, + decision_period: 7 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: MINUTES, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 31, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 100, + decision_deposit: 10 * DOLLARS, + prepare_period: 10 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: APP_BIG_TIPPER, + min_support: SUP_BIG_TIPPER, + }, + ), + ( + 32, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 50, + decision_deposit: 100 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 12 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_SMALL_SPENDER, + min_support: SUP_SMALL_SPENDER, + }, + ), + ( + 33, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 50, + decision_deposit: 200 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_MEDIUM_SPENDER, + min_support: SUP_MEDIUM_SPENDER, + }, + ), + ( + 34, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 50, + decision_deposit: 400 * DOLLARS, + prepare_period: 4 * HOURS, + decision_period: 28 * DAYS, + confirm_period: 48 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_BIG_SPENDER, + min_support: SUP_BIG_SPENDER, + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> 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::StakingAdmin => Ok(10), + origins::Origin::Treasurer => Ok(11), + origins::Origin::FellowshipAdmin => Ok(13), + origins::Origin::GeneralAdmin => Ok(14), + // Referendum admins + origins::Origin::ReferendumCanceller => Ok(20), + origins::Origin::ReferendumKiller => Ok(21), + // Limited treasury spenders + origins::Origin::SmallTipper => Ok(30), + origins::Origin::BigTipper => Ok(31), + origins::Origin::SmallSpender => Ok(32), + origins::Origin::MediumSpender => Ok(33), + origins::Origin::BigSpender => Ok(34), + } + } else { + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/runtime/cere/src/lib.rs b/runtime/cere/src/lib.rs index c408bc579..1053f5b6a 100644 --- a/runtime/cere/src/lib.rs +++ b/runtime/cere/src/lib.rs @@ -32,8 +32,8 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, - Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, + ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOf, EitherOfDiverse, + EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, Nothing, OnUnbalanced, WithdrawReasons, }, weights::{ @@ -103,6 +103,10 @@ use cere_runtime_common::{ use impls::Author; use sp_runtime::generic::Era; +// Governance configurations. +pub mod governance; +use governance::{pallet_custom_origins, GeneralAdmin, StakingAdmin, Treasurer, TreasurySpender}; + /// Generated voter bag information. mod voter_bags; @@ -302,15 +306,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Balances(..) | RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) | RuntimeCall::Indices(pallet_indices::Call::transfer { .. }) | - RuntimeCall::NominationPools(..) + RuntimeCall::NominationPools(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) ), ProxyType::Governance => matches!( c, - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | - RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::Elections(..) | - RuntimeCall::Treasury(..) + RuntimeCall::Treasury(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) ), ProxyType::Staking => matches!(c, RuntimeCall::Staking(..)), } @@ -532,11 +538,6 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxValidators = ConstU32<1000>; } -type StakingAdminOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, ->; - impl pallet_staking::Config for Runtime { type Currency = Balances; type CurrencyBalance = Balance; @@ -549,7 +550,7 @@ impl pallet_staking::Config for Runtime { type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = StakingAdminOrigin; + type AdminOrigin = EitherOf, StakingAdmin>; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; @@ -569,7 +570,7 @@ impl pallet_staking::Config for Runtime { impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ControlOrigin = frame_system::EnsureRoot; + type ControlOrigin = EnsureRoot; type Deposit = ConstU128<{ DOLLARS }>; type Currency = Balances; type BatchSize = frame_support::traits::ConstU32<64>; @@ -733,7 +734,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { )>; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen, OffchainRandomBalancing>; - type ForceOrigin = EnsureRootOrHalfCouncil; + type ForceOrigin = EitherOf, StakingAdmin>; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; type MaxWinners = MaxActiveValidators; @@ -753,165 +754,6 @@ impl pallet_bags_list::Config for Runtime { type Score = VoteWeight; } -parameter_types! { - pub const LaunchPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const VotingPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const FastTrackVotingPeriod: BlockNumber = 3 * 60 * MINUTES; - pub const MinimumDeposit: Balance = 50_000 * DOLLARS; - pub const EnactmentPeriod: BlockNumber = 24 * 60 * MINUTES; - pub const CooloffPeriod: BlockNumber = 7 * 24 * 60 * MINUTES; - pub const MaxProposals: u32 = 100; -} - -impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = EnactmentPeriod; // Same as EnactmentPeriod - type MinimumDeposit = MinimumDeposit; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = - pallet_collective::EnsureProportionAtLeast; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = - pallet_collective::EnsureProportionAtLeast; - /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantOrigin = - pallet_collective::EnsureProportionAtLeast; - type InstantAllowed = frame_support::traits::ConstBool; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = - pallet_collective::EnsureProportionAtLeast; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type BlacklistOrigin = EnsureRoot; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cool-off period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type SubmitOrigin = frame_system::EnsureSigned; - type PalletsOrigin = OriginCaller; - type MaxVotes = ConstU32<100>; - type WeightInfo = pallet_democracy::weights::SubstrateWeight; - type MaxProposals = MaxProposals; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; -} - -parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 7 * DAYS; - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; -} - -type CouncilCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type SetMembersOrigin = EnsureRoot; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type MaxProposalWeight = MaxCollectivesProposalWeight; -} - -parameter_types! { - pub const CandidacyBond: Balance = 5_000_000 * DOLLARS; - // 1 storage item created, key size is 32 bytes, value size is 16+16. - pub const VotingBondBase: Balance = deposit(1, 64); - pub const VotingBondFactor: Balance = DOLLARS; - pub const TermDuration: BlockNumber = 182 * DAYS; - pub const DesiredMembers: u32 = 13; - pub const DesiredRunnersUp: u32 = 20; - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; - pub const MaxVoters: u32 = 10 * 1000; - pub const MaxVotesPerVoter: u32 = 16; - pub const MaxCandidates: u32 = 1000; -} - -// Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. -const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); - -impl pallet_elections_phragmen::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletId = ElectionsPhragmenPalletId; - type Currency = Balances; - type ChangeMembers = Council; - // NOTE: this implies that council's genesis members cannot be set directly and must come from - // this module. - type InitializeMembers = Council; - type CurrencyToVote = CurrencyToVote; - type CandidacyBond = CandidacyBond; - type VotingBondBase = VotingBondBase; - type VotingBondFactor = VotingBondFactor; - type LoserCandidate = (); - type KickedMember = (); - type DesiredMembers = DesiredMembers; - type DesiredRunnersUp = DesiredRunnersUp; - type TermDuration = TermDuration; - type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; - type MaxVoters = MaxVoters; - type MaxVotesPerVoter = MaxVotesPerVoter; - type MaxCandidates = MaxCandidates; -} - -parameter_types! { - pub const TechnicalMotionDuration: BlockNumber = 5 * DAYS; - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; -} - -type TechnicalCollective = pallet_collective::Instance2; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type SetMembersOrigin = EnsureRoot; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type MaxProposalWeight = MaxCollectivesProposalWeight; -} - -type EnsureRootOrHalfCouncil = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, ->; -impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRootOrHalfCouncil; - type RemoveOrigin = EnsureRootOrHalfCouncil; - type SwapOrigin = EnsureRootOrHalfCouncil; - type ResetOrigin = EnsureRootOrHalfCouncil; - type PrimeOrigin = EnsureRootOrHalfCouncil; - type MembershipInitialized = TechnicalCommittee; - type MembershipChanged = TechnicalCommittee; - type MaxMembers = TechnicalMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; -} - parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const ProposalBondMinimum: Balance = 50_000 * DOLLARS; @@ -929,14 +771,8 @@ parameter_types! { impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; - type ApproveOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type RejectOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionMoreThan, - >; + type ApproveOrigin = EitherOfDiverse, Treasurer>; + type RejectOrigin = EitherOfDiverse, Treasurer>; type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; @@ -948,7 +784,7 @@ impl pallet_treasury::Config for Runtime { type SpendFunds = Bounties; type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; + type SpendOrigin = TreasurySpender; } parameter_types! { @@ -988,17 +824,6 @@ impl pallet_child_bounties::Config for Runtime { type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } -impl pallet_tips::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; - type Tippers = Elections; - type TipCountdown = TipCountdown; - type TipFindersFee = TipFindersFee; - type TipReportDepositBase = TipReportDepositBase; - type WeightInfo = pallet_tips::weights::SubstrateWeight; -} - parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); @@ -1183,8 +1008,8 @@ impl pallet_identity::Config for Runtime { type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; - type ForceOrigin = EnsureRootOrHalfCouncil; - type RegistrarOrigin = EnsureRootOrHalfCouncil; + type ForceOrigin = EitherOf, GeneralAdmin>; + type RegistrarOrigin = EitherOf, GeneralAdmin>; type WeightInfo = pallet_identity::weights::SubstrateWeight; } @@ -1369,11 +1194,6 @@ construct_runtime!( ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, Session: pallet_session, - Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, - Elections: pallet_elections_phragmen, - TechnicalMembership: pallet_membership::, Grandpa: pallet_grandpa, Treasury: pallet_treasury, Contracts: pallet_contracts, @@ -1391,7 +1211,6 @@ construct_runtime!( Proxy: pallet_proxy, Multisig: pallet_multisig, Bounties: pallet_bounties, - Tips: pallet_tips, VoterList: pallet_bags_list::, ChildBounties: pallet_child_bounties, NominationPools: pallet_nomination_pools, @@ -1403,7 +1222,13 @@ construct_runtime!( DdcCustomers: pallet_ddc_customers, DdcNodes: pallet_ddc_nodes, DdcClusters: pallet_ddc_clusters, - DdcPayouts: pallet_ddc_payouts + DdcPayouts: pallet_ddc_payouts, + // Start OpenGov. + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event}, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event}, + Origins: pallet_custom_origins::{Origin}, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event}, + // End OpenGov. } ); @@ -1442,27 +1267,83 @@ pub type SignedPayload = generic::SignedPayload; pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Runtime migrations -type Migrations = ( - pallet_contracts::migration::Migration, - // TODO: Leaving this for the OpenGov PR - // Gov v1 storage migrations - // https://github.com/paritytech/polkadot/issues/6749 - // pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - // pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, - // pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, - - // Delete all Gov v1 pallet storage key/values. - // frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, - // frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, -); +type Migrations = migrations::Unreleased; + +/// The runtime migrations per release. +#[allow(deprecated, missing_docs)] +pub mod migrations { + use frame_support::traits::LockIdentifier; + use frame_system::pallet_prelude::BlockNumberFor; + + use super::*; + + parameter_types! { + pub const DemocracyPalletName: &'static str = "Democracy"; + pub const CouncilPalletName: &'static str = "Council"; + pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; + pub const ElectionPalletName: &'static str = "Elections"; + pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; + pub const TipsPalletName: &'static str = "Tips"; + pub const ElectionPalletId: LockIdentifier = *b"phrelect"; + } + + // Special Config for Gov V1 pallets, allowing us to run migrations for them without + // implementing their configs on [`Runtime`]. + pub struct UnlockConfig; + impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { + type Currency = Balances; + type MaxVotes = ConstU32<100>; + type MaxDeposits = ConstU32<100>; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = DemocracyPalletName; + } + impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig + for UnlockConfig + { + type Currency = Balances; + type MaxVotesPerVoter = ConstU32<16>; + type PalletId = ElectionPalletId; + type AccountId = AccountId; + type DbWeight = ::DbWeight; + type PalletName = ElectionPalletName; + } + impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { + type Currency = Balances; + type Hash = Hash; + type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = TipReportDepositBase; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = TipsPalletName; + } + + /// Unreleased migrations. Add new ones here: + pub type Unreleased = ( + pallet_contracts::migration::Migration, + // Gov v1 storage migrations + // https://github.com/paritytech/polkadot/issues/6749 + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete all Gov v1 pallet storage key/values. + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + ); +} /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -1492,23 +1373,19 @@ mod benches { [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] - [pallet_collective, Council] [pallet_contracts, Contracts] [pallet_ddc_customers, DdcCustomers] [pallet_ddc_clusters, DdcClusters] [pallet_ddc_staking, DdcStaking] [pallet_ddc_nodes, DdcNodes] [pallet_ddc_payouts, DdcPayouts] - [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] - [pallet_elections_phragmen, Elections] [pallet_fast_unstake, FastUnstake] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_im_online, ImOnline] [pallet_indices, Indices] - [pallet_membership, TechnicalMembership] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] @@ -1519,10 +1396,12 @@ mod benches { [pallet_staking, Staking] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] - [pallet_tips, Tips] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_whitelist, Whitelist] ); } diff --git a/runtime/common/src/constants.rs b/runtime/common/src/constants.rs index aa4dcd79b..78831f532 100644 --- a/runtime/common/src/constants.rs +++ b/runtime/common/src/constants.rs @@ -24,6 +24,7 @@ pub mod currency { pub const MILLICENTS: Balance = 100_000; pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. pub const DOLLARS: Balance = 100 * CENTS; + pub const GRAND: Balance = DOLLARS * 1_000; pub const fn deposit(items: u32, bytes: u32) -> Balance { items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS