Browse Source

Merge pull request #1366 from iorveth/proposal_codex_upgrade

Proposal codex upgrade
Bedeho Mender 4 years ago
parent
commit
d8bba207a8

+ 24 - 5
Cargo.lock

@@ -2117,6 +2117,7 @@ dependencies = [
  "sp-std",
  "sp-transaction-pool",
  "sp-version",
+ "strum 0.19.2",
  "substrate-wasm-builder-runner",
 ]
 
@@ -3301,6 +3302,8 @@ dependencies = [
  "parity-scale-codec",
  "serde",
  "sp-runtime",
+ "strum 0.19.2",
+ "strum_macros 0.19.2",
 ]
 
 [[package]]
@@ -3529,7 +3532,6 @@ dependencies = [
  "frame-system",
  "pallet-balances",
  "pallet-common",
- "pallet-content-working-group",
  "pallet-governance",
  "pallet-hiring",
  "pallet-membership",
@@ -3541,8 +3543,6 @@ dependencies = [
  "pallet-staking-reward-curve",
  "pallet-timestamp",
  "pallet-token-mint",
- "pallet-versioned-store",
- "pallet-versioned-store-permissions",
  "pallet-working-group",
  "parity-scale-codec",
  "serde",
@@ -3552,6 +3552,7 @@ dependencies = [
  "sp-runtime",
  "sp-staking",
  "sp-std",
+ "strum 0.19.2",
 ]
 
 [[package]]
@@ -6459,7 +6460,7 @@ dependencies = [
  "lazy_static",
  "sp-core",
  "sp-runtime",
- "strum",
+ "strum 0.16.0",
 ]
 
 [[package]]
@@ -6802,9 +6803,15 @@ version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
 dependencies = [
- "strum_macros",
+ "strum_macros 0.16.0",
 ]
 
+[[package]]
+name = "strum"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3924a58d165da3b7b2922c667ab0673c7b5fd52b5c19ea3442747bcb3cd15abe"
+
 [[package]]
 name = "strum_macros"
 version = "0.16.0"
@@ -6817,6 +6824,18 @@ dependencies = [
  "syn 1.0.17",
 ]
 
+[[package]]
+name = "strum_macros"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d2ab682ecdcae7f5f45ae85cd7c1e6c8e68ea42c8a612d47fedf831c037146a"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote 1.0.7",
+ "syn 1.0.17",
+]
+
 [[package]]
 name = "substrate-bip39"
 version = "0.4.1"

+ 2 - 8
node/src/chain_spec/mod.rs

@@ -352,12 +352,6 @@ pub fn testnet_genesis(
                 .set_election_parameters_proposal_voting_period,
             set_election_parameters_proposal_grace_period: cpcp
                 .set_election_parameters_proposal_grace_period,
-            set_content_working_group_mint_capacity_proposal_voting_period: cpcp
-                .set_content_working_group_mint_capacity_proposal_voting_period,
-            set_content_working_group_mint_capacity_proposal_grace_period: cpcp
-                .set_content_working_group_mint_capacity_proposal_grace_period,
-            set_lead_proposal_voting_period: cpcp.set_lead_proposal_voting_period,
-            set_lead_proposal_grace_period: cpcp.set_lead_proposal_grace_period,
             spending_proposal_voting_period: cpcp.spending_proposal_voting_period,
             spending_proposal_grace_period: cpcp.spending_proposal_grace_period,
             add_working_group_opening_proposal_voting_period: cpcp
@@ -373,9 +367,9 @@ pub fn testnet_genesis(
             fill_working_group_leader_opening_proposal_grace_period: cpcp
                 .fill_working_group_leader_opening_proposal_grace_period,
             set_working_group_mint_capacity_proposal_voting_period: cpcp
-                .set_content_working_group_mint_capacity_proposal_voting_period,
+                .set_working_group_mint_capacity_proposal_voting_period,
             set_working_group_mint_capacity_proposal_grace_period: cpcp
-                .set_content_working_group_mint_capacity_proposal_grace_period,
+                .set_working_group_mint_capacity_proposal_grace_period,
             decrease_working_group_leader_stake_proposal_voting_period: cpcp
                 .decrease_working_group_leader_stake_proposal_voting_period,
             decrease_working_group_leader_stake_proposal_grace_period: cpcp

+ 4 - 0
runtime-modules/common/Cargo.toml

@@ -6,6 +6,8 @@ edition = '2018'
 
 [dependencies]
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
+strum = {version = "0.19", optional = true}
+strum_macros = {version = "0.19", optional = true}
 codec = { package = 'parity-scale-codec', version = '1.3.1', default-features = false, features = ['derive'] }
 sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
 frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
@@ -16,6 +18,8 @@ pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git
 default = ['std']
 std = [
 	'serde',
+	'strum',
+	'strum_macros',
 	'codec/std',
 	'sp-runtime/std',
 	'frame-support/std',

+ 5 - 1
runtime-modules/common/src/working_group.rs

@@ -1,9 +1,11 @@
 use codec::{Decode, Encode};
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
+#[cfg(feature = "std")]
+use strum_macros::EnumIter;
 
 /// Defines well-known working groups.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, EnumIter))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Copy, Debug)]
 pub enum WorkingGroup {
     /* Reserved
@@ -12,4 +14,6 @@ pub enum WorkingGroup {
     */
     /// Storage working group: working_group::Instance2.
     Storage,
+    /// Storage working group: working_group::Instance3.
+    Content,
 }

+ 2 - 2
runtime-modules/content-directory/src/lib.rs

@@ -2554,9 +2554,9 @@ impl<T: Trait> Module<T> {
         maximum_entities_count: T::EntityId,
         default_entity_creation_voucher_upper_bound: T::EntityId,
     ) -> Result<(), Error<T>> {
-        // Ensure `per_controller_entities_creation_limit` does not exceed
+        // Ensure default_entity_creation_voucher_upper_bound does not exceed default_entity_creation_voucher_upper_bound
         ensure!(
-            default_entity_creation_voucher_upper_bound < maximum_entities_count,
+            default_entity_creation_voucher_upper_bound <= maximum_entities_count,
             Error::<T>::PerControllerEntitiesCreationLimitExceedsOverallLimit
         );
 

+ 1 - 1
runtime-modules/governance/src/mock.rs

@@ -71,7 +71,7 @@ impl election::Trait for Test {
 }
 impl membership::Trait for Test {
     type Event = ();
-    type MemberId = u32;
+    type MemberId = u64;
     type SubscriptionId = u32;
     type PaidTermId = u32;
     type ActorId = u32;

+ 1 - 1
runtime-modules/membership/src/mock.rs

@@ -80,7 +80,7 @@ impl GovernanceCurrency for Test {
 
 impl Trait for Test {
     type Event = ();
-    type MemberId = u32;
+    type MemberId = u64;
     type PaidTermId = u32;
     type SubscriptionId = u32;
     type ActorId = u32;

+ 1 - 1
runtime-modules/membership/src/tests.rs

@@ -5,7 +5,7 @@ use super::mock::*;
 
 use frame_support::*;
 
-fn get_membership_by_id(member_id: u32) -> crate::Membership<Test> {
+fn get_membership_by_id(member_id: u64) -> crate::Membership<Test> {
     if <crate::MembershipById<Test>>::contains_key(member_id) {
         Members::membership(member_id)
     } else {

+ 1 - 4
runtime-modules/proposals/codex/Cargo.toml

@@ -21,7 +21,6 @@ governance = { package = 'pallet-governance', default-features = false, path = '
 hiring = { package = 'pallet-hiring', default-features = false, path = '../../hiring'}
 minting = { package = 'pallet-token-mint', default-features = false, path = '../../token-minting'}
 working-group = { package = 'pallet-working-group', default-features = false, path = '../../working-group'}
-content-working-group = { package = 'pallet-content-working-group', default-features = false, path = '../../content-working-group'}
 common = { package = 'pallet-common', default-features = false, path = '../../common'}
 proposals-engine = { package = 'pallet-proposals-engine', default-features = false, path = '../engine'}
 proposals-discussion = { package = 'pallet-proposals-discussion', default-features = false, path = '../discussion'}
@@ -32,8 +31,7 @@ sp-core = { package = 'sp-core', default-features = false, git = 'https://github
 sp-staking = { package = 'sp-staking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
 pallet-staking-reward-curve = { package = 'pallet-staking-reward-curve', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
 recurring-rewards = { package = 'pallet-recurring-reward', default-features = false, path = '../../recurring-reward'}
-versioned-store = { package = 'pallet-versioned-store', default-features = false, path = '../../versioned-store'}
-versioned-store-permissions = { package = 'pallet-versioned-store-permissions', default-features = false, path = '../../versioned-store-permissions'}
+strum = {version = "0.19", default-features = false}
 
 [features]
 default = ['std']
@@ -53,7 +51,6 @@ std = [
     'governance/std',
     'hiring/std',
     'minting/std',
-    'content-working-group/std',
     'working-group/std',
     'common/std',
     'proposals-engine/std',

+ 1 - 99
runtime-modules/proposals/codex/src/lib.rs

@@ -21,10 +21,6 @@
 //! - [create_set_election_parameters_proposal](./struct.Module.html#method.create_set_election_parameters_proposal)
 //! - [create_spending_proposal](./struct.Module.html#method.create_spending_proposal)
 //!
-//! ### Content working group proposals
-//! - [create_set_lead_proposal](./struct.Module.html#method.create_set_lead_proposal)
-//! - [create_set_content_working_group_mint_capacity_proposal](./struct.Module.html#method.create_set_content_working_group_mint_capacity_proposal)
-//!
 //! ### Working group proposals
 //! - [create_add_working_group_leader_opening_proposal](./struct.Module.html#method.create_add_working_group_leader_opening_proposal)
 //! - [create_begin_review_working_group_leader_applications_proposal](./struct.Module.html#method.create_begin_review_working_group_leader_applications_proposal)
@@ -86,8 +82,6 @@ pub use proposal_types::{ProposalDetails, ProposalDetailsOf, ProposalEncoder};
 
 // 'Set working group mint capacity' proposal limit
 const WORKING_GROUP_MINT_CAPACITY_MAX_VALUE: u32 = 5_000_000;
-// 'Set content working group mint capacity' proposal limit
-const CONTENT_WORKING_GROUP_MINT_CAPACITY_MAX_VALUE: u32 = 1_000_000;
 // Max allowed value for 'spending' proposal
 const MAX_SPENDING_PROPOSAL_VALUE: u32 = 5_000_000_u32;
 // Max validator count for the 'set validator count' proposal
@@ -145,7 +139,7 @@ pub trait Trait:
     + proposals_discussion::Trait
     + membership::Trait
     + governance::election::Trait
-    + content_working_group::Trait
+    + hiring::Trait
     + staking::Trait
 {
     /// Defines max allowed text proposal length.
@@ -294,22 +288,6 @@ decl_storage! {
         /// Grace period for the 'text' proposal
         pub TextProposalGracePeriod get(fn text_proposal_grace_period) config(): T::BlockNumber;
 
-        /// Voting period for the 'set content working group mint capacity' proposal
-        pub SetContentWorkingGroupMintCapacityProposalVotingPeriod get(fn set_content_working_group_mint_capacity_proposal_voting_period)
-            config(): T::BlockNumber;
-
-        /// Grace period for the 'set content working group mint capacity' proposal
-        pub SetContentWorkingGroupMintCapacityProposalGracePeriod get(fn set_content_working_group_mint_capacity_proposal_grace_period)
-            config(): T::BlockNumber;
-
-        /// Voting period for the 'set lead' proposal
-        pub SetLeadProposalVotingPeriod get(fn set_lead_proposal_voting_period)
-            config(): T::BlockNumber;
-
-        /// Grace period for the 'set lead' proposal
-        pub SetLeadProposalGracePeriod get(fn set_lead_proposal_grace_period)
-            config(): T::BlockNumber;
-
         /// Voting period for the 'spending' proposal
         pub SpendingProposalVotingPeriod get(fn spending_proposal_voting_period) config(): T::BlockNumber;
 
@@ -477,37 +455,6 @@ decl_module! {
             Self::create_proposal(params)?;
         }
 
-        /// Create 'Set content working group mint capacity' proposal type.
-        /// This proposal uses `set_mint_capacity()` extrinsic from the `content-working-group`  module.
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_set_content_working_group_mint_capacity_proposal(
-            origin,
-            member_id: MemberId<T>,
-            title: Vec<u8>,
-            description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
-            mint_balance: BalanceOfMint<T>,
-        ) {
-            ensure!(
-                mint_balance <= <BalanceOfMint<T>>::from(CONTENT_WORKING_GROUP_MINT_CAPACITY_MAX_VALUE),
-                Error::<T>::InvalidContentWorkingGroupMintCapacity
-            );
-
-            let proposal_details = ProposalDetails::SetContentWorkingGroupMintCapacity(mint_balance);
-            let params = CreateProposalParameters{
-                origin,
-                member_id,
-                title,
-                description,
-                stake_balance,
-                proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_content_working_group_mint_capacity_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
-            };
-
-            Self::create_proposal(params)?;
-        }
-
         /// Create 'Spending' proposal type.
         /// This proposal uses `spend_from_council_mint()` extrinsic from the `governance::council`  module.
         #[weight = 10_000_000] // TODO: adjust weight
@@ -541,39 +488,6 @@ decl_module! {
             Self::create_proposal(params)?;
         }
 
-        /// Create 'Set lead' proposal type.
-        /// This proposal uses `replace_lead()` extrinsic from the `content_working_group`  module.
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_set_lead_proposal(
-            origin,
-            member_id: MemberId<T>,
-            title: Vec<u8>,
-            description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
-            new_lead: Option<(T::MemberId, T::AccountId)>
-        ) {
-            if let Some(lead) = new_lead.clone() {
-                let account_id = lead.1;
-                ensure!(
-                    !<governance::council::Module<T>>::is_councilor(&account_id),
-                    Error::<T>::InvalidSetLeadParameterCannotBeCouncilor
-                );
-            }
-            let proposal_details = ProposalDetails::SetLead(new_lead);
-            let params = CreateProposalParameters{
-                origin,
-                member_id,
-                title,
-                description,
-                stake_balance,
-                proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_lead_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
-            };
-
-            Self::create_proposal(params)?;
-        }
-
         /// Create 'Evict storage provider' proposal type.
         /// This proposal uses `set_validator_count()` extrinsic from the Substrate `staking`  module.
         #[weight = 10_000_000] // TODO: adjust weight
@@ -1063,18 +977,6 @@ impl<T: Trait> Module<T> {
         <SetElectionParametersProposalGracePeriod<T>>::put(T::BlockNumber::from(
             p.set_election_parameters_proposal_grace_period,
         ));
-        <SetContentWorkingGroupMintCapacityProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_content_working_group_mint_capacity_proposal_voting_period,
-        ));
-        <SetContentWorkingGroupMintCapacityProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_content_working_group_mint_capacity_proposal_grace_period,
-        ));
-        <SetLeadProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_lead_proposal_voting_period,
-        ));
-        <SetLeadProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_lead_proposal_grace_period,
-        ));
         <SpendingProposalVotingPeriod<T>>::put(T::BlockNumber::from(
             p.spending_proposal_voting_period,
         ));

+ 0 - 20
runtime-modules/proposals/codex/src/proposal_types/mod.rs

@@ -22,7 +22,6 @@ pub type ProposalDetailsOf<T> = ProposalDetails<
     crate::BalanceOfGovernanceCurrency<T>,
     <T as system::Trait>::BlockNumber,
     <T as system::Trait>::AccountId,
-    crate::MemberId<T>,
     working_group::OpeningId<T>,
     working_group::ApplicationId<T>,
     crate::BalanceOf<T>,
@@ -37,7 +36,6 @@ pub enum ProposalDetails<
     CurrencyBalance,
     BlockNumber,
     AccountId,
-    MemberId,
     OpeningId,
     ApplicationId,
     StakeBalance,
@@ -55,12 +53,6 @@ pub enum ProposalDetails<
     /// Balance and destination account for the `spending` proposal
     Spending(MintedBalance, AccountId),
 
-    /// New leader memberId and account_id for the `set lead` proposal
-    SetLead(Option<(MemberId, AccountId)>),
-
-    /// Balance for the `set content working group mint capacity` proposal
-    SetContentWorkingGroupMintCapacity(MintedBalance),
-
     /// ********** Deprecated during the Nicaea release.
     /// It is kept only for backward compatibility in the Pioneer. **********
     /// AccountId for the `evict storage provider` proposal
@@ -106,7 +98,6 @@ impl<
         CurrencyBalance,
         BlockNumber,
         AccountId,
-        MemberId,
         OpeningId,
         ApplicationId,
         StakeBalance,
@@ -117,7 +108,6 @@ impl<
         CurrencyBalance,
         BlockNumber,
         AccountId,
-        MemberId,
         OpeningId,
         ApplicationId,
         StakeBalance,
@@ -246,12 +236,6 @@ pub struct ProposalsConfigParameters {
     /// 'Set election parameters' proposal grace period
     pub set_election_parameters_proposal_grace_period: u32,
 
-    /// 'Set content working group mint capacity' proposal voting period
-    pub set_content_working_group_mint_capacity_proposal_voting_period: u32,
-
-    /// 'Set content working group mint capacity' proposal grace period
-    pub set_content_working_group_mint_capacity_proposal_grace_period: u32,
-
     /// 'Set lead' proposal voting period
     pub set_lead_proposal_voting_period: u32,
 
@@ -324,8 +308,6 @@ impl Default for ProposalsConfigParameters {
             text_proposal_grace_period: 0u32,
             set_election_parameters_proposal_voting_period: 72000u32,
             set_election_parameters_proposal_grace_period: 201_601_u32,
-            set_content_working_group_mint_capacity_proposal_voting_period: 43200u32,
-            set_content_working_group_mint_capacity_proposal_grace_period: 0u32,
             set_lead_proposal_voting_period: 43200u32,
             set_lead_proposal_grace_period: 0u32,
             spending_proposal_voting_period: 72000u32,
@@ -364,8 +346,6 @@ impl ProposalsConfigParameters {
             text_proposal_grace_period: 0,
             set_election_parameters_proposal_voting_period: voting_period,
             set_election_parameters_proposal_grace_period: grace_period,
-            set_content_working_group_mint_capacity_proposal_voting_period: voting_period,
-            set_content_working_group_mint_capacity_proposal_grace_period: 0,
             set_lead_proposal_voting_period: voting_period,
             set_lead_proposal_grace_period: 0,
             spending_proposal_voting_period: voting_period,

+ 0 - 29
runtime-modules/proposals/codex/src/proposal_types/parameters.rs

@@ -55,21 +55,6 @@ pub(crate) fn set_election_parameters_proposal<T: crate::Trait>(
     }
 }
 
-// Proposal parameters for the 'Set content working group mint capacity' proposal
-pub(crate) fn set_content_working_group_mint_capacity_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_content_working_group_mint_capacity_proposal_voting_period(
-        ),
-        grace_period: <Module<T>>::set_content_working_group_mint_capacity_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
 // Proposal parameters for the 'Spending' proposal
 pub(crate) fn spending_proposal<T: crate::Trait>(
 ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
@@ -84,20 +69,6 @@ pub(crate) fn spending_proposal<T: crate::Trait>(
     }
 }
 
-// Proposal parameters for the 'Set lead' proposal
-pub(crate) fn set_lead_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_lead_proposal_voting_period(),
-        grace_period: <Module<T>>::set_lead_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
 // Proposal parameters for the 'Add working group leader' proposal
 pub(crate) fn add_working_group_leader_opening_proposal<T: crate::Trait>(
 ) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {

+ 17 - 11
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -154,8 +154,24 @@ impl governance::election::Trait for Test {
     type CouncilElected = ();
 }
 
-impl content_working_group::Trait for Test {
+// The content directory working group instance alias.
+pub type ContentDirectoryWorkingGroupInstance = working_group::Instance3;
+
+// The storage working group instance alias.
+pub type StorageWorkingGroupInstance = working_group::Instance2;
+
+parameter_types! {
+    pub const MaxWorkerNumberLimit: u32 = 100;
+}
+
+impl working_group::Trait<ContentDirectoryWorkingGroupInstance> for Test {
     type Event = ();
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+}
+
+impl working_group::Trait<StorageWorkingGroupInstance> for Test {
+    type Event = ();
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
 }
 
 impl recurring_rewards::Trait for Test {
@@ -164,16 +180,6 @@ impl recurring_rewards::Trait for Test {
     type RewardRelationshipId = u64;
 }
 
-impl versioned_store_permissions::Trait for Test {
-    type Credential = u64;
-    type CredentialChecker = ();
-    type CreateClassPermissionsChecker = ();
-}
-
-impl versioned_store::Trait for Test {
-    type Event = ();
-}
-
 impl hiring::Trait for Test {
     type OpeningId = u64;
     type ApplicationId = u64;

+ 131 - 206
runtime-modules/proposals/codex/src/tests/mod.rs

@@ -16,6 +16,8 @@ use crate::*;
 use crate::{BalanceOf, Error, ProposalDetails};
 pub use mock::*;
 
+use strum::IntoEnumIterator;
+
 pub(crate) fn increase_total_balance_issuance(balance: u64) {
     increase_total_balance_issuance_using_account_id(999, balance);
 }
@@ -40,7 +42,7 @@ where
     invalid_stake_call: InvalidStakeCall,
     successful_call: SuccessfulCall,
     proposal_parameters: ProposalParameters<u64, u64>,
-    proposal_details: ProposalDetails<u64, u64, u64, u64, u64, u64, u64, u64, u64>,
+    proposal_details: ProposalDetails<u64, u64, u64, u64, u64, u64, u64, u64>,
 }
 
 impl<InsufficientRightsCall, EmptyStakeCall, InvalidStakeCall, SuccessfulCall>
@@ -471,78 +473,6 @@ fn create_set_election_parameters_call_fails_with_incorrect_parameters() {
     });
 }
 
-#[test]
-fn create_content_working_group_mint_capacity_proposal_fails_with_invalid_parameters() {
-    initial_test_ext().execute_with(|| {
-        increase_total_balance_issuance_using_account_id(1, 500000);
-
-        assert_eq!(
-            ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                RawOrigin::Signed(1).into(),
-                1,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                Some(<BalanceOf<Test>>::from(50000u32)),
-                (crate::CONTENT_WORKING_GROUP_MINT_CAPACITY_MAX_VALUE + 1) as u64,
-            ),
-            Err(Error::<Test>::InvalidContentWorkingGroupMintCapacity.into())
-        );
-    });
-}
-
-#[test]
-fn create_set_content_working_group_mint_capacity_proposal_common_checks_succeed() {
-    initial_test_ext().execute_with(|| {
-        increase_total_balance_issuance(500000);
-
-        let proposal_fixture = ProposalTestFixture {
-            insufficient_rights_call: || {
-                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                    RawOrigin::None.into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    None,
-                    0,
-                )
-            },
-            empty_stake_call: || {
-                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    None,
-                    0,
-                )
-            },
-            invalid_stake_call: || {
-                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    Some(<BalanceOf<Test>>::from(5000u32)),
-                    0,
-                )
-            },
-            successful_call: || {
-                ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    Some(<BalanceOf<Test>>::from(50000u32)),
-                    10,
-                )
-            },
-            proposal_parameters: crate::proposal_types::parameters::set_content_working_group_mint_capacity_proposal::<Test>(),
-            proposal_details: ProposalDetails::SetContentWorkingGroupMintCapacity(10),
-        };
-        proposal_fixture.check_all();
-    });
-}
-
 #[test]
 fn create_spending_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
@@ -633,85 +563,6 @@ fn create_spending_proposal_call_fails_with_incorrect_balance() {
     });
 }
 
-#[test]
-fn create_set_lead_proposal_fails_with_proposed_councilor() {
-    initial_test_ext().execute_with(|| {
-        increase_total_balance_issuance_using_account_id(1, 500000);
-
-        let lead_account_id = 20;
-        <governance::council::Module<Test>>::set_council(
-            RawOrigin::Root.into(),
-            vec![lead_account_id],
-        )
-        .unwrap();
-
-        assert_eq!(
-            ProposalCodex::create_set_lead_proposal(
-                RawOrigin::Signed(1).into(),
-                1,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                Some(<BalanceOf<Test>>::from(1250u32)),
-                Some((20, lead_account_id)),
-            ),
-            Err(Error::<Test>::InvalidSetLeadParameterCannotBeCouncilor.into())
-        );
-    });
-}
-
-#[test]
-fn create_set_lead_proposal_common_checks_succeed() {
-    initial_test_ext().execute_with(|| {
-        increase_total_balance_issuance(500000);
-
-        let proposal_fixture = ProposalTestFixture {
-            insufficient_rights_call: || {
-                ProposalCodex::create_set_lead_proposal(
-                    RawOrigin::None.into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    None,
-                    Some((20, 10)),
-                )
-            },
-            empty_stake_call: || {
-                ProposalCodex::create_set_lead_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    None,
-                    Some((20, 10)),
-                )
-            },
-            invalid_stake_call: || {
-                ProposalCodex::create_set_lead_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    Some(<BalanceOf<Test>>::from(5000u32)),
-                    Some((20, 10)),
-                )
-            },
-            successful_call: || {
-                ProposalCodex::create_set_lead_proposal(
-                    RawOrigin::Signed(1).into(),
-                    1,
-                    b"title".to_vec(),
-                    b"body".to_vec(),
-                    Some(<BalanceOf<Test>>::from(50000u32)),
-                    Some((20, 10)),
-                )
-            },
-            proposal_parameters: crate::proposal_types::parameters::set_lead_proposal::<Test>(),
-            proposal_details: ProposalDetails::SetLead(Some((20, 10))),
-        };
-        proposal_fixture.check_all();
-    });
-}
-
 #[test]
 fn create_set_validator_count_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
@@ -838,22 +689,6 @@ fn set_default_proposal_parameters_succeeded() {
             <SetElectionParametersProposalGracePeriod<Test>>::get(),
             p.set_election_parameters_proposal_grace_period as u64
         );
-        assert_eq!(
-            <SetContentWorkingGroupMintCapacityProposalVotingPeriod<Test>>::get(),
-            p.set_content_working_group_mint_capacity_proposal_voting_period as u64
-        );
-        assert_eq!(
-            <SetContentWorkingGroupMintCapacityProposalGracePeriod<Test>>::get(),
-            p.set_content_working_group_mint_capacity_proposal_grace_period as u64
-        );
-        assert_eq!(
-            <SetLeadProposalVotingPeriod<Test>>::get(),
-            p.set_lead_proposal_voting_period as u64
-        );
-        assert_eq!(
-            <SetLeadProposalGracePeriod<Test>>::get(),
-            p.set_lead_proposal_grace_period as u64
-        );
         assert_eq!(
             <SpendingProposalVotingPeriod<Test>>::get(),
             p.spending_proposal_voting_period as u64
@@ -931,12 +766,21 @@ fn set_default_proposal_parameters_succeeded() {
 
 #[test]
 fn create_add_working_group_leader_opening_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_add_working_group_leader_opening_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_add_working_group_leader_opening_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         let add_opening_parameters = AddOpeningParameters {
             activate_at: ActivateOpeningAt::CurrentBlock,
             commitment: OpeningPolicyCommitment::default(),
             human_readable_text: b"some text".to_vec(),
-            working_group: WorkingGroup::Storage,
+            working_group,
         };
 
         increase_total_balance_issuance_using_account_id(1, 500000);
@@ -993,6 +837,17 @@ fn create_add_working_group_leader_opening_proposal_common_checks_succeed() {
 
 #[test]
 fn create_begin_review_working_group_leader_applications_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_begin_review_working_group_leader_applications_proposal_common_checks_succeed(
+            group,
+        );
+    }
+}
+
+fn run_create_begin_review_working_group_leader_applications_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         let opening_id = 1; // random opening id.
 
@@ -1007,7 +862,7 @@ fn create_begin_review_working_group_leader_applications_proposal_common_checks_
                     b"body".to_vec(),
                     None,
                     opening_id,
-                    WorkingGroup::Storage
+                    working_group
                 )
             },
             empty_stake_call: || {
@@ -1018,7 +873,7 @@ fn create_begin_review_working_group_leader_applications_proposal_common_checks_
                     b"body".to_vec(),
                     None,
                     opening_id,
-                    WorkingGroup::Storage
+                    working_group
                 )
             },
             invalid_stake_call: || {
@@ -1029,7 +884,7 @@ fn create_begin_review_working_group_leader_applications_proposal_common_checks_
                     b"body".to_vec(),
                     Some(<BalanceOf<Test>>::from(5000u32)),
                     opening_id,
-                    WorkingGroup::Storage
+                    working_group
                 )
             },
             successful_call: || {
@@ -1040,14 +895,14 @@ fn create_begin_review_working_group_leader_applications_proposal_common_checks_
                     b"body".to_vec(),
                     Some(<BalanceOf<Test>>::from(25000u32)),
                     opening_id,
-                    WorkingGroup::Storage
+                    working_group
                 )
             },
             proposal_parameters: crate::proposal_types::parameters::begin_review_working_group_leader_applications_proposal::<
                 Test,
             >(),
             proposal_details: ProposalDetails::BeginReviewWorkingGroupLeaderApplications(opening_id,
-                WorkingGroup::Storage),
+                working_group),
         };
         proposal_fixture.check_all();
     });
