Skip to content

Commit

Permalink
Add force remove vesting (paritytech#1982)
Browse files Browse the repository at this point in the history
This PR exposes a `force_remove_vesting` through a ROOT call. 
See linked
[issue](paritytech#269)

---------

Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com>
Co-authored-by: command-bot <>
Co-authored-by: Dónal Murray <donal.murray@parity.io>
  • Loading branch information
3 people authored Nov 6, 2023
1 parent 12ef0ee commit 878ed73
Show file tree
Hide file tree
Showing 4 changed files with 370 additions and 233 deletions.
27 changes: 27 additions & 0 deletions substrate/frame/vesting/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,33 @@ benchmarks! {
);
}

force_remove_vesting_schedule {
let l in 0 .. MaxLocksOf::<T>::get() - 1;
let s in 2 .. T::MAX_VESTING_SCHEDULES;

let source: T::AccountId = account("source", 0, SEED);
let source_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(source.clone());
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());

let target: T::AccountId = account("target", 0, SEED);
let target_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(target.clone());
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance());

// Give target existing locks.
add_locks::<T>(&target, l as u8);
let _ = add_vesting_schedules::<T>(target_lookup.clone(), s)?;

// The last vesting schedule.
let schedule_index = s - 1;
}: _(RawOrigin::Root, target_lookup, schedule_index)
verify {
assert_eq!(
Vesting::<T>::vesting(&target).unwrap().len(),
schedule_index as usize,
"Schedule count should reduce by 1"
);
}

impl_benchmark_test_suite!(
Vesting,
crate::mock::ExtBuilder::default().existential_deposit(256).build(),
Expand Down
30 changes: 30 additions & 0 deletions substrate/frame/vesting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,36 @@ pub mod pallet {

Ok(())
}

/// Force remove a vesting schedule
///
/// The dispatch origin for this call must be _Root_.
///
/// - `target`: An account that has a vesting schedule
/// - `schedule_index`: The vesting schedule index that should be removed
#[pallet::call_index(5)]
#[pallet::weight(
T::WeightInfo::force_remove_vesting_schedule(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
)]
pub fn force_remove_vesting_schedule(
origin: OriginFor<T>,
target: <T::Lookup as StaticLookup>::Source,
schedule_index: u32,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
let who = T::Lookup::lookup(target)?;

let schedules_count = Vesting::<T>::decode_len(&who).unwrap_or_default();
ensure!(schedule_index < schedules_count as u32, Error::<T>::InvalidScheduleParams);

Self::remove_vesting_schedule(&who, schedule_index)?;

Ok(Some(T::WeightInfo::force_remove_vesting_schedule(
MaxLocksOf::<T>::get(),
schedules_count as u32,
))
.into())
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions substrate/frame/vesting/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,3 +1155,39 @@ fn vested_transfer_less_than_existential_deposit_fails() {
);
});
}

#[test]
fn remove_vesting_schedule() {
ExtBuilder::default().existential_deposit(ED).build().execute_with(|| {
assert_eq!(Balances::free_balance(&3), 256 * 30);
assert_eq!(Balances::free_balance(&4), 256 * 40);
// Account 4 should not have any vesting yet.
assert_eq!(Vesting::vesting(&4), None);
// Make the schedule for the new transfer.
let new_vesting_schedule = VestingInfo::new(
ED * 5,
(ED * 5) / 20, // Vesting over 20 blocks
10,
);
assert_ok!(Vesting::vested_transfer(Some(3).into(), 4, new_vesting_schedule));
// Now account 4 should have vesting.
assert_eq!(Vesting::vesting(&4).unwrap(), vec![new_vesting_schedule]);
// Account 4 has 5 * 256 locked.
assert_eq!(Vesting::vesting_balance(&4), Some(256 * 5));
// Verify only root can call.
assert_noop!(Vesting::force_remove_vesting_schedule(Some(4).into(), 4, 0), BadOrigin);
// Verify that root can remove the schedule.
assert_ok!(Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0));
// Verify that last event is VestingCompleted.
System::assert_last_event(Event::VestingCompleted { account: 4 }.into());
// Appropriate storage is cleaned up.
assert!(!<VestingStorage<Test>>::contains_key(4));
// Check the vesting balance is zero.
assert_eq!(Vesting::vesting(&4), None);
// Verifies that trying to remove a schedule when it doesnt exist throws error.
assert_noop!(
Vesting::force_remove_vesting_schedule(RawOrigin::Root.into(), 4, 0),
Error::<Test>::InvalidScheduleParams
);
});
}
Loading

0 comments on commit 878ed73

Please sign in to comment.