I know the concept of existential deposit (ED) means that if the account balance is below this value, it will be wiped out. I tried to figure out how it works. The AccountData
is defined in the runtime while stored in the frame-system
pallet. try_mutate_exists
in the frame_system
pallet used to mutate AccountData
storage, but how and where does the substrate system wipe the account whose balance below ED? I find OnKilledAccount
type in the frame_system::Config
, but it's more like a callback after the account has been killed.
impl<T: Config> StoredMap<T::AccountId, T::AccountData> for Pallet<T> {
fn get(k: &T::AccountId) -> T::AccountData {
Account::<T>::get(k).data
}
fn try_mutate_exists<R, E: From<DispatchError>>(
k: &T::AccountId,
f: impl FnOnce(&mut Option<T::AccountData>) -> Result<R, E>,
) -> Result<R, E> {
let account = Account::<T>::get(k);
let was_providing = is_providing(&account.data);
let mut some_data = if was_providing {
Some(account.data)
} else {
None
};
let result = f(&mut some_data)?;
let is_providing = some_data.is_some();
if !was_providing && is_providing {
Self::inc_providers(k);
} else if was_providing && !is_providing {
match Self::dec_providers(k)? { // This may trigger account wipe
DecRefStatus::Reaped => return Ok(result),
DecRefStatus::Exists => {
// Update value as normal...
}
}
} else if !was_providing && !is_providing {
return Ok(result);
}
Account::<T>::mutate(k, |a| a.data = some_data.unwrap_or_default());
Ok(result)
}
}