@@ -1055,6 +910,15 @@ fn create_begin_review_working_group_leader_applications_proposal_common_checks_
 
 #[test]
 fn create_fill_working_group_leader_opening_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_fill_working_group_leader_opening_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_fill_working_group_leader_opening_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         let opening_id = 1; // random opening id.
 
@@ -1062,7 +926,7 @@ fn create_fill_working_group_leader_opening_proposal_common_checks_succeed() {
             opening_id,
             successful_application_id: 1,
             reward_policy: None,
-            working_group: WorkingGroup::Storage,
+            working_group,
         };
 
         increase_total_balance_issuance_using_account_id(1, 500000);
@@ -1119,6 +983,15 @@ fn create_fill_working_group_leader_opening_proposal_common_checks_succeed() {
 
 #[test]
 fn create_working_group_mint_capacity_proposal_fails_with_invalid_parameters() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_working_group_mint_capacity_proposal_fails_with_invalid_parameters(group);
+    }
+}
+
+fn run_create_working_group_mint_capacity_proposal_fails_with_invalid_parameters(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance_using_account_id(1, 500000);
 
@@ -1130,7 +1003,7 @@ fn create_working_group_mint_capacity_proposal_fails_with_invalid_parameters() {
                 b"body".to_vec(),
                 Some(<BalanceOf<Test>>::from(50000u32)),
                 (crate::WORKING_GROUP_MINT_CAPACITY_MAX_VALUE + 1) as u64,
-                WorkingGroup::Storage,
+                working_group,
             ),
             Err(Error::<Test>::InvalidWorkingGroupMintCapacity.into())
         );
