Fungibles and Non-Fungibles Create and Destroy Traits + Assets and Uniques Implementation (#9844)

* refactor `do_destroy`

* destroy trait

* refactor do_force_create

* impl create trait

* do not bleed weight into api

* Do the same for uniques

* add docs
This commit is contained in:
Shawn Tabrizi
2021-09-26 18:05:01 -04:00
committed by GitHub
parent 0daa2b66ec
commit f8a228859e
8 changed files with 243 additions and 88 deletions
+84
View File
@@ -478,4 +478,88 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), credit));
Ok(credit)
}
/// Create a new asset without taking a deposit.
///
/// * `id`: The `AssetId` you want the new asset to have. Must not already be in use.
/// * `owner`: The owner, issuer, admin, and freezer of this asset upon creation.
/// * `is_sufficient`: Whether this asset needs users to have an existential deposit to hold
/// this asset.
/// * `min_balance`: The minimum balance a user is allowed to have of this asset before they are
/// considered dust and cleaned up.
pub(super) fn do_force_create(
id: T::AssetId,
owner: T::AccountId,
is_sufficient: bool,
min_balance: T::Balance,
) -> DispatchResult {
ensure!(!Asset::<T, I>::contains_key(id), Error::<T, I>::InUse);
ensure!(!min_balance.is_zero(), Error::<T, I>::MinBalanceZero);
Asset::<T, I>::insert(
id,
AssetDetails {
owner: owner.clone(),
issuer: owner.clone(),
admin: owner.clone(),
freezer: owner.clone(),
supply: Zero::zero(),
deposit: Zero::zero(),
min_balance,
is_sufficient,
accounts: 0,
sufficients: 0,
approvals: 0,
is_frozen: false,
},
);
Self::deposit_event(Event::ForceCreated(id, owner));
Ok(())
}
/// Destroy an existing asset.
///
/// * `id`: The asset you want to destroy.
/// * `witness`: Witness data needed about the current state of the asset, used to confirm
/// complexity of the operation.
/// * `maybe_check_owner`: An optional check before destroying the asset, if the provided
/// account is the owner of that asset. Can be used for authorization checks.
pub(super) fn do_destroy(
id: T::AssetId,
witness: DestroyWitness,
maybe_check_owner: Option<T::AccountId>,
) -> Result<DestroyWitness, DispatchError> {
Asset::<T, I>::try_mutate_exists(id, |maybe_details| {
let mut details = maybe_details.take().ok_or(Error::<T, I>::Unknown)?;
if let Some(check_owner) = maybe_check_owner {
ensure!(details.owner == check_owner, Error::<T, I>::NoPermission);
}
ensure!(details.accounts <= witness.accounts, Error::<T, I>::BadWitness);
ensure!(details.sufficients <= witness.sufficients, Error::<T, I>::BadWitness);
ensure!(details.approvals <= witness.approvals, Error::<T, I>::BadWitness);
for (who, v) in Account::<T, I>::drain_prefix(id) {
Self::dead_account(id, &who, &mut details, v.sufficient);
}
debug_assert_eq!(details.accounts, 0);
debug_assert_eq!(details.sufficients, 0);
let metadata = Metadata::<T, I>::take(&id);
T::Currency::unreserve(
&details.owner,
details.deposit.saturating_add(metadata.deposit),
);
for ((owner, _), approval) in Approvals::<T, I>::drain_prefix((&id,)) {
T::Currency::unreserve(&owner, approval.deposit);
}
Self::deposit_event(Event::Destroyed(id));
Ok(DestroyWitness {
accounts: details.accounts,
sufficients: details.sufficients,
approvals: details.approvals,
})
})
}
}