diff --git a/integration-tests/src/staking.rs b/integration-tests/src/staking.rs index bdf825b7b..9f6cbb1c5 100644 --- a/integration-tests/src/staking.rs +++ b/integration-tests/src/staking.rs @@ -1041,9 +1041,259 @@ fn staking_should_not_allow_to_remove_vote_when_referendum_is_finished_and_staki }); } +#[test] +fn staking_should_allow_to_remove_vote_when_user_lost_and_conviction_expires() { + TestNet::reset(); + Hydra::execute_with(|| { + System::set_block_number(0); + init_omnipool(); + assert_ok!(Staking::initialize_staking(RawOrigin::Root.into())); + + let staking_account = pallet_staking::Pallet::::pot_account_id(); + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + staking_account, + HDX, + (10_000 * UNITS) as i128, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + ALICE.into(), + 1_000_000 * UNITS, + 0, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + BOB.into(), + 1_000_000 * UNITS, + 0, + )); + let r = begin_referendum(); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + 3_000 * UNITS + )); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + 1_000_000 * UNITS + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: true, + conviction: Conviction::Locked6x, + }, + balance: 1_000_000 * UNITS, + } + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: false, + conviction: Conviction::Locked1x, + }, + balance: 222 * UNITS, + } + )); + end_referendum(); + + fast_forward_to(18 * DAYS); + + let stake_position_id = pallet_staking::Pallet::::get_user_position_id( + &sp_runtime::AccountId32::from(BOB), + ) + .unwrap() + .unwrap(); + assert_ok!(Democracy::remove_vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r + ),); + assert_ok!(Democracy::unlock( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + BOB.into() + ),); + let stake_voting = pallet_staking::Pallet::::get_position_votes(stake_position_id); + assert!(stake_voting.votes.is_empty()); + let position = pallet_staking::Pallet::::get_position(stake_position_id).unwrap(); + assert_eq!(position.get_action_points(), 1); + assert_lock(&BOB.into(), 0, DEMOCRACY_ID); + }); +} + +#[test] +fn staking_should_allow_to_remove_vote_when_user_won() { + TestNet::reset(); + Hydra::execute_with(|| { + System::set_block_number(0); + init_omnipool(); + assert_ok!(Staking::initialize_staking(RawOrigin::Root.into())); + + let staking_account = pallet_staking::Pallet::::pot_account_id(); + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + staking_account, + HDX, + (10_000 * UNITS) as i128, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + ALICE.into(), + 1_000_000 * UNITS, + 0, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + BOB.into(), + 1_000_000 * UNITS, + 0, + )); + let r = begin_referendum(); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + 3_000 * UNITS + )); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + 1_000_000 * UNITS + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: true, + conviction: Conviction::Locked6x, + }, + balance: 1_000_000 * UNITS, + } + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: false, + conviction: Conviction::Locked1x, + }, + balance: 222 * UNITS, + } + )); + end_referendum(); + + let stake_position_id = pallet_staking::Pallet::::get_user_position_id( + &sp_runtime::AccountId32::from(ALICE), + ) + .unwrap() + .unwrap(); + assert_ok!(Democracy::remove_vote( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + r + ),); + assert_ok!(Democracy::unlock( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + ALICE.into() + ),); + let stake_voting = pallet_staking::Pallet::::get_position_votes(stake_position_id); + assert!(stake_voting.votes.is_empty()); + let position = pallet_staking::Pallet::::get_position(stake_position_id).unwrap(); + assert_eq!(position.get_action_points(), 100); + assert_lock(&ALICE.into(), 1_000_000 * UNITS, DEMOCRACY_ID); + }); +} + +#[test] +fn staking_should_allow_to_remove_vote_when_user_lost_with_no_conviction() { + TestNet::reset(); + Hydra::execute_with(|| { + System::set_block_number(0); + init_omnipool(); + assert_ok!(Staking::initialize_staking(RawOrigin::Root.into())); + + let staking_account = pallet_staking::Pallet::::pot_account_id(); + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + staking_account, + HDX, + (10_000 * UNITS) as i128, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + ALICE.into(), + 1_000_000 * UNITS, + 0, + )); + assert_ok!(Balances::set_balance( + RawOrigin::Root.into(), + BOB.into(), + 1_000_000 * UNITS, + 0, + )); + let r = begin_referendum(); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + 3_000 * UNITS + )); + assert_ok!(Staking::stake( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + 1_000_000 * UNITS + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: true, + conviction: Conviction::Locked6x, + }, + balance: 1_000_000 * UNITS, + } + )); + + assert_ok!(Democracy::vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r, + AccountVote::Standard { + vote: Vote { + aye: false, + conviction: Conviction::None, + }, + balance: 3_000 * UNITS, + } + )); + end_referendum(); + + let stake_position_id = pallet_staking::Pallet::::get_user_position_id( + &sp_runtime::AccountId32::from(BOB), + ) + .unwrap() + .unwrap(); + assert_ok!(Democracy::remove_vote( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + r + ),); + assert_ok!(Democracy::unlock( + hydradx_runtime::RuntimeOrigin::signed(BOB.into()), + BOB.into() + ),); + let stake_voting = pallet_staking::Pallet::::get_position_votes(stake_position_id); + assert!(stake_voting.votes.is_empty()); + let position = pallet_staking::Pallet::::get_position(stake_position_id).unwrap(); + assert_eq!(position.get_action_points(), 1); + assert_lock(&BOB.into(), 0, DEMOCRACY_ID); + }); +} + const DEMOCRACY_ID: LockIdentifier = *b"democrac"; use pallet_balances::BalanceLock; - fn assert_lock(who: &AccountId, amount: Balance, lock_id: LockIdentifier) { let locks = Balances::locks(who); let lock = locks.iter().find(|e| e.id == lock_id); diff --git a/pallets/staking/src/integrations/democracy.rs b/pallets/staking/src/integrations/democracy.rs index 6d538d187..052aeeb46 100644 --- a/pallets/staking/src/integrations/democracy.rs +++ b/pallets/staking/src/integrations/democracy.rs @@ -84,7 +84,6 @@ where } fn on_remove_vote(who: &T::AccountId, ref_index: ReferendumIndex, should_lock: bool) -> DispatchResult { - let position_id = if let Some(position_id) = Pallet::::get_user_position_id(who)? { position_id } else { @@ -93,7 +92,7 @@ where // This handles a case when user removes vote on finished referendum and the vote was in opposition to the referendum result // If user has a staking position, we keep the amount locked - if should_lock{ + if should_lock { return Err(Error::::RemoveVoteNotAllowed.into()); }