Browse Source

Add create_terminate_working_group_leader_role_proposal() to the codex

Shamil Gadelshin 4 years ago
parent
commit
4e68859098

+ 4 - 0
node/src/chain_spec.rs

@@ -359,6 +359,10 @@ pub fn testnet_genesis(
                 .set_working_group_leader_reward_proposal_voting_period,
             set_working_group_leader_reward_proposal_grace_period: cpcp
                 .set_working_group_leader_reward_proposal_grace_period,
+            terminate_working_group_leader_role_proposal_voting_period: cpcp
+                .terminate_working_group_leader_role_proposal_voting_period,
+            terminate_working_group_leader_role_proposal_grace_period: cpcp
+                .terminate_working_group_leader_role_proposal_grace_period,
         }),
     }
 }

+ 44 - 3
runtime-modules/proposals/codex/src/lib.rs

@@ -33,6 +33,7 @@
 //! - [create_decrease_working_group_leader_stake_proposal](./struct.Module.html#method.create_decrease_working_group_leader_stake_proposal)
 //! - [create_slash_working_group_leader_stake_proposal](./struct.Module.html#method.create_slash_working_group_leader_stake_proposal)
 //! - [create_set_working_group_leader_reward_proposal](./struct.Module.html#method.create_set_working_group_leader_reward_proposal)
+//! - [create_terminate_working_group_leader_role_proposal](./struct.Module.html#method.create_terminate_working_group_leader_role_proposal)
 //!
 //! ### Proposal implementations of this module
 //! - execute_text_proposal - prints the proposal to the log
@@ -83,7 +84,7 @@ use srml_support::{decl_error, decl_module, decl_storage, ensure, print};
 use system::ensure_root;
 
 pub use crate::proposal_types::{
-    AddOpeningParameters, FillOpeningParameters, ProposalsConfigParameters,
+    AddOpeningParameters, FillOpeningParameters, ProposalsConfigParameters, TerminateRoleParameters,
 };
 pub use proposal_types::{ProposalDetails, ProposalDetailsOf, ProposalEncoder};
 
@@ -398,6 +399,14 @@ decl_storage! {
         /// Grace period for the 'set working group leader reward' proposal
         pub SetWorkingGroupLeaderRewardProposalGracePeriod get(set_working_group_leader_reward_proposal_grace_period)
             config(): T::BlockNumber;
+
+        /// Voting period for the 'terminate working group leader role' proposal
+        pub TerminateWorkingGroupLeaderRoleProposalVotingPeriod get(terminate_working_group_leader_role_proposal_voting_period)
+            config(): T::BlockNumber;
+
+        /// Grace period for the 'terminate working group leader role' proposal
+        pub TerminateWorkingGroupLeaderRoleProposalGracePeriod get(terminate_working_group_leader_role_proposal_grace_period)
+            config(): T::BlockNumber;
     }
 }
 