@@ -1139,6 +1012,15 @@ fn create_working_group_mint_capacity_proposal_fails_with_invalid_parameters() {
 
 #[test]
 fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_set_working_group_mint_capacity_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_set_working_group_mint_capacity_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance(500000);
 
@@ -1151,7 +1033,7 @@ fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
                     b"body".to_vec(),
                     None,
                     0,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             empty_stake_call: || {
@@ -1162,7 +1044,7 @@ fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
                     b"body".to_vec(),
                     None,
                     0,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             invalid_stake_call: || {
@@ -1173,7 +1055,7 @@ fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
                     b"body".to_vec(),
                     Some(<BalanceOf<Test>>::from(5000u32)),
                     0,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             successful_call: || {
@@ -1184,16 +1066,13 @@ fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
                     b"body".to_vec(),
                     Some(<BalanceOf<Test>>::from(50000u32)),
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             proposal_parameters:
                 crate::proposal_types::parameters::set_working_group_mint_capacity_proposal::<Test>(
                 ),
-            proposal_details: ProposalDetails::SetWorkingGroupMintCapacity(
-                10,
-                WorkingGroup::Storage,
-            ),
+            proposal_details: ProposalDetails::SetWorkingGroupMintCapacity(10, working_group),
         };
         proposal_fixture.check_all();
     });
@@ -1201,6 +1080,15 @@ fn create_set_working_group_mint_capacity_proposal_common_checks_succeed() {
 
 #[test]
 fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_decrease_working_group_leader_stake_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_decrease_working_group_leader_stake_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance(500000);
 
@@ -1214,7 +1102,7 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             empty_stake_call: || {
@@ -1226,7 +1114,7 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             invalid_stake_call: || {
@@ -1238,7 +1126,7 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(5000u32)),
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             successful_call: || {
@@ -1250,7 +1138,7 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(50000u32)),
                     10,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             proposal_parameters:
@@ -1260,7 +1148,7 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
             proposal_details: ProposalDetails::DecreaseWorkingGroupLeaderStake(
                 10,
                 10,
-                WorkingGroup::Storage,
+                working_group,
             ),
         };
         proposal_fixture.check_all();
@@ -1269,6 +1157,15 @@ fn create_decrease_working_group_leader_stake_proposal_common_checks_succeed() {
 
 #[test]
 fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_slash_working_group_leader_stake_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_slash_working_group_leader_stake_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance(500000);
 
@@ -1282,7 +1179,7 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             empty_stake_call: || {
@@ -1294,7 +1191,7 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             invalid_stake_call: || {
@@ -1306,7 +1203,7 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(5000u32)),
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             successful_call: || {
@@ -1318,7 +1215,7 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(50000u32)),
                     10,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             proposal_parameters:
@@ -1328,7 +1225,7 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
             proposal_details: ProposalDetails::SlashWorkingGroupLeaderStake(
                 10,
                 10,
-                WorkingGroup::Storage,
+                working_group,
             ),
         };
         proposal_fixture.check_all();
@@ -1337,6 +1234,13 @@ fn create_slash_working_group_leader_stake_proposal_common_checks_succeed() {
 
 #[test]
 fn slash_stake_with_zero_staking_balance_fails() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_slash_stake_with_zero_staking_balance_fails(group);
+    }
+}
+
+fn run_slash_stake_with_zero_staking_balance_fails(working_group: WorkingGroup) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance_using_account_id(1, 500000);
 
@@ -1356,7 +1260,7 @@ fn slash_stake_with_zero_staking_balance_fails() {
                 Some(<BalanceOf<Test>>::from(50000u32)),
                 10,
                 0,
-                WorkingGroup::Storage,
+                working_group,
             ),
             Err(Error::<Test>::SlashingStakeIsZero.into())
         );
@@ -1365,6 +1269,13 @@ fn slash_stake_with_zero_staking_balance_fails() {
 
 #[test]
 fn decrease_stake_with_zero_staking_balance_fails() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_decrease_stake_with_zero_staking_balance_fails(group);
+    }
+}
+
+fn run_decrease_stake_with_zero_staking_balance_fails(working_group: WorkingGroup) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance_using_account_id(1, 500000);
 
