diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 0c736a632842..3a8e98d19f05 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -18,7 +18,10 @@ use frame_support::{ ensure, - traits::{Currency, Get, IsSubType, VestingSchedule}, + traits::{ + tokens::{fungible, fungible::freeze::VestingSchedule, Balance}, + Get, IsSubType, + }, weights::Weight, DefaultNoBound, }; @@ -41,8 +44,9 @@ use sp_std::{fmt::Debug, prelude::*}; type CurrencyOf = <::VestingSchedule as VestingSchedule< ::AccountId, ->>::Currency; -type BalanceOf = as Currency<::AccountId>>::Balance; +>>::Fungible; +type BalanceOf = + as fungible::Inspect<::AccountId>>::Balance; pub trait WeightInfo { fn claim() -> Weight; @@ -161,6 +165,7 @@ pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use sp_runtime::traits::MaybeSerializeDeserialize; #[pallet::pallet] #[pallet::without_storage_info] @@ -171,7 +176,14 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type VestingSchedule: VestingSchedule>; + type VestingSchedule: VestingSchedule< + Self::AccountId, + Moment = BlockNumberFor, + Fungible = Self::Fungible, + >; + type Fungible: fungible::Inspect + + fungible::Mutate; + type Balance: Balance + MaybeSerializeDeserialize; #[pallet::constant] type Prefix: Get<&'static [u8]>; type MoveClaimOrigin: EnsureOrigin; @@ -551,6 +563,8 @@ impl Pallet { } fn process_claim(signer: EthereumAddress, dest: T::AccountId) -> sp_runtime::DispatchResult { + use frame_support::traits::fungible::Mutate; + let balance_due = >::get(&signer).ok_or(Error::::SignerHasNoClaim)?; let new_total = Self::total().checked_sub(&balance_due).ok_or(Error::::PotUnderflow)?; @@ -561,7 +575,9 @@ impl Pallet { } // We first need to deposit the balance to ensure that the account exists. - CurrencyOf::::deposit_creating(&dest, balance_due); + //TODO: we need to ensure that this creates the account if it does not already exist + // was: CurrencyOf::::deposit_creating(&dest, balance_due); + CurrencyOf::::mint_into(&dest, balance_due)?; // Check if this claim should have a vesting schedule. if let Some(vs) = vesting { @@ -700,6 +716,7 @@ mod secp_utils { #[cfg(test)] mod tests { use super::*; + use frame_support::traits::tokens::Preservation; use hex_literal::hex; use secp_utils::*; @@ -713,7 +730,7 @@ mod tests { assert_err, assert_noop, assert_ok, dispatch::{GetDispatchInfo, Pays}, ord_parameter_types, parameter_types, - traits::{ConstU32, ExistenceRequirement, WithdrawReasons}, + traits::{ConstU32, WithdrawReasons}, }; use pallet_balances; use sp_runtime::{ @@ -731,7 +748,7 @@ mod tests { { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Vesting: pallet_vesting::{Pallet, Call, Storage, Config, Event}, + Vesting: pallet_vesting::{Pallet, Call, Storage, Config, Event, FreezeReason}, Claims: claims::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, } ); @@ -767,6 +784,7 @@ mod tests { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxFreezes: u32 = 1; } impl pallet_balances::Config for Test { @@ -780,9 +798,9 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<1>; + type MaxFreezes = MaxFreezes; } parameter_types! { @@ -793,12 +811,17 @@ mod tests { impl pallet_vesting::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type BlockNumberToBalance = Identity; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { @@ -811,6 +834,8 @@ mod tests { impl Config for Test { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; + type Fungible = Balances; + type Balance = u64; type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureSignedBy; type WeightInfo = TestWeightInfo; @@ -1197,11 +1222,11 @@ mod tests { // Make sure we can not transfer the vested balance. assert_err!( - >::transfer( + >::transfer( &69, &80, 180, - ExistenceRequirement::AllowDeath + Preservation::Expendable ), TokenError::Frozen, ); @@ -1291,7 +1316,8 @@ mod tests { #[test] fn claiming_while_vested_doesnt_work() { new_test_ext().execute_with(|| { - CurrencyOf::::make_free_balance_be(&69, total_claims()); + use frame_support::traits::tokens::fungible::Mutate; + CurrencyOf::::set_balance(&69, total_claims()); assert_eq!(Balances::free_balance(69), total_claims()); // A user is already vested assert_ok!(::VestingSchedule::add_vesting_schedule( diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 58ca19d0288c..451705ea5fc9 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -18,7 +18,10 @@ use frame_support::{ pallet_prelude::*, - traits::{Currency, EnsureOrigin, ExistenceRequirement, Get, VestingSchedule}, + traits::{ + tokens::{fungible, fungible::freeze::VestingSchedule, Preservation}, + EnsureOrigin, Get, + }, }; use frame_system::pallet_prelude::*; pub use pallet::*; @@ -32,7 +35,7 @@ use sp_runtime::{ use sp_std::prelude::*; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as fungible::Inspect<::AccountId>>::Balance; /// The kind of statement an account needs to make for a claim to be valid. #[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, TypeInfo)] @@ -101,13 +104,15 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Balances Pallet - type Currency: Currency; + type Currency: fungible::Inspect + + fungible::Mutate + + fungible::MutateFreeze; /// Vesting Pallet type VestingSchedule: VestingSchedule< Self::AccountId, Moment = BlockNumberFor, - Currency = Self::Currency, + Fungible = Self::Currency, >; /// The origin allowed to set account status. @@ -317,6 +322,7 @@ pub mod pallet { Accounts::::try_mutate( &who, |status: &mut AccountStatus>| -> DispatchResult { + use frame_support::traits::fungible::Mutate; // Account has a valid status (not Invalid, Pending, or Completed)... ensure!(status.validity.is_valid(), Error::::InvalidAccount); @@ -329,7 +335,7 @@ pub mod pallet { &payment_account, &who, total_balance, - ExistenceRequirement::AllowDeath, + Preservation::Expendable, )?; if !status.locked_balance.is_zero() { @@ -501,7 +507,7 @@ mod tests { { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Vesting: pallet_vesting::{Pallet, Call, Storage, Config, Event}, + Vesting: pallet_vesting::{Pallet, Call, Storage, Config, Event, FreezeReason}, Purchase: purchase::{Pallet, Call, Storage, Event}, } ); @@ -539,6 +545,7 @@ mod tests { parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxFreezes: u32 = 2; // Vesting + ? } impl pallet_balances::Config for Test { @@ -552,9 +559,9 @@ mod tests { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<1>; + type MaxFreezes = MaxFreezes; } parameter_types! { @@ -565,12 +572,17 @@ mod tests { impl pallet_vesting::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type BlockNumberToBalance = Identity; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 4bdcc1237394..0a34e2452248 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -280,6 +280,7 @@ parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; + pub const MaxFreezes: u32 = 2; // Vesting and ? } impl pallet_balances::Config for Runtime { @@ -292,8 +293,8 @@ impl pallet_balances::Config for Runtime { type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; type WeightInfo = weights::pallet_balances::WeightInfo; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<1>; + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = MaxFreezes; type RuntimeHoldReason = RuntimeHoldReason; type MaxHolds = ConstU32<1>; } @@ -562,6 +563,8 @@ parameter_types! { impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; + type Fungible = Balances; + type Balance = Balance; type Prefix = Prefix; type MoveClaimOrigin = EnsureRoot; type WeightInfo = weights::runtime_common_claims::WeightInfo; @@ -664,12 +667,17 @@ parameter_types! { impl pallet_vesting::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = weights::pallet_vesting::WeightInfo; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { @@ -1060,7 +1068,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = weights::pallet_balances_nis_counterpart_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<0>; type MaxFreezes = ConstU32<0>; } @@ -1265,7 +1273,7 @@ construct_runtime! { Recovery: pallet_recovery::{Pallet, Call, Storage, Event} = 27, // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config} = 28, + Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config, FreezeReason} = 28, // System scheduler. Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 29, diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 99fd2198400b..ea550394cd22 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -216,6 +216,7 @@ parameter_types! { pub const ExistentialDeposit: Balance = 1 * CENTS; pub storage MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; + pub const MaxFreezes: u32 = 1; } impl pallet_balances::Config for Runtime { @@ -229,9 +230,9 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type WeightInfo = (); type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); + type FreezeIdentifier = RuntimeFreezeReason; type MaxHolds = ConstU32<0>; - type MaxFreezes = ConstU32<0>; + type MaxFreezes = MaxFreezes; } parameter_types! { @@ -452,6 +453,8 @@ parameter_types! { impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type Fungible = Balances; + type Balance = Balance; type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureRoot; @@ -466,12 +469,17 @@ parameter_types! { impl pallet_vesting::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_sudo::Config for Runtime { @@ -687,7 +695,7 @@ construct_runtime! { Claims: claims::{Pallet, Call, Storage, Event, Config, ValidateUnsigned}, // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config}, + Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config, FreezeReason}, // Parachains runtime modules Configuration: parachains_configuration::{Pallet, Call, Storage, Config}, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 6085b6e37455..0110d55114d1 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -279,6 +279,7 @@ parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; + pub const MaxFreezes: u32 = 2; // Vesting } impl pallet_balances::Config for Runtime { @@ -293,7 +294,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = ConstU32<1>; + type MaxFreezes = MaxFreezes; type MaxHolds = ConstU32<1>; } @@ -910,12 +911,17 @@ parameter_types! { impl pallet_vesting::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RuntimeHoldReason = RuntimeHoldReason; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = weights::pallet_vesting::WeightInfo; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_sudo::Config for Runtime { @@ -1375,7 +1381,7 @@ construct_runtime! { Recovery: pallet_recovery::{Pallet, Call, Storage, Event} = 18, // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config} = 19, + Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config, FreezeReason} = 19, // System scheduler. Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 20, diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f018639b732e..f2af46f599fb 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -509,6 +509,7 @@ parameter_types! { // This number may need to be adjusted in the future if this assumption no longer holds true. pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; + pub const MaxFreezes: u32 = 2; } impl pallet_balances::Config for Runtime { @@ -522,7 +523,7 @@ impl pallet_balances::Config for Runtime { type AccountStore = frame_system::Pallet; type WeightInfo = pallet_balances::weights::SubstrateWeight; type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = ConstU32<1>; + type MaxFreezes = MaxFreezes; type RuntimeHoldReason = RuntimeHoldReason; type MaxHolds = ConstU32<2>; } @@ -1526,14 +1527,19 @@ parameter_types! { impl pallet_vesting::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; + type MaxFreezes = MaxFreezes; type WeightInfo = pallet_vesting::weights::SubstrateWeight; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the // highest number of schedules that encodes less than 2^10. const MAX_VESTING_SCHEDULES: u32 = 28; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_mmr::Config for Runtime { diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 2179ee38f848..51751a30602d 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -23,7 +23,7 @@ pub mod tokens; pub use tokens::{ currency::{ ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, - ReservableCurrency, TotalIssuanceOf, VestingSchedule, + ReservableCurrency, TotalIssuanceOf, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 0030e1261dac..f34b8f7c9f7f 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -27,7 +27,7 @@ use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; -pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; +pub use lockable::{LockIdentifier, LockableCurrency}; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs index 955814f5aa9d..0f9aae24224a 100644 --- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs @@ -18,7 +18,7 @@ //! The lockable currency trait and some associated types. use super::{super::misc::WithdrawReasons, Currency}; -use crate::{dispatch::DispatchResult, traits::misc::Get}; +use crate::traits::misc::Get; /// An identifier for a lock. Used for disambiguating different locks so that /// they can be individually replaced or removed. @@ -63,46 +63,3 @@ pub trait LockableCurrency: Currency { /// Remove an existing lock. fn remove_lock(id: LockIdentifier, who: &AccountId); } - -/// A vesting schedule over a currency. This allows a particular currency to have vesting limits -/// applied to it. -pub trait VestingSchedule { - /// The quantity used to denote time; usually just a `BlockNumber`. - type Moment; - - /// The currency that this schedule applies to. - type Currency: Currency; - - /// Get the amount that is currently being vested and cannot be transferred out of this account. - /// Returns `None` if the account has no vesting schedule. - fn vesting_balance(who: &AccountId) - -> Option<>::Balance>; - - /// Adds a vesting schedule to a given account. - /// - /// If the account has `MaxVestingSchedules`, an Error is returned and nothing - /// is updated. - /// - /// 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: &AccountId, - locked: >::Balance, - per_block: >::Balance, - starting_block: Self::Moment, - ) -> DispatchResult; - - /// Checks if `add_vesting_schedule` would work against `who`. - fn can_add_vesting_schedule( - who: &AccountId, - locked: >::Balance, - per_block: >::Balance, - starting_block: Self::Moment, - ) -> DispatchResult; - - /// Remove a vesting schedule for a given account. - /// - /// NOTE: This doesn't alter the free balance of the account. - fn remove_vesting_schedule(who: &AccountId, schedule_index: u32) -> DispatchResult; -} diff --git a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs index 8b542ee4c606..0b53eaa83db2 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs @@ -121,3 +121,47 @@ pub trait Mutate: Inspect { Self::set_frozen(id, who, a, Fortitude::Polite) } } + +/// A vesting schedule over a fungible. This allows a particular fungible to have vesting limits +/// applied to it. +pub trait VestingSchedule: Sized { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// The fungible that this schedule applies to. + type Fungible: super::Inspect; + + /// Get the amount that is currently being vested and cannot be transferred out of this account. + /// Returns `None` if the account has no vesting schedule. + fn vesting_balance( + who: &AccountId, + ) -> Option<>::Balance>; + + /// Adds a vesting schedule to a given account. + /// + /// If the account has `MaxVestingSchedules`, an Error is returned and nothing + /// is updated. + /// + /// 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: &AccountId, + locked: >::Balance, + per_block: >::Balance, + starting_block: Self::Moment, + ) -> DispatchResult; + + /// Checks if `add_vesting_schedule` would work against `who`. + fn can_add_vesting_schedule( + who: &AccountId, + locked: >::Balance, + per_block: >::Balance, + starting_block: Self::Moment, + ) -> DispatchResult; + + /// Remove a vesting schedule for a given account. + /// + /// NOTE: This doesn't alter the free balance of the account. + fn remove_vesting_schedule(who: &AccountId, schedule_index: u32) -> DispatchResult; +} diff --git a/substrate/frame/vesting/src/benchmarking.rs b/substrate/frame/vesting/src/benchmarking.rs index 4af48f5d368d..a4a40290307d 100644 --- a/substrate/frame/vesting/src/benchmarking.rs +++ b/substrate/frame/vesting/src/benchmarking.rs @@ -20,7 +20,13 @@ #![cfg(feature = "runtime-benchmarks")] use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; -use frame_support::assert_ok; +use frame_support::{ + assert_ok, + traits::{ + fungible::Mutate, + tokens::{fungible::freeze::VestingSchedule, Preservation}, + }, +}; use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul}; @@ -30,14 +36,16 @@ use crate::Pallet as Vesting; const SEED: u32 = 0; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as fungible::Inspect<::AccountId>>::Balance; fn add_locks(who: &T::AccountId, n: u8) { + use frame_support::traits::fungible::MutateFreeze; for id in 0..n { - let lock_id = [id; 8]; + let lock_id = T::BenchmarkHelper::freeze_id(id); let locked = 256u32; - let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; - T::Currency::set_lock(lock_id, who, locked.into(), reasons); + //TODO: what do we do with reasons? + // let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; + T::Currency::set_freeze(&lock_id, who, locked.into()).unwrap(); } } @@ -53,7 +61,7 @@ fn add_vesting_schedules( let source: T::AccountId = account("source", 0, SEED); let source_lookup = T::Lookup::unlookup(source.clone()); - T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); + T::Currency::set_balance(&source, BalanceOf::::max_value() >> 2); System::::set_block_number(BlockNumberFor::::zero()); @@ -69,7 +77,7 @@ fn add_vesting_schedules( )); // Top up to guarantee we can always transfer another schedule. - T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); + T::Currency::set_balance(&source, BalanceOf::::max_value() >> 2); } Ok(total_locked) @@ -77,12 +85,12 @@ fn add_vesting_schedules( benchmarks! { vest_locked { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 1 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); + T::Currency::set_balance(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); let expected_balance = add_vesting_schedules::(caller_lookup, s)?; @@ -105,12 +113,12 @@ benchmarks! { } vest_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 1 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); + T::Currency::set_balance(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); add_vesting_schedules::(caller_lookup, s)?; @@ -133,13 +141,13 @@ benchmarks! { } vest_other_locked { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 1 .. T::MAX_VESTING_SCHEDULES; let other: T::AccountId = account("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); - T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); + T::Currency::set_balance(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); let expected_balance = add_vesting_schedules::(other_lookup.clone(), s)?; @@ -163,13 +171,13 @@ benchmarks! { } vest_other_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 1 .. T::MAX_VESTING_SCHEDULES; let other: T::AccountId = account("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); - T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); + T::Currency::set_balance(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); add_vesting_schedules::(other_lookup.clone(), s)?; // At block 21 everything is unlocked. @@ -193,19 +201,19 @@ benchmarks! { } vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + T::Currency::set_balance(&caller, BalanceOf::::max_value() >> 2); let target: T::AccountId = account("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()); + T::Currency::set_balance(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one vesting schedules. - let orig_balance = T::Currency::free_balance(&target); + let orig_balance = T::Currency::balance(&target); let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; let transfer_amount = T::MinVestedTransfer::get(); @@ -221,7 +229,7 @@ benchmarks! { verify { assert_eq!( orig_balance + expected_balance, - T::Currency::free_balance(&target), + T::Currency::balance(&target), "Transfer didn't happen", ); assert_eq!( @@ -232,20 +240,20 @@ benchmarks! { } force_vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; let source: T::AccountId = account("source", 0, SEED); let source_lookup = T::Lookup::unlookup(source.clone()); - T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); + T::Currency::set_balance(&source, BalanceOf::::max_value()); let target: T::AccountId = account("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()); + T::Currency::set_balance(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one less than max vesting schedules - let orig_balance = T::Currency::free_balance(&target); + let orig_balance = T::Currency::balance(&target); let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; let transfer_amount = T::MinVestedTransfer::get(); @@ -261,7 +269,7 @@ benchmarks! { verify { assert_eq!( orig_balance + expected_balance, - T::Currency::free_balance(&target), + T::Currency::balance(&target), "Transfer didn't happen", ); assert_eq!( @@ -272,13 +280,13 @@ benchmarks! { } not_unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 2 .. T::MAX_VESTING_SCHEDULES; let caller: T::AccountId = account("caller", 0, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target existing locks. - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); + T::Currency::set_balance(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. let expected_balance = add_vesting_schedules::(caller_lookup, s)?; @@ -320,7 +328,7 @@ benchmarks! { } unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; + let l in 0 .. T::MaxFreezes::get() - 1; let s in 2 .. T::MAX_VESTING_SCHEDULES; // Destination used just for currency transfers in asserts. @@ -329,7 +337,7 @@ benchmarks! { let caller: T::AccountId = account("caller", 0, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target other locks. - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); + T::Currency::set_balance(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. let total_transferred = add_vesting_schedules::(caller_lookup, s)?; @@ -349,7 +357,7 @@ benchmarks! { "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()); + assert!(T::Currency::transfer(&caller, &test_dest, expected_balance, Preservation::Expendable).is_err()); }: merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1) verify { let expected_schedule = VestingInfo::new( @@ -379,7 +387,7 @@ benchmarks! { ); // Since merge unlocks all schedules we can now transfer the balance. assert_ok!( - T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath) + T::Currency::transfer(&caller, &test_dest, expected_balance, Preservation::Expendable) ); } diff --git a/substrate/frame/vesting/src/lib.rs b/substrate/frame/vesting/src/lib.rs index ee67a038e4d7..0fee8991529f 100644 --- a/substrate/frame/vesting/src/lib.rs +++ b/substrate/frame/vesting/src/lib.rs @@ -61,10 +61,7 @@ use frame_support::{ dispatch::DispatchResult, ensure, storage::bounded_vec::BoundedVec, - traits::{ - Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestingSchedule, - WithdrawReasons, - }, + traits::{fungible, fungible::Inspect, tokens::Preservation, Get, WithdrawReasons}, weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -76,19 +73,16 @@ use sp_runtime::{ }, DispatchError, RuntimeDebug, }; -use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; +use sp_std::{marker::PhantomData, prelude::*}; pub use pallet::*; pub use vesting_info::*; pub use weights::WeightInfo; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -type MaxLocksOf = - <::Currency as LockableCurrency<::AccountId>>::MaxLocks; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + <::Currency as fungible::Inspect<::AccountId>>::Balance; -const VESTING_ID: LockIdentifier = *b"vesting "; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; // 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. @@ -155,12 +149,25 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config + where + >::Balance: + frame_support::traits::tokens::Balance + MaybeSerializeDeserialize, + { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The currency trait. - type Currency: LockableCurrency; + /// The overarching hold reason. + type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Ord + Copy; + + /// The overarching freeze reason. + type RuntimeFreezeReason: From; + + /// The fungible trait. + type Currency: fungible::InspectFreeze + + fungible::MutateFreeze + + fungible::Inspect + + fungible::Mutate; /// Convert the block number into a balance. type BlockNumberToBalance: Convert, BalanceOf>; @@ -178,6 +185,17 @@ pub mod pallet { /// Maximum number of vesting schedules an account may have at a given moment. const MAX_VESTING_SCHEDULES: u32; + + /// The maximum number of freezes that should exist on a given account + /// (across all pallets). + /// Typically this might be set to pallet_balance::MaxFreezes. + type MaxFreezes: Get; + + /// The benchmarks need a way to create asset ids from u32s. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelper< + >::Id, + >; } #[pallet::extra_constants] @@ -192,6 +210,7 @@ pub mod pallet { impl Hooks> for Pallet { fn integrity_test() { assert!(T::MAX_VESTING_SCHEDULES > 0, "`MaxVestingSchedules` must ge greater than 0"); + assert!(T::MaxFreezes::get() > 0, "`MaxFreezes` must ge greater than 0"); } } @@ -214,6 +233,13 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); + /// Initial vesting configuration is a vec of tuples: + /// `(who, begin, length, liquid)` + /// where: + /// * 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 #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { @@ -223,18 +249,14 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { + use frame_support::traits::fungible::{Inspect, MutateFreeze}; use sp_runtime::traits::Saturating; // Genesis uses the latest storage version. StorageVersion::::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); + let balance = T::Currency::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); @@ -248,10 +270,12 @@ pub mod pallet { Vesting::::try_append(who, vesting_info) .expect("Too many vesting schedules at genesis."); - let reasons = - WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); + // let reasons = + // WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); - T::Currency::set_lock(VESTING_ID, who, locked, reasons); + //TODO: this was before recording the T::UnvestedFundsAllowedWithdrawReasons::get() + T::Currency::set_freeze(&FreezeReason::NotYetVested.into(), who, locked) + .expect("Can't freeze at genesis"); } } } @@ -266,6 +290,14 @@ pub mod pallet { VestingCompleted { account: T::AccountId }, } + /// A reason for freezing funds. + #[pallet::composite_enum] + pub enum FreezeReason { + /// Funds are currently locked and are not yet liquid. + #[codec(index = 0)] + NotYetVested, + } + /// Error for the vesting pallet. #[pallet::error] pub enum Error { @@ -294,8 +326,8 @@ pub mod pallet { /// ## Complexity /// - `O(1)`. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::vest_locked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) - .max(T::WeightInfo::vest_unlocked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) + #[pallet::weight(T::WeightInfo::vest_locked(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES) + .max(T::WeightInfo::vest_unlocked(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES)) )] pub fn vest(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -314,8 +346,8 @@ pub mod pallet { /// ## Complexity /// - `O(1)`. #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::vest_other_locked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) - .max(T::WeightInfo::vest_other_unlocked(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) + #[pallet::weight(T::WeightInfo::vest_other_locked(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES) + .max(T::WeightInfo::vest_other_unlocked(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES)) )] pub fn vest_other(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; @@ -337,9 +369,10 @@ pub mod pallet { /// ## Complexity /// - `O(1)`. #[pallet::call_index(2)] - #[pallet::weight( - T::WeightInfo::vested_transfer(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) - )] + #[pallet::weight(T::WeightInfo::vested_transfer( + T::MaxFreezes::get(), + T::MAX_VESTING_SCHEDULES + ))] pub fn vested_transfer( origin: OriginFor, target: AccountIdLookupOf, @@ -365,9 +398,10 @@ pub mod pallet { /// ## Complexity /// - `O(1)`. #[pallet::call_index(3)] - #[pallet::weight( - T::WeightInfo::force_vested_transfer(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) - )] + #[pallet::weight(T::WeightInfo::force_vested_transfer( + T::MaxFreezes::get(), + T::MAX_VESTING_SCHEDULES + ))] pub fn force_vested_transfer( origin: OriginFor, source: AccountIdLookupOf, @@ -401,8 +435,8 @@ pub mod pallet { /// - `schedule2_index`: index of the second schedule to merge. #[pallet::call_index(4)] #[pallet::weight( - T::WeightInfo::not_unlocking_merge_schedules(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES) - .max(T::WeightInfo::unlocking_merge_schedules(MaxLocksOf::::get(), T::MAX_VESTING_SCHEDULES)) + T::WeightInfo::not_unlocking_merge_schedules(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES) + .max(T::WeightInfo::unlocking_merge_schedules(T::MaxFreezes::get(), T::MAX_VESTING_SCHEDULES)) )] pub fn merge_schedules( origin: OriginFor, @@ -423,7 +457,8 @@ pub mod pallet { let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), merge_action)?; Self::write_vesting(&who, schedules)?; - Self::write_lock(&who, locked_now); + //TODO: is this now a problem with the ordering now that it's fallable? + Self::write_lock(&who, locked_now)?; Ok(()) } @@ -486,6 +521,7 @@ impl Pallet { target: AccountIdLookupOf, schedule: VestingInfo, BlockNumberFor>, ) -> DispatchResult { + use frame_support::traits::fungible::{freeze::VestingSchedule, Mutate}; // Validate user inputs. ensure!(schedule.locked() >= T::MinVestedTransfer::get(), Error::::AmountLow); if !schedule.is_valid() { @@ -502,12 +538,7 @@ impl Pallet { schedule.starting_block(), )?; - T::Currency::transfer( - &source, - &target, - schedule.locked(), - ExistenceRequirement::AllowDeath, - )?; + T::Currency::transfer(&source, &target, schedule.locked(), Preservation::Expendable)?; // We can't let this fail because the currency transfer has already happened. let res = Self::add_vesting_schedule( @@ -554,18 +585,23 @@ impl Pallet { } /// Write an accounts updated vesting lock to storage. - fn write_lock(who: &T::AccountId, total_locked_now: BalanceOf) { + fn write_lock(who: &T::AccountId, total_locked_now: BalanceOf) -> Result<(), DispatchError> { + use frame_support::traits::fungible::MutateFreeze; + if total_locked_now.is_zero() { - T::Currency::remove_lock(VESTING_ID, who); + T::Currency::thaw(&FreezeReason::NotYetVested.into(), who)?; Self::deposit_event(Event::::VestingCompleted { account: who.clone() }); } else { - let reasons = WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); - T::Currency::set_lock(VESTING_ID, who, total_locked_now, reasons); + // let reasons = WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); + //TODO: should we have a hold here with a reason as well? + T::Currency::set_freeze(&FreezeReason::NotYetVested.into(), who, total_locked_now)?; Self::deposit_event(Event::::VestingUpdated { account: who.clone(), unvested: total_locked_now, }); }; + + Ok(()) } /// Write an accounts updated vesting schedules to storage. @@ -595,7 +631,7 @@ impl Pallet { Self::exec_action(schedules.to_vec(), VestingAction::Passive)?; Self::write_vesting(&who, schedules)?; - Self::write_lock(&who, locked_now); + Self::write_lock(&who, locked_now)?; Ok(()) } @@ -645,11 +681,8 @@ impl Pallet { } } -impl VestingSchedule for Pallet -where - BalanceOf: MaybeSerializeDeserialize + Debug, -{ - type Currency = T::Currency; +impl fungible::freeze::VestingSchedule for Pallet { + type Fungible = T::Currency; type Moment = BlockNumberFor; /// Get the amount that is currently being vested and cannot be transferred out of this account. @@ -659,7 +692,7 @@ where let total_locked_now = v.iter().fold(Zero::zero(), |total, schedule| { schedule.locked_at::(now).saturating_add(total) }); - Some(T::Currency::free_balance(who).min(total_locked_now)) + Some(T::Currency::balance(who).min(total_locked_now)) } else { None } @@ -703,7 +736,7 @@ where Self::exec_action(schedules.to_vec(), VestingAction::Passive)?; Self::write_vesting(who, schedules)?; - Self::write_lock(who, locked_now); + Self::write_lock(who, locked_now)?; Ok(()) } @@ -737,7 +770,27 @@ where let (schedules, locked_now) = Self::exec_action(schedules.to_vec(), remove_action)?; Self::write_vesting(who, schedules)?; - Self::write_lock(who, locked_now); + Self::write_lock(who, locked_now)?; Ok(()) } } + +/// Benchmark Helper +#[cfg(feature = "runtime-benchmarks")] +pub trait BenchmarkHelper { + /// Returns a frozen `Id` from a given integer. + fn freeze_id(id: u8) -> FreezeId; +} + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelper for () +where + T: Decode, + T: From, +{ + /// Returns a frozen `Id` from a given integer. + fn freeze_id(id: u8) -> T { + let vec = vec![id]; + T::decode(&mut vec.as_slice()).unwrap_or(FreezeReason::NotYetVested.into()) + } +} diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index fe1779475a69..918bbac9f345 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -35,7 +35,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config}, + Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config, FreezeReason}, } ); @@ -65,6 +65,8 @@ impl frame_system::Config for Test { type Version = (); } +type MaxFreezes = ConstU32<1>; + impl pallet_balances::Config for Test { type AccountStore = System; type Balance = u64; @@ -75,9 +77,9 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = MaxFreezes; + type RuntimeHoldReason = RuntimeHoldReason; type MaxHolds = (); } parameter_types! { @@ -89,11 +91,16 @@ parameter_types! { impl Config for Test { type BlockNumberToBalance = Identity; type Currency = Balances; + type MaxFreezes = MaxFreezes; type RuntimeEvent = RuntimeEvent; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RuntimeHoldReason = RuntimeHoldReason; const MAX_VESTING_SCHEDULES: u32 = 3; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } pub struct ExtBuilder { diff --git a/substrate/frame/vesting/src/tests.rs b/substrate/frame/vesting/src/tests.rs index c35686bd5146..af2c243e60c2 100644 --- a/substrate/frame/vesting/src/tests.rs +++ b/substrate/frame/vesting/src/tests.rs @@ -16,7 +16,9 @@ // limitations under the License. use codec::EncodeLike; -use frame_support::{assert_noop, assert_ok, assert_storage_noop}; +use frame_support::{ + assert_noop, assert_ok, assert_storage_noop, traits::fungible::freeze::VestingSchedule, +}; use frame_system::RawOrigin; use sp_runtime::{ traits::{BadOrigin, Identity},