Newer
Older
Gavin Wood
committed
if let Some(amount) = maybe_dust {
Pallet::<T, I>::deposit_event(Event::DustLost { account: who.clone(), amount });
}
(result, maybe_dust)
})
Gavin Wood
committed
/// Update the account entry for `who`, given the locks.
pub(crate) fn update_locks(who: &T::AccountId, locks: &[BalanceLock<T::Balance>]) {
let bounded_locks = WeakBoundedVec::<_, T::MaxLocks>::force_from(
locks.to_vec(),
Some("Balances Update Locks"),
);
Gavin Wood
committed
if locks.len() as u32 > T::MaxLocks::get() {
log::warn!(
target: LOG_TARGET,
"Warning: A user has more currency locks than expected. \
A runtime configuration adjustment may be needed."
);
}
let freezes = Freezes::<T, I>::get(who);
let mut prev_frozen = Zero::zero();
let mut after_frozen = Zero::zero();
Gavin Wood
committed
// TODO: Revisit this assumption. We no manipulate consumer/provider refs.
// No way this can fail since we do not alter the existential balances.
let res = Self::mutate_account(who, |b| {
prev_frozen = b.frozen;
Gavin Wood
committed
b.frozen = Zero::zero();
for l in locks.iter() {
b.frozen = b.frozen.max(l.amount);
}
for l in freezes.iter() {
b.frozen = b.frozen.max(l.amount);
}
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 (_, maybe_dust) = Self::mutate_account(who, |b| {
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);
}
})?;
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);
Gavin Wood
committed
Ok(())
Gavin Wood
committed
/// Move the reserved balance of one account into the balance of another, according to
/// `status`.
///
/// Is a no-op if:
/// - the value to be moved is zero; or
/// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`.
///
/// 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,
best_effort: bool,
status: Status,
) -> Result<T::Balance, DispatchError> {
if value.is_zero() {
return Ok(Zero::zero())
Gavin Wood
committed
if slashed == beneficiary {
return match status {
Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))),
Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))),
}
}
Gavin Wood
committed
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
let ((actual, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account(
beneficiary,
|to_account, is_new| -> Result<(T::Balance, Option<T::Balance>), DispatchError> {
ensure!(!is_new, Error::<T, I>::DeadAccount);
Self::try_mutate_account(
slashed,
|from_account, _| -> Result<T::Balance, DispatchError> {
let actual = cmp::min(from_account.reserved, value);
ensure!(
best_effort || actual == value,
Error::<T, I>::InsufficientBalance
);
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 -= actual;
Ok(actual)
},
)
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)