@@ -1384,7 +1295,7 @@ fn decrease_stake_with_zero_staking_balance_fails() {
                 Some(<BalanceOf<Test>>::from(50000u32)),
                 10,
                 0,
-                WorkingGroup::Storage,
+                working_group,
             ),
             Err(Error::<Test>::DecreasingStakeIsZero.into())
         );
@@ -1393,6 +1304,15 @@ fn decrease_stake_with_zero_staking_balance_fails() {
 
 #[test]
 fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_set_working_group_leader_reward_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_set_working_group_leader_reward_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         let proposal_fixture = ProposalTestFixture {
             insufficient_rights_call: || {
@@ -1404,7 +1324,7 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             empty_stake_call: || {
@@ -1416,7 +1336,7 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
                     None,
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             invalid_stake_call: || {
@@ -1428,7 +1348,7 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(5000u32)),
                     0,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             successful_call: || {
@@ -1440,17 +1360,13 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
                     Some(<BalanceOf<Test>>::from(50000u32)),
                     10,
                     10,
-                    WorkingGroup::Storage,
+                    working_group,
                 )
             },
             proposal_parameters:
                 crate::proposal_types::parameters::set_working_group_leader_reward_proposal::<Test>(
                 ),
-            proposal_details: ProposalDetails::SetWorkingGroupLeaderReward(
-                10,
-                10,
-                WorkingGroup::Storage,
-            ),
+            proposal_details: ProposalDetails::SetWorkingGroupLeaderReward(10, 10, working_group),
         };
         proposal_fixture.check_all();
     });
@@ -1458,6 +1374,15 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
 
 #[test]
 fn create_terminate_working_group_leader_role_proposal_common_checks_succeed() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        run_create_terminate_working_group_leader_role_proposal_common_checks_succeed(group);
+    }
+}
+
+fn run_create_terminate_working_group_leader_role_proposal_common_checks_succeed(
+    working_group: WorkingGroup,
+) {
     initial_test_ext().execute_with(|| {
         increase_total_balance_issuance(500000);
 
@@ -1465,7 +1390,7 @@ fn create_terminate_working_group_leader_role_proposal_common_checks_succeed() {
             worker_id: 10,
             rationale: Vec::new(),
             slash: false,
-            working_group: WorkingGroup::Storage,
+            working_group,
         };
 
         let proposal_fixture = ProposalTestFixture {

+ 1 - 1
runtime/Cargo.toml

@@ -82,7 +82,7 @@ content-directory = { package = 'pallet-content-directory', default-features = f
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
-
+strum = {version = "0.19", default-features = false}
 [build-dependencies]
 wasm-builder-runner = { package = "substrate-wasm-builder-runner", git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4' }
 

+ 1 - 0
runtime/src/integration/content_working_group.rs

@@ -73,6 +73,7 @@ impl versioned_store_permissions::CredentialChecker<Runtime> for ContentWorkingG
     }
 }
 
+#[allow(dead_code)]
 pub struct ContentWorkingGroupStakingEventHandler {}
 impl stake::StakingEventsHandler<Runtime> for ContentWorkingGroupStakingEventHandler {
     fn unstaked(

+ 3 - 8
runtime/src/integration/proposals/proposal_encoder.rs

@@ -18,6 +18,9 @@ use sp_std::vec::Vec;
 macro_rules! wrap_working_group_call {
     ($working_group:expr, $working_group_instance_call:expr) => {{
         match $working_group {
+            WorkingGroup::Content => {
+                Call::ContentDirectoryWorkingGroup($working_group_instance_call)
+            }
             WorkingGroup::Storage => Call::StorageWorkingGroup($working_group_instance_call),
         }
     }};
@@ -35,17 +38,9 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
             ProposalDetails::SetElectionParameters(election_parameters) => Call::CouncilElection(
                 governance::election::Call::set_election_parameters(election_parameters),
             ),
-            ProposalDetails::SetContentWorkingGroupMintCapacity(mint_balance) => {
-                Call::ContentWorkingGroup(content_working_group::Call::set_mint_capacity(
-                    mint_balance,
-                ))
-            }
             ProposalDetails::Spending(balance, destination) => Call::Council(
                 governance::council::Call::spend_from_council_mint(balance, destination),
             ),
-            ProposalDetails::SetLead(new_lead) => {
-                Call::ContentWorkingGroup(content_working_group::Call::replace_lead(new_lead))
-            }
             ProposalDetails::SetValidatorCount(new_validator_count) => Call::Staking(
                 pallet_staking::Call::set_validator_count(new_validator_count),
             ),

+ 47 - 3
runtime/src/integration/working_group.rs

@@ -1,15 +1,59 @@
 use frame_support::StorageMap;
 use sp_std::marker::PhantomData;
 
-use crate::StorageWorkingGroupInstance;
+use crate::{ContentDirectoryWorkingGroupInstance, StorageWorkingGroupInstance};
 use stake::{BalanceOf, NegativeImbalance};
 
-pub struct StakingEventsHandler<T> {
+pub struct ContentDirectoryWGStakingEventsHandler<T> {
+    pub marker: PhantomData<T>,
+}
+
+impl<T: stake::Trait + working_group::Trait<ContentDirectoryWorkingGroupInstance>>
+    stake::StakingEventsHandler<T> for ContentDirectoryWGStakingEventsHandler<T>
+{
+    /// Unstake remaining sum back to the source_account_id
+    fn unstaked(
+        stake_id: &<T as stake::Trait>::StakeId,
+        _unstaked_amount: BalanceOf<T>,
+        remaining_imbalance: NegativeImbalance<T>,
+    ) -> NegativeImbalance<T> {
+        // Stake not related to a staked role managed by the hiring module.
+        if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
+            return remaining_imbalance;
+        }
+
+        let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
+
+        if working_group::MemberIdByHiringApplicationId::<T, ContentDirectoryWorkingGroupInstance>::contains_key(
+            hiring_application_id,
+        ) {
+            return <working_group::Module<T, ContentDirectoryWorkingGroupInstance>>::refund_working_group_stake(
+				*stake_id,
+				remaining_imbalance,
+			);
+        }
+
+        remaining_imbalance
+    }
+
+    /// Empty handler for the slashing.
+    fn slashed(
+        _: &<T as stake::Trait>::StakeId,
+        _: Option<<T as stake::Trait>::SlashId>,
+        _: BalanceOf<T>,
+        _: BalanceOf<T>,
+        remaining_imbalance: NegativeImbalance<T>,
+    ) -> NegativeImbalance<T> {
+        remaining_imbalance
+    }
+}
+
+pub struct StorageWgStakingEventsHandler<T> {
     pub marker: PhantomData<T>,
 }
 
 impl<T: stake::Trait + working_group::Trait<StorageWorkingGroupInstance>>
-    stake::StakingEventsHandler<T> for StakingEventsHandler<T>
+    stake::StakingEventsHandler<T> for StorageWgStakingEventsHandler<T>
 {
     /// Unstake remaining sum back to the source_account_id
     fn unstaked(

+ 3 - 5
runtime/src/lib.rs

@@ -453,10 +453,10 @@ impl stake::Trait for Runtime {
     type Currency = <Self as common::currency::GovernanceCurrency>::Currency;
     type StakePoolId = StakePoolId;
     type StakingEventsHandler = (
-        crate::integration::content_working_group::ContentWorkingGroupStakingEventHandler,
+        crate::integration::proposals::StakingEventsHandler<Self>,
         (
-            crate::integration::proposals::StakingEventsHandler<Self>,
-            crate::integration::working_group::StakingEventsHandler<Self>,
+            crate::integration::working_group::ContentDirectoryWGStakingEventsHandler<Self>,
+            crate::integration::working_group::StorageWgStakingEventsHandler<Self>,
         ),
     );
     type StakeId = u64;
@@ -509,8 +509,6 @@ impl storage::data_object_storage_registry::Trait for Runtime {
     type ContentIdExists = DataDirectory;
 }
 
-pub type MemberId = u64;
-
 impl membership::Trait for Runtime {
     type Event = Event;
     type MemberId = MemberId;

+ 3 - 0
runtime/src/primitives.rs

@@ -63,6 +63,9 @@ pub type PostId = u64;
 /// Represent an actor in membership group, which is the same in the working groups.
 pub type ActorId = u64;
 
+/// Represent an member in membership group, which is the same in the working groups.
+pub type MemberId = u64;
+
 /// App-specific crypto used for reporting equivocation/misbehavior in BABE and
 /// GRANDPA. Any rewards for misbehavior reporting will be paid out to this
 /// account.

+ 1 - 0
runtime/src/tests/mod.rs

@@ -1,6 +1,7 @@
 //! The Joystream Substrate Node runtime integration tests.
 
 #![cfg(test)]
+#[macro_use]
 
 mod proposals_integration;
 mod storage_integration;

+ 0 - 57
runtime/src/tests/proposals_integration/mod.rs

@@ -31,7 +31,6 @@ pub type ProposalsEngine = proposals_engine::Module<Runtime>;
 pub type Council = governance::council::Module<Runtime>;
 pub type Election = governance::election::Module<Runtime>;
 pub type ProposalCodex = proposals_codex::Module<Runtime>;
-pub type Mint = minting::Module<Runtime>;
 
 fn setup_members(count: u8) {
     let authority_account_id = <Runtime as system::Trait>::AccountId::default();
@@ -567,32 +566,6 @@ fn text_proposal_execution_succeeds() {
     });
 }
 
-#[test]
-fn set_lead_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 10;
-        let account_id: [u8; 32] = [member_id; 32];
-
-        let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
-            ProposalCodex::create_set_lead_proposal(
-                RawOrigin::Signed(account_id.clone().into()).into(),
-                member_id as u64,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(50000u32)),
-                Some((member_id as u64, account_id.into())),
-            )
-        })
-        .with_member_id(member_id as u64);
-
-        assert!(content_working_group::Module::<Runtime>::ensure_lead_is_set().is_err());
-
-        codex_extrinsic_test_fixture.call_extrinsic_and_assert();
-
-        assert!(content_working_group::Module::<Runtime>::ensure_lead_is_set().is_ok());
-    });
-}
-
 #[test]
 fn spending_proposal_execution_succeeds() {
     initial_test_ext().execute_with(|| {
@@ -626,36 +599,6 @@ fn spending_proposal_execution_succeeds() {
     });
 }
 
-#[test]
-fn set_content_working_group_mint_capacity_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let new_balance = <BalanceOf<Runtime>>::from(55u32);
-
-        let mint_id =
-            Mint::add_mint(0, None).expect("Failed to create a mint for the content working group");
-        <content_working_group::Mint<Runtime>>::put(mint_id);
-
-        assert_eq!(Mint::get_mint_capacity(mint_id), Ok(0));
-
-        let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
-            ProposalCodex::create_set_content_working_group_mint_capacity_proposal(
-                RawOrigin::Signed(account_id.clone().into()).into(),
-                member_id as u64,
-                b"title".to_vec(),
-                b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(50000u32)),
-                new_balance,
-            )
-        });
-
-        codex_extrinsic_test_fixture.call_extrinsic_and_assert();
-
-        assert_eq!(Mint::get_mint_capacity(mint_id), Ok(new_balance));
-    });
-}
-
 #[test]
 fn set_election_parameters_proposal_execution_succeeds() {
     initial_test_ext().execute_with(|| {

+ 883 - 524
runtime/src/tests/proposals_integration/working_group_proposals.rs

@@ -1,3 +1,6 @@
+#![allow(unnameable_test_items)]
+#![allow(dead_code)]
+
 use super::*;
 
 use system::RawOrigin;
@@ -7,33 +10,53 @@ use hiring::ActivateOpeningAt;
 use proposals_codex::AddOpeningParameters;
 use working_group::{OpeningPolicyCommitment, RewardPolicy};
 
-use crate::{Balance, BlockNumber, StorageWorkingGroupInstance};
+use crate::{
+    Balance, BlockNumber, ContentDirectoryWorkingGroup, ContentDirectoryWorkingGroupInstance,
+    StorageWorkingGroup, StorageWorkingGroupInstance,
+};
 use sp_std::collections::btree_set::BTreeSet;
 
-type StorageWorkingGroup = working_group::Module<Runtime, StorageWorkingGroupInstance>;
+use crate::primitives::{ActorId, MemberId};
+use frame_support::traits;
+use strum::IntoEnumIterator;
+
+type WorkingGroupInstance<T, I> = working_group::Module<T, I>;
 
 type Hiring = hiring::Module<Runtime>;
 
 fn add_opening(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
     activate_at: hiring::ActivateOpeningAt<BlockNumber>,
     opening_policy_commitment: Option<OpeningPolicyCommitment<BlockNumber, u128>>,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) -> u64 {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
-    let opening_id = StorageWorkingGroup::next_opening_id();
-
-    assert!(!<working_group::OpeningById<
-        Runtime,
-        StorageWorkingGroupInstance,
-    >>::contains_key(opening_id));
+    let opening_id = match working_group {
+        WorkingGroup::Content => {
+            let opening_id = ContentDirectoryWorkingGroup::next_opening_id();
+            assert!(!<working_group::OpeningById<
+                Runtime,
+                ContentDirectoryWorkingGroupInstance,
+            >>::contains_key(opening_id));
+            opening_id
+        }
+        WorkingGroup::Storage => {
+            let opening_id = StorageWorkingGroup::next_opening_id();
+            assert!(!<working_group::OpeningById<
+                Runtime,
+                StorageWorkingGroupInstance,
+            >>::contains_key(opening_id));
+            opening_id
+        }
+    };
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_add_working_group_leader_opening_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
+            RawOrigin::Signed(account_id.into()).into(),
             member_id as u64,
             b"title".to_vec(),
             b"body".to_vec(),
@@ -44,7 +67,7 @@ fn add_opening(
                     .clone()
                     .unwrap_or(OpeningPolicyCommitment::default()),
                 human_readable_text: Vec::new(),
-                working_group: WorkingGroup::Storage,
+                working_group,
             },
         )
     })
@@ -57,23 +80,24 @@ fn add_opening(
 }
 
 fn begin_review_applications(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
     opening_id: u64,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_begin_review_working_group_leader_applications_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(25_000_u32)),
             opening_id,
-            WorkingGroup::Storage,
+            working_group,
         )
     })
     .disable_setup_enviroment()
