feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,443 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Vesting pallet benchmarking.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use pezframe_benchmarking::{v2::*, BenchmarkError};
|
||||
use pezframe_support::assert_ok;
|
||||
use pezframe_system::{pezpallet_prelude::BlockNumberFor, RawOrigin};
|
||||
use pezsp_runtime::traits::{Bounded, CheckedDiv, CheckedMul};
|
||||
|
||||
use crate::*;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
|
||||
|
||||
fn add_locks<T: Config>(who: &T::AccountId, n: u8) {
|
||||
for id in 0..n {
|
||||
let lock_id = [id; 8];
|
||||
let locked = 256_u32;
|
||||
let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE;
|
||||
T::Currency::set_lock(lock_id, who, locked.into(), reasons);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_vesting_schedules<T: Config>(
|
||||
target: &T::AccountId,
|
||||
n: u32,
|
||||
) -> Result<BalanceOf<T>, &'static str> {
|
||||
let min_transfer = T::MinVestedTransfer::get();
|
||||
let locked = min_transfer.checked_mul(&20_u32.into()).unwrap();
|
||||
// Schedule has a duration of 20.
|
||||
let per_block = min_transfer;
|
||||
let starting_block = 1_u32;
|
||||
|
||||
let source = account("source", 0, SEED);
|
||||
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());
|
||||
|
||||
T::BlockNumberProvider::set_block_number(BlockNumberFor::<T>::zero());
|
||||
|
||||
let mut total_locked: BalanceOf<T> = Zero::zero();
|
||||
for _ in 0..n {
|
||||
total_locked += locked;
|
||||
|
||||
let schedule = VestingInfo::new(locked, per_block, starting_block.into());
|
||||
assert_ok!(Pallet::<T>::do_vested_transfer(&source, target, schedule));
|
||||
|
||||
// Top up to guarantee we can always transfer another schedule.
|
||||
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());
|
||||
}
|
||||
|
||||
Ok(total_locked)
|
||||
}
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn vest_locked(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<1, T::MAX_VESTING_SCHEDULES>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let caller = whitelisted_caller();
|
||||
T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance());
|
||||
|
||||
add_locks::<T>(&caller, l as u8);
|
||||
let expected_balance = add_vesting_schedules::<T>(&caller, s)?;
|
||||
|
||||
// At block zero, everything is vested.
|
||||
assert_eq!(pezframe_system::Pallet::<T>::block_number(), BlockNumberFor::<T>::zero());
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting schedule not added",
|
||||
);
|
||||
|
||||
#[extrinsic_call]
|
||||
vest(RawOrigin::Signed(caller.clone()));
|
||||
|
||||
// Nothing happened since everything is still vested.
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting schedule was removed",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn vest_unlocked(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<1, T::MAX_VESTING_SCHEDULES>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let caller = whitelisted_caller();
|
||||
T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance());
|
||||
|
||||
add_locks::<T>(&caller, l as u8);
|
||||
add_vesting_schedules::<T>(&caller, s)?;
|
||||
|
||||
// At block 21, everything is unlocked.
|
||||
T::BlockNumberProvider::set_block_number(21_u32.into());
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(BalanceOf::<T>::zero()),
|
||||
"Vesting schedule still active",
|
||||
);
|
||||
|
||||
#[extrinsic_call]
|
||||
vest(RawOrigin::Signed(caller.clone()));
|
||||
|
||||
// Vesting schedule is removed!
|
||||
assert_eq!(Pallet::<T>::vesting_balance(&caller), None, "Vesting schedule was not removed",);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn vest_other_locked(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<1, T::MAX_VESTING_SCHEDULES>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let other = account::<T::AccountId>("other", 0, SEED);
|
||||
let other_lookup = T::Lookup::unlookup(other.clone());
|
||||
|
||||
T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&other, l as u8);
|
||||
let expected_balance = add_vesting_schedules::<T>(&other, s)?;
|
||||
|
||||
// At block zero, everything is vested.
|
||||
assert_eq!(pezframe_system::Pallet::<T>::block_number(), BlockNumberFor::<T>::zero());
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&other),
|
||||
Some(expected_balance),
|
||||
"Vesting schedule not added",
|
||||
);
|
||||
|
||||
let caller = whitelisted_caller::<T::AccountId>();
|
||||
|
||||
#[extrinsic_call]
|
||||
vest_other(RawOrigin::Signed(caller.clone()), other_lookup);
|
||||
|
||||
// Nothing happened since everything is still vested.
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&other),
|
||||
Some(expected_balance),
|
||||
"Vesting schedule was removed",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn vest_other_unlocked(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<1, { T::MAX_VESTING_SCHEDULES }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let other = account::<T::AccountId>("other", 0, SEED);
|
||||
let other_lookup = T::Lookup::unlookup(other.clone());
|
||||
|
||||
T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&other, l as u8);
|
||||
add_vesting_schedules::<T>(&other, s)?;
|
||||
// At block 21 everything is unlocked.
|
||||
T::BlockNumberProvider::set_block_number(21_u32.into());
|
||||
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&other),
|
||||
Some(BalanceOf::<T>::zero()),
|
||||
"Vesting schedule still active",
|
||||
);
|
||||
|
||||
let caller = whitelisted_caller::<T::AccountId>();
|
||||
|
||||
#[extrinsic_call]
|
||||
vest_other(RawOrigin::Signed(caller.clone()), other_lookup);
|
||||
|
||||
// Vesting schedule is removed.
|
||||
assert_eq!(Pallet::<T>::vesting_balance(&other), None, "Vesting schedule was not removed",);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn vested_transfer(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let caller = whitelisted_caller();
|
||||
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
let target = account::<T::AccountId>("target", 0, SEED);
|
||||
let target_lookup = T::Lookup::unlookup(target.clone());
|
||||
// Give target existing locks.
|
||||
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&target, l as u8);
|
||||
// Add one vesting schedules.
|
||||
let orig_balance = T::Currency::free_balance(&target);
|
||||
let mut expected_balance = add_vesting_schedules::<T>(&target, s)?;
|
||||
|
||||
let transfer_amount = T::MinVestedTransfer::get();
|
||||
let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap();
|
||||
expected_balance += transfer_amount;
|
||||
|
||||
let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller.clone()), target_lookup, vesting_schedule);
|
||||
|
||||
assert_eq!(
|
||||
orig_balance + expected_balance,
|
||||
T::Currency::free_balance(&target),
|
||||
"Transfer didn't happen",
|
||||
);
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&target),
|
||||
Some(expected_balance),
|
||||
"Lock not correctly updated",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_vested_transfer(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let source = account::<T::AccountId>("source", 0, SEED);
|
||||
let source_lookup = T::Lookup::unlookup(source.clone());
|
||||
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());
|
||||
|
||||
let target = account::<T::AccountId>("target", 0, SEED);
|
||||
let target_lookup = T::Lookup::unlookup(target.clone());
|
||||
// Give target existing locks.
|
||||
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&target, l as u8);
|
||||
// Add one less than max vesting schedules.
|
||||
let orig_balance = T::Currency::free_balance(&target);
|
||||
let mut expected_balance = add_vesting_schedules::<T>(&target, s)?;
|
||||
|
||||
let transfer_amount = T::MinVestedTransfer::get();
|
||||
let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap();
|
||||
expected_balance += transfer_amount;
|
||||
|
||||
let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule);
|
||||
|
||||
assert_eq!(
|
||||
orig_balance + expected_balance,
|
||||
T::Currency::free_balance(&target),
|
||||
"Transfer didn't happen",
|
||||
);
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&target),
|
||||
Some(expected_balance),
|
||||
"Lock not correctly updated",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn not_unlocking_merge_schedules(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<2, { T::MAX_VESTING_SCHEDULES }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let caller = whitelisted_caller::<T::AccountId>();
|
||||
// Give target existing locks.
|
||||
T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&caller, l as u8);
|
||||
// Add max vesting schedules.
|
||||
let expected_balance = add_vesting_schedules::<T>(&caller, s)?;
|
||||
|
||||
// Schedules are not vesting at block 0.
|
||||
assert_eq!(pezframe_system::Pallet::<T>::block_number(), BlockNumberFor::<T>::zero());
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting balance should equal sum locked of all schedules",
|
||||
);
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&caller).unwrap().len(),
|
||||
s as usize,
|
||||
"There should be exactly max vesting schedules"
|
||||
);
|
||||
|
||||
#[extrinsic_call]
|
||||
merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1);
|
||||
|
||||
let expected_schedule = VestingInfo::new(
|
||||
T::MinVestedTransfer::get() * 20_u32.into() * 2_u32.into(),
|
||||
T::MinVestedTransfer::get() * 2_u32.into(),
|
||||
1_u32.into(),
|
||||
);
|
||||
let expected_index = (s - 2) as usize;
|
||||
assert_eq!(Vesting::<T>::get(&caller).unwrap()[expected_index], expected_schedule);
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting balance should equal total locked of all schedules",
|
||||
);
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&caller).unwrap().len(),
|
||||
(s - 1) as usize,
|
||||
"Schedule count should reduce by 1"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn unlocking_merge_schedules(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<2, { T::MAX_VESTING_SCHEDULES }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
// Destination used just for currency transfers in asserts.
|
||||
let test_dest: T::AccountId = account("test_dest", 0, SEED);
|
||||
|
||||
let caller = whitelisted_caller::<T::AccountId>();
|
||||
// Give target existing locks.
|
||||
T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance());
|
||||
add_locks::<T>(&caller, l as u8);
|
||||
// Add max vesting schedules.
|
||||
let total_transferred = add_vesting_schedules::<T>(&caller, s)?;
|
||||
|
||||
// Go to about half way through all the schedules duration. (They all start at 1, and have a
|
||||
// duration of 20 or 21).
|
||||
T::BlockNumberProvider::set_block_number(11_u32.into());
|
||||
// We expect half the original locked balance (+ any remainder that vests on the last
|
||||
// block).
|
||||
let expected_balance = total_transferred / 2_u32.into();
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting balance should reflect that we are half way through all schedules duration",
|
||||
);
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&caller).unwrap().len(),
|
||||
s as usize,
|
||||
"There should be exactly max vesting schedules"
|
||||
);
|
||||
// The balance is not actually transferable because it has not been unlocked.
|
||||
assert!(T::Currency::transfer(
|
||||
&caller,
|
||||
&test_dest,
|
||||
expected_balance,
|
||||
ExistenceRequirement::AllowDeath
|
||||
)
|
||||
.is_err());
|
||||
|
||||
#[extrinsic_call]
|
||||
merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1);
|
||||
|
||||
let expected_schedule = VestingInfo::new(
|
||||
T::MinVestedTransfer::get() * 2_u32.into() * 10_u32.into(),
|
||||
T::MinVestedTransfer::get() * 2_u32.into(),
|
||||
11_u32.into(),
|
||||
);
|
||||
let expected_index = (s - 2) as usize;
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&caller).unwrap()[expected_index],
|
||||
expected_schedule,
|
||||
"New schedule is properly created and placed"
|
||||
);
|
||||
assert_eq!(
|
||||
Pallet::<T>::vesting_balance(&caller),
|
||||
Some(expected_balance),
|
||||
"Vesting balance should equal half total locked of all schedules",
|
||||
);
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&caller).unwrap().len(),
|
||||
(s - 1) as usize,
|
||||
"Schedule count should reduce by 1"
|
||||
);
|
||||
// Since merge unlocks all schedules we can now transfer the balance.
|
||||
assert_ok!(T::Currency::transfer(
|
||||
&caller,
|
||||
&test_dest,
|
||||
expected_balance,
|
||||
ExistenceRequirement::AllowDeath
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_remove_vesting_schedule(
|
||||
l: Linear<0, { MaxLocksOf::<T>::get() - 1 }>,
|
||||
s: Linear<2, { T::MAX_VESTING_SCHEDULES }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let source = account::<T::AccountId>("source", 0, SEED);
|
||||
T::Currency::make_free_balance_be(&source, BalanceOf::<T>::max_value());
|
||||
|
||||
let target = account::<T::AccountId>("target", 0, SEED);
|
||||
let target_lookup = 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);
|
||||
add_vesting_schedules::<T>(&target, s)?;
|
||||
|
||||
// The last vesting schedule.
|
||||
let schedule_index = s - 1;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, target_lookup, schedule_index);
|
||||
|
||||
assert_eq!(
|
||||
Vesting::<T>::get(&target).unwrap().len(),
|
||||
schedule_index as usize,
|
||||
"Schedule count should reduce by 1"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite! {
|
||||
Pallet,
|
||||
mock::ExtBuilder::default().existential_deposit(256).build(),
|
||||
mock::Test
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,843 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Vesting Pallet
|
||||
//!
|
||||
//! - [`Config`]
|
||||
//! - [`Call`]
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! A simple pallet providing a means of placing a linear curve on an account's locked balance. This
|
||||
//! pallet ensures that there is a lock in place preventing the balance to drop below the *unvested*
|
||||
//! amount for any reason other than the ones specified in `UnvestedFundsAllowedWithdrawReasons`
|
||||
//! configuration value.
|
||||
//!
|
||||
//! As the amount vested increases over time, the amount unvested reduces. However, locks remain in
|
||||
//! place and explicit action is needed on behalf of the user to ensure that the amount locked is
|
||||
//! equivalent to the amount remaining to be vested. This is done through a dispatchable function,
|
||||
//! either `vest` (in typical case where the sender is calling on their own behalf) or `vest_other`
|
||||
//! in case the sender is calling on another account's behalf.
|
||||
//!
|
||||
//! ## Interface
|
||||
//!
|
||||
//! This pallet implements the `VestingSchedule` trait.
|
||||
//!
|
||||
//! ### Dispatchable Functions
|
||||
//!
|
||||
//! - `vest` - Update the lock, reducing it in line with the amount "vested" so far.
|
||||
//! - `vest_other` - Update the lock of another account, reducing it in line with the amount
|
||||
//! "vested" so far.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod benchmarking;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod vesting_info;
|
||||
|
||||
pub mod migrations;
|
||||
pub mod weights;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
|
||||
use core::{fmt::Debug, marker::PhantomData};
|
||||
use pezframe_support::{
|
||||
dispatch::DispatchResult,
|
||||
ensure,
|
||||
storage::bounded_vec::BoundedVec,
|
||||
traits::{
|
||||
Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestedTransfer,
|
||||
VestingSchedule, WithdrawReasons,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::BlockNumberFor;
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_runtime::{
|
||||
traits::{
|
||||
AtLeast32BitUnsigned, BlockNumberProvider, Bounded, Convert, MaybeSerializeDeserialize,
|
||||
One, Saturating, StaticLookup, Zero,
|
||||
},
|
||||
DispatchError, RuntimeDebug,
|
||||
};
|
||||
|
||||
pub use pallet::*;
|
||||
pub use vesting_info::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
|
||||
type MaxLocksOf<T> =
|
||||
<<T as Config>::Currency as LockableCurrency<<T as pezframe_system::Config>::AccountId>>::MaxLocks;
|
||||
type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
|
||||
|
||||
const VESTING_ID: LockIdentifier = *b"vesting ";
|
||||
|
||||
// A value placed in storage that represents the current version of the Vesting storage.
|
||||
// This value is used by `on_runtime_upgrade` to determine whether we run storage migration logic.
|
||||
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
|
||||
pub enum Releases {
|
||||
V0,
|
||||
V1,
|
||||
}
|
||||
|
||||
impl Default for Releases {
|
||||
fn default() -> Self {
|
||||
Releases::V0
|
||||
}
|
||||
}
|
||||
|
||||
/// Actions to take against a user's `Vesting` storage entry.
|
||||
#[derive(Clone, Copy)]
|
||||
enum VestingAction {
|
||||
/// Do not actively remove any schedules.
|
||||
Passive,
|
||||
/// Remove the schedule specified by the index.
|
||||
Remove { index: usize },
|
||||
/// Remove the two schedules, specified by index, so they can be merged.
|
||||
Merge { index1: usize, index2: usize },
|
||||
}
|
||||
|
||||
impl VestingAction {
|
||||
/// Whether or not the filter says the schedule index should be removed.
|
||||
fn should_remove(&self, index: usize) -> bool {
|
||||
match self {
|
||||
Self::Passive => false,
|
||||
Self::Remove { index: index1 } => *index1 == index,
|
||||
Self::Merge { index1, index2 } => *index1 == index || *index2 == index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Pick the schedules that this action dictates should continue vesting undisturbed.
|
||||
fn pick_schedules<T: Config>(
|
||||
&self,
|
||||
schedules: Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>,
|
||||
) -> impl Iterator<Item = VestingInfo<BalanceOf<T>, BlockNumberFor<T>>> + '_ {
|
||||
schedules.into_iter().enumerate().filter_map(move |(index, schedule)| {
|
||||
if self.should_remove(index) {
|
||||
None
|
||||
} else {
|
||||
Some(schedule)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for `T::MAX_VESTING_SCHEDULES` to satisfy `trait Get`.
|
||||
pub struct MaxVestingSchedulesGet<T>(PhantomData<T>);
|
||||
impl<T: Config> Get<u32> for MaxVestingSchedulesGet<T> {
|
||||
fn get() -> u32 {
|
||||
T::MAX_VESTING_SCHEDULES
|
||||
}
|
||||
}
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// The overarching event type.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
|
||||
|
||||
/// The currency trait.
|
||||
type Currency: LockableCurrency<Self::AccountId>;
|
||||
|
||||
/// Convert the block number into a balance.
|
||||
type BlockNumberToBalance: Convert<BlockNumberFor<Self>, BalanceOf<Self>>;
|
||||
|
||||
/// The minimum amount transferred to call `vested_transfer`.
|
||||
#[pallet::constant]
|
||||
type MinVestedTransfer: Get<BalanceOf<Self>>;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Reasons that determine under which conditions the balance may drop below
|
||||
/// the unvested amount.
|
||||
type UnvestedFundsAllowedWithdrawReasons: Get<WithdrawReasons>;
|
||||
|
||||
/// Query the current block number.
|
||||
///
|
||||
/// Must return monotonically increasing values when called from consecutive blocks.
|
||||
/// Can be configured to return either:
|
||||
/// - the local block number of the runtime via `pezframe_system::Pallet`
|
||||
/// - a remote block number, eg from the relay chain through `RelaychainDataProvider`
|
||||
/// - an arbitrary value through a custom implementation of the trait
|
||||
///
|
||||
/// There is currently no migration provided to "hot-swap" block number providers and it may
|
||||
/// result in undefined behavior when doing so. Teyrchains are therefore best off setting
|
||||
/// this to their local block number provider if they have the pallet already deployed.
|
||||
///
|
||||
/// Suggested values:
|
||||
/// - Solo- and Relay-chains: `pezframe_system::Pallet`
|
||||
/// - Teyrchains that may produce blocks sparingly or only when needed (on-demand):
|
||||
/// - already have the pallet deployed: `pezframe_system::Pallet`
|
||||
/// - are freshly deploying this pallet: `RelaychainDataProvider`
|
||||
/// - Teyrchains with a reliably block production rate (PLO or bulk-coretime):
|
||||
/// - already have the pallet deployed: `pezframe_system::Pallet`
|
||||
/// - are freshly deploying this pallet: no strong recommendation. Both local and remote
|
||||
/// providers can be used. Relay provider can be a bit better in cases where the
|
||||
/// teyrchain is lagging its block production to avoid clock skew.
|
||||
type BlockNumberProvider: BlockNumberProvider<BlockNumber = BlockNumberFor<Self>>;
|
||||
|
||||
/// Maximum number of vesting schedules an account may have at a given moment.
|
||||
const MAX_VESTING_SCHEDULES: u32;
|
||||
}
|
||||
|
||||
#[pallet::extra_constants]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::constant_name(MaxVestingSchedules)]
|
||||
fn max_vesting_schedules() -> u32 {
|
||||
T::MAX_VESTING_SCHEDULES
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn integrity_test() {
|
||||
assert!(T::MAX_VESTING_SCHEDULES > 0, "`MaxVestingSchedules` must be greater than 0");
|
||||
}
|
||||
}
|
||||
|
||||
/// Information regarding the vesting of a given account.
|
||||
#[pallet::storage]
|
||||
pub type Vesting<T: Config> = StorageMap<
|
||||
_,
|
||||
Blake2_128Concat,
|
||||
T::AccountId,
|
||||
BoundedVec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>, MaxVestingSchedulesGet<T>>,
|
||||
>;
|
||||
|
||||
/// Storage version of the pallet.
|
||||
///
|
||||
/// New networks start with latest version, as determined by the genesis build.
|
||||
#[pallet::storage]
|
||||
pub type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(pezframe_support::DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub vesting: Vec<(T::AccountId, BlockNumberFor<T>, BlockNumberFor<T>, BalanceOf<T>)>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {
|
||||
use pezsp_runtime::traits::Saturating;
|
||||
|
||||
// Genesis uses the latest storage version.
|
||||
StorageVersion::<T>::put(Releases::V1);
|
||||
|
||||
// Generate initial vesting configuration
|
||||
// * who - Account which we are generating vesting configuration for
|
||||
// * begin - Block when the account will start to vest
|
||||
// * length - Number of blocks from `begin` until fully vested
|
||||
// * liquid - Number of units which can be spent before vesting begins
|
||||
for &(ref who, begin, length, liquid) in self.vesting.iter() {
|
||||
let balance = T::Currency::free_balance(who);
|
||||
assert!(!balance.is_zero(), "Currencies must be init'd before vesting");
|
||||
// Total genesis `balance` minus `liquid` equals funds locked for vesting
|
||||
let locked = balance.saturating_sub(liquid);
|
||||
let length_as_balance = T::BlockNumberToBalance::convert(length);
|
||||
let per_block = locked / length_as_balance.max(pezsp_runtime::traits::One::one());
|
||||
let vesting_info = VestingInfo::new(locked, per_block, begin);
|
||||
if !vesting_info.is_valid() {
|
||||
panic!("Invalid VestingInfo params at genesis")
|
||||
};
|
||||
|
||||
Vesting::<T>::try_append(who, vesting_info)
|
||||
.expect("Too many vesting schedules at genesis.");
|
||||
|
||||
let reasons =
|
||||
WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get());
|
||||
|
||||
T::Currency::set_lock(VESTING_ID, who, locked, reasons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A vesting schedule has been created.
|
||||
VestingCreated { account: T::AccountId, schedule_index: u32 },
|
||||
/// The amount vested has been updated. This could indicate a change in funds available.
|
||||
/// The balance given is the amount which is left unvested (and thus locked).
|
||||
VestingUpdated { account: T::AccountId, unvested: BalanceOf<T> },
|
||||
/// An \[account\] has become fully vested.
|
||||
VestingCompleted { account: T::AccountId },
|
||||
}
|
||||
|
||||
/// Error for the vesting pallet.
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The account given is not vesting.
|
||||
NotVesting,
|
||||
/// The account already has `MaxVestingSchedules` count of schedules and thus
|
||||
/// cannot add another one. Consider merging existing schedules in order to add another.
|
||||
AtMaxVestingSchedules,
|
||||
/// Amount being transferred is too low to create a vesting schedule.
|
||||
AmountLow,
|
||||
/// An index was out of bounds of the vesting schedules.
|
||||
ScheduleIndexOutOfBounds,
|
||||
/// Failed to create a new schedule because some parameter was invalid.
|
||||
InvalidScheduleParams,
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Unlock any vested funds of the sender account.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_ and the sender must have funds still
|
||||
/// locked under this pallet.
|
||||
///
|
||||
/// Emits either `VestingCompleted` or `VestingUpdated`.
|
||||
///
|
||||
/// ## Complexity
|
||||
/// - `O(1)`.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::vest_locked(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
|
||||
.max(T::WeightInfo::vest_unlocked(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES))
|
||||
)]
|
||||
pub fn vest(origin: OriginFor<T>) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
Self::do_vest(who)
|
||||
}
|
||||
|
||||
/// Unlock any vested funds of a `target` account.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
///
|
||||
/// - `target`: The account whose vested funds should be unlocked. Must have funds still
|
||||
/// locked under this pallet.
|
||||
///
|
||||
/// Emits either `VestingCompleted` or `VestingUpdated`.
|
||||
///
|
||||
/// ## Complexity
|
||||
/// - `O(1)`.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(T::WeightInfo::vest_other_locked(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
|
||||
.max(T::WeightInfo::vest_other_unlocked(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES))
|
||||
)]
|
||||
pub fn vest_other(origin: OriginFor<T>, target: AccountIdLookupOf<T>) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
let who = T::Lookup::lookup(target)?;
|
||||
Self::do_vest(who)
|
||||
}
|
||||
|
||||
/// Create a vested transfer.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
///
|
||||
/// - `target`: The account receiving the vested funds.
|
||||
/// - `schedule`: The vesting schedule attached to the transfer.
|
||||
///
|
||||
/// Emits `VestingCreated`.
|
||||
///
|
||||
/// NOTE: This will unlock all schedules through the current block.
|
||||
///
|
||||
/// ## Complexity
|
||||
/// - `O(1)`.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::vested_transfer(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
|
||||
)]
|
||||
pub fn vested_transfer(
|
||||
origin: OriginFor<T>,
|
||||
target: AccountIdLookupOf<T>,
|
||||
schedule: VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
let transactor = ensure_signed(origin)?;
|
||||
let target = T::Lookup::lookup(target)?;
|
||||
Self::do_vested_transfer(&transactor, &target, schedule)
|
||||
}
|
||||
|
||||
/// Force a vested transfer.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Root_.
|
||||
///
|
||||
/// - `source`: The account whose funds should be transferred.
|
||||
/// - `target`: The account that should be transferred the vested funds.
|
||||
/// - `schedule`: The vesting schedule attached to the transfer.
|
||||
///
|
||||
/// Emits `VestingCreated`.
|
||||
///
|
||||
/// NOTE: This will unlock all schedules through the current block.
|
||||
///
|
||||
/// ## Complexity
|
||||
/// - `O(1)`.
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::force_vested_transfer(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
|
||||
)]
|
||||
pub fn force_vested_transfer(
|
||||
origin: OriginFor<T>,
|
||||
source: AccountIdLookupOf<T>,
|
||||
target: AccountIdLookupOf<T>,
|
||||
schedule: VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
let target = T::Lookup::lookup(target)?;
|
||||
let source = T::Lookup::lookup(source)?;
|
||||
Self::do_vested_transfer(&source, &target, schedule)
|
||||
}
|
||||
|
||||
/// Merge two vesting schedules together, creating a new vesting schedule that unlocks over
|
||||
/// the highest possible start and end blocks. If both schedules have already started the
|
||||
/// current block will be used as the schedule start; with the caveat that if one schedule
|
||||
/// is finished by the current block, the other will be treated as the new merged schedule,
|
||||
/// unmodified.
|
||||
///
|
||||
/// NOTE: If `schedule1_index == schedule2_index` this is a no-op.
|
||||
/// NOTE: This will unlock all schedules through the current block prior to merging.
|
||||
/// NOTE: If both schedules have ended by the current block, no new schedule will be created
|
||||
/// and both will be removed.
|
||||
///
|
||||
/// Merged schedule attributes:
|
||||
/// - `starting_block`: `MAX(schedule1.starting_block, scheduled2.starting_block,
|
||||
/// current_block)`.
|
||||
/// - `ending_block`: `MAX(schedule1.ending_block, schedule2.ending_block)`.
|
||||
/// - `locked`: `schedule1.locked_at(current_block) + schedule2.locked_at(current_block)`.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
///
|
||||
/// - `schedule1_index`: index of the first schedule to merge.
|
||||
/// - `schedule2_index`: index of the second schedule to merge.
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::not_unlocking_merge_schedules(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES)
|
||||
.max(T::WeightInfo::unlocking_merge_schedules(MaxLocksOf::<T>::get(), T::MAX_VESTING_SCHEDULES))
|
||||
)]
|
||||
pub fn merge_schedules(
|
||||
origin: OriginFor<T>,
|
||||
schedule1_index: u32,
|
||||
schedule2_index: u32,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
if schedule1_index == schedule2_index {
|
||||
return Ok(());
|
||||
};
|
||||
let schedule1_index = schedule1_index as usize;
|
||||
let schedule2_index = schedule2_index as usize;
|
||||
|
||||
let schedules = Vesting::<T>::get(&who).ok_or(Error::<T>::NotVesting)?;
|
||||
let merge_action =
|
||||
VestingAction::Merge { index1: schedule1_index, index2: schedule2_index };
|
||||
|
||||
let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), merge_action)?;
|
||||
|
||||
Self::write_vesting(&who, schedules)?;
|
||||
Self::write_lock(&who, locked_now);
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
// Public function for accessing vesting storage
|
||||
pub fn vesting(
|
||||
account: T::AccountId,
|
||||
) -> Option<BoundedVec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>, MaxVestingSchedulesGet<T>>>
|
||||
{
|
||||
Vesting::<T>::get(account)
|
||||
}
|
||||
|
||||
// Create a new `VestingInfo`, based off of two other `VestingInfo`s.
|
||||
// NOTE: We assume both schedules have had funds unlocked up through the current block.
|
||||
fn merge_vesting_info(
|
||||
now: BlockNumberFor<T>,
|
||||
schedule1: VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
schedule2: VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
) -> Option<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>> {
|
||||
let schedule1_ending_block = schedule1.ending_block_as_balance::<T::BlockNumberToBalance>();
|
||||
let schedule2_ending_block = schedule2.ending_block_as_balance::<T::BlockNumberToBalance>();
|
||||
let now_as_balance = T::BlockNumberToBalance::convert(now);
|
||||
|
||||
// Check if one or both schedules have ended.
|
||||
match (schedule1_ending_block <= now_as_balance, schedule2_ending_block <= now_as_balance) {
|
||||
// If both schedules have ended, we don't merge and exit early.
|
||||
(true, true) => return None,
|
||||
// If one schedule has ended, we treat the one that has not ended as the new
|
||||
// merged schedule.
|
||||
(true, false) => return Some(schedule2),
|
||||
(false, true) => return Some(schedule1),
|
||||
// If neither schedule has ended don't exit early.
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let locked = schedule1
|
||||
.locked_at::<T::BlockNumberToBalance>(now)
|
||||
.saturating_add(schedule2.locked_at::<T::BlockNumberToBalance>(now));
|
||||
// This shouldn't happen because we know at least one ending block is greater than now,
|
||||
// thus at least a schedule a some locked balance.
|
||||
debug_assert!(
|
||||
!locked.is_zero(),
|
||||
"merge_vesting_info validation checks failed to catch a locked of 0"
|
||||
);
|
||||
|
||||
let ending_block = schedule1_ending_block.max(schedule2_ending_block);
|
||||
let starting_block = now.max(schedule1.starting_block()).max(schedule2.starting_block());
|
||||
|
||||
let per_block = {
|
||||
let duration = ending_block
|
||||
.saturating_sub(T::BlockNumberToBalance::convert(starting_block))
|
||||
.max(One::one());
|
||||
(locked / duration).max(One::one())
|
||||
};
|
||||
|
||||
let schedule = VestingInfo::new(locked, per_block, starting_block);
|
||||
debug_assert!(schedule.is_valid(), "merge_vesting_info schedule validation check failed");
|
||||
|
||||
Some(schedule)
|
||||
}
|
||||
|
||||
// Execute a vested transfer from `source` to `target` with the given `schedule`.
|
||||
fn do_vested_transfer(
|
||||
source: &T::AccountId,
|
||||
target: &T::AccountId,
|
||||
schedule: VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
// Validate user inputs.
|
||||
ensure!(schedule.locked() >= T::MinVestedTransfer::get(), Error::<T>::AmountLow);
|
||||
if !schedule.is_valid() {
|
||||
return Err(Error::<T>::InvalidScheduleParams.into());
|
||||
};
|
||||
|
||||
// Check we can add to this account prior to any storage writes.
|
||||
Self::can_add_vesting_schedule(
|
||||
target,
|
||||
schedule.locked(),
|
||||
schedule.per_block(),
|
||||
schedule.starting_block(),
|
||||
)?;
|
||||
|
||||
T::Currency::transfer(source, target, schedule.locked(), ExistenceRequirement::AllowDeath)?;
|
||||
|
||||
// We can't let this fail because the currency transfer has already happened.
|
||||
// Must be successful as it has been checked before.
|
||||
// Better to return error on failure anyway.
|
||||
let res = Self::add_vesting_schedule(
|
||||
target,
|
||||
schedule.locked(),
|
||||
schedule.per_block(),
|
||||
schedule.starting_block(),
|
||||
);
|
||||
debug_assert!(res.is_ok(), "Failed to add a schedule when we had to succeed.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Iterate through the schedules to track the current locked amount and
|
||||
/// filter out completed and specified schedules.
|
||||
///
|
||||
/// Returns a tuple that consists of:
|
||||
/// - Vec of vesting schedules, where completed schedules and those specified
|
||||
/// by filter are removed. (Note the vec is not checked for respecting
|
||||
/// bounded length.)
|
||||
/// - The amount locked at the current block number based on the given schedules.
|
||||
///
|
||||
/// NOTE: the amount locked does not include any schedules that are filtered out via `action`.
|
||||
fn report_schedule_updates(
|
||||
schedules: Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>,
|
||||
action: VestingAction,
|
||||
) -> (Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>, BalanceOf<T>) {
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
|
||||
let mut total_locked_now: BalanceOf<T> = Zero::zero();
|
||||
let filtered_schedules = action
|
||||
.pick_schedules::<T>(schedules)
|
||||
.filter(|schedule| {
|
||||
let locked_now = schedule.locked_at::<T::BlockNumberToBalance>(now);
|
||||
let keep = !locked_now.is_zero();
|
||||
if keep {
|
||||
total_locked_now = total_locked_now.saturating_add(locked_now);
|
||||
}
|
||||
keep
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(filtered_schedules, total_locked_now)
|
||||
}
|
||||
|
||||
/// Write an accounts updated vesting lock to storage.
|
||||
fn write_lock(who: &T::AccountId, total_locked_now: BalanceOf<T>) {
|
||||
if total_locked_now.is_zero() {
|
||||
T::Currency::remove_lock(VESTING_ID, who);
|
||||
Self::deposit_event(Event::<T>::VestingCompleted { account: who.clone() });
|
||||
} else {
|
||||
let reasons = WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get());
|
||||
T::Currency::set_lock(VESTING_ID, who, total_locked_now, reasons);
|
||||
Self::deposit_event(Event::<T>::VestingUpdated {
|
||||
account: who.clone(),
|
||||
unvested: total_locked_now,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/// Write an accounts updated vesting schedules to storage.
|
||||
fn write_vesting(
|
||||
who: &T::AccountId,
|
||||
schedules: Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>,
|
||||
) -> Result<(), DispatchError> {
|
||||
let schedules: BoundedVec<
|
||||
VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
MaxVestingSchedulesGet<T>,
|
||||
> = schedules.try_into().map_err(|_| Error::<T>::AtMaxVestingSchedules)?;
|
||||
|
||||
if schedules.len() == 0 {
|
||||
Vesting::<T>::remove(&who);
|
||||
} else {
|
||||
Vesting::<T>::insert(who, schedules)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unlock any vested funds of `who`.
|
||||
fn do_vest(who: T::AccountId) -> DispatchResult {
|
||||
let schedules = Vesting::<T>::get(&who).ok_or(Error::<T>::NotVesting)?;
|
||||
|
||||
let (schedules, locked_now) =
|
||||
Self::exec_action(schedules.to_vec(), VestingAction::Passive)?;
|
||||
|
||||
Self::write_vesting(&who, schedules)?;
|
||||
Self::write_lock(&who, locked_now);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute a `VestingAction` against the given `schedules`. Returns the updated schedules
|
||||
/// and locked amount.
|
||||
fn exec_action(
|
||||
schedules: Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>,
|
||||
action: VestingAction,
|
||||
) -> Result<(Vec<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>>, BalanceOf<T>), DispatchError> {
|
||||
let (schedules, locked_now) = match action {
|
||||
VestingAction::Merge { index1: idx1, index2: idx2 } => {
|
||||
// The schedule index is based off of the schedule ordering prior to filtering out
|
||||
// any schedules that may be ending at this block.
|
||||
let schedule1 = *schedules.get(idx1).ok_or(Error::<T>::ScheduleIndexOutOfBounds)?;
|
||||
let schedule2 = *schedules.get(idx2).ok_or(Error::<T>::ScheduleIndexOutOfBounds)?;
|
||||
|
||||
// The length of `schedules` decreases by 2 here since we filter out 2 schedules.
|
||||
// Thus we know below that we can push the new merged schedule without error
|
||||
// (assuming initial state was valid).
|
||||
let (mut schedules, mut locked_now) =
|
||||
Self::report_schedule_updates(schedules.to_vec(), action);
|
||||
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
if let Some(new_schedule) = Self::merge_vesting_info(now, schedule1, schedule2) {
|
||||
// Merging created a new schedule so we:
|
||||
// 1) need to add it to the accounts vesting schedule collection,
|
||||
schedules.push(new_schedule);
|
||||
// (we use `locked_at` in case this is a schedule that started in the past)
|
||||
let new_schedule_locked =
|
||||
new_schedule.locked_at::<T::BlockNumberToBalance>(now);
|
||||
// and 2) update the locked amount to reflect the schedule we just added.
|
||||
locked_now = locked_now.saturating_add(new_schedule_locked);
|
||||
} // In the None case there was no new schedule to account for.
|
||||
|
||||
(schedules, locked_now)
|
||||
},
|
||||
_ => Self::report_schedule_updates(schedules.to_vec(), action),
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
locked_now > Zero::zero() && schedules.len() > 0 ||
|
||||
locked_now == Zero::zero() && schedules.len() == 0
|
||||
);
|
||||
|
||||
Ok((schedules, locked_now))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> VestingSchedule<T::AccountId> for Pallet<T>
|
||||
where
|
||||
BalanceOf<T>: MaybeSerializeDeserialize + Debug,
|
||||
{
|
||||
type Currency = T::Currency;
|
||||
type Moment = BlockNumberFor<T>;
|
||||
|
||||
/// Get the amount that is currently being vested and cannot be transferred out of this account.
|
||||
fn vesting_balance(who: &T::AccountId) -> Option<BalanceOf<T>> {
|
||||
if let Some(v) = Vesting::<T>::get(who) {
|
||||
let now = T::BlockNumberProvider::current_block_number();
|
||||
let total_locked_now = v.iter().fold(Zero::zero(), |total, schedule| {
|
||||
schedule.locked_at::<T::BlockNumberToBalance>(now).saturating_add(total)
|
||||
});
|
||||
Some(T::Currency::free_balance(who).min(total_locked_now))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a vesting schedule to a given account.
|
||||
///
|
||||
/// If the account has `MaxVestingSchedules`, an Error is returned and nothing
|
||||
/// is updated.
|
||||
///
|
||||
/// On success, a linearly reducing amount of funds will be locked. In order to realise any
|
||||
/// reduction of the lock over time as it diminishes, the account owner must use `vest` or
|
||||
/// `vest_other`.
|
||||
///
|
||||
/// It is a no-op if the amount to be vested is zero.
|
||||
///
|
||||
/// NOTE: This doesn't alter the free balance of the account.
|
||||
fn add_vesting_schedule(
|
||||
who: &T::AccountId,
|
||||
locked: BalanceOf<T>,
|
||||
per_block: BalanceOf<T>,
|
||||
starting_block: BlockNumberFor<T>,
|
||||
) -> DispatchResult {
|
||||
if locked.is_zero() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let vesting_schedule = VestingInfo::new(locked, per_block, starting_block);
|
||||
// Check for `per_block` or `locked` of 0.
|
||||
if !vesting_schedule.is_valid() {
|
||||
return Err(Error::<T>::InvalidScheduleParams.into());
|
||||
};
|
||||
|
||||
let mut schedules = Vesting::<T>::get(who).unwrap_or_default();
|
||||
|
||||
// NOTE: we must push the new schedule so that `exec_action`
|
||||
// will give the correct new locked amount.
|
||||
ensure!(schedules.try_push(vesting_schedule).is_ok(), Error::<T>::AtMaxVestingSchedules);
|
||||
|
||||
debug_assert!(schedules.len() > 0, "schedules cannot be empty after insertion");
|
||||
let schedule_index = schedules.len() - 1;
|
||||
Self::deposit_event(Event::<T>::VestingCreated {
|
||||
account: who.clone(),
|
||||
schedule_index: schedule_index as u32,
|
||||
});
|
||||
|
||||
let (schedules, locked_now) =
|
||||
Self::exec_action(schedules.to_vec(), VestingAction::Passive)?;
|
||||
|
||||
Self::write_vesting(who, schedules)?;
|
||||
Self::write_lock(who, locked_now);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure we can call `add_vesting_schedule` without error. This should always
|
||||
/// be called prior to `add_vesting_schedule`.
|
||||
fn can_add_vesting_schedule(
|
||||
who: &T::AccountId,
|
||||
locked: BalanceOf<T>,
|
||||
per_block: BalanceOf<T>,
|
||||
starting_block: BlockNumberFor<T>,
|
||||
) -> DispatchResult {
|
||||
// Check for `per_block` or `locked` of 0.
|
||||
if !VestingInfo::new(locked, per_block, starting_block).is_valid() {
|
||||
return Err(Error::<T>::InvalidScheduleParams.into());
|
||||
}
|
||||
|
||||
ensure!(
|
||||
(Vesting::<T>::decode_len(who).unwrap_or_default() as u32) < T::MAX_VESTING_SCHEDULES,
|
||||
Error::<T>::AtMaxVestingSchedules
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove a vesting schedule for a given account.
|
||||
fn remove_vesting_schedule(who: &T::AccountId, schedule_index: u32) -> DispatchResult {
|
||||
let schedules = Vesting::<T>::get(who).ok_or(Error::<T>::NotVesting)?;
|
||||
let remove_action = VestingAction::Remove { index: schedule_index as usize };
|
||||
|
||||
let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), remove_action)?;
|
||||
|
||||
Self::write_vesting(who, schedules)?;
|
||||
Self::write_lock(who, locked_now);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation that allows the Vesting Pallet to handle a vested transfer
|
||||
/// on behalf of another Pallet.
|
||||
impl<T: Config> VestedTransfer<T::AccountId> for Pallet<T>
|
||||
where
|
||||
BalanceOf<T>: MaybeSerializeDeserialize + Debug,
|
||||
{
|
||||
type Currency = T::Currency;
|
||||
type Moment = BlockNumberFor<T>;
|
||||
|
||||
fn vested_transfer(
|
||||
source: &T::AccountId,
|
||||
target: &T::AccountId,
|
||||
locked: BalanceOf<T>,
|
||||
per_block: BalanceOf<T>,
|
||||
starting_block: BlockNumberFor<T>,
|
||||
) -> DispatchResult {
|
||||
use pezframe_support::storage::{with_transaction, TransactionOutcome};
|
||||
let schedule = VestingInfo::new(locked, per_block, starting_block);
|
||||
with_transaction(|| -> TransactionOutcome<DispatchResult> {
|
||||
let result = Self::do_vested_transfer(source, target, schedule);
|
||||
|
||||
match &result {
|
||||
Ok(()) => TransactionOutcome::Commit(result),
|
||||
_ => TransactionOutcome::Rollback(result),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Storage migrations for the vesting pallet.
|
||||
|
||||
use super::*;
|
||||
use alloc::vec;
|
||||
|
||||
// Migration from single schedule to multiple schedules.
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
pub fn pre_migrate<T: Config>() -> Result<(), &'static str> {
|
||||
assert!(StorageVersion::<T>::get() == Releases::V0, "Storage version too high.");
|
||||
|
||||
log::debug!(
|
||||
target: "runtime::vesting",
|
||||
"migration: Vesting storage version v1 PRE migration checks successful!"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Migrate from single schedule to multi schedule storage.
|
||||
/// WARNING: This migration will delete schedules if `MaxVestingSchedules < 1`.
|
||||
pub fn migrate<T: Config>() -> Weight {
|
||||
let mut reads_writes = 0;
|
||||
|
||||
Vesting::<T>::translate::<VestingInfo<BalanceOf<T>, BlockNumberFor<T>>, _>(
|
||||
|_key, vesting_info| {
|
||||
reads_writes += 1;
|
||||
let v: Option<
|
||||
BoundedVec<
|
||||
VestingInfo<BalanceOf<T>, BlockNumberFor<T>>,
|
||||
MaxVestingSchedulesGet<T>,
|
||||
>,
|
||||
> = vec![vesting_info].try_into().ok();
|
||||
|
||||
if v.is_none() {
|
||||
log::warn!(
|
||||
target: "runtime::vesting",
|
||||
"migration: Failed to move a vesting schedule into a BoundedVec"
|
||||
);
|
||||
}
|
||||
|
||||
v
|
||||
},
|
||||
);
|
||||
|
||||
T::DbWeight::get().reads_writes(reads_writes, reads_writes)
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
pub fn post_migrate<T: Config>() -> Result<(), &'static str> {
|
||||
assert_eq!(StorageVersion::<T>::get(), Releases::V1);
|
||||
|
||||
for (_key, schedules) in Vesting::<T>::iter() {
|
||||
assert!(
|
||||
schedules.len() >= 1,
|
||||
"A bounded vec with incorrect count of items was created."
|
||||
);
|
||||
|
||||
for s in schedules {
|
||||
// It is ok if this does not pass, but ideally pre-existing schedules would pass
|
||||
// this validation logic so we can be more confident about edge cases.
|
||||
if !s.is_valid() {
|
||||
log::warn!(
|
||||
target: "runtime::vesting",
|
||||
"migration: A schedule does not pass new validation logic.",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
target: "runtime::vesting",
|
||||
"migration: Vesting storage version v1 POST migration checks successful!"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use pezframe_support::{derive_impl, parameter_types, traits::WithdrawReasons};
|
||||
use pezsp_runtime::{traits::Identity, BuildStorage};
|
||||
|
||||
use super::*;
|
||||
use crate as pezpallet_vesting;
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
|
||||
pezframe_support::construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: pezframe_system,
|
||||
Balances: pezpallet_balances,
|
||||
Vesting: pezpallet_vesting,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Test {
|
||||
type AccountData = pezpallet_balances::AccountData<u64>;
|
||||
type Block = Block;
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_balances::Config for Test {
|
||||
type AccountStore = System;
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
}
|
||||
parameter_types! {
|
||||
pub const MinVestedTransfer: u64 = 256 * 2;
|
||||
pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons =
|
||||
WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE);
|
||||
pub static ExistentialDeposit: u64 = 1;
|
||||
}
|
||||
impl Config for Test {
|
||||
type BlockNumberToBalance = Identity;
|
||||
type Currency = Balances;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
const MAX_VESTING_SCHEDULES: u32 = 3;
|
||||
type MinVestedTransfer = MinVestedTransfer;
|
||||
type WeightInfo = ();
|
||||
type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons;
|
||||
type BlockNumberProvider = System;
|
||||
}
|
||||
|
||||
pub struct ExtBuilder {
|
||||
existential_deposit: u64,
|
||||
vesting_genesis_config: Option<Vec<(u64, u64, u64, u64)>>,
|
||||
}
|
||||
|
||||
impl Default for ExtBuilder {
|
||||
fn default() -> Self {
|
||||
Self { existential_deposit: 1, vesting_genesis_config: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtBuilder {
|
||||
pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
|
||||
self.existential_deposit = existential_deposit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn vesting_genesis_config(mut self, config: Vec<(u64, u64, u64, u64)>) -> Self {
|
||||
self.vesting_genesis_config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> pezsp_io::TestExternalities {
|
||||
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
|
||||
let mut t = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
pezpallet_balances::GenesisConfig::<Test> {
|
||||
balances: vec![
|
||||
(1, 10 * self.existential_deposit),
|
||||
(2, 20 * self.existential_deposit),
|
||||
(3, 30 * self.existential_deposit),
|
||||
(4, 40 * self.existential_deposit),
|
||||
(12, 10 * self.existential_deposit),
|
||||
(13, 9999 * self.existential_deposit),
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let vesting = if let Some(vesting_config) = self.vesting_genesis_config {
|
||||
vesting_config
|
||||
} else {
|
||||
vec![
|
||||
(1, 0, 10, 5 * self.existential_deposit),
|
||||
(2, 10, 20, 0),
|
||||
(12, 10, 20, 5 * self.existential_deposit),
|
||||
]
|
||||
};
|
||||
|
||||
pezpallet_vesting::GenesisConfig::<Test> { vesting }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
let mut ext = pezsp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| System::set_block_number(1));
|
||||
ext
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
static ObservedEventsVesting: usize = 0;
|
||||
}
|
||||
|
||||
pub(crate) fn vesting_events_since_last_call() -> Vec<pezpallet_vesting::Event<Test>> {
|
||||
let events = System::read_events_for_pallet::<pezpallet_vesting::Event<Test>>();
|
||||
let already_seen = ObservedEventsVesting::get();
|
||||
ObservedEventsVesting::set(events.len());
|
||||
events.into_iter().skip(already_seen).collect()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Module to enforce private fields on `VestingInfo`.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Struct to encode the vesting schedule of an individual account.
|
||||
#[derive(
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
Copy,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
RuntimeDebug,
|
||||
MaxEncodedLen,
|
||||
TypeInfo,
|
||||
)]
|
||||
pub struct VestingInfo<Balance, BlockNumber> {
|
||||
/// Locked amount at genesis.
|
||||
locked: Balance,
|
||||
/// Amount that gets unlocked every block after `starting_block`.
|
||||
per_block: Balance,
|
||||
/// Starting block for unlocking(vesting).
|
||||
starting_block: BlockNumber,
|
||||
}
|
||||
|
||||
impl<Balance, BlockNumber> VestingInfo<Balance, BlockNumber>
|
||||
where
|
||||
Balance: AtLeast32BitUnsigned + Copy,
|
||||
BlockNumber: AtLeast32BitUnsigned + Copy + Bounded,
|
||||
{
|
||||
/// Instantiate a new `VestingInfo`.
|
||||
pub fn new(
|
||||
locked: Balance,
|
||||
per_block: Balance,
|
||||
starting_block: BlockNumber,
|
||||
) -> VestingInfo<Balance, BlockNumber> {
|
||||
VestingInfo { locked, per_block, starting_block }
|
||||
}
|
||||
|
||||
/// Validate parameters for `VestingInfo`. Note that this does not check
|
||||
/// against `MinVestedTransfer`.
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!self.locked.is_zero() && !self.raw_per_block().is_zero()
|
||||
}
|
||||
|
||||
/// Locked amount at schedule creation.
|
||||
pub fn locked(&self) -> Balance {
|
||||
self.locked
|
||||
}
|
||||
|
||||
/// Amount that gets unlocked every block after `starting_block`. Corrects for `per_block` of 0.
|
||||
/// We don't let `per_block` be less than 1, or else the vesting will never end.
|
||||
/// This should be used whenever accessing `per_block` unless explicitly checking for 0 values.
|
||||
pub fn per_block(&self) -> Balance {
|
||||
self.per_block.max(One::one())
|
||||
}
|
||||
|
||||
/// Get the unmodified `per_block`. Generally should not be used, but is useful for
|
||||
/// validating `per_block`.
|
||||
pub(crate) fn raw_per_block(&self) -> Balance {
|
||||
self.per_block
|
||||
}
|
||||
|
||||
/// Starting block for unlocking(vesting).
|
||||
pub fn starting_block(&self) -> BlockNumber {
|
||||
self.starting_block
|
||||
}
|
||||
|
||||
/// Amount locked at block `n`.
|
||||
pub fn locked_at<BlockNumberToBalance: Convert<BlockNumber, Balance>>(
|
||||
&self,
|
||||
n: BlockNumber,
|
||||
) -> Balance {
|
||||
// Number of blocks that count toward vesting;
|
||||
// saturating to 0 when n < starting_block.
|
||||
let vested_block_count = n.saturating_sub(self.starting_block);
|
||||
let vested_block_count = BlockNumberToBalance::convert(vested_block_count);
|
||||
// Return amount that is still locked in vesting.
|
||||
vested_block_count
|
||||
.checked_mul(&self.per_block()) // `per_block` accessor guarantees at least 1.
|
||||
.map(|to_unlock| self.locked.saturating_sub(to_unlock))
|
||||
.unwrap_or(Zero::zero())
|
||||
}
|
||||
|
||||
/// Block number at which the schedule ends (as type `Balance`).
|
||||
pub fn ending_block_as_balance<BlockNumberToBalance: Convert<BlockNumber, Balance>>(
|
||||
&self,
|
||||
) -> Balance {
|
||||
let starting_block = BlockNumberToBalance::convert(self.starting_block);
|
||||
let duration = if self.per_block() >= self.locked {
|
||||
// If `per_block` is bigger than `locked`, the schedule will end
|
||||
// the block after starting.
|
||||
One::one()
|
||||
} else {
|
||||
self.locked / self.per_block() +
|
||||
if (self.locked % self.per_block()).is_zero() {
|
||||
Zero::zero()
|
||||
} else {
|
||||
// `per_block` does not perfectly divide `locked`, so we need an extra block to
|
||||
// unlock some amount less than `per_block`.
|
||||
One::one()
|
||||
}
|
||||
};
|
||||
|
||||
starting_block.saturating_add(duration)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for `pezpallet_vesting`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `4563561839a5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --extrinsic=*
|
||||
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
|
||||
// --pallet=pezpallet_vesting
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/vesting/src/weights.rs
|
||||
// --wasm-execution=compiled
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --heap-pages=4096
|
||||
// --template=bizinikiwi/.maintain/frame-weight-template.hbs
|
||||
// --no-storage-info
|
||||
// --no-min-squares
|
||||
// --no-median-slopes
|
||||
// --genesis-builder-policy=none
|
||||
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pezpallet_vesting`.
|
||||
pub trait WeightInfo {
|
||||
fn vest_locked(l: u32, s: u32, ) -> Weight;
|
||||
fn vest_unlocked(l: u32, s: u32, ) -> Weight;
|
||||
fn vest_other_locked(l: u32, s: u32, ) -> Weight;
|
||||
fn vest_other_unlocked(l: u32, s: u32, ) -> Weight;
|
||||
fn vested_transfer(l: u32, s: u32, ) -> Weight;
|
||||
fn force_vested_transfer(l: u32, s: u32, ) -> Weight;
|
||||
fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight;
|
||||
fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight;
|
||||
fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_vesting` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_locked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 29_108_000 picoseconds.
|
||||
Weight::from_parts(28_662_441, 4764)
|
||||
// Standard Error: 954
|
||||
.saturating_add(Weight::from_parts(30_514, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 1_698
|
||||
.saturating_add(Weight::from_parts(62_299, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_unlocked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 30_994_000 picoseconds.
|
||||
Weight::from_parts(30_464_494, 4764)
|
||||
// Standard Error: 1_481
|
||||
.saturating_add(Weight::from_parts(28_285, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_636
|
||||
.saturating_add(Weight::from_parts(66_703, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_other_locked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 31_696_000 picoseconds.
|
||||
Weight::from_parts(31_191_832, 4764)
|
||||
// Standard Error: 1_199
|
||||
.saturating_add(Weight::from_parts(29_734, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_133
|
||||
.saturating_add(Weight::from_parts(65_658, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_other_unlocked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 33_388_000 picoseconds.
|
||||
Weight::from_parts(32_877_344, 4764)
|
||||
// Standard Error: 1_245
|
||||
.saturating_add(Weight::from_parts(34_308, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_216
|
||||
.saturating_add(Weight::from_parts(58_989, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[0, 27]`.
|
||||
fn vested_transfer(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 67_470_000 picoseconds.
|
||||
Weight::from_parts(68_202_160, 4764)
|
||||
// Standard Error: 2_799
|
||||
.saturating_add(Weight::from_parts(48_357, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 4_979
|
||||
.saturating_add(Weight::from_parts(102_560, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[0, 27]`.
|
||||
fn force_vested_transfer(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `328 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 69_510_000 picoseconds.
|
||||
Weight::from_parts(69_862_164, 6196)
|
||||
// Standard Error: 2_523
|
||||
.saturating_add(Weight::from_parts(49_783, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 4_489
|
||||
.saturating_add(Weight::from_parts(114_991, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 29_865_000 picoseconds.
|
||||
Weight::from_parts(29_471_812, 4764)
|
||||
// Standard Error: 1_177
|
||||
.saturating_add(Weight::from_parts(30_158, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_174
|
||||
.saturating_add(Weight::from_parts(65_109, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 32_137_000 picoseconds.
|
||||
Weight::from_parts(31_237_719, 4764)
|
||||
// Standard Error: 1_135
|
||||
.saturating_add(Weight::from_parts(35_827, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_097
|
||||
.saturating_add(Weight::from_parts(79_394, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 35_493_000 picoseconds.
|
||||
Weight::from_parts(34_502_101, 4764)
|
||||
// Standard Error: 1_833
|
||||
.saturating_add(Weight::from_parts(40_786, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 3_385
|
||||
.saturating_add(Weight::from_parts(81_931, 0).saturating_mul(s.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_locked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 29_108_000 picoseconds.
|
||||
Weight::from_parts(28_662_441, 4764)
|
||||
// Standard Error: 954
|
||||
.saturating_add(Weight::from_parts(30_514, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 1_698
|
||||
.saturating_add(Weight::from_parts(62_299, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_unlocked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 30_994_000 picoseconds.
|
||||
Weight::from_parts(30_464_494, 4764)
|
||||
// Standard Error: 1_481
|
||||
.saturating_add(Weight::from_parts(28_285, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_636
|
||||
.saturating_add(Weight::from_parts(66_703, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_other_locked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 31_696_000 picoseconds.
|
||||
Weight::from_parts(31_191_832, 4764)
|
||||
// Standard Error: 1_199
|
||||
.saturating_add(Weight::from_parts(29_734, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_133
|
||||
.saturating_add(Weight::from_parts(65_658, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[1, 28]`.
|
||||
fn vest_other_unlocked(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 33_388_000 picoseconds.
|
||||
Weight::from_parts(32_877_344, 4764)
|
||||
// Standard Error: 1_245
|
||||
.saturating_add(Weight::from_parts(34_308, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_216
|
||||
.saturating_add(Weight::from_parts(58_989, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[0, 27]`.
|
||||
fn vested_transfer(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 67_470_000 picoseconds.
|
||||
Weight::from_parts(68_202_160, 4764)
|
||||
// Standard Error: 2_799
|
||||
.saturating_add(Weight::from_parts(48_357, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 4_979
|
||||
.saturating_add(Weight::from_parts(102_560, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[0, 27]`.
|
||||
fn force_vested_transfer(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `328 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `6196`
|
||||
// Minimum execution time: 69_510_000 picoseconds.
|
||||
Weight::from_parts(69_862_164, 6196)
|
||||
// Standard Error: 2_523
|
||||
.saturating_add(Weight::from_parts(49_783, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 4_489
|
||||
.saturating_add(Weight::from_parts(114_991, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(4_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 29_865_000 picoseconds.
|
||||
Weight::from_parts(29_471_812, 4764)
|
||||
// Standard Error: 1_177
|
||||
.saturating_add(Weight::from_parts(30_158, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_174
|
||||
.saturating_add(Weight::from_parts(65_109, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `123 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 32_137_000 picoseconds.
|
||||
Weight::from_parts(31_237_719, 4764)
|
||||
// Standard Error: 1_135
|
||||
.saturating_add(Weight::from_parts(35_827, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 2_097
|
||||
.saturating_add(Weight::from_parts(79_394, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `Vesting::Vesting` (r:1 w:1)
|
||||
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Locks` (r:1 w:1)
|
||||
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Freezes` (r:1 w:0)
|
||||
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `l` is `[0, 49]`.
|
||||
/// The range of component `s` is `[2, 28]`.
|
||||
fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `225 + l * (25 ±0) + s * (36 ±0)`
|
||||
// Estimated: `4764`
|
||||
// Minimum execution time: 35_493_000 picoseconds.
|
||||
Weight::from_parts(34_502_101, 4764)
|
||||
// Standard Error: 1_833
|
||||
.saturating_add(Weight::from_parts(40_786, 0).saturating_mul(l.into()))
|
||||
// Standard Error: 3_385
|
||||
.saturating_add(Weight::from_parts(81_931, 0).saturating_mul(s.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user