Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api/nonfungibles): destroy collection witness data & weights #383

Merged
110 changes: 110 additions & 0 deletions pallets/api/src/nonfungibles/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! Benchmarking setup for pallet_api::nonfungibles

use frame_benchmarking::{account, v2::*};
use frame_support::{traits::nonfungibles_v2::Inspect, BoundedVec};
use sp_runtime::traits::Zero;

use super::{AttributeNamespace, CollectionIdOf, Config, ItemIdOf, NftsInstanceOf, Pallet, Read};
use crate::Read as _;

const SEED: u32 = 1;

#[benchmarks(
where
<pallet_nfts::Pallet<T, NftsInstanceOf<T>> as Inspect<<T as frame_system::Config>::AccountId>>::ItemId: Zero,
<pallet_nfts::Pallet<T, NftsInstanceOf<T>> as Inspect<<T as frame_system::Config>::AccountId>>::CollectionId: Zero,
)]
mod benchmarks {
use super::*;

#[benchmark]
// Storage: `Collection`
fn total_supply() {
#[block]
{
Pallet::<T>::read(Read::TotalSupply(CollectionIdOf::<T>::zero()));
}
}

#[benchmark]
// Storage: `AccountBalance`
fn balance_of() {
#[block]
{
Pallet::<T>::read(Read::BalanceOf {
collection: CollectionIdOf::<T>::zero(),
owner: account("Alice", 0, SEED),
});
}
}

#[benchmark]
// Storage: `Allowances`, `Item`
fn allowance() {
#[block]
{
Pallet::<T>::read(Read::Allowance {
collection: CollectionIdOf::<T>::zero(),
owner: account("Alice", 0, SEED),
operator: account("Bob", 0, SEED),
item: Some(ItemIdOf::<T>::zero()),
});
}
}

#[benchmark]
// Storage: `Item`
fn owner_of() {
#[block]
{
Pallet::<T>::read(Read::OwnerOf {
collection: CollectionIdOf::<T>::zero(),
item: ItemIdOf::<T>::zero(),
});
}
}

#[benchmark]
// Storage: `Attribute`
fn get_attribute() {
#[block]
{
Pallet::<T>::read(Read::GetAttribute {
key: BoundedVec::default(),
collection: CollectionIdOf::<T>::zero(),
item: ItemIdOf::<T>::zero(),
namespace: AttributeNamespace::CollectionOwner,
});
}
}

#[benchmark]
// Storage: `Collection`
fn collection() {
#[block]
{
Pallet::<T>::read(Read::Collection(CollectionIdOf::<T>::zero()));
}
}

#[benchmark]
// Storage: `NextCollectionId`
fn next_collection_id() {
#[block]
{
Pallet::<T>::read(Read::NextCollectionId);
}
}

#[benchmark]
// Storage: `ItemMetadata`
fn item_metadata() {
#[block]
{
Pallet::<T>::read(Read::ItemMetadata {
collection: CollectionIdOf::<T>::zero(),
item: ItemIdOf::<T>::zero(),
});
}
}
}
114 changes: 73 additions & 41 deletions pallets/api/src/nonfungibles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
use frame_support::traits::{nonfungibles_v2::Inspect, Currency};
use frame_system::pallet_prelude::BlockNumberFor;
pub use pallet::*;
use pallet_nfts::WeightInfo;
use pallet_nfts::WeightInfo as NftsWeightInfoTrait;
pub use pallet_nfts::{
AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings,
DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness,
AttributeNamespace, CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails,
CollectionSetting, CollectionSettings, DestroyWitness, ItemDeposit, ItemDetails, ItemMetadata,
ItemSetting, MintSettings, MintType, MintWitness,
};
use sp_runtime::traits::StaticLookup;
use weights::WeightInfo;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(test)]
mod tests;
pub mod weights;

