Newer
Older
value: Self::Balance
) -> (Self::NegativeImbalance, 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);
let remaining_slash = value - free_slash;
// NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn
// from in extreme circumstances. `can_slash()` should be used prior to `slash()` to avoid having
// to draw from reserved funds, however we err on the side of punishment if things are inconsistent
// or `can_slash` wasn't used appropriately.
if !remaining_slash.is_zero() {
let reserved_balance = Self::reserved_balance(who);
let reserved_slash = cmp::min(reserved_balance, remaining_slash);
Self::set_reserved_balance(who, reserved_balance - reserved_slash);
(NegativeImbalance::new(free_slash + reserved_slash), remaining_slash - reserved_slash)
(NegativeImbalance::new(value), Zero::zero())
fn deposit_into_existing(
who: &T::AccountId,
value: Self::Balance
) -> result::Result<Self::PositiveImbalance, &'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);
Ok(PositiveImbalance::new(value))
fn deposit_creating(
who: &T::AccountId,
value: Self::Balance,
) -> Self::PositiveImbalance {
let (imbalance, _) = Self::make_free_balance_be(who, Self::free_balance(who) + value);
if let SignedImbalance::Positive(p) = imbalance {
p
} else {
// Impossible, but be defensive.
Self::PositiveImbalance::zero()
}
}
fn make_free_balance_be(who: &T::AccountId, balance: Self::Balance) -> (
SignedImbalance<Self::Balance, Self::PositiveImbalance>,
UpdateBalanceOutcome
) {
let original = Self::free_balance(who);
if balance < T::ExistentialDeposit::get() && original.is_zero() {
// If we're attempting to set an existing account to less than ED, then
// bypass the entire operation. It's a no-op if you follow it through, but
// since this is an instance where we might account for a negative imbalance
// (in the dust cleaner of set_free_balance) before we account for its actual
// equal and opposite cause (returned as an Imbalance), then in the
// instance that there's no other accounts on the system at all, we might
// underflow the issuance and our arithmetic will be off.
return (
SignedImbalance::Positive(Self::PositiveImbalance::zero()),
UpdateBalanceOutcome::AccountKilled,
)
}
let imbalance = if original <= balance {
SignedImbalance::Positive(PositiveImbalance::new(balance - original))
SignedImbalance::Negative(NegativeImbalance::new(original - balance))
};
// If the balance is too low, then the account is reaped.
// NOTE: There are two balances for every account: `reserved_balance` and
// `free_balance`. This contract subsystem only cares about the latter: whenever
// the term "balance" is used *here* it should be assumed to mean "free balance"
// in the rest of the module.
// Free balance can never be less than ED. If that happens, it gets reduced to zero
// and the account information relevant to this subsystem is deleted (i.e. the
// account is reaped).
let outcome = if balance < T::ExistentialDeposit::get() {
Self::set_free_balance(who, balance);
UpdateBalanceOutcome::AccountKilled
} else {
if !<FreeBalance<T, I>>::exists(who) {
Self::new_account(&who, balance);
}
Self::set_free_balance(who, balance);
UpdateBalanceOutcome::Updated
};
(imbalance, outcome)
}
impl<T: Trait<I>, I: Instance> ReservableCurrency<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDeserialize + Debug
{
fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool {
Self::free_balance(who)
.checked_sub(&value)
.map_or(false, |new_balance|
Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance).is_ok()
)
}
fn reserved_balance(who: &T::AccountId) -> Self::Balance {
<ReservedBalance<T, I>>::get(who)
}
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")
}
let new_balance = b - value;
Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance)?;
Self::set_reserved_balance(who, Self::reserved_balance(who) + value);
Self::set_free_balance(who, new_balance);
fn unreserve(who: &T::AccountId, value: Self::Balance) -> 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);
fn slash_reserved(
who: &T::AccountId,
value: Self::Balance
) -> (Self::NegativeImbalance, Self::Balance) {
let b = Self::reserved_balance(who);
let slash = cmp::min(b, value);
// underflow should never happen, but it if does, there's nothing to be done here.
Self::set_reserved_balance(who, b - slash);
(NegativeImbalance::new(slash), value - slash)
}
fn repatriate_reserved(
slashed: &T::AccountId,
beneficiary: &T::AccountId,
value: Self::Balance,
) -> result::Result<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);
impl<T: Trait<I>, I: Instance> LockableCurrency<T::AccountId> for Module<T, I>
T::Balance: MaybeSerializeDeserialize + Debug
{
type Moment = T::BlockNumber;
fn set_lock(
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
let now = <frame_system::Module<T>>::block_number();
let mut new_lock = Some(BalanceLock { id, amount, until, reasons });
let mut locks = Self::locks(who).into_iter().filter_map(|l|
if l.id == id {
new_lock.take()
} else if l.until > now {
Some(l)
} else {
None
}).collect::<Vec<_>>();
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T, I>>::insert(who, locks);
}
fn extend_lock(
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
let now = <frame_system::Module<T>>::block_number();
let mut new_lock = Some(BalanceLock { id, amount, until, reasons });
let mut locks = Self::locks(who).into_iter().filter_map(|l|
if l.id == id {
new_lock.take().map(|nl| {
BalanceLock {
id: l.id,
amount: l.amount.max(nl.amount),
until: l.until.max(nl.until),
reasons: l.reasons | nl.reasons,
}
})
} else if l.until > now {
Some(l)
} else {
None
}).collect::<Vec<_>>();
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T, I>>::insert(who, locks);
}
fn remove_lock(
id: LockIdentifier,
who: &T::AccountId,
) {
let now = <frame_system::Module<T>>::block_number();
let locks = Self::locks(who).into_iter().filter_map(|l|
if l.until > now && l.id != id {
Some(l)
} else {
None
}).collect::<Vec<_>>();
<Locks<T, I>>::insert(who, locks);
}
}
impl<T: Trait<I>, I: Instance> VestingCurrency<T::AccountId> for Module<T, I>
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(<frame_system::Module<T>>::block_number()))
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
} 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 <Vesting<T, I>>::exists(who) {
return Err("A vesting schedule already exists for this account.");
}
let vesting_schedule = VestingSchedule {
locked,
per_block,
starting_block
};
<Vesting<T, I>>::insert(who, vesting_schedule);
Ok(())
}
/// Remove a vesting schedule for a given account.
fn remove_vesting_schedule(who: &T::AccountId) {
<Vesting<T, I>>::remove(who);
}
}
impl<T: Trait<I>, I: Instance> IsDeadAccount<T::AccountId> for Module<T, I>
T::Balance: MaybeSerializeDeserialize + Debug