diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index cee4f9dbe9..553592364b 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -167,7 +167,7 @@ use support::{ traits::{ UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnUnbalanced, TryDrop, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, - Imbalance, SignedImbalance, ReservableCurrency, Get, + Imbalance, SignedImbalance, ReservableCurrency, Get, VestingCurrency, }, weights::SimpleDispatchInfo, dispatch::Result, @@ -510,19 +510,6 @@ decl_module! { } impl, I: Instance> Module { - - // PUBLIC IMMUTABLES - - /// Get the amount that is currently being vested and cannot be transferred out of this account. - pub fn vesting_balance(who: &T::AccountId) -> T::Balance { - if let Some(v) = Self::vesting(who) { - Self::free_balance(who) - .min(v.locked_at(>::block_number())) - } else { - Zero::zero() - } - } - // PRIVATE MUTABLES /// Set the reserved balance of an account to some new value. Will enforce `ExistentialDeposit` @@ -1209,6 +1196,50 @@ where } } +impl, I: Instance> VestingCurrency for Module +where + T::Balance: MaybeSerializeDeserialize + Debug +{ + type Moment = T::BlockNumber; + + /// Get the amount that is currently being vested and cannot be transferred out of this account. + fn vesting_balance(who: &T::AccountId) -> T::Balance { + if let Some(v) = Self::vesting(who) { + Self::free_balance(who) + .min(v.locked_at(>::block_number())) + } else { + Zero::zero() + } + } + + /// Adds a vesting schedule to a given account. + /// + /// If there already exists a vesting schedule for the given account, an `Err` is returned + /// and nothing is updated. + fn add_vesting_schedule( + who: &T::AccountId, + locked: T::Balance, + per_block: T::Balance, + starting_block: T::BlockNumber + ) -> Result { + if >::exists(who) { + return Err("A vesting schedule already exists for this account."); + } + let vesting_schedule = VestingSchedule { + locked, + per_block, + starting_block + }; + >::insert(who, vesting_schedule); + Ok(()) + } + + /// Remove a vesting schedule for a given account. + fn remove_vesting_schedule(who: &T::AccountId) { + >::remove(who); + } +} + impl, I: Instance> IsDeadAccount for Module where T::Balance: MaybeSerializeDeserialize + Debug diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 3de5c4770b..d06d728454 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -602,6 +602,29 @@ pub trait LockableCurrency: Currency { ); } +/// A currency whose accounts can have balances which vest over time. +pub trait VestingCurrency: Currency { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// Get the amount that is currently being vested and cannot be transferred out of this account. + fn vesting_balance(who: &AccountId) -> Self::Balance; + + /// Adds a vesting schedule to a given account. + /// + /// If there already exists a vesting schedule for the given account, an `Err` is returned + /// and nothing is updated. + fn add_vesting_schedule( + who: &AccountId, + locked: Self::Balance, + per_block: Self::Balance, + starting_block: Self::Moment, + ) -> result::Result<(), &'static str>; + + /// Remove a vesting schedule for a given account. + fn remove_vesting_schedule(who: &AccountId); +} + bitmask! { /// Reasons for moving funds out of an account. #[derive(Encode, Decode)]