Newer
Older
Gavin Wood
committed
})
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
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
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);
// 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| {
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);
}
});
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."
);
}
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
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
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)