@@ -689,7 +698,7 @@ decl_module! {
             title: Vec<u8>,
             description: Vec<u8>,
             stake_balance: Option<BalanceOf<T>>,
-            params: FillOpeningParameters<
+            fill_opening_parameters: FillOpeningParameters<
                 T::BlockNumber,
                 BalanceOfMint<T>,
                 working_group::OpeningId<T>,
@@ -697,7 +706,7 @@ decl_module! {
             >
         ) {
 
-            let proposal_details = ProposalDetails::FillWorkingGroupLeaderOpening(params);
+            let proposal_details = ProposalDetails::FillWorkingGroupLeaderOpening(fill_opening_parameters);
             let params = CreateProposalParameters{
                 origin,
                 member_id,
@@ -846,6 +855,32 @@ decl_module! {
             Self::create_proposal(params)?;
         }
 
+        /// Create 'terminate working group leader rolw' proposal type.
+        /// This proposal uses `terminate_role()` extrinsic from the `working-group`  module.
+        pub fn create_terminate_working_group_leader_role_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            stake_balance: Option<BalanceOf<T>>,
+            terminate_role_parameters: TerminateRoleParameters<working_group::WorkerId<T>>,
+        ) {
+            let proposal_details = ProposalDetails::TerminateWorkingGroupLeaderRole(terminate_role_parameters);
+
+            let params = CreateProposalParameters{
+                origin,
+                member_id,
+                title,
+                description,
+                stake_balance,
+                proposal_details: proposal_details.clone(),
+                proposal_parameters: proposal_types::parameters::terminate_working_group_leader_role_proposal::<T>(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+            };
+
+            Self::create_proposal(params)?;
+        }
+
 
 // *************** Extrinsic to execute
 
@@ -1111,5 +1146,11 @@ impl<T: Trait> Module<T> {
         <SetWorkingGroupLeaderRewardProposalGracePeriod<T>>::put(T::BlockNumber::from(
             p.set_working_group_leader_reward_proposal_grace_period,
         ));
+        <TerminateWorkingGroupLeaderRoleProposalVotingPeriod<T>>::put(T::BlockNumber::from(
+            p.terminate_working_group_leader_role_proposal_voting_period,
+        ));
+        <TerminateWorkingGroupLeaderRoleProposalGracePeriod<T>>::put(T::BlockNumber::from(
+            p.terminate_working_group_leader_role_proposal_grace_period,
+        ));
     } //TODO set defaults for new proposals
 }

+ 32 - 4
runtime-modules/proposals/codex/src/proposal_types/mod.rs

@@ -85,17 +85,20 @@ pub enum ProposalDetails<
         FillOpeningParameters<BlockNumber, MintedBalance, OpeningId, ApplicationId>,
     ),
 
-    /// Balance for the `set working group mint capacity` proposal
+    /// Set working group mint capacity.
     SetWorkingGroupMintCapacity(MintedBalance, WorkingGroup),
 
-    /// Balance for the `decrease working group leader stake` proposal
+    /// Decrease the working group leader stake.
     DecreaseWorkingGroupLeaderStake(WorkerId, StakeBalance, WorkingGroup),
 
-    /// Balance for the `slash working group leader stake` proposal
+    /// Slash the working group leader stake.
     SlashWorkingGroupLeaderStake(WorkerId, StakeBalance, WorkingGroup),
 
-    /// Balance for the `set working group leader reward` proposal
+    /// Set working group leader reward balance.
     SetWorkingGroupLeaderReward(WorkerId, MintedBalance, WorkingGroup),
+
+    /// Fire the working group leader with possible slashing.
+    TerminateWorkingGroupLeaderRole(TerminateRoleParameters<WorkerId>),
 }
 
 impl<
@@ -126,6 +129,23 @@ impl<
     }
 }
 
+/// Parameters for the 'terminate the leader position' proposal.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Debug)]
+pub struct TerminateRoleParameters<WorkerId> {
+    /// Leader worker id to fire.
+    pub worker_id: WorkerId,
+
+    /// Terminate role rationale.
+    pub rationale: Vec<u8>,
+
+    /// Slash the leader stake on terminating.
+    pub slash: bool,
+
+    /// Defines working group with the open position.
+    pub working_group: WorkingGroup,
+}
+
 /// Parameters for the 'fill opening for the leader position' proposal.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Debug)]
@@ -284,6 +304,12 @@ pub struct ProposalsConfigParameters {
 
     /// 'Set working group leader reward' proposal grace period
     pub set_working_group_leader_reward_proposal_grace_period: u32,
+
+    /// 'Terminate working group leader role' proposal voting period
+    pub terminate_working_group_leader_role_proposal_voting_period: u32,
+
+    /// 'Terminate working group leader role' proposal grace period
+    pub terminate_working_group_leader_role_proposal_grace_period: u32,
 }
 
 impl Default for ProposalsConfigParameters {
@@ -317,6 +343,8 @@ impl Default for ProposalsConfigParameters {
             slash_working_group_leader_stake_proposal_grace_period: 0u32,
             set_working_group_leader_reward_proposal_voting_period: 43200u32,
             set_working_group_leader_reward_proposal_grace_period: 0u32,
+            terminate_working_group_leader_role_proposal_voting_period: 72200u32,
+            terminate_working_group_leader_role_proposal_grace_period: 0u32,
         }
     }
 }

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

