git.delta.rocks / unique-network / refs/commits / 99353211bdc0

difftreelog

feat added `unstake_partial` extrinsic

PraetorP2023-02-13parent: #d6d8a45.patch.diff
in: master

1 file changed

modifiedpallets/app-promotion/src/lib.rsdiffbeforeafterboth
72 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};
7777
78use 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();
500500
538 Ok(None::<Weight>.into())538 Ok(None::<Weight>.into())
539 }539 }
540
541 /// Unstakes all stakes.
542 /// Moves the sum of all stakes to the `reserved` state.
543 /// After the end of `PendingInterval` this sum becomes completely
544 /// 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();
550
551 // calculate block number where the sum would be free
552 let block = <frame_system::Pallet<T>>::block_number() + config.pending_interval;
553
554 let mut pendings = <PendingUnstake<T>>::get(block);
555
556 // checks that we can do unreserve stakes in the block
557 ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);
558
559 Self::partial_unstake(&staker_id, amount, pendings, block)?;
560
561 let mut total_stakes = 0u64;
562
563 let total_staked: BalanceOf<T> = Staked::<T>::drain_prefix((&staker_id,))
564 .map(|(_, (amount, _))| {
565 total_stakes += 1;
566 amount
567 })
568 .sum();
569
570 if total_staked.is_zero() {
571 return Ok(()); // TO-DO
572 }
573
574 // pendings
575 // .try_push((staker_id.clone(), total_staked))
576 // .map_err(|_| Error::<T>::PendingForBlockOverflow)?;
577
578 // <PendingUnstake<T>>::insert(block, pendings);
579
580 // TotalStaked::<T>::set(
581 // TotalStaked::<T>::get()
582 // .checked_sub(&total_staked)
583 // .ok_or(ArithmeticError::Underflow)?,
584 // );
585
586 // StakesPerAccount::<T>::remove(&staker_id);
587
588 Self::deposit_event(Event::Unstake(staker_id, total_staked));
589
590 Ok(())
591 }
540592
541 /// 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 }
863
864 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 }
876
877 let mut stakes = Staked::<T>::iter_prefix((staker_id,)).collect::<Vec<_>>();
878
879 let total_staked = stakes
880 .iter()
881 .fold(<BalanceOf<T>>::default(), |acc, (_, (balance, _))| {
882 acc + *balance
883 });
884
885 ensure!(total_staked >= unstaked_balance, ArithmeticError::Underflow);
886
887 <TotalStaked<T>>::set(
888 <TotalStaked<T>>::get()
889 .checked_sub(&unstaked_balance)
890 .ok_or(ArithmeticError::Underflow)?,
891 );
892
893 stakes.sort_by_key(|(block, _)| *block);
894
895 let mut acc_amount = unstaked_balance;
896 let mut will_deleted_stakes_count = 0u8;
897
898 let changed_stakes = stakes
899 .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<_>>();
915
916 pendings
917 .try_push((staker_id.clone(), unstaked_balance))
918 .map_err(|_| Error::<T>::PendingForBlockOverflow)?;
919
920 StakesPerAccount::<T>::try_mutate(staker_id, |stakes| -> DispatchResult {
921 *stakes = stakes
922 .checked_div(will_deleted_stakes_count)
923 .ok_or(ArithmeticError::Underflow)?;
924 Ok(())
925 })?;
926
927 changed_stakes
928 .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_state
935 });
936 }
937 });
938
939 <PendingUnstake<T>>::insert(pending_block, pendings);
940
941 Ok(())
942 }
811943
812 /// Adds the balance to locked by the pallet.944 /// Adds the balance to locked by the pallet.
813 ///945 ///