type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
type NftsOf<T> = pallet_nfts::Pallet<T, NftsInstanceOf<T>>;
Expand All @@ -31,15 +36,19 @@
type AttributeNamespaceOf<T> = AttributeNamespace<AccountIdOf<T>>;
type CollectionConfigFor<T> =
CollectionConfig<ItemPriceOf<T>, BlockNumberFor<T>, CollectionIdOf<T>>;
// Type aliases for storage items.
pub(super) type NextCollectionIdOf<T> = pallet_nfts::NextCollectionId<T, NftsInstanceOf<T>>;
// Type aliases for pallet-nfts storage items.
pub(super) type AccountBalanceOf<T> = pallet_nfts::AccountBalance<T, NftsInstanceOf<T>>;
pub(super) type AttributeOf<T> = pallet_nfts::Attribute<T, NftsInstanceOf<T>>;
pub(super) type NextCollectionIdOf<T> = pallet_nfts::NextCollectionId<T, NftsInstanceOf<T>>;
pub(super) type CollectionOf<T> = pallet_nfts::Collection<T, NftsInstanceOf<T>>;

#[frame_support::pallet]

Check warning on line 45 in pallets/api/src/nonfungibles/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for an associated function

warning: missing documentation for an associated function --> pallets/api/src/nonfungibles/mod.rs:45:1 | 45 | #[frame_support::pallet] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this warning originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info)
pub mod pallet {
use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::Incrementable};
use frame_support::{
dispatch::{DispatchResult, DispatchResultWithPostInfo, WithPostDispatchInfo},
pallet_prelude::*,
traits::Incrementable,
};
use frame_system::pallet_prelude::*;
use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness};
use sp_runtime::BoundedVec;
Expand All @@ -59,42 +68,42 @@
/// Account balance for a specified collection.
#[codec(index = 1)]
BalanceOf {
// The collection.
/// The collection.
collection: CollectionIdOf<T>,
// The owner of the collection .
/// The owner of the collection .
owner: AccountIdOf<T>,
},
/// Allowance for an operator approved by an owner, for a specified collection or item.
#[codec(index = 2)]
Allowance {
// The collection.
/// The collection.
collection: CollectionIdOf<T>,
// The collection item.
/// The collection item.
item: Option<ItemIdOf<T>>,
// The owner of the collection item.
/// The owner of the collection item.
owner: AccountIdOf<T>,
// The delegated operator of collection item.
/// The delegated operator of collection item.
operator: AccountIdOf<T>,
},
/// Owner of a specified collection item.
#[codec(index = 5)]
OwnerOf {
// The collection.
/// The collection.
collection: CollectionIdOf<T>,
// The collection item.
/// The collection item.
item: ItemIdOf<T>,
},
/// Attribute value of a specified collection item. (Error: bounded collection is not
/// partial)
#[codec(index = 6)]
GetAttribute {
// The collection.
/// The collection.
collection: CollectionIdOf<T>,
// The collection item.
/// The collection item.
item: ItemIdOf<T>,
// The namespace of the attribute.
/// The namespace of the attribute.
namespace: AttributeNamespaceOf<T>,
// The key of the attribute.
/// The key of the attribute.
key: BoundedVec<u8, T::KeyLimit>,
},
/// Details of a specified collection.
Expand All @@ -106,9 +115,9 @@
/// Metadata of a specified collection item.
#[codec(index = 11)]
ItemMetadata {
// The collection.
/// The collection.
collection: CollectionIdOf<T>,
// The collection item.
/// The collection item.
item: ItemIdOf<T>,
},
}
Expand Down Expand Up @@ -208,175 +217,188 @@
},
}

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Transfers the collection item from the caller's account to account `to`.
///
/// # Parameters
/// - `collection` - The collection of the item to be transferred.
/// - `item` - The item to be transferred.
/// - `collection` - The collection of the item to transfer.
/// - `item` - The item to transfer.
/// - `to` - The recipient account.
#[pallet::call_index(3)]
#[pallet::weight(NftsWeightInfoOf::<T>::transfer())]
pub fn transfer(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: ItemIdOf<T>,
to: AccountIdOf<T>,
) -> DispatchResult {
let from = ensure_signed(origin.clone())?;
NftsOf::<T>::transfer(origin, collection, item, T::Lookup::unlookup(to.clone()))?;
Self::deposit_event(Event::Transfer {
collection,
item,
from: Some(from),
to: Some(to),
price: None,
});
Ok(())
}