@@ -197,3 +197,17 @@ pub(crate) fn set_working_group_leader_reward_proposal<T: crate::Trait>(
         required_stake: Some(<BalanceOf<T>>::from(50000u32)),
     }
 }
+
+// Proposal parameters for the 'Terminate working group leader role' proposal
+pub(crate) fn terminate_working_group_leader_role_proposal<T: crate::Trait>(
+) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
+    ProposalParameters {
+        voting_period: <Module<T>>::terminate_working_group_leader_role_proposal_voting_period(),
+        grace_period: <Module<T>>::terminate_working_group_leader_role_proposal_grace_period(),
+        approval_quorum_percentage: 66,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(<BalanceOf<T>>::from(100_000_u32)),
+    }
+}

+ 66 - 3
runtime-modules/proposals/codex/src/tests/mod.rs

@@ -70,7 +70,7 @@ where
 
     fn check_for_successful_call(&self) {
         let account_id = 1;
-        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 50000);
+        let _imbalance = <Test as stake::Trait>::Currency::deposit_creating(&account_id, 150000);
 
         assert_eq!((self.successful_call)(), Ok(()));
 
@@ -1328,8 +1328,6 @@ fn decrease_stake_with_zero_staking_balance_fails() {
 #[test]
 fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
     initial_test_ext().execute_with(|| {
-        increase_total_balance_issuance(500000);
-
         let proposal_fixture = ProposalTestFixture {
             insufficient_rights_call: || {
                 ProposalCodex::create_set_working_group_leader_reward_proposal(
@@ -1391,3 +1389,68 @@ fn create_set_working_group_leader_reward_proposal_common_checks_succeed() {
         proposal_fixture.check_all();
     });
 }
+
+#[test]
+fn create_terminate_working_group_leader_role_proposal_common_checks_succeed() {
+    initial_test_ext().execute_with(|| {
+        increase_total_balance_issuance(500000);
+
+        let terminate_role_parameters = TerminateRoleParameters {
+            worker_id: 10,
+            rationale: Vec::new(),
+            slash: false,
+            working_group: WorkingGroup::Storage,
+        };
+
+        let proposal_fixture = ProposalTestFixture {
+            insufficient_rights_call: || {
+                ProposalCodex::create_terminate_working_group_leader_role_proposal(
+                    RawOrigin::None.into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    terminate_role_parameters.clone(),
+                )
+            },
+            empty_stake_call: || {
+                ProposalCodex::create_terminate_working_group_leader_role_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    None,
+                    terminate_role_parameters.clone(),
+                )
+            },
+            invalid_stake_call: || {
+                ProposalCodex::create_terminate_working_group_leader_role_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(5000u32)),
+                    terminate_role_parameters.clone(),
+                )
+            },
+            successful_call: || {
+                ProposalCodex::create_terminate_working_group_leader_role_proposal(
+                    RawOrigin::Signed(1).into(),
+                    1,
+                    b"title".to_vec(),
+                    b"body".to_vec(),
+                    Some(<BalanceOf<Test>>::from(100_000_u32)),
+                    terminate_role_parameters.clone(),
+                )
+            },
+            proposal_parameters:
+                crate::proposal_types::parameters::terminate_working_group_leader_role_proposal::<
+                    Test,
+                >(),
+            proposal_details: ProposalDetails::TerminateWorkingGroupLeaderRole(
+                terminate_role_parameters.clone(),
+            ),
+        };
+        proposal_fixture.check_all();
+    });
+}

+ 56 - 62
runtime/src/integration/proposals/proposal_encoder.rs

@@ -14,127 +14,110 @@ use srml_support::print;
 pub struct ExtrinsicProposalEncoder;
 impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
     fn encode_proposal(proposal_details: ProposalDetailsOf<Runtime>) -> Vec<u8> {
-        match proposal_details {
+        let call = match proposal_details {
             ProposalDetails::Text(text) => {
-                Call::ProposalsCodex(proposals_codex::Call::execute_text_proposal(text)).encode()
+                Call::ProposalsCodex(proposals_codex::Call::execute_text_proposal(text))
             }
             ProposalDetails::SetElectionParameters(election_parameters) => Call::CouncilElection(
                 governance::election::Call::set_election_parameters(election_parameters),
-            )
-            .encode(),
+            ),
             ProposalDetails::SetContentWorkingGroupMintCapacity(mint_balance) => {
                 Call::ContentWorkingGroup(content_working_group::Call::set_mint_capacity(
                     mint_balance,
                 ))
-                .encode()
             }
             ProposalDetails::Spending(balance, destination) => Call::Council(
                 governance::council::Call::spend_from_council_mint(balance, destination),
-            )
-            .encode(),
+            ),
             ProposalDetails::SetLead(new_lead) => {
                 Call::ContentWorkingGroup(content_working_group::Call::replace_lead(new_lead))
-                    .encode()
             }
             ProposalDetails::SetValidatorCount(new_validator_count) => {
-                Call::Staking(staking::Call::set_validator_count(new_validator_count)).encode()
+                Call::Staking(staking::Call::set_validator_count(new_validator_count))
             }
             ProposalDetails::RuntimeUpgrade(wasm_code) => Call::ProposalsCodex(
                 proposals_codex::Call::execute_runtime_upgrade_proposal(wasm_code),
-            )
-            .encode(),
+            ),
             // ********** Deprecated during the Nicaea release.
             // It is kept only for backward compatibility in the Pioneer. **********
             ProposalDetails::EvictStorageProvider(_) => {
                 print("Error: Calling deprecated EvictStorageProvider encoding option.");
-                Vec::new()
+                return Vec::new();
             }
             // ********** Deprecated during the Nicaea release.
             // It is kept only for backward compatibility in the Pioneer. **********
             ProposalDetails::SetStorageRoleParameters(_) => {
                 print("Error: Calling deprecated SetStorageRoleParameters encoding option.");
-                Vec::new()
+                return Vec::new();
             }
             ProposalDetails::AddWorkingGroupLeaderOpening(add_opening_params) => {
-                let call = match add_opening_params.working_group {
+                match add_opening_params.working_group {
                     WorkingGroup::Storage => {
                         Call::StorageWorkingGroup(Wg::create_add_opening_call(add_opening_params))
                     }
-                };
-
-                call.encode()
+                }
             }
             ProposalDetails::BeginReviewWorkingGroupLeaderApplications(
                 opening_id,
                 working_group,
-            ) => {
-                let call = match working_group {
-                    WorkingGroup::Storage => Call::StorageWorkingGroup(
-                        Wg::create_begin_review_applications_call(opening_id),
-                    ),
-                };
-
-                call.encode()
-            }
+            ) => match working_group {
+                WorkingGroup::Storage => {
+                    Call::StorageWorkingGroup(Wg::create_begin_review_applications_call(opening_id))
+                }
+            },
             ProposalDetails::FillWorkingGroupLeaderOpening(fill_opening_params) => {
-                let call = match fill_opening_params.working_group {
+                match fill_opening_params.working_group {
                     WorkingGroup::Storage => {
                         Call::StorageWorkingGroup(Wg::create_fill_opening_call(fill_opening_params))
                     }
-                };
-
-                call.encode()
+                }
             }
             ProposalDetails::SetWorkingGroupMintCapacity(mint_balance, working_group) => {
-                let call = match working_group {
+                match working_group {
                     WorkingGroup::Storage => {
                         Call::StorageWorkingGroup(Wg::create_set_mint_capacity_call(mint_balance))
                     }
-                };
-
-                call.encode()
+                }
             }
             ProposalDetails::DecreaseWorkingGroupLeaderStake(
                 worker_id,
                 decreasing_stake,
                 working_group,
-            ) => {
-                let call = match working_group {
-                    WorkingGroup::Storage => Call::StorageWorkingGroup(
-                        Wg::create_decrease_stake_call(worker_id, decreasing_stake),
-                    ),
-                };
-
-                call.encode()
-            }
+            ) => match working_group {
+                WorkingGroup::Storage => Call::StorageWorkingGroup(Wg::create_decrease_stake_call(
+                    worker_id,
+                    decreasing_stake,
+                )),
+            },
             ProposalDetails::SlashWorkingGroupLeaderStake(
                 worker_id,
                 slashing_stake,
                 working_group,
-            ) => {
-                let call = match working_group {
-                    WorkingGroup::Storage => Call::StorageWorkingGroup(
-                        Wg::create_slash_stake_call(worker_id, slashing_stake),
-                    ),
-                };
-
-                call.encode()
-            }
+            ) => match working_group {
+                WorkingGroup::Storage => Call::StorageWorkingGroup(Wg::create_slash_stake_call(
+                    worker_id,
+                    slashing_stake,
+                )),
+            },
             ProposalDetails::SetWorkingGroupLeaderReward(
                 worker_id,
                 reward_amount,
                 working_group,
-            ) => {
-                let call = match working_group {
-                    WorkingGroup::Storage => Call::StorageWorkingGroup(Wg::create_set_reward_call(
-                        worker_id,
-                        reward_amount,
-                    )),
-                };
-
-                call.encode()
+            ) => match working_group {
+                WorkingGroup::Storage => {
+                    Call::StorageWorkingGroup(Wg::create_set_reward_call(worker_id, reward_amount))
+                }
+            },
+            ProposalDetails::TerminateWorkingGroupLeaderRole(terminate_role_params) => {
+                match terminate_role_params.working_group {
+                    WorkingGroup::Storage => {
+                        Call::StorageWorkingGroup(Wg::terminate_role_call(terminate_role_params))
+                    }
+                }
             }
