difftreelog
feat added `unstake_partial` extrinsic
in: master
1 file changed
pallets/app-promotion/src/lib.rsdiffbeforeafterboth72 traits::{72 traits::{73 Currency, Get, LockableCurrency, WithdrawReasons, tokens::Balance, ExistenceRequirement,73 Currency, Get, LockableCurrency, WithdrawReasons, tokens::Balance, ExistenceRequirement,74 },74 },75 ensure,75 ensure, BoundedVec,76};76};777778use weights::WeightInfo;78use weights::WeightInfo;494 /// free for further use.494 /// free for further use.495 #[pallet::call_index(2)]495 #[pallet::call_index(2)]496 #[pallet::weight(<T as Config>::WeightInfo::unstake())]496 #[pallet::weight(<T as Config>::WeightInfo::unstake())]497 pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {497 pub fn unstake_all(staker: OriginFor<T>) -> DispatchResultWithPostInfo {498 let staker_id = ensure_signed(staker)?;498 let staker_id = ensure_signed(staker)?;499 let config = <PalletConfiguration<T>>::get();499 let config = <PalletConfiguration<T>>::get();500500538 Ok(None::<Weight>.into())538 Ok(None::<Weight>.into())539 }539 }540541 /// Unstakes all stakes.542 /// Moves the sum of all stakes to the `reserved` state.543 /// After the end of `PendingInterval` this sum becomes completely544 /// free for further use.545 #[pallet::call_index(8)]546 #[pallet::weight(<T as Config>::WeightInfo::unstake())]547 pub fn unstake_partial(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {548 let staker_id = ensure_signed(staker)?;549 let config = <PalletConfiguration<T>>::get();550551 // calculate block number where the sum would be free552 let block = <frame_system::Pallet<T>>::block_number() + config.pending_interval;553554 let mut pendings = <PendingUnstake<T>>::get(block);555556 // checks that we can do unreserve stakes in the block557 ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);558559 Self::partial_unstake(&staker_id, amount, pendings, block)?;560561 let mut total_stakes = 0u64;562563 let total_staked: BalanceOf<T> = Staked::<T>::drain_prefix((&staker_id,))564 .map(|(_, (amount, _))| {565 total_stakes += 1;566 amount567 })568 .sum();569570 if total_staked.is_zero() {571 return Ok(()); // TO-DO572 }573574 // pendings575 // .try_push((staker_id.clone(), total_staked))576 // .map_err(|_| Error::<T>::PendingForBlockOverflow)?;577578 // <PendingUnstake<T>>::insert(block, pendings);579580 // TotalStaked::<T>::set(581 // TotalStaked::<T>::get()582 // .checked_sub(&total_staked)583 // .ok_or(ArithmeticError::Underflow)?,584 // );585586 // StakesPerAccount::<T>::remove(&staker_id);587588 Self::deposit_event(Event::Unstake(staker_id, total_staked));589590 Ok(())591 }540592541 /// Sets the pallet to be the sponsor for the collection.593 /// Sets the pallet to be the sponsor for the collection.542 ///594 ///809 T::PalletId::get().into_account_truncating()861 T::PalletId::get().into_account_truncating()810 }862 }863864 fn partial_unstake(865 staker_id: &T::AccountId,866 unstaked_balance: BalanceOf<T>,867 mut pendings: BoundedVec<868 (T::AccountId, BalanceOf<T>),869 sp_core::ConstU32<PENDING_LIMIT_PER_BLOCK>,870 >,871 pending_block: T::BlockNumber,872 ) -> DispatchResult {873 if unstaked_balance == Default::default() {874 return Ok(());875 }876877 let mut stakes = Staked::<T>::iter_prefix((staker_id,)).collect::<Vec<_>>();878879 let total_staked = stakes880 .iter()881 .fold(<BalanceOf<T>>::default(), |acc, (_, (balance, _))| {882 acc + *balance883 });884885 ensure!(total_staked >= unstaked_balance, ArithmeticError::Underflow);886887 <TotalStaked<T>>::set(888 <TotalStaked<T>>::get()889 .checked_sub(&unstaked_balance)890 .ok_or(ArithmeticError::Underflow)?,891 );892893 stakes.sort_by_key(|(block, _)| *block);894895 let mut acc_amount = unstaked_balance;896 let mut will_deleted_stakes_count = 0u8;897898 let changed_stakes = stakes899 .into_iter()900 .map_while(|(block, (balance_per_block, recalc_block))| {901 if acc_amount == <BalanceOf<T>>::default() {902 return None;903 }904 if acc_amount <= balance_per_block {905 let res = (block, (balance_per_block - acc_amount, recalc_block));906 acc_amount = <BalanceOf<T>>::default();907 return Some(res);908 } else {909 acc_amount -= balance_per_block;910 will_deleted_stakes_count += 1;911 return Some((block, (<BalanceOf<T>>::default(), recalc_block)));912 }913 })914 .collect::<Vec<_>>();915916 pendings917 .try_push((staker_id.clone(), unstaked_balance))918 .map_err(|_| Error::<T>::PendingForBlockOverflow)?;919920 StakesPerAccount::<T>::try_mutate(staker_id, |stakes| -> DispatchResult {921 *stakes = stakes922 .checked_div(will_deleted_stakes_count)923 .ok_or(ArithmeticError::Underflow)?;924 Ok(())925 })?;926927 changed_stakes928 .iter()929 .for_each(|(staked_block, (current_stake_state, _))| {930 if current_stake_state == &Default::default() {931 <Staked<T>>::remove((staker_id, staked_block));932 } else {933 <Staked<T>>::mutate((staker_id, staked_block), |(old_stake_state, _)| {934 *old_stake_state = *current_stake_state935 });936 }937 });938939 <PendingUnstake<T>>::insert(pending_block, pendings);940941 Ok(())942 }811943812 /// Adds the balance to locked by the pallet.944 /// Adds the balance to locked by the pallet.813 ///945 ///