@@ -84,20 +108,21 @@ fn begin_review_applications(
 }
 
 fn fill_opening(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
     opening_id: u64,
     successful_application_id: u64,
     reward_policy: Option<RewardPolicy<Balance, BlockNumber>>,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_fill_working_group_leader_opening_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(50_000_u32)),
@@ -105,7 +130,7 @@ fn fill_opening(
                 opening_id,
                 successful_application_id,
                 reward_policy: reward_policy.clone(),
-                working_group: WorkingGroup::Storage,
+                working_group,
             },
         )
     })
@@ -125,25 +150,26 @@ fn get_stake_balance(stake: stake::Stake<BlockNumber, Balance, u64>) -> Balance
 }
 
 fn decrease_stake(
-    member_id: u8,
+    member_id: u64,
     account_id: [u8; 32],
     leader_worker_id: u64,
     stake_amount: Balance,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_decrease_working_group_leader_stake_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(50_000_u32)),
             leader_worker_id,
             stake_amount,
-            WorkingGroup::Storage,
+            working_group,
         )
     })
     .disable_setup_enviroment()
@@ -154,25 +180,26 @@ fn decrease_stake(
 }
 
 fn slash_stake(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
-    leader_worker_id: u64,
+    leader_worker_id: ActorId,
     stake_amount: Balance,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_slash_working_group_leader_stake_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(50_000_u32)),
             leader_worker_id,
             stake_amount,
-            WorkingGroup::Storage,
+            working_group,
         )
     })
     .disable_setup_enviroment()
@@ -183,25 +210,26 @@ fn slash_stake(
 }
 
 fn set_reward(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
     leader_worker_id: u64,
     reward_amount: Balance,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_set_working_group_leader_reward_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
+            RawOrigin::Signed(account_id.into()).into(),
             member_id as u64,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(50_000_u32)),
             leader_worker_id,
             reward_amount,
-            WorkingGroup::Storage,
+            working_group,
         )
     })
     .disable_setup_enviroment()
@@ -211,31 +239,38 @@ fn set_reward(
     codex_extrinsic_test_fixture.call_extrinsic_and_assert();
 }
 
-fn set_mint_capacity(
-    member_id: u8,
+fn set_mint_capacity<
+    T: working_group::Trait<I> + system::Trait + minting::Trait,
+    I: working_group::Instance,
+>(
+    member_id: MemberId,
     account_id: [u8; 32],
     mint_capacity: Balance,
     sequence_number: u32, // action sequence number to align with other actions
     setup_environment: bool,
-) {
+    working_group: WorkingGroup,
+) where
+    <T as minting::Trait>::MintId: From<u64>,
+{
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let mint_id_result = <minting::Module<Runtime>>::add_mint(0, None);
 
     if let Ok(mint_id) = mint_id_result {
-        <working_group::Mint<Runtime, StorageWorkingGroupInstance>>::put(mint_id);
+        let mint_id: <T as minting::Trait>::MintId = mint_id.into();
+        <working_group::Mint<T, I>>::put(mint_id);
     }
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_set_working_group_mint_capacity_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(50_000_u32)),
             mint_capacity,
-            WorkingGroup::Storage,
+            working_group,
         )
     })
     .with_setup_enviroment(setup_environment)
@@ -246,19 +281,20 @@ fn set_mint_capacity(
 }
 
 fn terminate_role(
-    member_id: u8,
+    member_id: MemberId,
     account_id: [u8; 32],
     leader_worker_id: u64,
     slash: bool,
     sequence_number: u32, // action sequence number to align with other actions
+    working_group: WorkingGroup,
 ) {
     let expected_proposal_id = sequence_number;
     let run_to_block = sequence_number * 2;
 
     let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
         ProposalCodex::create_terminate_working_group_leader_role_proposal(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
+            RawOrigin::Signed(account_id.into()).into(),
+            member_id,
             b"title".to_vec(),
             b"body".to_vec(),
             Some(<BalanceOf<Runtime>>::from(100_000_u32)),
@@ -266,7 +302,7 @@ fn terminate_role(
                 worker_id: leader_worker_id,
                 rationale: Vec::new(),
                 slash,
-                working_group: WorkingGroup::Storage,
+                working_group,
             },
         )
     })
