mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
decouple balances from some modules (#1641)
* decouple balances from some module by creating a new traits in support/traits * improve decl_event
This commit is contained in:
+121
-187
@@ -31,65 +31,15 @@ use rstd::prelude::*;
|
||||
use rstd::{cmp, result};
|
||||
use parity_codec::Codec;
|
||||
use runtime_support::{StorageValue, StorageMap, Parameter};
|
||||
use runtime_support::traits::{UpdateBalanceOutcome, Currency, EnsureAccountLiquid, OnFreeBalanceZero};
|
||||
use runtime_support::dispatch::Result;
|
||||
use primitives::traits::{Zero, SimpleArithmetic, MakePayment,
|
||||
As, StaticLookup, Member, CheckedAdd, CheckedSub};
|
||||
As, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug};
|
||||
use system::{IsDeadAccount, OnNewAccount, ensure_signed};
|
||||
|
||||
mod mock;
|
||||
mod tests;
|
||||
|
||||
/// The account with the given id was killed.
|
||||
pub trait OnFreeBalanceZero<AccountId> {
|
||||
/// The account was the given id was killed.
|
||||
fn on_free_balance_zero(who: &AccountId);
|
||||
}
|
||||
|
||||
impl<AccountId> OnFreeBalanceZero<AccountId> for () {
|
||||
fn on_free_balance_zero(_who: &AccountId) {}
|
||||
}
|
||||
impl<
|
||||
AccountId,
|
||||
X: OnFreeBalanceZero<AccountId>,
|
||||
Y: OnFreeBalanceZero<AccountId>,
|
||||
> OnFreeBalanceZero<AccountId> for (X, Y) {
|
||||
fn on_free_balance_zero(who: &AccountId) {
|
||||
X::on_free_balance_zero(who);
|
||||
Y::on_free_balance_zero(who);
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for a hook to get called when some balance has been minted, causing dilution.
|
||||
pub trait OnDilution<Balance> {
|
||||
/// Some `portion` of the total balance just "grew" by `minted`. `portion` is the pre-growth
|
||||
/// amount (it doesn't take account of the recent growth).
|
||||
fn on_dilution(minted: Balance, portion: Balance);
|
||||
}
|
||||
|
||||
impl<Balance> OnDilution<Balance> for () {
|
||||
fn on_dilution(_minted: Balance, _portion: Balance) {}
|
||||
}
|
||||
|
||||
/// Determinator for whether a given account is able to transfer balance.
|
||||
pub trait EnsureAccountLiquid<AccountId> {
|
||||
/// Returns `Ok` iff the account is able to transfer funds normally. `Err(...)`
|
||||
/// with the reason why not otherwise.
|
||||
fn ensure_account_liquid(who: &AccountId) -> Result;
|
||||
}
|
||||
impl<
|
||||
AccountId,
|
||||
X: EnsureAccountLiquid<AccountId>,
|
||||
Y: EnsureAccountLiquid<AccountId>,
|
||||
> EnsureAccountLiquid<AccountId> for (X, Y) {
|
||||
fn ensure_account_liquid(who: &AccountId) -> Result {
|
||||
X::ensure_account_liquid(who)?;
|
||||
Y::ensure_account_liquid(who)
|
||||
}
|
||||
}
|
||||
impl<AccountId> EnsureAccountLiquid<AccountId> for () {
|
||||
fn ensure_account_liquid(_who: &AccountId) -> Result { Ok(()) }
|
||||
}
|
||||
|
||||
pub trait Trait: system::Trait {
|
||||
/// The balance of an account.
|
||||
type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As<usize> + As<u64>;
|
||||
@@ -205,40 +155,8 @@ decl_storage! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Outcome of a balance update.
|
||||
pub enum UpdateBalanceOutcome {
|
||||
/// Account balance was simply updated.
|
||||
Updated,
|
||||
/// The update has led to killing of the account.
|
||||
AccountKilled,
|
||||
}
|
||||
|
||||
// For funding methods, see Currency trait
|
||||
impl<T: Trait> Module<T> {
|
||||
// PUBLIC IMMUTABLES
|
||||
|
||||
/// The combined balance of `who`.
|
||||
pub fn total_balance(who: &T::AccountId) -> T::Balance {
|
||||
Self::free_balance(who) + Self::reserved_balance(who)
|
||||
}
|
||||
|
||||
/// Some result as `slash(who, value)` (but without the side-effects) assuming there are no
|
||||
/// balance changes in the meantime and only the reserved balance is not taken into account.
|
||||
pub fn can_slash(who: &T::AccountId, value: T::Balance) -> bool {
|
||||
Self::free_balance(who) >= value
|
||||
}
|
||||
|
||||
/// Same result as `reserve(who, value)` (but without the side-effects) assuming there
|
||||
/// are no balance changes in the meantime.
|
||||
pub fn can_reserve(who: &T::AccountId, value: T::Balance) -> bool {
|
||||
if T::EnsureAccountLiquid::ensure_account_liquid(who).is_ok() {
|
||||
Self::free_balance(who) >= value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
//PUBLIC MUTABLES (DANGEROUS)
|
||||
|
||||
/// Set the free balance of an account to some new value.
|
||||
///
|
||||
/// Will enforce ExistentialDeposit law, anulling the account as needed.
|
||||
@@ -334,67 +252,6 @@ impl<T: Trait> Module<T> {
|
||||
Ok(Self::set_free_balance(who, b - value))
|
||||
}
|
||||
|
||||
/// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the
|
||||
/// free balance. This function cannot fail.
|
||||
///
|
||||
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
|
||||
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
|
||||
pub fn slash(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
|
||||
let free_balance = Self::free_balance(who);
|
||||
let free_slash = cmp::min(free_balance, value);
|
||||
Self::set_free_balance(who, free_balance - free_slash);
|
||||
Self::decrease_total_stake_by(free_slash);
|
||||
if free_slash < value {
|
||||
Self::slash_reserved(who, value - free_slash)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds up to `value` to the free balance of `who`.
|
||||
///
|
||||
/// If `who` doesn't exist, nothing is done and an Err returned.
|
||||
pub fn reward(who: &T::AccountId, value: T::Balance) -> Result {
|
||||
if Self::total_balance(who).is_zero() {
|
||||
return Err("beneficiary account must pre-exist");
|
||||
}
|
||||
Self::set_free_balance(who, Self::free_balance(who) + value);
|
||||
Self::increase_total_stake_by(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Moves `value` from balance to reserved balance.
|
||||
///
|
||||
/// If the free balance is lower than `value`, then no funds will be moved and an `Err` will
|
||||
/// be returned to notify of this. This is different behaviour to `unreserve`.
|
||||
pub fn reserve(who: &T::AccountId, value: T::Balance) -> Result {
|
||||
let b = Self::free_balance(who);
|
||||
if b < value {
|
||||
return Err("not enough free funds")
|
||||
}
|
||||
T::EnsureAccountLiquid::ensure_account_liquid(who)?;
|
||||
Self::set_reserved_balance(who, Self::reserved_balance(who) + value);
|
||||
Self::set_free_balance(who, b - value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Moves up to `value` from reserved balance to balance. This function cannot fail.
|
||||
///
|
||||
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
|
||||
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
|
||||
/// NOTE: This is different to `reserve`.
|
||||
pub fn unreserve(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
|
||||
let b = Self::reserved_balance(who);
|
||||
let actual = cmp::min(b, value);
|
||||
Self::set_free_balance(who, Self::free_balance(who) + actual);
|
||||
Self::set_reserved_balance(who, b - actual);
|
||||
if actual == value {
|
||||
None
|
||||
} else {
|
||||
Some(value - actual)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transfer some liquid free balance to another staker.
|
||||
pub fn make_transfer(transactor: &T::AccountId, dest: &T::AccountId, value: T::Balance) -> Result {
|
||||
let from_balance = Self::free_balance(transactor);
|
||||
@@ -432,46 +289,6 @@ impl<T: Trait> Module<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deducts up to `value` from reserved balance of `who`. This function cannot fail.
|
||||
///
|
||||
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
|
||||
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
|
||||
pub fn slash_reserved(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
|
||||
let b = Self::reserved_balance(who);
|
||||
let slash = cmp::min(b, value);
|
||||
Self::set_reserved_balance(who, b - slash);
|
||||
Self::decrease_total_stake_by(slash);
|
||||
if value == slash {
|
||||
None
|
||||
} else {
|
||||
Some(value - slash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves up to `value` from reserved balance of account `slashed` to free balance of account
|
||||
/// `beneficiary`. `beneficiary` must exist for this to succeed. If it does not, `Err` will be
|
||||
/// returned.
|
||||
///
|
||||
/// As much funds up to `value` will be moved as possible. If this is less than `value`, then
|
||||
/// `Ok(Some(remaining))` will be returned. Full completion is given by `Ok(None)`.
|
||||
pub fn repatriate_reserved(
|
||||
slashed: &T::AccountId,
|
||||
beneficiary: &T::AccountId,
|
||||
value: T::Balance
|
||||
) -> result::Result<Option<T::Balance>, &'static str> {
|
||||
if Self::total_balance(beneficiary).is_zero() {
|
||||
return Err("beneficiary account must pre-exist");
|
||||
}
|
||||
let b = Self::reserved_balance(slashed);
|
||||
let slash = cmp::min(b, value);
|
||||
Self::set_free_balance(beneficiary, Self::free_balance(beneficiary) + slash);
|
||||
Self::set_reserved_balance(slashed, b - slash);
|
||||
if value == slash {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(value - slash))
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a new account (with existential balance).
|
||||
fn new_account(who: &T::AccountId, balance: T::Balance) {
|
||||
@@ -520,6 +337,120 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Currency<T::AccountId> for Module<T>
|
||||
where
|
||||
T::Balance: MaybeSerializeDebug
|
||||
{
|
||||
type Balance = T::Balance;
|
||||
|
||||
fn total_balance(who: &T::AccountId) -> Self::Balance {
|
||||
Self::free_balance(who) + Self::reserved_balance(who)
|
||||
}
|
||||
|
||||
fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool {
|
||||
Self::free_balance(who) >= value
|
||||
}
|
||||
|
||||
fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool {
|
||||
if T::EnsureAccountLiquid::ensure_account_liquid(who).is_ok() {
|
||||
Self::free_balance(who) >= value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn total_issuance() -> Self:: Balance {
|
||||
Self::total_issuance()
|
||||
}
|
||||
|
||||
fn free_balance(who: &T::AccountId) -> Self::Balance {
|
||||
Self::free_balance(who)
|
||||
}
|
||||
|
||||
fn reserved_balance(who: &T::AccountId) -> Self::Balance {
|
||||
Self::reserved_balance(who)
|
||||
}
|
||||
|
||||
fn slash(who: &T::AccountId, value: Self::Balance) -> Option<Self::Balance> {
|
||||
let free_balance = Self::free_balance(who);
|
||||
let free_slash = cmp::min(free_balance, value);
|
||||
Self::set_free_balance(who, free_balance - free_slash);
|
||||
Self::decrease_total_stake_by(free_slash);
|
||||
if free_slash < value {
|
||||
Self::slash_reserved(who, value - free_slash)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn reward(who: &T::AccountId, value: Self::Balance) -> result::Result<(), &'static str> {
|
||||
if Self::total_balance(who).is_zero() {
|
||||
return Err("beneficiary account must pre-exist");
|
||||
}
|
||||
Self::set_free_balance(who, Self::free_balance(who) + value);
|
||||
Self::increase_total_stake_by(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn increase_free_balance_creating(who: &T::AccountId, value: Self::Balance) -> UpdateBalanceOutcome {
|
||||
Self::set_free_balance_creating(who, Self::free_balance(who) + value)
|
||||
}
|
||||
|
||||
fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), &'static str> {
|
||||
let b = Self::free_balance(who);
|
||||
if b < value {
|
||||
return Err("not enough free funds")
|
||||
}
|
||||
T::EnsureAccountLiquid::ensure_account_liquid(who)?;
|
||||
Self::set_reserved_balance(who, Self::reserved_balance(who) + value);
|
||||
Self::set_free_balance(who, b - value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unreserve(who: &T::AccountId, value: Self::Balance) -> Option<Self::Balance> {
|
||||
let b = Self::reserved_balance(who);
|
||||
let actual = cmp::min(b, value);
|
||||
Self::set_free_balance(who, Self::free_balance(who) + actual);
|
||||
Self::set_reserved_balance(who, b - actual);
|
||||
if actual == value {
|
||||
None
|
||||
} else {
|
||||
Some(value - actual)
|
||||
}
|
||||
}
|
||||
|
||||
fn slash_reserved(who: &T::AccountId, value: Self::Balance) -> Option<Self::Balance> {
|
||||
let b = Self::reserved_balance(who);
|
||||
let slash = cmp::min(b, value);
|
||||
Self::set_reserved_balance(who, b - slash);
|
||||
Self::decrease_total_stake_by(slash);
|
||||
if value == slash {
|
||||
None
|
||||
} else {
|
||||
Some(value - slash)
|
||||
}
|
||||
}
|
||||
|
||||
fn repatriate_reserved(
|
||||
slashed: &T::AccountId,
|
||||
beneficiary: &T::AccountId,
|
||||
value: Self::Balance
|
||||
) -> result::Result<Option<Self::Balance>, &'static str> {
|
||||
if Self::total_balance(beneficiary).is_zero() {
|
||||
return Err("beneficiary account must pre-exist");
|
||||
}
|
||||
let b = Self::reserved_balance(slashed);
|
||||
let slash = cmp::min(b, value);
|
||||
Self::set_free_balance(beneficiary, Self::free_balance(beneficiary) + slash);
|
||||
Self::set_reserved_balance(slashed, b - slash);
|
||||
if value == slash {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(value - slash))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> MakePayment<T::AccountId> for Module<T> {
|
||||
fn make_payment(transactor: &T::AccountId, encoded_len: usize) -> Result {
|
||||
let b = Self::free_balance(transactor);
|
||||
@@ -533,7 +464,10 @@ impl<T: Trait> MakePayment<T::AccountId> for Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> IsDeadAccount<T::AccountId> for Module<T> {
|
||||
impl<T: Trait> IsDeadAccount<T::AccountId> for Module<T>
|
||||
where
|
||||
T::Balance: MaybeSerializeDebug
|
||||
{
|
||||
fn is_dead_account(who: &T::AccountId) -> bool {
|
||||
Self::total_balance(who).is_zero()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user