-        }
+        };
+
+        call.encode()
     }
 }
 
@@ -220,4 +203,15 @@ where
     ) -> working_group::Call<T, I> {
         working_group::Call::<T, I>::update_reward_amount(worker_id, reward_amount)
     }
+
+    // Generic call constructor for the working group 'terminate role'.
+    fn terminate_role_call(
+        terminate_role_params: proposals_codex::TerminateRoleParameters<working_group::WorkerId<T>>,
+    ) -> working_group::Call<T, I> {
+        working_group::Call::<T, I>::terminate_role(
+            terminate_role_params.worker_id,
+            terminate_role_params.rationale,
+            terminate_role_params.slash,
+        )
+    }
 }

+ 196 - 0
runtime/src/tests/proposals_integration/working_group_proposals.rs

@@ -246,6 +246,38 @@ fn set_mint_capacity(
     codex_extrinsic_test_fixture.call_extrinsic_and_assert();
 }
 
+fn terminate_role(
+    member_id: u8,
+    account_id: [u8; 32],
+    leader_worker_id: u64,
+    slash: bool,
+    sequence_number: u32, // action sequence number to align with other actions
+) {
+    let expected_proposal_id = sequence_number;
+    let run_to_block = sequence_number + 1;
+
+    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,
+            b"title".to_vec(),
+            b"body".to_vec(),
+            Some(<BalanceOf<Runtime>>::from(100_000_u32)),
+            proposals_codex::TerminateRoleParameters {
+                worker_id: leader_worker_id,
+                rationale: Vec::new(),
+                slash,
+                working_group: WorkingGroup::Storage,
+            },
+        )
+    })
+    .disable_setup_enviroment()
+    .with_expected_proposal_id(expected_proposal_id)
+    .with_run_to_block(run_to_block);
+
+    codex_extrinsic_test_fixture.call_extrinsic_and_assert();
+}
+
 #[test]
 fn create_add_working_group_leader_opening_proposal_execution_succeeds() {
     initial_test_ext().execute_with(|| {
@@ -637,3 +669,167 @@ fn create_set_group_leader_reward_proposal_execution_succeeds() {
         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());
+
+        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(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::<&AccountId32>(&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::<&AccountId32>(&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());
+
+        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(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::<&AccountId32>(&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::<&AccountId32>(&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);
+    });
+}