Skip to content

Commit

Permalink
Merge pull request #216 from InvArch/gabriel-move_stake
Browse files Browse the repository at this point in the history
OCIF Staking: Move stake between cores
  • Loading branch information
arrudagates authored Nov 30, 2023
2 parents 82061c3 + 4205046 commit 2830b0a
Show file tree
Hide file tree
Showing 7 changed files with 509 additions and 51 deletions.
5 changes: 1 addition & 4 deletions INV4/pallet-inv4/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ impl<
> MultisigInternalOrigin<T, CoreId, AccountId>
{
pub fn new(id: CoreId) -> Self {
Self {
id,
t: PhantomData::default(),
}
Self { id, t: PhantomData }
}

pub fn to_account_id(&self) -> AccountId {
Expand Down
40 changes: 40 additions & 0 deletions OCIF/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,28 @@ where
)
}

fn mock_register_2<T: Config>() -> DispatchResultWithPostInfo
where
Result<
INV4Origin<T, <T as pallet_inv4::Config>::CoreId, <T as frame_system::Config>::AccountId>,
<T as frame_system::Config>::RuntimeOrigin,
>: From<<T as frame_system::Config>::RuntimeOrigin>,
<T as frame_system::Config>::RuntimeOrigin:
From<INV4Origin<T, <T as pallet::Config>::CoreId, <T as frame_system::Config>::AccountId>>,
{
<T as Config>::Currency::make_free_balance_be(
&derive_account::<T>(1u32.into()),
T::RegisterDeposit::get() + T::RegisterDeposit::get(),
);

OcifStaking::<T>::register_core(
INV4Origin::Multisig(MultisigInternalOrigin::new(1u32.into())).into(),
vec![].try_into().unwrap(),
vec![].try_into().unwrap(),
vec![].try_into().unwrap(),
)
}

fn mock_stake<T: Config>() -> DispatchResultWithPostInfo
where
Result<
Expand Down Expand Up @@ -268,4 +290,22 @@ benchmarks! {
is_halted: true
}.into());
}

move_stake {
mock_register().unwrap();
mock_register_2().unwrap();

mock_stake().unwrap();

let staker: T::AccountId = whitelisted_caller();
let amount = T::StakeThresholdForActiveCore::get() + T::StakeThresholdForActiveCore::get();
}: _(RawOrigin::Signed(staker.clone()), 0u32.into(), amount, 1u32.into())
verify {
assert_last_event::<T>(Event::<T>::StakeMoved {
staker,
from_core: 0u32.into(),
amount,
to_core: 1u32.into()
}.into());
}
}
63 changes: 63 additions & 0 deletions OCIF/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ pub mod pallet {
old_metadata: CoreMetadata<Vec<u8>, Vec<u8>, Vec<u8>>,
new_metadata: CoreMetadata<Vec<u8>, Vec<u8>, Vec<u8>>,
},
StakeMoved {
staker: T::AccountId,
from_core: <T as Config>::CoreId,
to_core: <T as Config>::CoreId,
amount: BalanceOf<T>,
},
}

#[pallet::error]
Expand Down Expand Up @@ -309,6 +315,7 @@ pub mod pallet {
NotRegistered,
Halted,
NoHaltChange,
MoveStakeToSameCore,
}

#[pallet::hooks]
Expand Down Expand Up @@ -789,6 +796,62 @@ pub mod pallet {

Ok(().into())
}