@@ -279,53 +315,110 @@ fn terminate_role(
 
 #[test]
 fn create_add_working_group_leader_opening_proposal_execution_succeeds() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        match group {
+            WorkingGroup::Content => {
+                run_create_add_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    ContentDirectoryWorkingGroupInstance,
+                >(group);
+            }
+            WorkingGroup::Storage => {
+                run_create_add_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    StorageWorkingGroupInstance,
+                >(group);
+            }
+        }
+    }
+}
+
+fn run_create_add_working_group_leader_opening_proposal_execution_succeeds<
+    T: working_group::Trait<I> + system::Trait + stake::Trait,
+    I: working_group::Instance,
+>(
+    working_group: WorkingGroup,
+) where
+    <T as membership::Trait>::MemberId: From<u64>,
+    <T as hiring::Trait>::OpeningId: From<u64>,
+{
     initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
+        let member_id: MemberId = 1;
+        let account_id: [u8; 32] = [member_id as u8; 32];
 
-        let next_opening_id = StorageWorkingGroup::next_opening_id();
+        let next_opening_id = WorkingGroupInstance::<T, I>::next_opening_id();
 
-        assert!(!<working_group::OpeningById<
-            Runtime,
-            StorageWorkingGroupInstance,
-        >>::contains_key(next_opening_id));
+        assert!(!<working_group::OpeningById<T, I>>::contains_key(
+            next_opening_id
+        ));
 
-        let opening_id = add_opening(
+        let opening_id: <T as hiring::Trait>::OpeningId = add_opening(
             member_id,
             account_id,
             ActivateOpeningAt::CurrentBlock,
             None,
             1,
-        );
+            working_group,
+        )
+        .into();
 
         // Check for expected opening id.
         assert_eq!(opening_id, next_opening_id);
 
         // Check for the new opening creation.
-        assert!(<working_group::OpeningById<
-            Runtime,
-            StorageWorkingGroupInstance,
-        >>::contains_key(opening_id));
+        assert!(<working_group::OpeningById<T, I>>::contains_key(opening_id));
     });
 }
 
 #[test]
 fn create_begin_review_working_group_leader_applications_proposal_execution_succeeds() {
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        match group {
+            WorkingGroup::Content => {
+                run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
+                Runtime,
+                ContentDirectoryWorkingGroupInstance,
+            >(group);
+            }
+            WorkingGroup::Storage => {
+                run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
+                Runtime,
+                StorageWorkingGroupInstance,
+            >(group);
+            }
+        }
+    }
+}
+
+fn run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds<
+    T: working_group::Trait<I> + system::Trait + stake::Trait,
+    I: working_group::Instance,
+>(
+    working_group: WorkingGroup,
+) where
+    <T as hiring::Trait>::OpeningId: From<u64> + Into<u64>,
+{
     initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
+        let member_id: MemberId = 1;
+        let account_id: [u8; 32] = [member_id as u8; 32];
 
         let opening_id = add_opening(
             member_id,
-            account_id.clone(),
+            account_id,
             ActivateOpeningAt::CurrentBlock,
             None,
             1,
+            working_group,
         );
 
-        let opening = StorageWorkingGroup::opening_by_id(opening_id);
+        let opening = WorkingGroupInstance::<T, I>::opening_by_id(
+            <T as hiring::Trait>::OpeningId::from(opening_id),
+        );
 
-        let hiring_opening = Hiring::opening_by_id(opening.hiring_opening_id);
+        let hiring_opening_id: u64 = opening.hiring_opening_id.into();
+        let hiring_opening = Hiring::opening_by_id(hiring_opening_id);
         assert_eq!(
             hiring_opening.stage,
             hiring::OpeningStage::Active {
@@ -339,9 +432,9 @@ fn create_begin_review_working_group_leader_applications_proposal_execution_succ
             }
         );
 
-        begin_review_applications(member_id, account_id, opening_id, 2);
+        begin_review_applications(member_id, account_id, opening_id, 2, working_group);
 
-        let hiring_opening = Hiring::opening_by_id(opening.hiring_opening_id);
+        let hiring_opening = Hiring::opening_by_id(hiring_opening_id);
         assert_eq!(
             hiring_opening.stage,
             hiring::OpeningStage::Active {
@@ -360,475 +453,741 @@ fn create_begin_review_working_group_leader_applications_proposal_execution_succ
 
 #[test]
 fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            None,
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            None,
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            None,
-            3,
-        );
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_some());
-    });
-}
-
-#[test]
-fn create_decrease_group_leader_stake_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let stake_amount = 100;
-
-        let opening_policy_commitment = OpeningPolicyCommitment {
-            role_staking_policy: Some(hiring::StakingPolicy {
-                amount: 100,
-                amount_mode: hiring::StakingAmountLimitMode::AtLeast,
-                crowded_out_unstaking_period_length: None,
-                review_period_expired_unstaking_period_length: None,
-            }),
-            ..OpeningPolicyCommitment::default()
-        };
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            Some(opening_policy_commitment),
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            Some(stake_amount),
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            None,
-            3,
-        );
-
-        let leader_worker_id = StorageWorkingGroup::current_lead().unwrap();
-
-        let stake_id = 1;
-        let old_balance = Balances::free_balance(&account_id.into());
-        let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(get_stake_balance(old_stake), stake_amount);
-
-        let decreasing_stake_amount = 30;
-        decrease_stake(
-            member_id,
-            account_id,
-            leader_worker_id,
-            decreasing_stake_amount,
-            4,
-        );
-
-        let new_balance = Balances::free_balance(&account_id.into());
-        let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(
-            get_stake_balance(new_stake),
-            stake_amount - decreasing_stake_amount
-        );
-        assert_eq!(new_balance, old_balance + decreasing_stake_amount);
-    });
-}
-
-#[test]
-fn create_slash_group_leader_stake_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let stake_amount = 100;
-
-        let opening_policy_commitment = OpeningPolicyCommitment {
-            role_staking_policy: Some(hiring::StakingPolicy {
-                amount: 100,
-                amount_mode: hiring::StakingAmountLimitMode::AtLeast,
-                crowded_out_unstaking_period_length: None,
-                review_period_expired_unstaking_period_length: None,
-            }),
-            ..OpeningPolicyCommitment::default()
-        };
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            Some(opening_policy_commitment),
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            Some(stake_amount),
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            None,
-            3,
-        );
-
-        let leader_worker_id = StorageWorkingGroup::current_lead().unwrap();
-
-        let stake_id = 1;
-        let old_balance = Balances::free_balance(&account_id.into());
-        let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(get_stake_balance(old_stake), stake_amount);
-
-        let slashing_stake_amount = 30;
-        slash_stake(
-            member_id,
-            account_id,
-            leader_worker_id,
-            slashing_stake_amount,
-            4,
-        );
-
-        let new_balance = Balances::free_balance(&account_id.into());
-        let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(
-            get_stake_balance(new_stake),
-            stake_amount - slashing_stake_amount
-        );
-        assert_eq!(new_balance, old_balance);
-    });
-}
-
-#[test]
-fn create_set_working_group_mint_capacity_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-
-        assert_eq!(StorageWorkingGroup::mint(), 0);
-
-        let mint_capacity = 999999;
-        set_mint_capacity(member_id, account_id, mint_capacity, 1, true);
-
-        let mint_id = StorageWorkingGroup::mint();
-        let mint = <minting::Module<Runtime>>::mints(mint_id);
-
-        assert_eq!(mint.capacity(), mint_capacity);
-    });
-}
-
-#[test]
-fn create_set_group_leader_reward_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let stake_amount = 100;
-
-        let opening_policy_commitment = OpeningPolicyCommitment {
-            role_staking_policy: Some(hiring::StakingPolicy {
-                amount: 100,
-                amount_mode: hiring::StakingAmountLimitMode::AtLeast,
-                crowded_out_unstaking_period_length: None,
-                review_period_expired_unstaking_period_length: None,
-            }),
-            ..OpeningPolicyCommitment::default()
-        };
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            Some(opening_policy_commitment),
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            Some(stake_amount),
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
+    // This uses strum crate for enum iteration
+    for group in WorkingGroup::iter() {
+        match group {
+            WorkingGroup::Content => {
+                run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    ContentDirectoryWorkingGroupInstance,
+                >(group);
+            }
+            WorkingGroup::Storage => {
+                run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    StorageWorkingGroupInstance,
+                >(group);
+            }
+        }
+    }
 
-        let old_reward_amount = 100;
-        let reward_policy = Some(RewardPolicy {
-            amount_per_payout: old_reward_amount,
-            next_payment_at_block: 9999,
-            payout_interval: None,
+    fn run_create_fill_working_group_leader_opening_proposal_execution_succeeds<
+        T: working_group::Trait<I> + system::Trait + stake::Trait,
+        I: working_group::Instance,
+    >(
+        working_group: WorkingGroup,
+    ) where
+        <T as system::Trait>::AccountId: From<[u8; 32]>,
+        <T as membership::Trait>::MemberId: From<u64>,
+        <T as hiring::Trait>::OpeningId: From<u64>,
+    {
+        initial_test_ext().execute_with(|| {
+            let member_id: MemberId = 1;
+            let account_id: [u8; 32] = [member_id as u8; 32];
+
+            let opening_id = add_opening(
+                member_id,
+                account_id,
+                ActivateOpeningAt::CurrentBlock,
+                None,
+                1,
+                working_group,
+            );
+
+            let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                RawOrigin::Signed(account_id.into()).into(),
+                member_id.into(),
+                opening_id.into(),
+                account_id.into(),
+                None,
+                None,
+                Vec::new(),
+            );
+
+            assert_eq!(apply_result, Ok(()));
+
+            let expected_application_id = 0;
+
+            begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+
+            let lead = WorkingGroupInstance::<T, I>::current_lead();
+            assert!(lead.is_none());
+
+            fill_opening(
+                member_id,
+                account_id,
+                opening_id,
+                expected_application_id,
+                None,
+                3,
+                working_group,
+            );
+
+            let lead = WorkingGroupInstance::<T, I>::current_lead();
+            assert!(lead.is_some());
         });
+    }
 
-        set_mint_capacity(member_id, account_id, 999999, 3, false);
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            reward_policy,
-            4,
-        );
-
-        let leader_worker_id = StorageWorkingGroup::current_lead().unwrap();
-
-        let worker = StorageWorkingGroup::worker_by_id(leader_worker_id);
-        let relationship_id = worker.reward_relationship.unwrap();
-
-        let relationship = recurring_rewards::RewardRelationships::<Runtime>::get(relationship_id);
-        assert_eq!(relationship.amount_per_payout, old_reward_amount);
-
-        let new_reward_amount = 999;
-        set_reward(
-            member_id,
-            account_id,
-            leader_worker_id,
-            new_reward_amount,
-            5,
-        );
-
-        let relationship = recurring_rewards::RewardRelationships::<Runtime>::get(relationship_id);
-        assert_eq!(relationship.amount_per_payout, new_reward_amount);
-    });
-}
-
-#[test]
-fn create_terminate_group_leader_role_proposal_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let stake_amount = 100;
-
-        let opening_policy_commitment = OpeningPolicyCommitment {
-            role_staking_policy: Some(hiring::StakingPolicy {
-                amount: 100,
-                amount_mode: hiring::StakingAmountLimitMode::AtLeast,
-                crowded_out_unstaking_period_length: None,
-                review_period_expired_unstaking_period_length: None,
-            }),
-            ..OpeningPolicyCommitment::default()
-        };
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            Some(opening_policy_commitment),
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            Some(stake_amount),
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
+    #[test]
+    fn create_decrease_group_leader_stake_proposal_execution_succeeds() {
+        // This uses strum crate for enum iteration
+        for group in WorkingGroup::iter() {
+            match group {
+                WorkingGroup::Content => {
+                    run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        ContentDirectoryWorkingGroupInstance,
+                    >(group);
+                }
+                WorkingGroup::Storage => {
+                    run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        StorageWorkingGroupInstance,
+                    >(group);
+                }
+            }
+        }
+    }
 
