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:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
+55
View File
@@ -0,0 +1,55 @@
[package]
name = "pezpallet-vesting"
version = "28.0.0"
authors.workspace = true
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
description = "FRAME pallet for manage vesting"
readme = "README.md"
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { features = ["derive"], workspace = true }
pezframe-benchmarking = { optional = true, workspace = true }
pezframe-support = { workspace = true }
pezframe-system = { workspace = true }
log = { workspace = true }
scale-info = { features = ["derive"], workspace = true }
pezsp-runtime = { workspace = true }
[dev-dependencies]
pezpallet-balances = { workspace = true, default-features = true }
pezsp-io = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"codec/std",
"pezframe-benchmarking?/std",
"pezframe-support/std",
"pezframe-system/std",
"log/std",
"scale-info/std",
"pezsp-runtime/std",
]
runtime-benchmarks = [
"pezframe-benchmarking/runtime-benchmarks",
"pezframe-support/runtime-benchmarks",
"pezframe-system/runtime-benchmarks",
"pezpallet-balances/runtime-benchmarks",
"pezsp-io/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
]
try-runtime = [
"pezframe-support/try-runtime",
"pezframe-system/try-runtime",
"pezpallet-balances/try-runtime",
"pezsp-runtime/try-runtime",
]
+32
View File
@@ -0,0 +1,32 @@
# Vesting Module
- [`Config`](https://docs.rs/pezpallet-vesting/latest/pallet_vesting/pallet/trait.Config.html)
- [`Call`](https://docs.rs/pezpallet-vesting/latest/pallet_vesting/pallet/enum.Call.html)
## Overview
A simple module providing a means of placing a linear curve on an account's locked balance. This
module ensures that there is a lock in place preventing the balance to drop below the *unvested*
amount for 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 module 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.
[`Call`]: ./enum.Call.html
[`Config`]: ./trait.Config.html
License: Apache-2.0
@@ -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
}
}
+843
View File
@@ -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(())
}
}
+130
View File
@@ -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)
}
}
+491
View File
@@ -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))
}
}