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

Commit 78619d9

Browse files
committed
First commit
Types UTs
1 parent a3d4ac9 commit 78619d9

5 files changed

Lines changed: 432 additions & 33 deletions

File tree

frame/dapp-staking-v3/src/lib.rs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ pub mod pallet {
9999
/// Minimum amount an account has to lock in dApp staking in order to participate.
100100
#[pallet::constant]
101101
type MinimumLockedAmount: Get<BalanceOf<Self>>;
102+
103+
/// Amount of blocks that need to pass before unlocking chunks can be claimed by the owner.
104+
#[pallet::constant]
105+
type UnlockingPeriod: Get<BlockNumberFor<Self>>;
102106
}
103107

104108
#[pallet::event]
@@ -130,6 +134,12 @@ pub mod pallet {
130134
account: T::AccountId,
131135
amount: BalanceOf<T>,
132136
},
137+
// TODO: do we also add unlocking block info to the event?
138+
/// Account has started the unlocking process for some amount.
139+
Unlocking {
140+
account: T::AccountId,
141+
amount: BalanceOf<T>,
142+
},
133143
}
134144

135145
#[pallet::error]
@@ -155,6 +165,10 @@ pub mod pallet {
155165
LockedAmountBelowThreshold,
156166
/// Cannot add additional locked balance chunks due to size limit.
157167
TooManyLockedBalanceChunks,
168+
/// Cannot add additional unlocking chunks due to size limit
169+
TooManyUnlockingChunks,
170+
/// Remaining stake prevents entire balance of starting the unlocking process.
171+
RemainingStakePreventsFullUnlock,
158172
}
159173

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

389403
// Calculate & check amount available for locking
390404
let available_balance =
391-
T::Currency::free_balance(&account).saturating_sub(ledger.locked_amount());
405+
T::Currency::free_balance(&account).saturating_sub(ledger.active_locked_amount());
392406
let amount_to_lock = available_balance.min(amount);
393407
ensure!(!amount_to_lock.is_zero(), Error::<T>::ZeroAmount);
394408

@@ -398,13 +412,13 @@ pub mod pallet {
398412
.add_lock_amount(amount_to_lock, lock_era)
399413
.map_err(|_| Error::<T>::TooManyLockedBalanceChunks)?;
400414
ensure!(
401-
ledger.locked_amount() >= T::MinimumLockedAmount::get(),
415+
ledger.active_locked_amount() >= T::MinimumLockedAmount::get(),
402416
Error::<T>::LockedAmountBelowThreshold
403417
);
404418

405419
Self::update_ledger(&account, ledger);
406420
CurrentEraInfo::<T>::mutate(|era_info| {
407-
era_info.total_locked.saturating_accrue(amount_to_lock);
421+
era_info.add_locked(amount_to_lock);
408422
});
409423

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

415429
Ok(())
416430
}
431+
432+
/// Attempts to start the unlocking process for the specified amount.
433+
///
434+
/// Only the amount that isn't actively used for staking can be unlocked.
435+
/// If the amount is greater than the available amount for unlocking, everything is unlocked.
436+
/// If the remaining locked amount would take the account below the minimum locked amount, everything is unlocked.
437+
#[pallet::call_index(6)]
438+
#[pallet::weight(Weight::zero())]
439+
pub fn unlock(
440+
origin: OriginFor<T>,
441+
#[pallet::compact] amount: BalanceOf<T>,
442+
) -> DispatchResult {
443+
Self::ensure_pallet_enabled()?;
444+
let account = ensure_signed(origin)?;
445+
446+
let state = ActiveProtocolState::<T>::get();
447+
let mut ledger = Ledger::<T>::get(&account);
448+
449+
let available_for_unlocking = ledger.unlockable_amount(state.period);
450+
let amount_to_unlock = available_for_unlocking.min(amount);
451+
452+
// Ensure we unlock everything if remaining amount is below threshold.
453+
let remaining_amount = ledger
454+
.active_locked_amount()
455+
.saturating_sub(amount_to_unlock);
456+
let amount_to_unlock = if remaining_amount < T::MinimumLockedAmount::get() {
457+
ensure!(
458+
ledger.active_stake(state.period).is_zero(),
459+
Error::<T>::RemainingStakePreventsFullUnlock
460+
);
461+
ledger.active_locked_amount()
462+
} else {
463+
amount_to_unlock
464+
};
465+
466+
// Sanity check
467+
ensure!(!amount.is_zero(), Error::<T>::ZeroAmount);
468+
469+
// Update ledger with new lock and unlocking amounts
470+
ledger
471+
.subtract_lock_amount(amount_to_unlock, state.era)
472+
.map_err(|_| Error::<T>::TooManyLockedBalanceChunks)?;
473+
474+
let current_block = frame_system::Pallet::<T>::block_number();
475+
let unlock_block = current_block.saturating_add(T::UnlockingPeriod::get());
476+
ledger
477+
.add_unlocking_chunk(amount_to_unlock, unlock_block)
478+
.map_err(|_| Error::<T>::TooManyUnlockingChunks)?;
479+
480+
// Update storage
481+
Self::update_ledger(&account, ledger);
482+
CurrentEraInfo::<T>::mutate(|era_info| {
483+
era_info.unlocking_started(amount_to_unlock);
484+
});
485+
486+
Self::deposit_event(Event::<T>::Unlocking {
487+
account,
488+
amount: amount_to_unlock,
489+
});
490+
491+
Ok(())
492+
}
417493
}
418494

419495
impl<T: Config> Pallet<T> {
@@ -450,7 +526,7 @@ pub mod pallet {
450526
T::Currency::set_lock(
451527
STAKING_ID,
452528
account,
453-
ledger.locked_amount(),
529+
ledger.active_locked_amount(),
454530
WithdrawReasons::all(),
455531
);
456532
Ledger::<T>::insert(account, ledger);

frame/dapp-staking-v3/src/test/mock.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{self as pallet_dapp_staking, *};
2020

2121
use frame_support::{
2222
construct_runtime, parameter_types,
23-
traits::{ConstU128, ConstU16, ConstU32},
23+
traits::{ConstU128, ConstU16, ConstU32, ConstU64},
2424
weights::Weight,
2525
};
2626
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
@@ -109,6 +109,7 @@ impl pallet_dapp_staking::Config for Test {
109109
type MaxLockedChunks = ConstU32<5>;
110110
type MaxUnlockingChunks = ConstU32<5>;
111111
type MinimumLockedAmount = ConstU128<MINIMUM_LOCK_AMOUNT>;
112+
type UnlockingPeriod = ConstU64<20>;
112113
}
113114

114115
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, Hash)]

frame/dapp-staking-v3/src/test/testing_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl MemorySnapshot {
5252
pub fn locked_balance(&self, account: &AccountId) -> Balance {
5353
self.ledger
5454
.get(&account)
55-
.map_or(Balance::zero(), |ledger| ledger.locked_amount())
55+
.map_or(Balance::zero(), |ledger| ledger.active_locked_amount())
5656
}
5757
}
5858

@@ -196,7 +196,7 @@ pub(crate) fn assert_lock(account: AccountId, amount: Balance) {
196196
.ledger
197197
.get(&account)
198198
.expect("Ledger entry has to exist after succcessful lock call")
199-
.era(),
199+
.lock_era(),
200200
post_snapshot.active_protocol_state.era + 1
201201
);
202202

0 commit comments

Comments
 (0)