-        let old_reward_amount = 100;
-        let reward_policy = Some(RewardPolicy {
-            amount_per_payout: old_reward_amount,
-            next_payment_at_block: 9999,
-            payout_interval: None,
+fn run_create_decrease_group_leader_stake_proposal_execution_succeeds<
+    T: working_group::Trait<I> + system::Trait + stake::Trait,
+    I: working_group::Instance,
+>(
+    working_group: WorkingGroup,
+) where
+    <T as system::Trait>::AccountId: From<[u8; 32]>,
+    <T as hiring::Trait>::OpeningId: From<u64>,
+    <T as membership::Trait>::MemberId: From<u64>,
+    <T as membership::Trait>::ActorId: Into<u64>,
+    <<T as stake::Trait>::Currency as traits::Currency<<T as system::Trait>::AccountId>>::Balance:
+        From<u128>,
+{
+        initial_test_ext().execute_with(|| {
+            let member_id: MemberId = 1;
+            let account_id: [u8; 32] = [member_id as u8; 32];
+            let stake_amount: Balance = 100;
+
+            let opening_policy_commitment = OpeningPolicyCommitment {
+                role_staking_policy: Some(hiring::StakingPolicy {
+                    amount: 100,
+                    amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+                    crowded_out_unstaking_period_length: None,
+                    review_period_expired_unstaking_period_length: None,
+                }),
+                ..OpeningPolicyCommitment::default()
+            };
+
+            let opening_id = add_opening(
+                member_id,
+                account_id,
+                ActivateOpeningAt::CurrentBlock,
+                Some(opening_policy_commitment),
+                1,
+                working_group,
+            );
+
+            let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                RawOrigin::Signed(account_id.into()).into(),
+                member_id.into(),
+                opening_id.into(),
+                account_id.into(),
+                Some(stake_amount.into()),
+                None,
+                Vec::new(),
+            );
+
+            assert_eq!(apply_result, Ok(()));
+
+            let expected_application_id = 0;
+
+            begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+
+            let lead = WorkingGroupInstance::<T, I>::current_lead();
+            assert!(lead.is_none());
+
+            fill_opening(
+                member_id,
+                account_id,
+                opening_id,
+                expected_application_id,
+                None,
+                3,
+                working_group,
+            );
+
+            let leader_worker_id = WorkingGroupInstance::<T, I>::current_lead().unwrap();
+
+            let stake_id = 1;
+            let old_balance = Balances::free_balance(&account_id.into());
+            let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+            assert_eq!(get_stake_balance(old_stake), stake_amount);
+
+            let decreasing_stake_amount = 30;
+            decrease_stake(
+                member_id,
+                account_id,
+                leader_worker_id.into(),
+                decreasing_stake_amount,
+                4,
+                working_group,
+            );
+
+            let new_balance = Balances::free_balance(&account_id.into());
+            let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+            assert_eq!(
+                get_stake_balance(new_stake),
+                stake_amount - decreasing_stake_amount
+            );
+            assert_eq!(new_balance, old_balance + decreasing_stake_amount);
         });
+    }
 
-        set_mint_capacity(member_id, account_id, 999999, 3, false);
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            reward_policy,
-            4,
-        );
-
-        let leader_worker_id = StorageWorkingGroup::current_lead().unwrap();
-
-        let stake_id = 1;
-        let old_balance = Balances::free_balance(&account_id.into());
-        let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(get_stake_balance(old_stake), stake_amount);
-
-        terminate_role(member_id, account_id, leader_worker_id, false, 5);
-
-        assert!(StorageWorkingGroup::current_lead().is_none());
-
-        let new_balance = Balances::free_balance(&account_id.into());
-        let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(new_stake.staking_status, stake::StakingStatus::NotStaked);
-        assert_eq!(new_balance, old_balance + stake_amount);
-    });
-}
-
-#[test]
-fn create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds() {
-    initial_test_ext().execute_with(|| {
-        let member_id = 1;
-        let account_id: [u8; 32] = [member_id; 32];
-        let stake_amount = 100;
-
-        let opening_policy_commitment = OpeningPolicyCommitment {
-            role_staking_policy: Some(hiring::StakingPolicy {
-                amount: 100,
-                amount_mode: hiring::StakingAmountLimitMode::AtLeast,
-                crowded_out_unstaking_period_length: None,
-                review_period_expired_unstaking_period_length: None,
-            }),
-            ..OpeningPolicyCommitment::default()
-        };
-
-        let opening_id = add_opening(
-            member_id,
-            account_id.clone(),
-            ActivateOpeningAt::CurrentBlock,
-            Some(opening_policy_commitment),
-            1,
-        );
-
-        let apply_result = StorageWorkingGroup::apply_on_opening(
-            RawOrigin::Signed(account_id.clone().into()).into(),
-            member_id as u64,
-            opening_id,
-            account_id.clone().into(),
-            Some(stake_amount),
-            None,
-            Vec::new(),
-        );
-
-        assert_eq!(apply_result, Ok(()));
-
-        let expected_application_id = 0;
-
-        begin_review_applications(member_id, account_id, opening_id, 2);
-
-        let lead = StorageWorkingGroup::current_lead();
-        assert!(lead.is_none());
+    #[test]
+    fn create_slash_group_leader_stake_proposal_execution_succeeds() {
+        // This uses strum crate for enum iteration
+        for group in WorkingGroup::iter() {
+            match group {
+                WorkingGroup::Content => {
+                    run_create_slash_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        ContentDirectoryWorkingGroupInstance,
+                    >(group)
+                }
+                WorkingGroup::Storage => {
+                    run_create_slash_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        StorageWorkingGroupInstance,
+                    >(group)
+                }
+            }
+        }
+    }
 
-        let old_reward_amount = 100;
-        let reward_policy = Some(RewardPolicy {
-            amount_per_payout: old_reward_amount,
-            next_payment_at_block: 9999,
-            payout_interval: None,
+fn run_create_slash_group_leader_stake_proposal_execution_succeeds<
+    T: working_group::Trait<I> + system::Trait + stake::Trait,
+    I: working_group::Instance,
+>(
+    working_group: WorkingGroup,
+) where
+    <T as system::Trait>::AccountId: From<[u8; 32]>,
+    <T as hiring::Trait>::OpeningId: From<u64>,
+    <T as membership::Trait>::MemberId: From<u64>,
+    <T as membership::Trait>::ActorId: Into<u64>,
+    <<T as stake::Trait>::Currency as traits::Currency<<T as system::Trait>::AccountId>>::Balance:
+        From<u128>,
+{
+        initial_test_ext().execute_with(|| {
+            let member_id: MemberId = 1;
+            let account_id: [u8; 32] = [member_id as u8; 32];
+            let stake_amount: Balance = 100;
+
+            let opening_policy_commitment = OpeningPolicyCommitment {
+                role_staking_policy: Some(hiring::StakingPolicy {
+                    amount: 100,
+                    amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+                    crowded_out_unstaking_period_length: None,
+                    review_period_expired_unstaking_period_length: None,
+                }),
+                ..OpeningPolicyCommitment::default()
+            };
+
+            let opening_id = add_opening(
+                member_id,
+                account_id,
+                ActivateOpeningAt::CurrentBlock,
+                Some(opening_policy_commitment),
+                1,
+                working_group,
+            );
+
+            let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                RawOrigin::Signed(account_id.into()).into(),
+                member_id.into(),
+                opening_id.into(),
+                account_id.into(),
+                Some(stake_amount.into()),
+                None,
+                Vec::new(),
+            );
+
+            assert_eq!(apply_result, Ok(()));
+
+            let expected_application_id = 0;
+
+            begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+
+            let lead = WorkingGroupInstance::<T, I>::current_lead();
+
+            assert!(lead.is_none());
+
+            fill_opening(
+                member_id,
+                account_id,
+                opening_id,
+                expected_application_id,
+                None,
+                3,
+                working_group,
+            );
+
+            let leader_worker_id = WorkingGroupInstance::<T, I>::current_lead().unwrap();
+
+            let stake_id = 1;
+            let old_balance = Balances::free_balance(&account_id.into());
+            let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+            assert_eq!(get_stake_balance(old_stake), stake_amount);
+
+            let slashing_stake_amount = 30;
+            slash_stake(
+                member_id,
+                account_id,
+                leader_worker_id.into(),
+                slashing_stake_amount,
+                4,
+                working_group,
+            );
+
+            let new_balance = Balances::free_balance(&account_id.into());
+            let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+            assert_eq!(
+                get_stake_balance(new_stake),
+                stake_amount as u128 - slashing_stake_amount
+            );
+            assert_eq!(new_balance, old_balance);
         });
+    }
 
-        set_mint_capacity(member_id, account_id, 999999, 3, false);
-
-        fill_opening(
-            member_id,
-            account_id,
-            opening_id,
-            expected_application_id,
-            reward_policy,
-            4,
-        );
-
-        let leader_worker_id = StorageWorkingGroup::current_lead().unwrap();
-
-        let stake_id = 1;
-        let old_balance = Balances::free_balance(&account_id.into());
-        let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(get_stake_balance(old_stake), stake_amount);
-
-        terminate_role(member_id, account_id, leader_worker_id, true, 5);
-
-        assert!(StorageWorkingGroup::current_lead().is_none());
-
-        let new_balance = Balances::free_balance(&account_id.into());
-        let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
-
-        assert_eq!(new_stake.staking_status, stake::StakingStatus::NotStaked);
-        assert_eq!(new_balance, old_balance);
-    });
+    #[test]
+    fn create_set_working_group_mint_capacity_proposal_execution_succeeds() {
+        // This uses strum crate for enum iteration
+        for group in WorkingGroup::iter() {
+            match group {
+                WorkingGroup::Content => {
+                    run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        Runtime,
+                        ContentDirectoryWorkingGroupInstance,
+                    >(group);
+                }
+                WorkingGroup::Storage => {
+                    run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        Runtime,
+                        StorageWorkingGroupInstance,
+                    >(group);
+                }
+            }
+        }
+
+        fn run_create_set_working_group_mint_capacity_proposal_execution_succeeds<
+            T: working_group::Trait<I> + system::Trait + minting::Trait,
+            I: working_group::Instance,
+        >(
+            working_group: WorkingGroup,
+        ) where
+            <T as system::Trait>::AccountId: From<[u8; 32]>,
+            <T as membership::Trait>::MemberId: From<u64>,
+            <T as minting::Trait>::MintId: From<u64>,
+            <<T as minting::Trait>::Currency as traits::Currency<
+                <T as system::Trait>::AccountId,
+            >>::Balance: From<u128>,
+        {
+            initial_test_ext().execute_with(|| {
+                let member_id: MemberId = 1;
+                let account_id: [u8; 32] = [member_id as u8; 32];
+
+                assert_eq!(WorkingGroupInstance::<T, I>::mint(), 0.into());
+
+                let mint_capacity = 999999;
+                set_mint_capacity::<T, I>(
+                    member_id,
+                    account_id,
+                    mint_capacity,
+                    1,
+                    true,
+                    working_group,
+                );
+
+                let mint_id = WorkingGroupInstance::<T, I>::mint();
+                let mint = <minting::Module<T>>::mints(mint_id);
+
+                assert_eq!(mint.capacity(), mint_capacity.into());
+            });
+        }
+
+        #[test]
+        fn create_set_group_leader_reward_proposal_execution_succeeds() {
+            // This uses strum crate for enum iteration
+            for group in WorkingGroup::iter() {
+                match group {
+                    WorkingGroup::Content => {
+                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                            Runtime,
+                            ContentDirectoryWorkingGroupInstance,
+                        >(group);
+                    }
+                    WorkingGroup::Storage => {
+                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                            Runtime,
+                            StorageWorkingGroupInstance,
+                        >(group);
+                    }
+                }
+            }
+        }
+
+        fn run_create_set_group_leader_reward_proposal_execution_succeeds<
+            T: working_group::Trait<I> + system::Trait + minting::Trait,
+            I: working_group::Instance,
+        >(
+            working_group: WorkingGroup,
+        ) where
+            <T as system::Trait>::AccountId: From<[u8; 32]>,
+            <T as membership::Trait>::MemberId: From<u64>,
+            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as minting::Trait>::MintId: From<u64>,
+            <T as hiring::Trait>::OpeningId: From<u64>,
+            <<T as minting::Trait>::Currency as traits::Currency<
+                <T as system::Trait>::AccountId,
+            >>::Balance: From<u128>,
+        {
+            initial_test_ext().execute_with(|| {
+                let member_id: MemberId = 1;
+                let account_id: [u8; 32] = [member_id as u8; 32];
+                let stake_amount = 100;
+
+                let opening_policy_commitment = OpeningPolicyCommitment {
+                    role_staking_policy: Some(hiring::StakingPolicy {
+                        amount: 100,
+                        amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+                        crowded_out_unstaking_period_length: None,
+                        review_period_expired_unstaking_period_length: None,
+                    }),
+                    ..OpeningPolicyCommitment::default()
+                };
+
+                let opening_id = add_opening(
+                    member_id,
+                    account_id,
+                    ActivateOpeningAt::CurrentBlock,
+                    Some(opening_policy_commitment),
+                    1,
+                    working_group,
+                );
+
+                let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                    RawOrigin::Signed(account_id.into()).into(),
+                    member_id.into(),
+                    opening_id.into(),
+                    account_id.into(),
+                    Some(stake_amount.into()),
+                    None,
+                    Vec::new(),
+                );
+
+                assert_eq!(apply_result, Ok(()));
+
+                let expected_application_id = 0;
+
+                begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+
+                let lead = WorkingGroupInstance::<T, I>::current_lead();
+                assert!(lead.is_none());
+
+                let old_reward_amount = 100;
+                let reward_policy = Some(RewardPolicy {
+                    amount_per_payout: old_reward_amount,
+                    next_payment_at_block: 9999,
+                    payout_interval: None,
+                });
+
+                set_mint_capacity::<T, I>(member_id, account_id, 999999, 3, false, working_group);
+
+                fill_opening(
+                    member_id,
+                    account_id,
+                    opening_id,
+                    expected_application_id,
+                    reward_policy,
+                    4,
+                    working_group,
+                );
+
+                let leader_worker_id = WorkingGroupInstance::<T, I>::current_lead().unwrap();
+
+                let worker = WorkingGroupInstance::<T, I>::worker_by_id(leader_worker_id);
+                let relationship_id = worker.reward_relationship.unwrap();
+
+                let relationship =
+                    recurring_rewards::RewardRelationships::<T>::get(relationship_id);
+                assert_eq!(relationship.amount_per_payout, old_reward_amount.into());
+
+                let new_reward_amount = 999;
+                set_reward(
+                    member_id,
+                    account_id,
+                    leader_worker_id.into(),
+                    new_reward_amount,
+                    5,
+                    working_group,
+                );
+
+                let relationship =
+                    recurring_rewards::RewardRelationships::<T>::get(relationship_id);
+                assert_eq!(relationship.amount_per_payout, new_reward_amount.into());
+            });
+        }
+
+        #[test]
+        fn create_terminate_group_leader_role_proposal_execution_succeeds() {
+            // This uses strum crate for enum iteration
+            for group in WorkingGroup::iter() {
+                match group {
+                    WorkingGroup::Content => {
+                        run_create_terminate_group_leader_role_proposal_execution_succeeds::<
+                            Runtime,
+                            ContentDirectoryWorkingGroupInstance,
+                        >(group);
+                    }
+                    WorkingGroup::Storage => {
+                        run_create_terminate_group_leader_role_proposal_execution_succeeds::<
+                            Runtime,
+                            StorageWorkingGroupInstance,
+                        >(group);
+                    }
+                }
+            }
+        }
+
+        fn run_create_terminate_group_leader_role_proposal_execution_succeeds<
+            T: working_group::Trait<I> + system::Trait + minting::Trait,
+            I: working_group::Instance,
+        >(
+            working_group: WorkingGroup,
+        ) where
+            <T as system::Trait>::AccountId: From<[u8; 32]>,
+            <T as membership::Trait>::MemberId: From<u64>,
+            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as minting::Trait>::MintId: From<u64>,
+            <T as hiring::Trait>::OpeningId: From<u64>,
+            <<T as stake::Trait>::Currency as traits::Currency<
+                <T as system::Trait>::AccountId,
+            >>::Balance: From<u128>,
+        {
+            initial_test_ext().execute_with(|| {
+                let member_id: MemberId = 1;
+                let account_id: [u8; 32] = [0; 32];
+                let stake_amount = 100_u128;
+
+                let opening_policy_commitment = OpeningPolicyCommitment {
+                    role_staking_policy: Some(hiring::StakingPolicy {
+                        amount: 100,
+                        amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+                        crowded_out_unstaking_period_length: None,
+                        review_period_expired_unstaking_period_length: None,
+                    }),
+                    ..OpeningPolicyCommitment::default()
+                };
+
+                let opening_id = add_opening(
+                    member_id.into(),
+                    account_id,
+                    ActivateOpeningAt::CurrentBlock,
+                    Some(opening_policy_commitment),
+                    1,
+                    working_group,
+                );
+
+                let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                    RawOrigin::Signed(account_id.into()).into(),
+                    member_id.into(),
+                    opening_id.into(),
+                    account_id.into(),
+                    Some(stake_amount.into()),
+                    None,
+                    Vec::new(),
+                );
+
+                assert_eq!(apply_result, Ok(()));
+
+                let expected_application_id = 0;
+
+                begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+
+                let lead = WorkingGroupInstance::<T, I>::current_lead();
+                assert!(lead.is_none());
+
+                let old_reward_amount = 100;
+                let reward_policy = Some(RewardPolicy {
+                    amount_per_payout: old_reward_amount,
+                    next_payment_at_block: 9999,
+                    payout_interval: None,
+                });
+
+                set_mint_capacity::<T, I>(member_id, account_id, 999999, 3, false, working_group);
+
+                fill_opening(
+                    member_id,
+                    account_id,
+                    opening_id,
+                    expected_application_id,
+                    reward_policy,
+                    4,
+                    working_group,
+                );
+
+                let stake_id = 1;
+                let old_balance = Balances::free_balance(&account_id.into());
+                let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+                assert_eq!(get_stake_balance(old_stake), stake_amount);
+
+                let leader_worker_id = WorkingGroupInstance::<T, I>::current_lead().unwrap();
+
+                terminate_role(
+                    member_id,
+                    account_id,
+                    leader_worker_id.into(),
+                    false,
+                    5,
+                    working_group,
+                );
+
+                assert!(WorkingGroupInstance::<T, I>::current_lead().is_none());
+
+                let new_balance = Balances::free_balance(&account_id.into());
+                let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+                assert_eq!(new_stake.staking_status, stake::StakingStatus::NotStaked);
+                assert_eq!(new_balance, old_balance + stake_amount);
+            });
+        }
+
+        #[test]
+        fn create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds() {
+            // This uses strum crate for enum iteration
+            for group in WorkingGroup::iter() {
+                match group {
+                    WorkingGroup::Content => {
+                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, ContentDirectoryWorkingGroupInstance>(group);
+                    }
+                    WorkingGroup::Storage => {
+                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, StorageWorkingGroupInstance>(group);
+                    }
+                }
+            }
+        }
+
+        fn run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds<
+            T: working_group::Trait<I> + system::Trait + minting::Trait,
+            I: working_group::Instance,
+        >(
+            working_group: WorkingGroup,
+        ) where
+            <T as system::Trait>::AccountId: From<[u8; 32]>,
+            <T as membership::Trait>::MemberId: From<u64>,
+            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as minting::Trait>::MintId: From<u64>,
+            <T as hiring::Trait>::OpeningId: From<u64>,
+            <<T as stake::Trait>::Currency as traits::Currency<
+                <T as system::Trait>::AccountId,
+            >>::Balance: From<u128>,
+        {
+            initial_test_ext().execute_with(|| {
+                let member_id: MemberId = 1;
+                let account_id: [u8; 32] = [0; 32];
+                let stake_amount = 100_u128;
+
+                let opening_policy_commitment = OpeningPolicyCommitment {
+                    role_staking_policy: Some(hiring::StakingPolicy {
+                        amount: 100,
+                        amount_mode: hiring::StakingAmountLimitMode::AtLeast,
+                        crowded_out_unstaking_period_length: None,
+                        review_period_expired_unstaking_period_length: None,
+                    }),
+                    ..OpeningPolicyCommitment::default()
+                };
+
+                let opening_id = add_opening(
+                    member_id,
+                    account_id,
+                    ActivateOpeningAt::CurrentBlock,
+                    Some(opening_policy_commitment),
+                    1,
+                    working_group,
+                );
+
+                let apply_result = WorkingGroupInstance::<T, I>::apply_on_opening(
+                    RawOrigin::Signed(account_id.into()).into(),
+                    member_id.into(),
+                    opening_id.into(),
+                    account_id.into(),
+                    Some(stake_amount.into()),
+                    None,
+                    Vec::new(),
+                );
+
+                assert_eq!(apply_result, Ok(()));
+
+                let expected_application_id = 0;
+
+                begin_review_applications(
+                    member_id,
+                    account_id,
+                    opening_id.into(),
+                    2,
+                    working_group,
+                );
+
+                let lead = WorkingGroupInstance::<T, I>::current_lead();
+                assert!(lead.is_none());
+
+                let old_reward_amount = 100;
+                let reward_policy = Some(RewardPolicy {
+                    amount_per_payout: old_reward_amount,
+                    next_payment_at_block: 9999,
+                    payout_interval: None,
+                });
+
+                set_mint_capacity::<T, I>(member_id, account_id, 999999, 3, false, working_group);
+
+                fill_opening(
+                    member_id,
+                    account_id,
+                    opening_id,
+                    expected_application_id,
+                    reward_policy,
+                    4,
+                    working_group,
+                );
+
+                let stake_id = 1;
+                let old_balance = Balances::free_balance(&account_id.into());
+                let old_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+                assert_eq!(get_stake_balance(old_stake), stake_amount);
+
+                let leader_worker_id = WorkingGroupInstance::<T, I>::current_lead().unwrap();
+
+                terminate_role(
+                    member_id,
+                    account_id,
+                    leader_worker_id.into(),
+                    true,
+                    5,
+                    working_group,
+                );
+
+                assert!(WorkingGroupInstance::<T, I>::current_lead().is_none());
+
+                let new_balance = Balances::free_balance(&account_id.into());
+                let new_stake = <stake::Module<Runtime>>::stakes(stake_id);
+
+                assert_eq!(new_stake.staking_status, stake::StakingStatus::NotStaked);
+                assert_eq!(new_balance, old_balance);
+            });
+        }
+    }
 }