mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 12:51:02 +00:00
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:
@@ -478,4 +478,88 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
|||||||
Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), credit));
|
Self::deposit_event(Event::Transferred(id, source.clone(), dest.clone(), credit));
|
||||||
Ok(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,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,3 +147,30 @@ impl<T: Config<I>, I: 'static> fungibles::Unbalanced<T::AccountId> for Pallet<T,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> fungibles::Create<T::AccountId> for Pallet<T, I> {
|
||||||
|
fn create(
|
||||||
|
id: T::AssetId,
|
||||||
|
admin: T::AccountId,
|
||||||
|
is_sufficient: bool,
|
||||||
|
min_balance: Self::Balance,
|
||||||
|
) -> DispatchResult {
|
||||||
|
Self::do_force_create(id, admin, is_sufficient, min_balance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> fungibles::Destroy<T::AccountId> for Pallet<T, I> {
|
||||||
|
type DestroyWitness = DestroyWitness;
|
||||||
|
|
||||||
|
fn get_destroy_witness(asset: &T::AssetId) -> Option<Self::DestroyWitness> {
|
||||||
|
Asset::<T, I>::get(asset).map(|asset_details| asset_details.destroy_witness())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(
|
||||||
|
id: T::AssetId,
|
||||||
|
witness: Self::DestroyWitness,
|
||||||
|
maybe_check_owner: Option<T::AccountId>,
|
||||||
|
) -> Result<Self::DestroyWitness, DispatchError> {
|
||||||
|
Self::do_destroy(id, witness, maybe_check_owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ use codec::HasCompact;
|
|||||||
use frame_support::{
|
use frame_support::{
|
||||||
dispatch::{DispatchError, DispatchResult},
|
dispatch::{DispatchError, DispatchResult},
|
||||||
ensure,
|
ensure,
|
||||||
|
pallet_prelude::DispatchResultWithPostInfo,
|
||||||
traits::{
|
traits::{
|
||||||
tokens::{fungibles, DepositConsequence, WithdrawConsequence},
|
tokens::{fungibles, DepositConsequence, WithdrawConsequence},
|
||||||
BalanceStatus::Reserved,
|
BalanceStatus::Reserved,
|
||||||
@@ -437,29 +438,7 @@ pub mod pallet {
|
|||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
T::ForceOrigin::ensure_origin(origin)?;
|
T::ForceOrigin::ensure_origin(origin)?;
|
||||||
let owner = T::Lookup::lookup(owner)?;
|
let owner = T::Lookup::lookup(owner)?;
|
||||||
|
Self::do_force_create(id, owner, is_sufficient, min_balance)
|
||||||
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 a class of fungible assets.
|
/// Destroy a class of fungible assets.
|
||||||
@@ -494,39 +473,13 @@ pub mod pallet {
|
|||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(origin) => Some(ensure_signed(origin)?),
|
Err(origin) => Some(ensure_signed(origin)?),
|
||||||
};
|
};
|
||||||
Asset::<T, I>::try_mutate_exists(id, |maybe_details| {
|
let details = Self::do_destroy(id, witness, maybe_check_owner)?;
|
||||||
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(Some(T::WeightInfo::destroy(
|
Ok(Some(T::WeightInfo::destroy(
|
||||||
details.accounts.saturating_sub(details.sufficients),
|
details.accounts.saturating_sub(details.sufficients),
|
||||||
details.sufficients,
|
details.sufficients,
|
||||||
details.approvals,
|
details.approvals,
|
||||||
))
|
))
|
||||||
.into())
|
.into())
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mint assets of a particular class.
|
/// Mint assets of a particular class.
|
||||||
|
|||||||
@@ -227,3 +227,39 @@ impl<AccountId, T: Balanced<AccountId> + MutateHold<AccountId>> BalancedHold<Acc
|
|||||||
<Self as fungibles::Balanced<AccountId>>::slash(asset, who, actual)
|
<Self as fungibles::Balanced<AccountId>>::slash(asset, who, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for providing the ability to create new fungible assets.
|
||||||
|
pub trait Create<AccountId>: Inspect<AccountId> {
|
||||||
|
/// Create a new fungible asset.
|
||||||
|
fn create(
|
||||||
|
id: Self::AssetId,
|
||||||
|
admin: AccountId,
|
||||||
|
is_sufficient: bool,
|
||||||
|
min_balance: Self::Balance,
|
||||||
|
) -> DispatchResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for providing the ability to destroy existing fungible assets.
|
||||||
|
pub trait Destroy<AccountId>: Inspect<AccountId> {
|
||||||
|
/// The witness data needed to destroy an asset.
|
||||||
|
type DestroyWitness;
|
||||||
|
|
||||||
|
/// Provide the appropriate witness data needed to destroy an asset.
|
||||||
|
fn get_destroy_witness(id: &Self::AssetId) -> Option<Self::DestroyWitness>;
|
||||||
|
|
||||||
|
/// Destroy an existing fungible asset.
|
||||||
|
/// * `id`: The `AssetId` to be destroyed.
|
||||||
|
/// * `witness`: Any witness data that needs to be provided to complete the operation
|
||||||
|
/// successfully.
|
||||||
|
/// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy
|
||||||
|
/// command. If not provided, we will not do any authorization checks before destroying the
|
||||||
|
/// asset.
|
||||||
|
///
|
||||||
|
/// If successful, this function will return the actual witness data from the destroyed asset.
|
||||||
|
/// This may be different than the witness data provided, and can be used to refund weight.
|
||||||
|
fn destroy(
|
||||||
|
id: Self::AssetId,
|
||||||
|
witness: Self::DestroyWitness,
|
||||||
|
maybe_check_owner: Option<AccountId>,
|
||||||
|
) -> Result<Self::DestroyWitness, DispatchError>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
//! Implementations of these traits may be converted to implementations of corresponding
|
//! Implementations of these traits may be converted to implementations of corresponding
|
||||||
//! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter.
|
//! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter.
|
||||||
|
|
||||||
use crate::dispatch::DispatchResult;
|
use crate::dispatch::{DispatchError, DispatchResult};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use sp_runtime::TokenError;
|
use sp_runtime::TokenError;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
@@ -123,6 +123,31 @@ pub trait Create<AccountId>: Inspect<AccountId> {
|
|||||||
fn create_class(class: &Self::ClassId, who: &AccountId, admin: &AccountId) -> DispatchResult;
|
fn create_class(class: &Self::ClassId, who: &AccountId, admin: &AccountId) -> DispatchResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for providing the ability to destroy classes of nonfungible assets.
|
||||||
|
pub trait Destroy<AccountId>: Inspect<AccountId> {
|
||||||
|
/// The witness data needed to destroy an asset.
|
||||||
|
type DestroyWitness;
|
||||||
|
|
||||||
|
/// Provide the appropriate witness data needed to destroy an asset.
|
||||||
|
fn get_destroy_witness(class: &Self::ClassId) -> Option<Self::DestroyWitness>;
|
||||||
|
|
||||||
|
/// Destroy an existing fungible asset.
|
||||||
|
/// * `class`: The `ClassId` to be destroyed.
|
||||||
|
/// * `witness`: Any witness data that needs to be provided to complete the operation
|
||||||
|
/// successfully.
|
||||||
|
/// * `maybe_check_owner`: An optional account id that can be used to authorize the destroy
|
||||||
|
/// command. If not provided, we will not do any authorization checks before destroying the
|
||||||
|
/// asset.
|
||||||
|
///
|
||||||
|
/// If successful, this function will return the actual witness data from the destroyed asset.
|
||||||
|
/// This may be different than the witness data provided, and can be used to refund weight.
|
||||||
|
fn destroy(
|
||||||
|
class: Self::ClassId,
|
||||||
|
witness: Self::DestroyWitness,
|
||||||
|
maybe_check_owner: Option<AccountId>,
|
||||||
|
) -> Result<Self::DestroyWitness, DispatchError>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait for providing an interface for multiple classes of NFT-like assets which may be minted,
|
/// Trait for providing an interface for multiple classes of NFT-like assets which may be minted,
|
||||||
/// burned and/or have attributes set on them.
|
/// burned and/or have attributes set on them.
|
||||||
pub trait Mutate<AccountId>: Inspect<AccountId> {
|
pub trait Mutate<AccountId>: Inspect<AccountId> {
|
||||||
|
|||||||
@@ -80,6 +80,41 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn do_destroy_class(
|
||||||
|
class: T::ClassId,
|
||||||
|
witness: DestroyWitness,
|
||||||
|
maybe_check_owner: Option<T::AccountId>,
|
||||||
|
) -> Result<DestroyWitness, DispatchError> {
|
||||||
|
Class::<T, I>::try_mutate_exists(class, |maybe_details| {
|
||||||
|
let class_details = maybe_details.take().ok_or(Error::<T, I>::Unknown)?;
|
||||||
|
if let Some(check_owner) = maybe_check_owner {
|
||||||
|
ensure!(class_details.owner == check_owner, Error::<T, I>::NoPermission);
|
||||||
|
}
|
||||||
|
ensure!(class_details.instances == witness.instances, Error::<T, I>::BadWitness);
|
||||||
|
ensure!(
|
||||||
|
class_details.instance_metadatas == witness.instance_metadatas,
|
||||||
|
Error::<T, I>::BadWitness
|
||||||
|
);
|
||||||
|
ensure!(class_details.attributes == witness.attributes, Error::<T, I>::BadWitness);
|
||||||
|
|
||||||
|
for (instance, details) in Asset::<T, I>::drain_prefix(&class) {
|
||||||
|
Account::<T, I>::remove((&details.owner, &class, &instance));
|
||||||
|
}
|
||||||
|
InstanceMetadataOf::<T, I>::remove_prefix(&class, None);
|
||||||
|
ClassMetadataOf::<T, I>::remove(&class);
|
||||||
|
Attribute::<T, I>::remove_prefix((&class,), None);
|
||||||
|
T::Currency::unreserve(&class_details.owner, class_details.total_deposit);
|
||||||
|
|
||||||
|
Self::deposit_event(Event::Destroyed(class));
|
||||||
|
|
||||||
|
Ok(DestroyWitness {
|
||||||
|
instances: class_details.instances,
|
||||||
|
instance_metadatas: class_details.instance_metadatas,
|
||||||
|
attributes: class_details.attributes,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn do_mint(
|
pub(super) fn do_mint(
|
||||||
class: T::ClassId,
|
class: T::ClassId,
|
||||||
instance: T::InstanceId,
|
instance: T::InstanceId,
|
||||||
|
|||||||
@@ -19,13 +19,10 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
traits::{
|
traits::{tokens::nonfungibles::*, Get},
|
||||||
tokens::nonfungibles::{Create, Inspect, InspectEnumerable, Mutate, Transfer},
|
|
||||||
Get,
|
|
||||||
},
|
|
||||||
BoundedSlice,
|
BoundedSlice,
|
||||||
};
|
};
|
||||||
use sp_runtime::DispatchResult;
|
use sp_runtime::{DispatchError, DispatchResult};
|
||||||
use sp_std::convert::TryFrom;
|
use sp_std::convert::TryFrom;
|
||||||
|
|
||||||
impl<T: Config<I>, I: 'static> Inspect<<T as SystemConfig>::AccountId> for Pallet<T, I> {
|
impl<T: Config<I>, I: 'static> Inspect<<T as SystemConfig>::AccountId> for Pallet<T, I> {
|
||||||
@@ -106,6 +103,22 @@ impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId> for Pallet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Config<I>, I: 'static> Destroy<<T as SystemConfig>::AccountId> for Pallet<T, I> {
|
||||||
|
type DestroyWitness = DestroyWitness;
|
||||||
|
|
||||||
|
fn get_destroy_witness(class: &Self::ClassId) -> Option<DestroyWitness> {
|
||||||
|
Class::<T, I>::get(class).map(|a| a.destroy_witness())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(
|
||||||
|
class: Self::ClassId,
|
||||||
|
witness: Self::DestroyWitness,
|
||||||
|
maybe_check_owner: Option<T::AccountId>,
|
||||||
|
) -> Result<Self::DestroyWitness, DispatchError> {
|
||||||
|
Self::do_destroy_class(class, witness, maybe_check_owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId> for Pallet<T, I> {
|
impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId> for Pallet<T, I> {
|
||||||
fn mint_into(
|
fn mint_into(
|
||||||
class: &Self::ClassId,
|
class: &Self::ClassId,
|
||||||
|
|||||||
@@ -381,37 +381,19 @@ pub mod pallet {
|
|||||||
origin: OriginFor<T>,
|
origin: OriginFor<T>,
|
||||||
#[pallet::compact] class: T::ClassId,
|
#[pallet::compact] class: T::ClassId,
|
||||||
witness: DestroyWitness,
|
witness: DestroyWitness,
|
||||||
) -> DispatchResult {
|
) -> DispatchResultWithPostInfo {
|
||||||
let maybe_check_owner = match T::ForceOrigin::try_origin(origin) {
|
let maybe_check_owner = match T::ForceOrigin::try_origin(origin) {
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(origin) => Some(ensure_signed(origin)?),
|
Err(origin) => Some(ensure_signed(origin)?),
|
||||||
};
|
};
|
||||||
Class::<T, I>::try_mutate_exists(class, |maybe_details| {
|
let details = Self::do_destroy_class(class, witness, maybe_check_owner)?;
|
||||||
let class_details = maybe_details.take().ok_or(Error::<T, I>::Unknown)?;
|
|
||||||
if let Some(check_owner) = maybe_check_owner {
|
|
||||||
ensure!(class_details.owner == check_owner, Error::<T, I>::NoPermission);
|
|
||||||
}
|
|
||||||
ensure!(class_details.instances == witness.instances, Error::<T, I>::BadWitness);
|
|
||||||
ensure!(
|
|
||||||
class_details.instance_metadatas == witness.instance_metadatas,
|
|
||||||
Error::<T, I>::BadWitness
|
|
||||||
);
|
|
||||||
ensure!(class_details.attributes == witness.attributes, Error::<T, I>::BadWitness);
|
|
||||||
|
|
||||||
for (instance, details) in Asset::<T, I>::drain_prefix(&class) {
|
Ok(Some(T::WeightInfo::destroy(
|
||||||
Account::<T, I>::remove((&details.owner, &class, &instance));
|
details.instances,
|
||||||
}
|
details.instance_metadatas,
|
||||||
InstanceMetadataOf::<T, I>::remove_prefix(&class, None);
|
details.attributes,
|
||||||
ClassMetadataOf::<T, I>::remove(&class);
|
))
|
||||||
Attribute::<T, I>::remove_prefix((&class,), None);
|
.into())
|
||||||
T::Currency::unreserve(&class_details.owner, class_details.total_deposit);
|
|
||||||
|
|
||||||
Self::deposit_event(Event::Destroyed(class));
|
|
||||||
|
|
||||||
// NOTE: could use postinfo to reflect the actual number of
|
|
||||||
// accounts/sufficient/approvals
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mint an asset instance of a particular class.
|
/// Mint an asset instance of a particular class.
|
||||||
|
|||||||
Reference in New Issue
Block a user