Skip to content
This repository has been archived by the owner on Sep 28, 2023. It is now read-only.

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
Types UTs
  • Loading branch information
Dinonard committed Jun 14, 2023
1 parent a3d4ac9 commit 78619d9
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 33 deletions.
84 changes: 80 additions & 4 deletions frame/dapp-staking-v3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ pub mod pallet {
/// Minimum amount an account has to lock in dApp staking in order to participate.
#[pallet::constant]
type MinimumLockedAmount: Get<BalanceOf<Self>>;

/// Amount of blocks that need to pass before unlocking chunks can be claimed by the owner.
#[pallet::constant]
type UnlockingPeriod: Get<BlockNumberFor<Self>>;
}

#[pallet::event]
Expand Down Expand Up @@ -130,6 +134,12 @@ pub mod pallet {
account: T::AccountId,
amount: BalanceOf<T>,
},
// TODO: do we also add unlocking block info to the event?
/// Account has started the unlocking process for some amount.
Unlocking {
account: T::AccountId,
amount: BalanceOf<T>,
},
}

#[pallet::error]
Expand All @@ -155,6 +165,10 @@ pub mod pallet {
LockedAmountBelowThreshold,
/// Cannot add additional locked balance chunks due to size limit.
TooManyLockedBalanceChunks,
/// Cannot add additional unlocking chunks due to size limit
TooManyUnlockingChunks,
/// Remaining stake prevents entire balance of starting the unlocking process.
RemainingStakePreventsFullUnlock,
}

/// General information about dApp staking protocol state.
Expand Down Expand Up @@ -388,7 +402,7 @@ pub mod pallet {

// Calculate & check amount available for locking
let available_balance =
T::Currency::free_balance(&account).saturating_sub(ledger.locked_amount());
T::Currency::free_balance(&account).saturating_sub(ledger.active_locked_amount());
let amount_to_lock = available_balance.min(amount);
ensure!(!amount_to_lock.is_zero(), Error::<T>::ZeroAmount);

Expand All @@ -398,13 +412,13 @@ pub mod pallet {
.add_lock_amount(amount_to_lock, lock_era)
.map_err(|_| Error::<T>::TooManyLockedBalanceChunks)?;
ensure!(
ledger.locked_amount() >= T::MinimumLockedAmount::get(),
ledger.active_locked_amount() >= T::MinimumLockedAmount::get(),
Error::<T>::LockedAmountBelowThreshold
);

Self::update_ledger(&account, ledger);
CurrentEraInfo::<T>::mutate(|era_info| {
era_info.total_locked.saturating_accrue(amount_to_lock);
era_info.add_locked(amount_to_lock);
});

Self::deposit_event(Event::<T>::Locked {
Expand All @@ -414,6 +428,68 @@ pub mod pallet {

Ok(())
}

/// Attempts to start the unlocking process for the specified amount.
///
/// Only the amount that isn't actively used for staking can be unlocked.
/// If the amount is greater than the available amount for unlocking, everything is unlocked.
/// If the remaining locked amount would take the account below the minimum locked amount, everything is unlocked.
#[pallet::call_index(6)]
#[pallet::weight(Weight::zero())]
pub fn unlock(
origin: OriginFor<T>,
#[pallet::compact] amount: BalanceOf<T>,
) -> DispatchResult {
Self::ensure_pallet_enabled()?;
let account = ensure_signed(origin)?;

let state = ActiveProtocolState::<T>::get();
let mut ledger = Ledger::<T>::get(&account);

let available_for_unlocking = ledger.unlockable_amount(state.period);
let amount_to_unlock = available_for_unlocking.min(amount);

// Ensure we unlock everything if remaining amount is below threshold.
let remaining_amount = ledger
.active_locked_amount()
.saturating_sub(amount_to_unlock);
let amount_to_unlock = if remaining_amount < T::MinimumLockedAmount::get() {
ensure!(
ledger.active_stake(state.period).is_zero(),
Error::<T>::RemainingStakePreventsFullUnlock
);
ledger.active_locked_amount()
} else {
amount_to_unlock
};

// Sanity check
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);

// Update ledger with new lock and unlocking amounts
ledger
.subtract_lock_amount(amount_to_unlock, state.era)
.map_err(|_| Error::<T>::TooManyLockedBalanceChunks)?;

let current_block = frame_system::Pallet::<T>::block_number();
let unlock_block = current_block.saturating_add(T::UnlockingPeriod::get());
ledger
.add_unlocking_chunk(amount_to_unlock, unlock_block)
.map_err(|_| Error::<T>::TooManyUnlockingChunks)?;

// Update storage
Self::update_ledger(&account, ledger);
CurrentEraInfo::<T>::mutate(|era_info| {
era_info.unlocking_started(amount_to_unlock);
});

Self::deposit_event(Event::<T>::Unlocking {
account,
amount: amount_to_unlock,
});

Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -450,7 +526,7 @@ pub mod pallet {
T::Currency::set_lock(
STAKING_ID,
account,
ledger.locked_amount(),
ledger.active_locked_amount(),
WithdrawReasons::all(),
);
Ledger::<T>::insert(account, ledger);
Expand Down
3 changes: 2 additions & 1 deletion frame/dapp-staking-v3/src/test/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{self as pallet_dapp_staking, *};

use frame_support::{
construct_runtime, parameter_types,
traits::{ConstU128, ConstU16, ConstU32},
traits::{ConstU128, ConstU16, ConstU32, ConstU64},
weights::Weight,
};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
Expand Down Expand Up @@ -109,6 +109,7 @@ impl pallet_dapp_staking::Config for Test {
type MaxLockedChunks = ConstU32<5>;
type MaxUnlockingChunks = ConstU32<5>;
type MinimumLockedAmount = ConstU128<MINIMUM_LOCK_AMOUNT>;
type UnlockingPeriod = ConstU64<20>;
}

#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, Hash)]
Expand Down
4 changes: 2 additions & 2 deletions frame/dapp-staking-v3/src/test/testing_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl MemorySnapshot {
pub fn locked_balance(&self, account: &AccountId) -> Balance {
self.ledger
.get(&account)
.map_or(Balance::zero(), |ledger| ledger.locked_amount())
.map_or(Balance::zero(), |ledger| ledger.active_locked_amount())
}
}

Expand Down Expand Up @@ -196,7 +196,7 @@ pub(crate) fn assert_lock(account: AccountId, amount: Balance) {
.ledger
.get(&account)
.expect("Ledger entry has to exist after succcessful lock call")
.era(),
.lock_era(),
post_snapshot.active_protocol_state.era + 1
);

Expand Down
Loading

0 comments on commit 78619d9

Please sign in to comment.