#[pallet::call_index(9)]
#[pallet::weight(<T as Config>::WeightInfo::move_stake())]
pub fn move_stake(
origin: OriginFor<T>,
from_core: <T as pallet::Config>::CoreId,
#[pallet::compact] amount: BalanceOf<T>,
to_core: <T as pallet::Config>::CoreId,
) -> DispatchResultWithPostInfo {
Self::ensure_not_halted()?;

let staker = ensure_signed(origin)?;

ensure!(from_core != to_core, Error::<T>::MoveStakeToSameCore);
ensure!(
Self::core_info(to_core).is_some(),
Error::<T>::NotRegistered
);

let current_era = Self::current_era();
let mut from_staker_info = Self::staker_info(from_core, &staker);
let mut from_core_info =
Self::core_stake_info(from_core, current_era).unwrap_or_default();

let unstaked_amount = Self::internal_unstake(
&mut from_staker_info,
&mut from_core_info,
amount,
current_era,
)?;

let mut to_staker_info = Self::staker_info(to_core, &staker);
let mut to_core_info = Self::core_stake_info(to_core, current_era).unwrap_or_default();

Self::internal_stake(
&mut to_staker_info,
&mut to_core_info,
unstaked_amount,
current_era,
)?;

CoreEraStake::<T>::insert(from_core, current_era, from_core_info);
Self::update_staker_info(&staker, from_core, from_staker_info);

CoreEraStake::<T>::insert(to_core, current_era, to_core_info);
Self::update_staker_info(&staker, to_core, to_staker_info);

Self::deposit_event(Event::<T>::StakeMoved {
staker,
from_core,
to_core,
amount: unstaked_amount,
});

Ok(().into())
}
}

impl<T: Config> Pallet<T> {
Expand Down
74 changes: 74 additions & 0 deletions OCIF/staking/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,77 @@ fn assert_reward(
final_state_current_era.core_stake_info
);
}

pub(crate) fn assert_move_stake(
staker: AccountId,
from_core: &CoreId,
to_core: &CoreId,
amount: Balance,
) {
let current_era = OcifStaking::current_era();
let from_init_state = MemorySnapshot::all(current_era, &from_core, staker);
let to_init_state = MemorySnapshot::all(current_era, &to_core, staker);

let init_staked_value = from_init_state.staker_info.latest_staked_value();
let expected_transfer_amount = if init_staked_value - amount >= MINIMUM_STAKING_AMOUNT {
amount
} else {
init_staked_value
};

assert_ok!(OcifStaking::move_stake(
RuntimeOrigin::signed(staker),
from_core.clone(),
amount,
to_core.clone()
));
System::assert_last_event(mock::RuntimeEvent::OcifStaking(Event::StakeMoved {
staker,
from_core: from_core.clone(),
amount: expected_transfer_amount,
to_core: to_core.clone(),
}));

let from_final_state = MemorySnapshot::all(current_era, &from_core, staker);
let to_final_state = MemorySnapshot::all(current_era, &to_core, staker);

assert_eq!(
from_final_state.staker_info.latest_staked_value(),
init_staked_value - expected_transfer_amount
);
assert_eq!(
to_final_state.staker_info.latest_staked_value(),
to_init_state.staker_info.latest_staked_value() + expected_transfer_amount
);

assert_eq!(
from_final_state.core_stake_info.total,
from_init_state.core_stake_info.total - expected_transfer_amount
);
assert_eq!(
to_final_state.core_stake_info.total,
to_init_state.core_stake_info.total + expected_transfer_amount
);

let from_core_fully_unstaked = init_staked_value == expected_transfer_amount;
if from_core_fully_unstaked {
assert_eq!(
from_final_state.core_stake_info.number_of_stakers + 1,
from_init_state.core_stake_info.number_of_stakers
);
}

let no_init_stake_on_to_core = to_init_state.staker_info.latest_staked_value().is_zero();
if no_init_stake_on_to_core {
assert_eq!(
to_final_state.core_stake_info.number_of_stakers,
to_init_state.core_stake_info.number_of_stakers + 1
);
}

let fully_unstaked_and_nothing_to_claim =
from_core_fully_unstaked && to_final_state.staker_info.clone().claim() == (0, 0);
if fully_unstaked_and_nothing_to_claim {
assert!(!GeneralStakerInfo::<Test>::contains_key(&to_core, &staker));
}
}
Loading

0 comments on commit 2830b0a

Please sign in to comment.