Newer
Older
after_frozen = b.frozen;
Gavin Wood
committed
});
debug_assert!(res.is_ok());
if let Ok((_, maybe_dust)) = res {
debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed");
}
Gavin Wood
committed
let existed = Locks::<T, I>::contains_key(who);
if locks.is_empty() {
Locks::<T, I>::remove(who);
if existed {
// TODO: use Locks::<T, I>::hashed_key
// https://github.com/paritytech/substrate/issues/4969
system::Pallet::<T>::dec_consumers(who);
Gavin Wood
committed
Locks::<T, I>::insert(who, bounded_locks);
if !existed && system::Pallet::<T>::inc_consumers_without_limit(who).is_err() {
// No providers for the locks. This is impossible under normal circumstances
// since the funds that are under the lock will themselves be stored in the
// account and therefore will need a reference.
log::warn!(
target: LOG_TARGET,
"Warning: Attempt to introduce lock consumer reference, yet no providers. \
This is unexpected but should be safe."
);
}
if prev_frozen > after_frozen {
let amount = prev_frozen.saturating_sub(after_frozen);
Self::deposit_event(Event::Unlocked { who: who.clone(), amount });
} else if after_frozen > prev_frozen {
let amount = after_frozen.saturating_sub(prev_frozen);
Self::deposit_event(Event::Locked { who: who.clone(), amount });
}
Gavin Wood
committed
/// Update the account entry for `who`, given the locks.
pub(crate) fn update_freezes(
who: &T::AccountId,
freezes: BoundedSlice<IdAmount<T::FreezeIdentifier, T::Balance>, T::MaxFreezes>,
) -> DispatchResult {
let mut prev_frozen = Zero::zero();
let mut after_frozen = Zero::zero();
Gavin Wood
committed
let (_, maybe_dust) = Self::mutate_account(who, |b| {
Gavin Wood
committed
b.frozen = Zero::zero();
for l in Locks::<T, I>::get(who).iter() {
b.frozen = b.frozen.max(l.amount);
}
for l in freezes.iter() {
b.frozen = b.frozen.max(l.amount);
}
Gavin Wood
committed
})?;
debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed");
if freezes.is_empty() {
Freezes::<T, I>::remove(who);
} else {
Freezes::<T, I>::insert(who, freezes);
if prev_frozen > after_frozen {
let amount = prev_frozen.saturating_sub(after_frozen);
Self::deposit_event(Event::Thawed { who: who.clone(), amount });
} else if after_frozen > prev_frozen {
let amount = after_frozen.saturating_sub(prev_frozen);
Self::deposit_event(Event::Frozen { who: who.clone(), amount });
}
Gavin Wood
committed
Ok(())
Gavin Wood
committed
/// Move the reserved balance of one account into the balance of another, according to
/// `status`. This will respect freezes/locks only if `fortitude` is `Polite`.
Gavin Wood
committed
///
/// Is a no-op if the value to be moved is zero.
Gavin Wood
committed
///
/// NOTE: returns actual amount of transferred value in `Ok` case.
pub(crate) fn do_transfer_reserved(
slashed: &T::AccountId,
beneficiary: &T::AccountId,
value: T::Balance,
precision: Precision,
fortitude: Fortitude,
Gavin Wood
committed
status: Status,
) -> Result<T::Balance, DispatchError> {
if value.is_zero() {
return Ok(Zero::zero())
let max = <Self as fungible::InspectHold<_>>::reducible_total_balance_on_hold(
slashed, fortitude,
);
let actual = match precision {
Precision::BestEffort => value.min(max),
Precision::Exact => value,
};
ensure!(actual <= max, TokenError::FundsUnavailable);
Gavin Wood
committed
if slashed == beneficiary {
return match status {
Status::Free => Ok(actual.saturating_sub(Self::unreserve(slashed, actual))),
Status::Reserved => Ok(actual),
Gavin Wood
committed
}
}
let ((_, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account(
Gavin Wood
committed
beneficiary,
|to_account, is_new| -> Result<((), Option<T::Balance>), DispatchError> {
Gavin Wood
committed
ensure!(!is_new, Error::<T, I>::DeadAccount);
Self::try_mutate_account(slashed, |from_account, _| -> DispatchResult {
match status {
Status::Free =>
to_account.free = to_account
.free
.checked_add(&actual)
.ok_or(ArithmeticError::Overflow)?,
Status::Reserved =>
to_account.reserved = to_account
.reserved
.checked_add(&actual)
.ok_or(ArithmeticError::Overflow)?,
}
from_account.reserved.saturating_reduce(actual);
Ok(())
})
Gavin Wood
committed
)?;
Gavin Wood
committed
if let Some(dust) = maybe_dust_1 {
<Self as fungible::Unbalanced<_>>::handle_raw_dust(dust);
}
if let Some(dust) = maybe_dust_2 {
<Self as fungible::Unbalanced<_>>::handle_raw_dust(dust);
}
Gavin Wood
committed
Self::deposit_event(Event::ReserveRepatriated {
from: slashed.clone(),
to: beneficiary.clone(),
amount: actual,
destination_status: status,
});
Ok(actual)