/// Approves `operator` to spend the collection item on behalf of the caller.
///
/// # Parameters
/// - `collection` - The collection of the item to be approved for delegated transfer.
/// - `item` - The item to be approved for delegated transfer.
/// - `collection` - The collection of the item to approve for a delegated transfer.
/// - `item` - The item to approve for a delegated transfer.
/// - `operator` - The account that is allowed to spend the collection item.
/// - `approved` - The approval status of the collection item.
#[pallet::call_index(4)]
#[pallet::weight(NftsWeightInfoOf::<T>::approve_transfer() + NftsWeightInfoOf::<T>::cancel_approval())]
#[pallet::weight(
NftsWeightInfoOf::<T>::approve_transfer(item.is_some() as u32) +
NftsWeightInfoOf::<T>::cancel_approval(item.is_some() as u32)
)]
pub fn approve(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: Option<ItemIdOf<T>>,
operator: AccountIdOf<T>,
approved: bool,
) -> DispatchResult {
) -> DispatchResultWithPostInfo {
let owner = ensure_signed(origin.clone())?;
if approved {
let weight = if approved {
NftsOf::<T>::approve_transfer(
origin,
collection,
item,
T::Lookup::unlookup(operator.clone()),
None,
)?;
)
.map_err(|e| {
e.with_weight(NftsWeightInfoOf::<T>::approve_transfer(item.is_some() as u32))
})?;
NftsWeightInfoOf::<T>::approve_transfer(item.is_some() as u32)
} else {
NftsOf::<T>::cancel_approval(
origin,
collection,
item,
T::Lookup::unlookup(operator.clone()),
)?;
}
)
.map_err(|e| {
e.with_weight(NftsWeightInfoOf::<T>::cancel_approval(item.is_some() as u32))
})?;
NftsWeightInfoOf::<T>::cancel_approval(item.is_some() as u32)
};
Self::deposit_event(Event::Approval { collection, item, operator, owner, approved });
Ok(())
Ok(Some(weight).into())
}

/// Issue a new collection of non-fungible items from a public origin.
///
/// # Parameters
/// - `admin` - The admin of this collection. The admin is the initial address of each
/// member of the collection's admin team.
/// - `config` - The configuration of the collection.
#[pallet::call_index(7)]
#[pallet::weight(NftsWeightInfoOf::<T>::create())]
pub fn create(
origin: OriginFor<T>,
admin: AccountIdOf<T>,
config: CollectionConfigFor<T>,
) -> DispatchResult {
let creator = ensure_signed(origin.clone())?;
// TODO: re-evaluate next collection id in nfts pallet. The `Incrementable` trait causes
// issues for setting it to xcm's `Location`. This can easily be done differently.
let id = NextCollectionIdOf::<T>::get()
.or(T::CollectionId::initial_value())
.ok_or(NftsErrorOf::<T>::UnknownCollection)?;
let creator = ensure_signed(origin.clone())?;
NftsOf::<T>::create(origin, T::Lookup::unlookup(admin.clone()), config)?;
Self::deposit_event(Event::Created { id, admin, creator });
Self::deposit_event(Event::Created { id, creator, admin });
Ok(())
}

/// Destroy a collection of fungible items.
///
/// # Parameters
/// - `collection` - The identifier of the collection to be destroyed.
/// - `collection` - The collection to destroy.
/// - `witness` - Information on the items minted in the collection. This must be
/// correct.
#[pallet::call_index(8)]
#[pallet::weight(NftsWeightInfoOf::<T>::destroy(
witness.item_metadatas,
witness.item_configs,
witness.attributes,
witness.item_holders,
witness.allowances,
))]
pub fn destroy(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
witness: DestroyWitness,
) -> DispatchResultWithPostInfo {
NftsOf::<T>::destroy(origin, collection, witness)
}

/// Set an attribute for a collection or item.
///
/// # Parameters
/// - `collection` - The collection whose item's metadata to set.
/// - `maybe_item` - The item whose metadata to set.
/// - `namespace` - Attribute's namespace.
/// - `key` - The key of the attribute.
/// - `value` - The value to which to set the attribute.
#[pallet::call_index(12)]
#[pallet::weight(NftsWeightInfoOf::<T>::set_attribute())]
pub fn set_attribute(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: Option<ItemIdOf<T>>,
namespace: AttributeNamespaceOf<T>,
key: BoundedVec<u8, T::KeyLimit>,
value: BoundedVec<u8, T::ValueLimit>,
) -> DispatchResult {
NftsOf::<T>::set_attribute(origin, collection, item, namespace, key, value)
}

/// Clear an attribute for the collection or item.
///
/// # Parameters
/// - `collection` - The collection whose item's metadata to clear.
/// - `maybe_item` - The item whose metadata to clear.
/// - `namespace` - Attribute's namespace.
/// - `key` - The key of the attribute.
#[pallet::call_index(13)]
#[pallet::weight(NftsWeightInfoOf::<T>::clear_attribute())]
pub fn clear_attribute(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: Option<ItemIdOf<T>>,
namespace: AttributeNamespaceOf<T>,
key: BoundedVec<u8, T::KeyLimit>,
) -> DispatchResult {
NftsOf::<T>::clear_attribute(origin, collection, item, namespace, key)
}

/// Set the metadata for an item.
///
/// # Parameters
/// - `collection` - The collection whose item's metadata to set.
/// - `item` - The item whose metadata to set.
/// - `data` - The general information of this item. Limited in length by `StringLimit`.
#[pallet::call_index(14)]
#[pallet::weight(NftsWeightInfoOf::<T>::set_metadata())]
pub fn set_metadata(
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: ItemIdOf<T>,
data: BoundedVec<u8, T::StringLimit>,
) -> DispatchResult {
NftsOf::<T>::set_metadata(origin, collection, item, data)
}

#[pallet::call_index(15)]
#[pallet::weight(NftsWeightInfoOf::<T>::clear_metadata())]
pub fn clear_metadata(

Check warning on line 401 in pallets/api/src/nonfungibles/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> pallets/api/src/nonfungibles/mod.rs:220:12 | 220 | #[pallet::call] | _______________^ 221 | | impl<T: Config> Pallet<T> { 222 | | /// Transfers the collection item from the caller's account to account `to`. 223 | | /// ... | 400 | | #[pallet::weight(NftsWeightInfoOf::<T>::clear_metadata())] 401 | | pub fn clear_metadata( | |_____________________________^
origin: OriginFor<T>,
collection: CollectionIdOf<T>,
item: ItemIdOf<T>,
Expand Down Expand Up @@ -410,7 +432,7 @@
/// All the previously set attributes by the `delegate` will be removed.
///
/// # Parameters
/// - `collection` - Collection that the item is contained within.
/// - `collection` - The collection that the item is contained within.
/// - `item` - The item that holds attributes.
/// - `delegate` - The previously approved account to remove.
/// - `witness` - A witness data to cancel attributes approval operation.
Expand Down Expand Up @@ -450,9 +472,9 @@
/// Mint an item of a particular collection.
///
/// # Parameters
/// - `collection` - The collection of the item to be minted.
/// - `to` - Account into which the item will be minted.
/// - `collection` - The collection of the item to mint.
/// - `item` - An identifier of the new item.
/// - `mint_to` - Account into which the item will be minted.
/// - `witness_data` - When the mint type is `HolderOf(collection_id)`, then the owned
/// item_id from that collection needs to be provided within the witness data object. If
/// the mint price is set, then it should be additionally confirmed in the `witness_data`.
Expand Down Expand Up @@ -487,8 +509,8 @@
/// Destroy a single collection item.
///
/// # Parameters
/// - `collection` - The collection of the item to be burned.
/// - `item` - The item to be burned.
/// - `collection` - The collection of the item to burn.
/// - `item` - The item to burn.
#[pallet::call_index(20)]
#[pallet::weight(NftsWeightInfoOf::<T>::burn())]
pub fn burn(
Expand Down Expand Up @@ -520,8 +542,18 @@
///
/// # Parameters
/// - `request` - The read request.
fn weight(_request: &Self::Read) -> Weight {
Default::default()
fn weight(request: &Self::Read) -> Weight {
use Read::*;
match request {
TotalSupply(_) => <T as Config>::WeightInfo::total_supply(),
BalanceOf { .. } => <T as Config>::WeightInfo::balance_of(),
Allowance { .. } => <T as Config>::WeightInfo::allowance(),
OwnerOf { .. } => <T as Config>::WeightInfo::owner_of(),
GetAttribute { .. } => <T as Config>::WeightInfo::get_attribute(),
Collection(_) => <T as Config>::WeightInfo::collection(),
ItemMetadata { .. } => <T as Config>::WeightInfo::item_metadata(),
NextCollectionId => <T as Config>::WeightInfo::next_collection_id(),
}
}

/// Performs the requested read and returns the result.
Expand Down
Loading
Loading