From bf343f6274a7fe65b0e9b45a115d50b272c61af3 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:23:51 +0700 Subject: [PATCH 01/64] chore: forked pallet nfts --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/common_functions.rs | 4 +- pallets/nfts/src/features/approvals.rs | 3 +- pallets/nfts/src/features/atomic_swap.rs | 4 +- pallets/nfts/src/features/attributes.rs | 3 +- pallets/nfts/src/features/buy_sell.rs | 3 +- .../src/features/create_delete_collection.rs | 3 +- .../nfts/src/features/create_delete_item.rs | 3 +- pallets/nfts/src/features/lock.rs | 4 +- pallets/nfts/src/features/metadata.rs | 4 +- pallets/nfts/src/features/roles.rs | 4 +- pallets/nfts/src/features/settings.rs | 3 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/impl_nonfungibles.rs | 9 ++-- pallets/nfts/src/lib.rs | 10 ++-- pallets/nfts/src/migration.rs | 4 +- pallets/nfts/src/mock.rs | 48 +++++++++---------- pallets/nfts/src/tests.rs | 3 +- pallets/nfts/src/types.rs | 24 +--------- 19 files changed, 49 insertions(+), 93 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..bc81096b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -19,6 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] +use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -31,7 +32,6 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; use sp_runtime::traits::{Bounded, One}; -use super::*; use crate::Pallet as Nfts; const SEED: u32 = 0; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index f51de192..2c4778c1 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -17,12 +17,10 @@ //! Various pieces of common functionality. +use crate::*; use alloc::vec::Vec; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ad5d93c2..053fa671 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,9 +19,8 @@ //! The bitflag [`PalletFeature::Approvals`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Approves the transfer of an item to a delegate. diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 31c93fba..830283b7 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -20,13 +20,12 @@ //! The bitflag [`PalletFeature::Swaps`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. +use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement::KeepAlive}, }; -use crate::*; - impl, I: 'static> Pallet { /// Creates a new swap offer for the specified item. /// @@ -102,7 +101,6 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the specified swap offer. /// /// This function is used to cancel the specified swap offer created by the `caller` account. If diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index ab0cdc68..28f7bd2c 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -20,9 +20,8 @@ //! The bitflag [`PalletFeature::Attributes`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Sets the attribute of an item or a collection. diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index 8cf86f79..d6ec6f50 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -20,13 +20,12 @@ //! The bitflag [`PalletFeature::Trading`] needs to be set in the [`Config::Features`] for NFTs //! to have the functionality defined in this module. +use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, }; -use crate::*; - impl, I: 'static> Pallet { /// Pays the specified tips to the corresponding receivers. /// diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..f03df7fd 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform functionality associated with creating and //! destroying collections for the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Create a new collection with the given `collection`, `owner`, `admin`, `config`, `deposit`, diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9843b2e..37f64ae1 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform functionality associated with minting and burning //! items for the NFTs pallet. -use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; - use crate::*; +use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; impl, I: 'static> Pallet { /// Mint a new unique item with the given `collection`, `item`, and other minting configuration diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs index 4649f4a0..1c3c9c86 100644 --- a/pallets/nfts/src/features/lock.rs +++ b/pallets/nfts/src/features/lock.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to configure locks on collections and items for the NFTs //! pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Locks a collection with specified settings. @@ -30,6 +29,7 @@ impl, I: 'static> Pallet { /// /// Note: it's possible only to lock the setting, but not to unlock it after. + /// /// - `origin`: The origin of the transaction, representing the account attempting to lock the /// collection. /// - `collection`: The identifier of the collection to be locked. diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index b3d16b12..26006160 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -17,12 +17,10 @@ //! This module contains helper methods to configure the metadata of collections and items. +use crate::*; use alloc::vec::Vec; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Sets the metadata for a specific item within a collection. /// diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs index 053eaf0b..aa6394f7 100644 --- a/pallets/nfts/src/features/roles.rs +++ b/pallets/nfts/src/features/roles.rs @@ -17,12 +17,10 @@ //! This module contains helper methods to configure account roles for existing collections. +use crate::*; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Set the team roles for a specific collection. /// diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs index 9c7ac7ca..d4f7533f 100644 --- a/pallets/nfts/src/features/settings.rs +++ b/pallets/nfts/src/features/settings.rs @@ -17,9 +17,8 @@ //! This module provides helper methods to configure collection settings for the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Forcefully change the configuration of a collection. diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index b7223a7c..bba83448 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Transfer an NFT to the specified destination account. @@ -161,7 +160,6 @@ impl, I: 'static> Pallet { Ok(()) }) } - /// Set or unset the ownership acceptance for an account regarding a specific collection. /// /// - `who`: The account for which to set or unset the ownership acceptance. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index 362cccd9..c90655aa 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -17,6 +17,7 @@ //! Implementations for `nonfungibles` traits. +use super::*; use frame_support::{ ensure, storage::KeyPrefixIterator, @@ -25,11 +26,9 @@ use frame_support::{ }; use sp_runtime::{DispatchError, DispatchResult}; -use super::*; - impl, I: 'static> Inspect<::AccountId> for Pallet { - type CollectionId = T::CollectionId; type ItemId = T::ItemId; + type CollectionId = T::CollectionId; fn owner( collection: &Self::CollectionId, @@ -141,11 +140,9 @@ impl, I: 'static> InspectRole<::AccountId> for P fn is_issuer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Issuer) } - fn is_admin(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Admin) } - fn is_freezer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Freezer) } @@ -472,9 +469,9 @@ impl, I: 'static> Trading> for Pallet impl, I: 'static> InspectEnumerable for Pallet { type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; type ItemsIterator = KeyPrefixIterator<>::ItemId>; - type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; type OwnedIterator = KeyPrefixIterator<(>::CollectionId, >::ItemId)>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; /// Returns an iterator of the collections in existence. /// diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 89bfb963..4e5493a3 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -51,18 +51,18 @@ pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; - use codec::{Decode, Encode}; use frame_support::traits::{ tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, }; use frame_system::Config as SystemConfig; -pub use pallet::*; use sp_runtime::{ traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; + +pub use pallet::*; pub use types::*; pub use weights::WeightInfo; @@ -74,11 +74,10 @@ type AccountIdLookupOf = <::Lookup as StaticLookup>::Sourc #[frame_support::pallet] pub mod pallet { + use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; - use super::*; - /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -109,17 +108,14 @@ pub mod pallet { fn collection(i: u16) -> CollectionId { i.into() } - fn item(i: u16) -> ItemId { i.into() } - fn signer() -> (sp_runtime::MultiSigner, sp_runtime::AccountId32) { let public = sp_io::crypto::sr25519_generate(0.into(), None); let account = sp_runtime::MultiSigner::Sr25519(public).into_account(); (public.into(), account) } - fn sign(signer: &sp_runtime::MultiSigner, message: &[u8]) -> sp_runtime::MultiSignature { sp_runtime::MultiSignature::Sr25519( sp_io::crypto::sr25519_sign(0.into(), &signer.clone().try_into().unwrap(), message) diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index af611bf1..8f82e092 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::*; use frame_support::traits::OnRuntimeUpgrade; use log; + #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -use super::*; - pub mod v1 { use frame_support::{pallet_prelude::*, weights::Weight}; diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index 5532be8f..5b589f59 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -17,6 +17,9 @@ //! Test environment for Nfts pallet. +use super::*; +use crate as pallet_nfts; + use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, @@ -27,9 +30,6 @@ use sp_runtime::{ BuildStorage, MultiSignature, }; -use super::*; -use crate as pallet_nfts; - type Block = frame_system::mocking::MockBlock; construct_runtime!( @@ -47,10 +47,10 @@ pub type AccountId = ::AccountId; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { - type AccountData = pallet_balances::AccountData; type AccountId = AccountId; - type Block = Block; type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] @@ -63,35 +63,35 @@ parameter_types! { } impl Config for Test { - type ApprovalsLimit = ConstU32<10>; - type AttributeDepositBase = ConstU64<1>; - type CollectionDeposit = ConstU64<2>; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; - type CreateOrigin = AsEnsureOriginWithArg>; + type ItemId = u32; type Currency = Balances; - type DepositPerByte = ConstU64<1>; - type Features = Features; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type ItemAttributesApprovalsLimit = ConstU32<2>; + type Locker = (); + type CollectionDeposit = ConstU64<2>; type ItemDeposit = ConstU64<1>; - type ItemId = u32; + type MetadataDepositBase = ConstU64<1>; + type AttributeDepositBase = ConstU64<1>; + type DepositPerByte = ConstU64<1>; + type StringLimit = ConstU32<50>; type KeyLimit = ConstU32<50>; - type Locker = (); - type MaxAttributesPerCall = ConstU32<2>; - type MaxDeadlineDuration = ConstU64<10000>; + type ValueLimit = ConstU32<50>; + type ApprovalsLimit = ConstU32<10>; + type ItemAttributesApprovalsLimit = ConstU32<2>; type MaxTips = ConstU32<10>; - type MetadataDepositBase = ConstU64<1>; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxAttributesPerCall = ConstU32<2>; + type Features = Features; /// Off-chain = signature On-chain - therefore no conversion needed. /// It needs to be From for benchmarking. type OffchainSignature = Signature; - type RuntimeEvent = RuntimeEvent; - type StringLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 44f2f32a..e1b598ca 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -17,6 +17,7 @@ //! Tests for Nfts pallet. +use crate::{mock::*, Event, SystemConfig, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, @@ -32,8 +33,6 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; -use crate::{mock::*, Event, SystemConfig, *}; - type AccountIdOf = ::AccountId; fn account(id: u8) -> AccountIdOf { diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index f08f1d09..1687a035 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -17,8 +17,9 @@ //! This module contains various basic types and data structures used in the NFTs pallet. +use super::*; +use crate::macros::*; use alloc::{vec, vec::Vec}; - use codec::EncodeLike; use enumflags2::{bitflags, BitFlags}; use frame_support::{ @@ -29,9 +30,6 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; -use super::*; -use crate::macros::*; - /// A type alias for handling balance deposits. pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -278,15 +276,12 @@ impl CollectionSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn get_disabled(&self) -> BitFlags { self.0 } - pub fn is_disabled(&self, setting: CollectionSetting) -> bool { self.0.contains(setting) } - pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -382,15 +377,12 @@ impl CollectionConfig bool { !self.settings.is_disabled(setting) } - pub fn has_disabled_setting(&self, setting: CollectionSetting) -> bool { self.settings.is_disabled(setting) } - pub fn enable_setting(&mut self, setting: CollectionSetting) { self.settings.0.remove(setting); } - pub fn disable_setting(&mut self, setting: CollectionSetting) { self.settings.0.insert(setting); } @@ -417,15 +409,12 @@ impl ItemSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn get_disabled(&self) -> BitFlags { self.0 } - pub fn is_disabled(&self, setting: ItemSetting) -> bool { self.0.contains(setting) } - pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -446,19 +435,15 @@ impl ItemConfig { pub fn is_setting_enabled(&self, setting: ItemSetting) -> bool { !self.settings.is_disabled(setting) } - pub fn has_disabled_setting(&self, setting: ItemSetting) -> bool { self.settings.is_disabled(setting) } - pub fn has_disabled_settings(&self) -> bool { !self.settings.get_disabled().is_empty() } - pub fn enable_setting(&mut self, setting: ItemSetting) { self.settings.0.remove(setting); } - pub fn disable_setting(&mut self, setting: ItemSetting) { self.settings.0.insert(setting); } @@ -487,11 +472,9 @@ impl PalletFeatures { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn from_disabled(features: BitFlags) -> Self { Self(features) } - pub fn is_enabled(&self, feature: PalletFeature) -> bool { !self.0.contains(feature) } @@ -519,15 +502,12 @@ impl CollectionRoles { pub fn none() -> Self { Self(BitFlags::EMPTY) } - pub fn has_role(&self, role: CollectionRole) -> bool { self.0.contains(role) } - pub fn add_role(&mut self, role: CollectionRole) { self.0.insert(role); } - pub fn max_roles() -> u8 { let all: BitFlags = BitFlags::all(); all.len() as u8 From 958b9e8d827131ab13565bcf1172a6575f0fe008 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:24:10 +0700 Subject: [PATCH 02/64] fix: formatting --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/common_functions.rs | 4 +- pallets/nfts/src/features/approvals.rs | 3 +- pallets/nfts/src/features/atomic_swap.rs | 4 +- pallets/nfts/src/features/attributes.rs | 3 +- pallets/nfts/src/features/buy_sell.rs | 3 +- .../src/features/create_delete_collection.rs | 3 +- .../nfts/src/features/create_delete_item.rs | 3 +- pallets/nfts/src/features/lock.rs | 4 +- pallets/nfts/src/features/metadata.rs | 4 +- pallets/nfts/src/features/roles.rs | 4 +- pallets/nfts/src/features/settings.rs | 3 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/impl_nonfungibles.rs | 9 ++-- pallets/nfts/src/lib.rs | 10 ++-- pallets/nfts/src/migration.rs | 4 +- pallets/nfts/src/mock.rs | 48 +++++++++---------- pallets/nfts/src/tests.rs | 3 +- pallets/nfts/src/types.rs | 24 +++++++++- 19 files changed, 93 insertions(+), 49 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index bc81096b..8fa87557 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -19,7 +19,6 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -32,6 +31,7 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; use sp_runtime::traits::{Bounded, One}; +use super::*; use crate::Pallet as Nfts; const SEED: u32 = 0; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 2c4778c1..f51de192 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -17,10 +17,12 @@ //! Various pieces of common functionality. -use crate::*; use alloc::vec::Vec; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 053fa671..ad5d93c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,9 +19,10 @@ //! The bitflag [`PalletFeature::Approvals`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Approves the transfer of an item to a delegate. /// diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 830283b7..31c93fba 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -20,12 +20,13 @@ //! The bitflag [`PalletFeature::Swaps`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement::KeepAlive}, }; +use crate::*; + impl, I: 'static> Pallet { /// Creates a new swap offer for the specified item. /// @@ -101,6 +102,7 @@ impl, I: 'static> Pallet { Ok(()) } + /// Cancels the specified swap offer. /// /// This function is used to cancel the specified swap offer created by the `caller` account. If diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index 28f7bd2c..ab0cdc68 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -20,9 +20,10 @@ //! The bitflag [`PalletFeature::Attributes`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Sets the attribute of an item or a collection. /// diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index d6ec6f50..8cf86f79 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -20,12 +20,13 @@ //! The bitflag [`PalletFeature::Trading`] needs to be set in the [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, }; +use crate::*; + impl, I: 'static> Pallet { /// Pays the specified tips to the corresponding receivers. /// diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index f03df7fd..348ec6b9 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform functionality associated with creating and //! destroying collections for the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Create a new collection with the given `collection`, `owner`, `admin`, `config`, `deposit`, /// and `event`. diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 37f64ae1..e9843b2e 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform functionality associated with minting and burning //! items for the NFTs pallet. -use crate::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; +use crate::*; + impl, I: 'static> Pallet { /// Mint a new unique item with the given `collection`, `item`, and other minting configuration /// details. diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs index 1c3c9c86..4649f4a0 100644 --- a/pallets/nfts/src/features/lock.rs +++ b/pallets/nfts/src/features/lock.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to configure locks on collections and items for the NFTs //! pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Locks a collection with specified settings. /// @@ -29,7 +30,6 @@ impl, I: 'static> Pallet { /// /// Note: it's possible only to lock the setting, but not to unlock it after. - /// /// - `origin`: The origin of the transaction, representing the account attempting to lock the /// collection. /// - `collection`: The identifier of the collection to be locked. diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index 26006160..b3d16b12 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -17,10 +17,12 @@ //! This module contains helper methods to configure the metadata of collections and items. -use crate::*; use alloc::vec::Vec; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Sets the metadata for a specific item within a collection. /// diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs index aa6394f7..053eaf0b 100644 --- a/pallets/nfts/src/features/roles.rs +++ b/pallets/nfts/src/features/roles.rs @@ -17,10 +17,12 @@ //! This module contains helper methods to configure account roles for existing collections. -use crate::*; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Set the team roles for a specific collection. /// diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs index d4f7533f..9c7ac7ca 100644 --- a/pallets/nfts/src/features/settings.rs +++ b/pallets/nfts/src/features/settings.rs @@ -17,9 +17,10 @@ //! This module provides helper methods to configure collection settings for the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Forcefully change the configuration of a collection. /// diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index bba83448..b7223a7c 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Transfer an NFT to the specified destination account. /// @@ -160,6 +161,7 @@ impl, I: 'static> Pallet { Ok(()) }) } + /// Set or unset the ownership acceptance for an account regarding a specific collection. /// /// - `who`: The account for which to set or unset the ownership acceptance. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index c90655aa..362cccd9 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -17,7 +17,6 @@ //! Implementations for `nonfungibles` traits. -use super::*; use frame_support::{ ensure, storage::KeyPrefixIterator, @@ -26,9 +25,11 @@ use frame_support::{ }; use sp_runtime::{DispatchError, DispatchResult}; +use super::*; + impl, I: 'static> Inspect<::AccountId> for Pallet { - type ItemId = T::ItemId; type CollectionId = T::CollectionId; + type ItemId = T::ItemId; fn owner( collection: &Self::CollectionId, @@ -140,9 +141,11 @@ impl, I: 'static> InspectRole<::AccountId> for P fn is_issuer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Issuer) } + fn is_admin(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Admin) } + fn is_freezer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Freezer) } @@ -469,9 +472,9 @@ impl, I: 'static> Trading> for Pallet impl, I: 'static> InspectEnumerable for Pallet { type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; type ItemsIterator = KeyPrefixIterator<>::ItemId>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; type OwnedIterator = KeyPrefixIterator<(>::CollectionId, >::ItemId)>; - type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; /// Returns an iterator of the collections in existence. /// diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 4e5493a3..89bfb963 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -51,18 +51,18 @@ pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; + use codec::{Decode, Encode}; use frame_support::traits::{ tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, }; use frame_system::Config as SystemConfig; +pub use pallet::*; use sp_runtime::{ traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; - -pub use pallet::*; pub use types::*; pub use weights::WeightInfo; @@ -74,10 +74,11 @@ type AccountIdLookupOf = <::Lookup as StaticLookup>::Sourc #[frame_support::pallet] pub mod pallet { - use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; + use super::*; + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -108,14 +109,17 @@ pub mod pallet { fn collection(i: u16) -> CollectionId { i.into() } + fn item(i: u16) -> ItemId { i.into() } + fn signer() -> (sp_runtime::MultiSigner, sp_runtime::AccountId32) { let public = sp_io::crypto::sr25519_generate(0.into(), None); let account = sp_runtime::MultiSigner::Sr25519(public).into_account(); (public.into(), account) } + fn sign(signer: &sp_runtime::MultiSigner, message: &[u8]) -> sp_runtime::MultiSignature { sp_runtime::MultiSignature::Sr25519( sp_io::crypto::sr25519_sign(0.into(), &signer.clone().try_into().unwrap(), message) diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index 8f82e092..af611bf1 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::*; use frame_support::traits::OnRuntimeUpgrade; use log; - #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +use super::*; + pub mod v1 { use frame_support::{pallet_prelude::*, weights::Weight}; diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index 5b589f59..5532be8f 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -17,9 +17,6 @@ //! Test environment for Nfts pallet. -use super::*; -use crate as pallet_nfts; - use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, @@ -30,6 +27,9 @@ use sp_runtime::{ BuildStorage, MultiSignature, }; +use super::*; +use crate as pallet_nfts; + type Block = frame_system::mocking::MockBlock; construct_runtime!( @@ -47,10 +47,10 @@ pub type AccountId = ::AccountId; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { + type AccountData = pallet_balances::AccountData; type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type AccountData = pallet_balances::AccountData; + type Lookup = IdentityLookup; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] @@ -63,35 +63,35 @@ parameter_types! { } impl Config for Test { - type RuntimeEvent = RuntimeEvent; + type ApprovalsLimit = ConstU32<10>; + type AttributeDepositBase = ConstU64<1>; + type CollectionDeposit = ConstU64<2>; type CollectionId = u32; - type ItemId = u32; - type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = ConstU64<1>; + type Features = Features; type ForceOrigin = frame_system::EnsureRoot; - type Locker = (); - type CollectionDeposit = ConstU64<2>; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<2>; type ItemDeposit = ConstU64<1>; - type MetadataDepositBase = ConstU64<1>; - type AttributeDepositBase = ConstU64<1>; - type DepositPerByte = ConstU64<1>; - type StringLimit = ConstU32<50>; + type ItemId = u32; type KeyLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; - type ApprovalsLimit = ConstU32<10>; - type ItemAttributesApprovalsLimit = ConstU32<2>; - type MaxTips = ConstU32<10>; - type MaxDeadlineDuration = ConstU64<10000>; + type Locker = (); type MaxAttributesPerCall = ConstU32<2>; - type Features = Features; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxTips = ConstU32<10>; + type MetadataDepositBase = ConstU64<1>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; /// Off-chain = signature On-chain - therefore no conversion needed. /// It needs to be From for benchmarking. type OffchainSignature = Signature; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index e1b598ca..44f2f32a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -17,7 +17,6 @@ //! Tests for Nfts pallet. -use crate::{mock::*, Event, SystemConfig, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, @@ -33,6 +32,8 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; +use crate::{mock::*, Event, SystemConfig, *}; + type AccountIdOf = ::AccountId; fn account(id: u8) -> AccountIdOf { diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 1687a035..f08f1d09 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -17,9 +17,8 @@ //! This module contains various basic types and data structures used in the NFTs pallet. -use super::*; -use crate::macros::*; use alloc::{vec, vec::Vec}; + use codec::EncodeLike; use enumflags2::{bitflags, BitFlags}; use frame_support::{ @@ -30,6 +29,9 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; +use super::*; +use crate::macros::*; + /// A type alias for handling balance deposits. pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -276,12 +278,15 @@ impl CollectionSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn get_disabled(&self) -> BitFlags { self.0 } + pub fn is_disabled(&self, setting: CollectionSetting) -> bool { self.0.contains(setting) } + pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -377,12 +382,15 @@ impl CollectionConfig bool { !self.settings.is_disabled(setting) } + pub fn has_disabled_setting(&self, setting: CollectionSetting) -> bool { self.settings.is_disabled(setting) } + pub fn enable_setting(&mut self, setting: CollectionSetting) { self.settings.0.remove(setting); } + pub fn disable_setting(&mut self, setting: CollectionSetting) { self.settings.0.insert(setting); } @@ -409,12 +417,15 @@ impl ItemSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn get_disabled(&self) -> BitFlags { self.0 } + pub fn is_disabled(&self, setting: ItemSetting) -> bool { self.0.contains(setting) } + pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -435,15 +446,19 @@ impl ItemConfig { pub fn is_setting_enabled(&self, setting: ItemSetting) -> bool { !self.settings.is_disabled(setting) } + pub fn has_disabled_setting(&self, setting: ItemSetting) -> bool { self.settings.is_disabled(setting) } + pub fn has_disabled_settings(&self) -> bool { !self.settings.get_disabled().is_empty() } + pub fn enable_setting(&mut self, setting: ItemSetting) { self.settings.0.remove(setting); } + pub fn disable_setting(&mut self, setting: ItemSetting) { self.settings.0.insert(setting); } @@ -472,9 +487,11 @@ impl PalletFeatures { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn from_disabled(features: BitFlags) -> Self { Self(features) } + pub fn is_enabled(&self, feature: PalletFeature) -> bool { !self.0.contains(feature) } @@ -502,12 +519,15 @@ impl CollectionRoles { pub fn none() -> Self { Self(BitFlags::EMPTY) } + pub fn has_role(&self, role: CollectionRole) -> bool { self.0.contains(role) } + pub fn add_role(&mut self, role: CollectionRole) { self.0.insert(role); } + pub fn max_roles() -> u8 { let all: BitFlags = BitFlags::all(); all.len() as u8 From 293b02ecfe42ade43ef88830848accbf202d8f18 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:47:40 +0700 Subject: [PATCH 03/64] feat: add nonfungibles implementation --- Cargo.lock | 1 + pallets/api/Cargo.toml | 3 + pallets/api/src/fungibles/tests.rs | 286 ++++++++++++++++---------- pallets/api/src/lib.rs | 1 + pallets/api/src/mock.rs | 74 ++++++- pallets/api/src/nonfungibles/mod.rs | 260 +++++++++++++++++++++++ pallets/api/src/nonfungibles/tests.rs | 183 ++++++++++++++++ pallets/api/src/nonfungibles/types.rs | 61 ++++++ 8 files changed, 750 insertions(+), 119 deletions(-) create mode 100644 pallets/api/src/nonfungibles/mod.rs create mode 100644 pallets/api/src/nonfungibles/tests.rs create mode 100644 pallets/api/src/nonfungibles/types.rs diff --git a/Cargo.lock b/Cargo.lock index d2bf2ace..6f98f910 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,6 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", + "pallet-nfts", "parity-scale-codec", "pop-chain-extension", "scale-info", diff --git a/pallets/api/Cargo.toml b/pallets/api/Cargo.toml index 55a00789..5d398724 100644 --- a/pallets/api/Cargo.toml +++ b/pallets/api/Cargo.toml @@ -22,6 +22,7 @@ frame-benchmarking.workspace = true frame-support.workspace = true frame-system.workspace = true pallet-assets.workspace = true +pallet-nfts.workspace = true sp-runtime.workspace = true sp-std.workspace = true @@ -37,6 +38,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-assets/runtime-benchmarks", + "pallet-nfts/runtime-benchmarks", "pop-chain-extension/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -47,6 +49,7 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-balances/std", + "pallet-nfts/std", "pop-chain-extension/std", "scale-info/std", "sp-core/std", diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index f5c560bb..6e181a6f 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -83,17 +83,21 @@ fn transfer_works() { let to = BOB; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer(origin, token, to, value), BadOrigin); + assert_noop!(Fungibles::transfer(origin, token, account(to), value), BadOrigin); } // Check error works for `Assets::transfer_keep_alive()`. - assert_noop!(Fungibles::transfer(signed(from), token, to, value), AssetsError::Unknown); + assert_noop!( + Fungibles::transfer(signed(from), token, account(to), value), + AssetsError::Unknown + ); assets::create_and_mint_to(from, token, from, value * 2); - let balance_before_transfer = Assets::balance(token, &to); - assert_ok!(Fungibles::transfer(signed(from), token, to, value)); - let balance_after_transfer = Assets::balance(token, &to); + let balance_before_transfer = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::transfer(signed(from), token, account(to), value)); + let balance_after_transfer = Assets::balance(token, &account(to)); assert_eq!(balance_after_transfer, balance_before_transfer + value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), + Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } + .into(), ); }); } @@ -108,26 +112,36 @@ fn transfer_from_works() { let spender = CHARLIE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer_from(origin, token, from, to, value), BadOrigin); + assert_noop!( + Fungibles::transfer_from(origin, token, account(from), account(to), value), + BadOrigin + ); } // Check error works for `Assets::transfer_approved()`. assert_noop!( - Fungibles::transfer_from(signed(spender), token, from, to, value), + Fungibles::transfer_from(signed(spender), token, account(from), account(to), value), AssetsError::Unknown ); // Approve `spender` to transfer up to `value`. assets::create_mint_and_approve(spender, token, from, value * 2, spender, value); // Successfully call transfer from. - let from_balance_before_transfer = Assets::balance(token, &from); - let to_balance_before_transfer = Assets::balance(token, &to); - assert_ok!(Fungibles::transfer_from(signed(spender), token, from, to, value)); - let from_balance_after_transfer = Assets::balance(token, &from); - let to_balance_after_transfer = Assets::balance(token, &to); + let from_balance_before_transfer = Assets::balance(token, &account(from)); + let to_balance_before_transfer = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::transfer_from( + signed(spender), + token, + account(from), + account(to), + value + )); + let from_balance_after_transfer = Assets::balance(token, &account(from)); + let to_balance_after_transfer = Assets::balance(token, &account(to)); // Check that `to` has received the `value` tokens from `from`. assert_eq!(to_balance_after_transfer, to_balance_before_transfer + value); assert_eq!(from_balance_after_transfer, from_balance_before_transfer - value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), + Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } + .into(), ); }); } @@ -144,7 +158,7 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, spender, value), + Fungibles::approve(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } @@ -161,20 +175,20 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, spender, value), + Fungibles::approve(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()` in `Greater` match arm. assert_noop!( - Fungibles::approve(signed(owner), token, spender, value), + Fungibles::approve(signed(owner), token, account(spender), value), AssetsError::Unknown.with_weight(WeightInfo::approve(1, 0)) ); assets::create_mint_and_approve(owner, token, owner, value, spender, value); // Check error works for `Assets::cancel_approval()` in `Less` match arm. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); @@ -193,38 +207,61 @@ mod approve { // Approves a value to spend that is higher than the current allowance. assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(Assets::allowance(token, &owner, &spender), 0); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); assert_eq!( - Fungibles::approve(signed(owner), token, spender, value), + Fungibles::approve(signed(owner), token, account(spender), value), Ok(Some(WeightInfo::approve(1, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value); - System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + System::assert_last_event( + Event::Approval { token, owner: account(owner), spender: account(spender), value } + .into(), + ); // Approves a value to spend that is lower than the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); // Approves a value to spend that is equal to the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); // Sets allowance to zero. assert_eq!( - Fungibles::approve(signed(owner), token, spender, 0), + Fungibles::approve(signed(owner), token, account(spender), 0), Ok(Some(WeightInfo::approve(0, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), 0); - System::assert_last_event(Event::Approval { token, owner, spender, value: 0 }.into()); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); + System::assert_last_event( + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: 0, + } + .into(), + ); }); } } @@ -239,25 +276,34 @@ fn increase_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::increase_allowance(origin, token, spender, value), + Fungibles::increase_allowance(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()`. assert_noop!( - Fungibles::increase_allowance(signed(owner), token, spender, value), + Fungibles::increase_allowance(signed(owner), token, account(spender), value), AssetsError::Unknown.with_weight(AssetsWeightInfo::approve_transfer()) ); assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(0, Assets::allowance(token, &owner, &spender)); - assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); - assert_eq!(Assets::allowance(token, &owner, &spender), value); - System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); + assert_eq!(0, Assets::allowance(token, &account(owner), &account(spender))); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + System::assert_last_event( + Event::Approval { token, owner: account(owner), spender: account(spender), value } + .into(), + ); // Additive. - assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); - assert_eq!(Assets::allowance(token, &owner, &spender), value * 2); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value * 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value * 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value * 2, + } + .into(), ); }); } @@ -272,40 +318,46 @@ fn decrease_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::decrease_allowance(origin, token, spender, 0), + Fungibles::decrease_allowance(origin, token, account(spender), 0), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } assets::create_mint_and_approve(owner, token, owner, value, spender, value); - assert_eq!(Assets::allowance(token, &owner, &spender), value); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); // Check error works for `Assets::cancel_approval()`. No error test for `approve_transfer` // because it is not possible. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // Owner balance is not changed if decreased by zero. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, spender, 0), + Fungibles::decrease_allowance(signed(owner), token, account(spender), 0), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); // "Unapproved" error is returned if the current allowance is less than amount to decrease // with. assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, spender, value * 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value * 2), AssetsError::Unapproved ); // Decrease allowance successfully. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); }); } @@ -318,14 +370,19 @@ fn create_works() { let admin = ALICE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::create(origin, id, admin, 100), BadOrigin); + assert_noop!(Fungibles::create(origin, id, account(admin), 100), BadOrigin); } assert!(!Assets::asset_exists(id)); - assert_ok!(Fungibles::create(signed(creator), id, admin, 100)); + assert_ok!(Fungibles::create(signed(creator), id, account(admin), 100)); assert!(Assets::asset_exists(id)); - System::assert_last_event(Event::Created { id, creator, admin }.into()); + System::assert_last_event( + Event::Created { id, creator: account(creator), admin: account(admin) }.into(), + ); // Check error works for `Assets::create()`. - assert_noop!(Fungibles::create(signed(creator), id, admin, 100), AssetsError::InUse); + assert_noop!( + Fungibles::create(signed(creator), id, account(admin), 100), + AssetsError::InUse + ); }); } @@ -336,11 +393,11 @@ fn start_destroy_works() { // Check error works for `Assets::start_destroy()`. assert_noop!(Fungibles::start_destroy(signed(ALICE), token), AssetsError::Unknown); - assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); assert_ok!(Fungibles::start_destroy(signed(ALICE), token)); // Check that the token is not live after starting the destroy process. assert_noop!( - Assets::mint(signed(ALICE), token, ALICE, 10 * UNIT), + Assets::mint(signed(ALICE), token, account(ALICE), 10 * UNIT), AssetsError::AssetNotLive ); }); @@ -359,7 +416,7 @@ fn set_metadata_works() { Fungibles::set_metadata(signed(ALICE), token, name.clone(), symbol.clone(), decimals), AssetsError::Unknown ); - assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); assert_ok!(Fungibles::set_metadata( signed(ALICE), token, @@ -398,16 +455,16 @@ fn mint_works() { // Check error works for `Assets::mint()`. assert_noop!( - Fungibles::mint(signed(from), token, to, value), + Fungibles::mint(signed(from), token, account(to), value), sp_runtime::TokenError::UnknownAsset ); - assert_ok!(Assets::create(signed(from), token, from, 1)); - let balance_before_mint = Assets::balance(token, &to); - assert_ok!(Fungibles::mint(signed(from), token, to, value)); - let balance_after_mint = Assets::balance(token, &to); + assert_ok!(Assets::create(signed(from), token, account(from), 1)); + let balance_before_mint = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::mint(signed(from), token, account(to), value)); + let balance_after_mint = Assets::balance(token, &account(to)); assert_eq!(balance_after_mint, balance_before_mint + value); System::assert_last_event( - Event::Transfer { token, from: None, to: Some(to), value }.into(), + Event::Transfer { token, from: None, to: Some(account(to)), value }.into(), ); }); } @@ -423,27 +480,30 @@ fn burn_works() { // "BalanceLow" error is returned if token is not created. assert_noop!( - Fungibles::burn(signed(owner), token, from, value), + Fungibles::burn(signed(owner), token, account(from), value), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); assets::create_and_mint_to(owner, token, from, total_supply); assert_eq!(Assets::total_supply(TOKEN), total_supply); // Check error works for `Assets::burn()`. assert_ok!(Assets::freeze_asset(signed(owner), token)); - assert_noop!(Fungibles::burn(signed(owner), token, from, value), AssetsError::AssetNotLive); + assert_noop!( + Fungibles::burn(signed(owner), token, account(from), value), + AssetsError::AssetNotLive + ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // "BalanceLow" error is returned if the balance is less than amount to burn. assert_noop!( - Fungibles::burn(signed(owner), token, from, total_supply * 2), + Fungibles::burn(signed(owner), token, account(from), total_supply * 2), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); - let balance_before_burn = Assets::balance(token, &from); - assert_ok!(Fungibles::burn(signed(owner), token, from, value)); + let balance_before_burn = Assets::balance(token, &account(from)); + assert_ok!(Fungibles::burn(signed(owner), token, account(from), value)); assert_eq!(Assets::total_supply(TOKEN), total_supply - value); - let balance_after_burn = Assets::balance(token, &from); + let balance_after_burn = Assets::balance(token, &account(from)); assert_eq!(balance_after_burn, balance_before_burn - value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: None, value }.into(), + Event::Transfer { token, from: Some(account(from)), to: None, value }.into(), ); }); } @@ -470,17 +530,17 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), ReadResult::BalanceOf(Default::default()) ); assets::create_and_mint_to(ALICE, TOKEN, ALICE, value); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), ReadResult::BalanceOf(value) ); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }).encode(), - Assets::balance(TOKEN, ALICE).encode(), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }).encode(), + Assets::balance(TOKEN, account(ALICE)).encode(), ); }); } @@ -490,17 +550,30 @@ fn allowance_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }), ReadResult::Allowance(Default::default()) ); assets::create_mint_and_approve(ALICE, TOKEN, ALICE, value * 2, BOB, value); assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }), ReadResult::Allowance(value) ); assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }).encode(), - Assets::allowance(TOKEN, &ALICE, &BOB).encode(), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }) + .encode(), + Assets::allowance(TOKEN, &account(ALICE), &account(BOB)).encode(), ); }); } @@ -534,7 +607,7 @@ fn token_metadata_works() { fn token_exists_works() { new_test_ext().execute_with(|| { assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(false)); - assert_ok!(Assets::create(signed(ALICE), TOKEN, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), TOKEN, account(ALICE), 1)); assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(true)); assert_eq!( Fungibles::read(TokenExists(TOKEN)).encode(), @@ -543,8 +616,8 @@ fn token_exists_works() { }); } -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) +fn signed(account_id: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(account(account_id)) } fn root() -> RuntimeOrigin { @@ -559,36 +632,31 @@ fn none() -> RuntimeOrigin { mod assets { use super::*; - pub(super) fn create_and_mint_to( - owner: AccountId, - token: TokenId, - to: AccountId, - value: Balance, - ) { - assert_ok!(Assets::create(signed(owner), token, owner, 1)); - assert_ok!(Assets::mint(signed(owner), token, to, value)); + pub(super) fn create_and_mint_to(owner: u8, token: TokenId, to: u8, value: Balance) { + assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); + assert_ok!(Assets::mint(signed(owner), token, account(to), value)); } pub(super) fn create_mint_and_approve( - owner: AccountId, + owner: u8, token: TokenId, - to: AccountId, + to: u8, mint: Balance, - spender: AccountId, + spender: u8, approve: Balance, ) { create_and_mint_to(owner, token, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), token, spender, approve,)); + assert_ok!(Assets::approve_transfer(signed(to), token, account(spender), approve,)); } pub(super) fn create_and_set_metadata( - owner: AccountId, + owner: u8, token: TokenId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), token, owner, 1)); + assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); assert_ok!(Assets::set_metadata(signed(owner), token, name, symbol, decimals)); } } @@ -613,11 +681,11 @@ mod read_weights { fn new() -> Self { Self { total_supply: Fungibles::weight(&TotalSupply(TOKEN)), - balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: ALICE }), + balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: account(ALICE) }), allowance: Fungibles::weight(&Allowance { token: TOKEN, - owner: ALICE, - spender: BOB, + owner: account(ALICE), + spender: account(BOB), }), token_name: Fungibles::weight(&TokenName(TOKEN)), token_symbol: Fungibles::weight(&TokenSymbol(TOKEN)), @@ -699,15 +767,15 @@ mod ensure_codec_indexes { [ (TotalSupply::(Default::default()), 0u8, "TotalSupply"), ( - BalanceOf:: { token: Default::default(), owner: Default::default() }, + BalanceOf:: { token: Default::default(), owner: account(Default::default()) }, 1, "BalanceOf", ), ( Allowance:: { token: Default::default(), - owner: Default::default(), - spender: Default::default(), + owner: account(Default::default()), + spender: account(Default::default()), }, 2, "Allowance", @@ -731,7 +799,7 @@ mod ensure_codec_indexes { ( transfer { token: Default::default(), - to: Default::default(), + to: account(Default::default()), value: Default::default(), }, 3u8, @@ -740,8 +808,8 @@ mod ensure_codec_indexes { ( transfer_from { token: Default::default(), - from: Default::default(), - to: Default::default(), + from: account(Default::default()), + to: account(Default::default()), value: Default::default(), }, 4, @@ -750,7 +818,7 @@ mod ensure_codec_indexes { ( approve { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 5, @@ -759,7 +827,7 @@ mod ensure_codec_indexes { ( increase_allowance { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 6, @@ -768,7 +836,7 @@ mod ensure_codec_indexes { ( decrease_allowance { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 7, @@ -777,7 +845,7 @@ mod ensure_codec_indexes { ( create { id: Default::default(), - admin: Default::default(), + admin: account(Default::default()), min_balance: Default::default(), }, 11, @@ -798,7 +866,7 @@ mod ensure_codec_indexes { ( mint { token: Default::default(), - account: Default::default(), + account: account(Default::default()), value: Default::default(), }, 19, @@ -807,7 +875,7 @@ mod ensure_codec_indexes { ( burn { token: Default::default(), - account: Default::default(), + account: account(Default::default()), value: Default::default(), }, 20, diff --git a/pallets/api/src/lib.rs b/pallets/api/src/lib.rs index d94d1978..e3d706e2 100644 --- a/pallets/api/src/lib.rs +++ b/pallets/api/src/lib.rs @@ -7,6 +7,7 @@ pub mod extension; pub mod fungibles; #[cfg(test)] mod mock; +pub mod nonfungibles; /// Trait for performing reads of runtime state. pub trait Read { diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 42c8bf0e..920d590f 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -1,25 +1,28 @@ use frame_support::{ derive_impl, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; +use pallet_nfts::PalletFeatures; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, MultiSignature, }; -pub(crate) const ALICE: AccountId = 1; -pub(crate) const BOB: AccountId = 2; -pub(crate) const CHARLIE: AccountId = 3; +pub(crate) const ALICE: u8 = 1; +pub(crate) const BOB: u8 = 2; +pub(crate) const CHARLIE: u8 = 3; pub(crate) const INIT_AMOUNT: Balance = 100_000_000 * UNIT; pub(crate) const UNIT: Balance = 10_000_000_000; type Block = frame_system::mocking::MockBlock; -pub(crate) type AccountId = u64; +pub(crate) type AccountId = ::AccountId; pub(crate) type Balance = u128; // For terminology in tests. pub(crate) type TokenId = u32; +type Signature = MultiSignature; +type AccountPublic = ::Signer; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -29,6 +32,8 @@ frame_support::construct_runtime!( Assets: pallet_assets::, Balances: pallet_balances, Fungibles: crate::fungibles, + Nfts: pallet_nfts, + NonFungibles: crate::nonfungibles } ); @@ -91,10 +96,10 @@ impl pallet_assets::Config for Test { #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); type CallbackHandle = (); - type CreateOrigin = AsEnsureOriginWithArg>; + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type Extra = (); - type ForceOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; @@ -110,13 +115,62 @@ impl crate::fungibles::Config for Test { type WeightInfo = (); } +parameter_types! { + pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); +} + +impl pallet_nfts::Config for Test { + type ApprovalsLimit = ConstU32<10>; + type AttributeDepositBase = ConstU128<1>; + type CollectionDeposit = ConstU128<2>; + type CollectionId = u32; + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = ConstU128<1>; + type Features = Features; + type ForceOrigin = frame_system::EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<2>; + type ItemDeposit = ConstU128<1>; + type ItemId = u32; + type KeyLimit = ConstU32<50>; + type Locker = (); + type MaxAttributesPerCall = ConstU32<2>; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxTips = ConstU32<10>; + type MetadataDepositBase = ConstU128<1>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; + /// Off-chain = signature On-chain - therefore no conversion needed. + /// It needs to be From for benchmarking. + type OffchainSignature = Signature; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; + type WeightInfo = (); +} + +impl crate::nonfungibles::Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +/// Initialize a new account ID. +pub(crate) fn account(id: u8) -> AccountId { + [id; 32].into() +} + pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default() .build_storage() .expect("Frame system builds valid default genesis config"); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, INIT_AMOUNT), (BOB, INIT_AMOUNT), (CHARLIE, INIT_AMOUNT)], + balances: vec![ + (account(ALICE), INIT_AMOUNT), + (account(BOB), INIT_AMOUNT), + (account(CHARLIE), INIT_AMOUNT), + ], } .assimilate_storage(&mut t) .expect("Pallet balances storage can be assimilated"); diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs new file mode 100644 index 00000000..cac0cbba --- /dev/null +++ b/pallets/api/src/nonfungibles/mod.rs @@ -0,0 +1,260 @@ +//! The non-fungibles pallet offers a streamlined interface for interacting with non-fungible +//! assets. The goal is to provide a simplified, consistent API that adheres to standards in the +//! smart contract space. + +use frame_support::traits::nonfungibles_v2::InspectEnumerable; +pub use pallet::*; +use pallet_nfts::WeightInfo; +use sp_runtime::traits::StaticLookup; + +#[cfg(test)] +mod tests; +mod types; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use sp_std::vec::Vec; + use types::{AccountIdOf, CollectionIdOf, ItemDetails, ItemIdOf, NftsOf, NftsWeightInfoOf}; + + use super::*; + + /// State reads for the fungibles API with required input. + #[derive(Encode, Decode, Debug, MaxEncodedLen)] + #[repr(u8)] + #[allow(clippy::unnecessary_cast)] + pub enum Read { + /// Returns the owner of an item. + #[codec(index = 0)] + OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, + /// Returns the owner of a collection. + #[codec(index = 1)] + CollectionOwner(CollectionIdOf), + /// Number of items existing in a concrete collection. + #[codec(index = 2)] + TotalSupply(CollectionIdOf), + /// Returns the total number of items in the collection owned by the account. + #[codec(index = 3)] + BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, + /// Returns the details of a collection. + #[codec(index = 4)] + Collection(CollectionIdOf), + /// Returns the details of an item. + #[codec(index = 5)] + Item { collection: CollectionIdOf, item: ItemIdOf }, + /// Whether a spender is allowed to transfer an item or items from owner. + #[codec(index = 6)] + Allowance { spender: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf }, + } + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config + pallet_nfts::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// The events that can be emitted. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Event emitted when allowance by `owner` to `spender` canceled. + CancelApproval { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The beneficiary of the allowance. + spender: AccountIdOf, + }, + /// Event emitted when allowance by `owner` to `spender` changes. + Approval { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The owner providing the allowance. + owner: AccountIdOf, + /// The beneficiary of the allowance. + spender: AccountIdOf, + }, + /// Event emitted when new item is minted to the account. + Mint { + /// The owner of the item. + to: AccountIdOf, + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + }, + /// Event emitted when item is burned. + Burn { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + }, + /// Event emitted when an item transfer occurs. + Transfer { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The source of the transfer. + from: AccountIdOf, + /// The recipient of the transfer. + to: AccountIdOf, + }, + } + + #[pallet::call] + impl Pallet { + /// Create a new non-fungible token to the collection. + /// + /// # Parameters + /// - `to` - The owner of the collection item. + /// - `collection` - The collection ID. + /// - `item` - The item ID. + #[pallet::call_index(0)] + #[pallet::weight(NftsWeightInfoOf::::mint())] + pub fn mint( + origin: OriginFor, + to: AccountIdOf, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::mint(origin, collection, item, T::Lookup::unlookup(to.clone()), None)?; + Self::deposit_event(Event::Mint { to, collection, item }); + Ok(()) + } + + /// Destroy a new non-fungible token to the collection. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + #[pallet::call_index(1)] + #[pallet::weight(NftsWeightInfoOf::::burn())] + pub fn burn( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::burn(origin, collection, item)?; + Self::deposit_event(Event::Burn { collection, item }); + Ok(()) + } + + /// Transfer a token from one account to the another account. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `to` - The recipient account. + #[pallet::call_index(2)] + #[pallet::weight(NftsWeightInfoOf::::transfer())] + pub fn transfer( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + to: AccountIdOf, + ) -> DispatchResult { + let from = ensure_signed(origin.clone())?; + NftsOf::::transfer(origin, collection, item, T::Lookup::unlookup(to.clone()))?; + Self::deposit_event(Event::Transfer { from, to, collection, item }); + Ok(()) + } + + /// Delegate a permission to perform actions on the collection item to an account. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `spender` - The account that is allowed to transfer the collection item. + #[pallet::call_index(3)] + #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] + pub fn approve( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> DispatchResult { + let owner = ensure_signed(origin.clone())?; + NftsOf::::approve_transfer( + origin, + collection, + item, + T::Lookup::unlookup(spender.clone()), + None, + )?; + Self::deposit_event(Event::Approval { collection, item, spender, owner }); + Ok(()) + } + + /// Cancel one of the transfer approvals for a specific item. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `spender` - The account that is revoked permission to transfer the collection item. + #[pallet::call_index(4)] + #[pallet::weight(NftsWeightInfoOf::::cancel_approval())] + pub fn cancel_approval( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> DispatchResult { + NftsOf::::cancel_approval( + origin, + collection, + item, + T::Lookup::unlookup(spender.clone()), + )?; + Self::deposit_event(Event::CancelApproval { collection, item, spender }); + Ok(()) + } + } + + impl Pallet { + /// Reads fungible asset state based on the provided value. + /// + /// This function matches the value to determine the type of state query and returns the + /// encoded result. + /// + /// # Parameter + /// - `value` - An instance of `Read`, which specifies the type of state query and the + /// associated parameters. + pub fn read_state(value: Read) -> Vec { + use Read::*; + match value { + OwnerOf { collection, item } => NftsOf::::owner(collection, item).encode(), + CollectionOwner(collection) => NftsOf::::collection_owner(collection).encode(), + TotalSupply(collection) => (NftsOf::::items(&collection).count() as u8).encode(), + Collection(collection) => pallet_nfts::Collection::::get(&collection).encode(), + Item { collection, item } => pallet_nfts::Item::::get(collection, item).encode(), + Allowance { collection, item, spender } => + Self::allowance(collection, item, spender).encode(), + BalanceOf { collection, owner } => + (NftsOf::::owned_in_collection(&collection, &owner).count() as u8).encode(), + } + } + + /// Check if the `spender` is approved to transfer the collection item + pub(super) fn allowance( + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> bool { + let data = pallet_nfts::Item::::get(collection, item).encode(); + if let Ok(detail) = ItemDetails::::decode(&mut data.as_slice()) { + return detail.approvals.contains_key(&spender); + } + false + } + } +} diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs new file mode 100644 index 00000000..9e9da5c2 --- /dev/null +++ b/pallets/api/src/nonfungibles/tests.rs @@ -0,0 +1,183 @@ +use codec::Encode; +use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; + +use super::types::*; +use crate::{ + mock::*, + nonfungibles::{Event, Read::*}, +}; + +const ITEM: u32 = 1; + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let collection = create_collection(owner.clone()); + // Successfully mint a new collection item. + assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); + System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + System::assert_last_event(Event::Burn { collection, item }.into()); + }); +} + +#[test] +fn transfer() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let dest = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + System::assert_last_event( + Event::Transfer { collection, item, from: owner, to: dest }.into(), + ); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully approve `spender` to transfer the collection item. + assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); + System::assert_last_event( + Event::Approval { collection, item, owner, spender: spender.clone() }.into(), + ); + // Successfully transfer the item by the delegated account `spender`. + assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); + }); +} + +#[test] +fn cancel_approval_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + // Successfully cancel the transfer approval of `spender` by `owner`. + assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); + // Failed to transfer the item by `spender` without permission. + assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + }); +} + +#[test] +fn owner_of_works() {} + +#[test] +fn collection_owner_works() { + new_test_ext().execute_with(|| { + let collection = create_collection(account(ALICE)); + assert_eq!( + NonFungibles::read_state(CollectionOwner(collection)), + Nfts::collection_owner(collection).encode() + ); + }); +} + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read_state(TotalSupply(collection)), + (Nfts::items(&collection).count() as u8).encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read_state(Collection(collection)), + pallet_nfts::Collection::::get(&collection).encode(), + ); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, _) = create_collection_mint(owner.clone(), ITEM); + assert_eq!( + NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), + (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() + ); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + assert_eq!( + NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), + super::Pallet::::allowance(collection, item, spender).encode() + ); + }); +} + +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) +} + +fn create_collection_mint_and_approve( + owner: AccountIdOf, + item: ItemIdOf, + spender: AccountIdOf, +) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner.clone(), item); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); + (collection, item) +} + +fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner.clone()); + assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); + (collection, item) +} + +fn create_collection(owner: AccountIdOf) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner.clone()), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + next_id +} + +fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() +} + +fn collection_config_with_all_settings_enabled( +) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs new file mode 100644 index 00000000..0174ef77 --- /dev/null +++ b/pallets/api/src/nonfungibles/types.rs @@ -0,0 +1,61 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; +use frame_system::pallet_prelude::BlockNumberFor; +use scale_info::TypeInfo; +use sp_runtime::BoundedBTreeMap; + +use super::Config; + +pub(super) type AccountIdOf = ::AccountId; + +pub(super) type NftsOf = pallet_nfts::Pallet; + +/// Weight information for extrinsics in this pallet. +pub(super) type NftsWeightInfoOf = ::WeightInfo; + +/// A type alias for the collection ID. +pub(super) type CollectionIdOf = + as Inspect<::AccountId>>::CollectionId; + +/// A type alias for the collection item ID. +pub(super) type ItemIdOf = + as Inspect<::AccountId>>::ItemId; + +// TODO: Even though this serves the `allowance` method, it creates the maintenance cost. + +/// A type that holds the deposit for a single item. +pub(super) type ItemDepositOf = + ItemDeposit, ::AccountId>; + +/// A type alias for handling balance deposits. +pub(super) type DepositBalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +/// A type alias for keeping track of approvals used by a single item. +pub(super) type ApprovalsOf = BoundedBTreeMap< + AccountIdOf, + Option>, + ::ApprovalsLimit, +>; + +/// Information concerning the ownership of a single unique item. +#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub(super) struct ItemDetails { + /// The owner of this item. + pub(super) owner: AccountIdOf, + /// The approved transferrer of this item, if one is set. + pub(super) approvals: ApprovalsOf, + /// The amount held in the pallet's default account for this item. Free-hold items will have + /// this as zero. + pub(super) deposit: ItemDepositOf, +} + +/// Information about the reserved item deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub struct ItemDeposit { + /// A depositor account. + pub(super) account: AccountId, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} From 4c0acaf6e907237b5fd51b4596148687e57baf86 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:12:39 +0700 Subject: [PATCH 04/64] chore: add nfts pallet --- Cargo.lock | 2 +- pallets/api/src/nonfungibles/mod.rs | 171 +++++++++--- pallets/api/src/nonfungibles/tests.rs | 367 +++++++++++++------------- pallets/api/src/nonfungibles/types.rs | 57 ++-- pallets/nfts/Cargo.toml | 1 - 5 files changed, 357 insertions(+), 241 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f98f910..ed534195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index cac0cbba..c5e8cffb 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -2,10 +2,9 @@ //! assets. The goal is to provide a simplified, consistent API that adheres to standards in the //! smart contract space. -use frame_support::traits::nonfungibles_v2::InspectEnumerable; pub use pallet::*; use pallet_nfts::WeightInfo; -use sp_runtime::traits::StaticLookup; +use sp_runtime::{traits::StaticLookup, RuntimeDebug}; #[cfg(test)] mod tests; @@ -16,12 +15,16 @@ pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_std::vec::Vec; - use types::{AccountIdOf, CollectionIdOf, ItemDetails, ItemIdOf, NftsOf, NftsWeightInfoOf}; + use types::{ + AccountIdOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, + NftsOf, NftsWeightInfoOf, + }; use super::*; - /// State reads for the fungibles API with required input. + /// State reads for the non-fungibles API with required input. #[derive(Encode, Decode, Debug, MaxEncodedLen)] + #[cfg_attr(feature = "std", derive(PartialEq, Clone))] #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { @@ -45,7 +48,41 @@ pub mod pallet { Item { collection: CollectionIdOf, item: ItemIdOf }, /// Whether a spender is allowed to transfer an item or items from owner. #[codec(index = 6)] - Allowance { spender: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf }, + Allowance { + collection: CollectionIdOf, + owner: AccountIdOf, + operator: AccountIdOf, + item: Option>, + }, + } + + /// Results of state reads for the non-fungibles API. + #[derive(Debug)] + #[cfg_attr(feature = "std", derive(PartialEq, Clone))] + pub enum ReadResult { + OwnerOf(Option>), + CollectionOwner(Option>), + TotalSupply(u32), + BalanceOf(BalanceOf), + Collection(Option>), + Item(Option>), + Allowance(bool), + } + + impl ReadResult { + /// Encodes the result. + pub fn encode(&self) -> Vec { + use ReadResult::*; + match self { + OwnerOf(result) => result.encode(), + CollectionOwner(result) => result.encode(), + TotalSupply(result) => result.encode(), + BalanceOf(result) => result.encode(), + Collection(result) => result.encode(), + Item(result) => result.encode(), + Allowance(result) => result.encode(), + } + } } /// Configure the pallet by specifying the parameters and types on which it depends. @@ -55,6 +92,32 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } + #[pallet::storage] + type AccountBalance = StorageNMap< + Key = ( + // Collection ID + NMapKey>, + // Collection Owner ID + NMapKey>, + ), + Value = BalanceOf, + QueryKind = ValueQuery, + >; + + #[pallet::storage] + type Allowances = StorageNMap< + Key = ( + // Collection ID + NMapKey>, + // Collection Owner ID + NMapKey>, + // Collection Operator ID + NMapKey>, + ), + Value = bool, + QueryKind = ValueQuery, + >; + #[pallet::pallet] pub struct Pallet(_); @@ -221,40 +284,86 @@ pub mod pallet { } impl Pallet { - /// Reads fungible asset state based on the provided value. - /// - /// This function matches the value to determine the type of state query and returns the - /// encoded result. - /// - /// # Parameter - /// - `value` - An instance of `Read`, which specifies the type of state query and the - /// associated parameters. - pub fn read_state(value: Read) -> Vec { - use Read::*; - match value { - OwnerOf { collection, item } => NftsOf::::owner(collection, item).encode(), - CollectionOwner(collection) => NftsOf::::collection_owner(collection).encode(), - TotalSupply(collection) => (NftsOf::::items(&collection).count() as u8).encode(), - Collection(collection) => pallet_nfts::Collection::::get(&collection).encode(), - Item { collection, item } => pallet_nfts::Item::::get(collection, item).encode(), - Allowance { collection, item, spender } => - Self::allowance(collection, item, spender).encode(), - BalanceOf { collection, owner } => - (NftsOf::::owned_in_collection(&collection, &owner).count() as u8).encode(), - } + /// Check if the `spender` is approved to transfer the collection item. + pub(super) fn allowance( + collection: CollectionIdOf, + owner: AccountIdOf, + operator: AccountIdOf, + maybe_item: Option>, + ) -> bool { + // Check if has a permission to transfer all collection items. + Allowances::::get((collection, owner, operator.clone())) || + maybe_item + .and_then(|item| Some(Self::allowance_item(collection, operator, item))) + .unwrap_or(false) } - /// Check if the `spender` is approved to transfer the collection item - pub(super) fn allowance( + // Check the permission for the single item. + pub(super) fn allowance_item( collection: CollectionIdOf, + operator: AccountIdOf, item: ItemIdOf, - spender: AccountIdOf, ) -> bool { let data = pallet_nfts::Item::::get(collection, item).encode(); - if let Ok(detail) = ItemDetails::::decode(&mut data.as_slice()) { - return detail.approvals.contains_key(&spender); + if let Ok(detail) = ItemDetailsFor::::decode(&mut data.as_slice()) { + return detail.approvals.contains_key(&operator); } false } } + + impl crate::Read for Pallet { + /// The type of read requested. + type Read = Read; + /// The type or result returned. + type Result = ReadResult; + + /// Determines the weight of the requested read, used to charge the appropriate weight + /// before the read is performed. + /// + /// # Parameters + /// - `request` - The read request. + fn weight(_request: &Self::Read) -> Weight { + Default::default() + } + + /// Performs the requested read and returns the result. + /// + /// # Parameters + /// - `request` - The read request. + fn read(value: Self::Read) -> Self::Result { + use Read::*; + match value { + OwnerOf { collection, item } => + ReadResult::OwnerOf(NftsOf::::owner(collection, item)), + CollectionOwner(collection) => + ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), + TotalSupply(collection) => { + let data = pallet_nfts::Collection::::get(collection).encode(); + ReadResult::TotalSupply( + CollectionDetailsFor::::decode(&mut data.as_slice()) + .map(|detail| detail.items) + .unwrap_or_default(), + ) + }, + Collection(collection) => { + let data = pallet_nfts::Collection::::get(collection).encode(); + ReadResult::Collection( + Option::>::decode(&mut data.as_slice()) + .unwrap_or(None), + ) + }, + Item { collection, item } => { + let data = pallet_nfts::Item::::get(collection, item).encode(); + ReadResult::Item( + Option::>::decode(&mut data.as_slice()).unwrap_or(None), + ) + }, + Allowance { collection, owner, operator, item } => + ReadResult::Allowance(Self::allowance(collection, owner, operator, item)), + BalanceOf { collection, owner } => + ReadResult::BalanceOf(AccountBalance::::get((collection, owner))), + } + } + } } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 9e9da5c2..54d85516 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,183 +1,184 @@ -use codec::Encode; -use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; -use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; - -use super::types::*; -use crate::{ - mock::*, - nonfungibles::{Event, Read::*}, -}; - -const ITEM: u32 = 1; - -#[test] -fn mint_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let collection = create_collection(owner.clone()); - // Successfully mint a new collection item. - assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); - System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); - }); -} - -#[test] -fn burn_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); - System::assert_last_event(Event::Burn { collection, item }.into()); - }); -} - -#[test] -fn transfer() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let dest = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); - System::assert_last_event( - Event::Transfer { collection, item, from: owner, to: dest }.into(), - ); - }); -} - -#[test] -fn approve_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully approve `spender` to transfer the collection item. - assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); - System::assert_last_event( - Event::Approval { collection, item, owner, spender: spender.clone() }.into(), - ); - // Successfully transfer the item by the delegated account `spender`. - assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); - }); -} - -#[test] -fn cancel_approval_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - // Successfully cancel the transfer approval of `spender` by `owner`. - assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); - // Failed to transfer the item by `spender` without permission. - assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); - }); -} - -#[test] -fn owner_of_works() {} - -#[test] -fn collection_owner_works() { - new_test_ext().execute_with(|| { - let collection = create_collection(account(ALICE)); - assert_eq!( - NonFungibles::read_state(CollectionOwner(collection)), - Nfts::collection_owner(collection).encode() - ); - }); -} - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); - assert_eq!( - NonFungibles::read_state(TotalSupply(collection)), - (Nfts::items(&collection).count() as u8).encode() - ); - }); -} - -#[test] -fn collection_works() { - new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); - assert_eq!( - NonFungibles::read_state(Collection(collection)), - pallet_nfts::Collection::::get(&collection).encode(), - ); - }); -} - -#[test] -fn balance_of_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, _) = create_collection_mint(owner.clone(), ITEM); - assert_eq!( - NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), - (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() - ); - }); -} - -#[test] -fn allowance_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - assert_eq!( - NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), - super::Pallet::::allowance(collection, item, spender).encode() - ); - }); -} - -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) -} - -fn create_collection_mint_and_approve( - owner: AccountIdOf, - item: ItemIdOf, - spender: AccountIdOf, -) -> (u32, u32) { - let (collection, item) = create_collection_mint(owner.clone(), item); - assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); - (collection, item) -} - -fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { - let collection = create_collection(owner.clone()); - assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); - (collection, item) -} - -fn create_collection(owner: AccountIdOf) -> u32 { - let next_id = next_collection_id(); - assert_ok!(Nfts::create( - signed(owner.clone()), - owner.clone(), - collection_config_with_all_settings_enabled() - )); - next_id -} - -fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() -} - -fn collection_config_with_all_settings_enabled( -) -> CollectionConfig, CollectionIdOf> { - CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: None, - mint_settings: MintSettings::default(), - } -} +// TODO +// use codec::Encode; +// use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +// use frame_system::pallet_prelude::BlockNumberFor; +// use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; + +// use super::types::*; +// use crate::{ +// mock::*, +// nonfungibles::{Event, Read::*}, +// }; + +// const ITEM: u32 = 1; + +// #[test] +// fn mint_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let collection = create_collection(owner.clone()); +// // Successfully mint a new collection item. +// assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); +// System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); +// }); +// } + +// #[test] +// fn burn_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully burn an existing new collection item. +// assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); +// System::assert_last_event(Event::Burn { collection, item }.into()); +// }); +// } + +// #[test] +// fn transfer() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let dest = account(BOB); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully burn an existing new collection item. +// assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); +// System::assert_last_event( +// Event::Transfer { collection, item, from: owner, to: dest }.into(), +// ); +// }); +// } + +// #[test] +// fn approve_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully approve `spender` to transfer the collection item. +// assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); +// System::assert_last_event( +// Event::Approval { collection, item, owner, spender: spender.clone() }.into(), +// ); +// // Successfully transfer the item by the delegated account `spender`. +// assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); +// }); +// } + +// #[test] +// fn cancel_approval_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = +// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); +// // Successfully cancel the transfer approval of `spender` by `owner`. +// assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); +// // Failed to transfer the item by `spender` without permission. +// assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); +// }); +// } + +// #[test] +// fn owner_of_works() {} + +// #[test] +// fn collection_owner_works() { +// new_test_ext().execute_with(|| { +// let collection = create_collection(account(ALICE)); +// assert_eq!( +// NonFungibles::read_state(CollectionOwner(collection)), +// Nfts::collection_owner(collection).encode() +// ); +// }); +// } + +// #[test] +// fn total_supply_works() { +// new_test_ext().execute_with(|| { +// let (collection, _) = create_collection_mint(account(ALICE), ITEM); +// assert_eq!( +// NonFungibles::read_state(TotalSupply(collection)), +// (Nfts::items(&collection).count() as u8).encode() +// ); +// }); +// } + +// #[test] +// fn collection_works() { +// new_test_ext().execute_with(|| { +// let (collection, _) = create_collection_mint(account(ALICE), ITEM); +// assert_eq!( +// NonFungibles::read_state(Collection(collection)), +// pallet_nfts::Collection::::get(&collection).encode(), +// ); +// }); +// } + +// #[test] +// fn balance_of_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let (collection, _) = create_collection_mint(owner.clone(), ITEM); +// assert_eq!( +// NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), +// (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() +// ); +// }); +// } + +// #[test] +// fn allowance_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = +// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); +// assert_eq!( +// NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), +// super::Pallet::::allowance(collection, item, spender).encode() +// ); +// }); +// } + +// fn signed(account: AccountId) -> RuntimeOrigin { +// RuntimeOrigin::signed(account) +// } + +// fn create_collection_mint_and_approve( +// owner: AccountIdOf, +// item: ItemIdOf, +// spender: AccountIdOf, +// ) -> (u32, u32) { +// let (collection, item) = create_collection_mint(owner.clone(), item); +// assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); +// (collection, item) +// } + +// fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { +// let collection = create_collection(owner.clone()); +// assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); +// (collection, item) +// } + +// fn create_collection(owner: AccountIdOf) -> u32 { +// let next_id = next_collection_id(); +// assert_ok!(Nfts::create( +// signed(owner.clone()), +// owner.clone(), +// collection_config_with_all_settings_enabled() +// )); +// next_id +// } + +// fn next_collection_id() -> u32 { +// pallet_nfts::NextCollectionId::::get().unwrap_or_default() +// } + +// fn collection_config_with_all_settings_enabled( +// ) -> CollectionConfig, CollectionIdOf> { +// CollectionConfig { +// settings: CollectionSettings::all_enabled(), +// max_supply: None, +// mint_settings: MintSettings::default(), +// } +// } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index 0174ef77..a55a8ec2 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -4,34 +4,22 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; use sp_runtime::BoundedBTreeMap; -use super::Config; +use super::*; pub(super) type AccountIdOf = ::AccountId; - pub(super) type NftsOf = pallet_nfts::Pallet; - /// Weight information for extrinsics in this pallet. pub(super) type NftsWeightInfoOf = ::WeightInfo; - /// A type alias for the collection ID. pub(super) type CollectionIdOf = - as Inspect<::AccountId>>::CollectionId; - + as Inspect<::AccountId>>::CollectionId; /// A type alias for the collection item ID. pub(super) type ItemIdOf = - as Inspect<::AccountId>>::ItemId; - -// TODO: Even though this serves the `allowance` method, it creates the maintenance cost. - -/// A type that holds the deposit for a single item. -pub(super) type ItemDepositOf = - ItemDeposit, ::AccountId>; - + as Inspect<::AccountId>>::ItemId; /// A type alias for handling balance deposits. -pub(super) type DepositBalanceOf = <::Currency as Currency< +pub(super) type BalanceOf = <::Currency as Currency< ::AccountId, >>::Balance; - /// A type alias for keeping track of approvals used by a single item. pub(super) type ApprovalsOf = BoundedBTreeMap< AccountIdOf, @@ -39,23 +27,42 @@ pub(super) type ApprovalsOf = BoundedBTreeMap< ::ApprovalsLimit, >; +pub(super) type ItemDetailsFor = ItemDetails, BalanceOf, ApprovalsOf>; +pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; + /// Information concerning the ownership of a single unique item. -#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] -pub(super) struct ItemDetails { +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountIdOf, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approvals: ApprovalsOf, + pub approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: ItemDepositOf, + pub deposit: Deposit, } - /// Information about the reserved item deposit. -#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub(super) account: AccountId, + account: AccountId, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + amount: DepositBalance, +} +/// Information about a collection. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectionDetails { + /// Collection's owner. + pub owner: AccountId, + /// The total balance deposited by the owner for all the storage data associated with this + /// collection. Used by `destroy`. + pub owner_deposit: DepositBalance, + /// The total number of outstanding items of this collection. + pub items: u32, + /// The total number of outstanding item metadata of this collection. + pub item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + pub item_configs: u32, + /// The total number of attributes for this collection. + pub attributes: u32, } diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index f23b50f0..7644a35b 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -9,7 +9,6 @@ readme = "README.md" repository.workspace = true version = "31.0.0" - [package.metadata.docs.rs] targets = [ "x86_64-unknown-linux-gnu" ] From b4420cb53585ce149f5cdfbe1937b617aad4df55 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:23:52 +0700 Subject: [PATCH 05/64] feat: add new storage items to pallet-nfts --- pallets/api/src/nonfungibles/mod.rs | 101 +++--------------- pallets/api/src/nonfungibles/types.rs | 68 +++--------- pallets/nfts/src/common_functions.rs | 7 +- pallets/nfts/src/features/approvals.rs | 85 ++++++++++++++- .../src/features/create_delete_collection.rs | 3 + .../nfts/src/features/create_delete_item.rs | 6 ++ pallets/nfts/src/features/transfer.rs | 8 ++ pallets/nfts/src/lib.rs | 88 ++++++++++++++- 8 files changed, 220 insertions(+), 146 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index c5e8cffb..cf2b14e7 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -4,7 +4,7 @@ pub use pallet::*; use pallet_nfts::WeightInfo; -use sp_runtime::{traits::StaticLookup, RuntimeDebug}; +use sp_runtime::traits::StaticLookup; #[cfg(test)] mod tests; @@ -16,8 +16,8 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_std::vec::Vec; use types::{ - AccountIdOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, - NftsOf, NftsWeightInfoOf, + AccountIdOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, NftsOf, + NftsWeightInfoOf, }; use super::*; @@ -63,7 +63,7 @@ pub mod pallet { OwnerOf(Option>), CollectionOwner(Option>), TotalSupply(u32), - BalanceOf(BalanceOf), + BalanceOf(u32), Collection(Option>), Item(Option>), Allowance(bool), @@ -92,32 +92,6 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } - #[pallet::storage] - type AccountBalance = StorageNMap< - Key = ( - // Collection ID - NMapKey>, - // Collection Owner ID - NMapKey>, - ), - Value = BalanceOf, - QueryKind = ValueQuery, - >; - - #[pallet::storage] - type Allowances = StorageNMap< - Key = ( - // Collection ID - NMapKey>, - // Collection Owner ID - NMapKey>, - // Collection Operator ID - NMapKey>, - ), - Value = bool, - QueryKind = ValueQuery, - >; - #[pallet::pallet] pub struct Pallet(_); @@ -283,35 +257,6 @@ pub mod pallet { } } - impl Pallet { - /// Check if the `spender` is approved to transfer the collection item. - pub(super) fn allowance( - collection: CollectionIdOf, - owner: AccountIdOf, - operator: AccountIdOf, - maybe_item: Option>, - ) -> bool { - // Check if has a permission to transfer all collection items. - Allowances::::get((collection, owner, operator.clone())) || - maybe_item - .and_then(|item| Some(Self::allowance_item(collection, operator, item))) - .unwrap_or(false) - } - - // Check the permission for the single item. - pub(super) fn allowance_item( - collection: CollectionIdOf, - operator: AccountIdOf, - item: ItemIdOf, - ) -> bool { - let data = pallet_nfts::Item::::get(collection, item).encode(); - if let Ok(detail) = ItemDetailsFor::::decode(&mut data.as_slice()) { - return detail.approvals.contains_key(&operator); - } - false - } - } - impl crate::Read for Pallet { /// The type of read requested. type Read = Read; @@ -338,31 +283,19 @@ pub mod pallet { ReadResult::OwnerOf(NftsOf::::owner(collection, item)), CollectionOwner(collection) => ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), - TotalSupply(collection) => { - let data = pallet_nfts::Collection::::get(collection).encode(); - ReadResult::TotalSupply( - CollectionDetailsFor::::decode(&mut data.as_slice()) - .map(|detail| detail.items) - .unwrap_or_default(), - ) - }, - Collection(collection) => { - let data = pallet_nfts::Collection::::get(collection).encode(); - ReadResult::Collection( - Option::>::decode(&mut data.as_slice()) - .unwrap_or(None), - ) - }, - Item { collection, item } => { - let data = pallet_nfts::Item::::get(collection, item).encode(); - ReadResult::Item( - Option::>::decode(&mut data.as_slice()).unwrap_or(None), - ) - }, - Allowance { collection, owner, operator, item } => - ReadResult::Allowance(Self::allowance(collection, owner, operator, item)), - BalanceOf { collection, owner } => - ReadResult::BalanceOf(AccountBalance::::get((collection, owner))), + TotalSupply(collection) => ReadResult::TotalSupply( + NftsOf::::collection_items(collection).unwrap_or_default(), + ), + Collection(collection) => + ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + Item { collection, item } => + ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + Allowance { collection, owner, operator, item } => ReadResult::Allowance( + NftsOf::::allowance(collection, item, owner, operator).unwrap_or(false), + ), + BalanceOf { collection, owner } => ReadResult::BalanceOf( + pallet_nfts::AccountBalance::::get((collection, owner)), + ), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index a55a8ec2..f81ea535 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,68 +1,28 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use scale_info::TypeInfo; +use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; use sp_runtime::BoundedBTreeMap; -use super::*; - -pub(super) type AccountIdOf = ::AccountId; +// Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; -/// Weight information for extrinsics in this pallet. pub(super) type NftsWeightInfoOf = ::WeightInfo; -/// A type alias for the collection ID. +// Type aliases for pallet-nfts storage items. +pub(super) type AccountIdOf = ::AccountId; +pub(super) type BalanceOf = <>::Currency as Currency< + ::AccountId, +>>::Balance; pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; -/// A type alias for the collection item ID. pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -/// A type alias for handling balance deposits. -pub(super) type BalanceOf = <::Currency as Currency< - ::AccountId, ->>::Balance; -/// A type alias for keeping track of approvals used by a single item. -pub(super) type ApprovalsOf = BoundedBTreeMap< +type ApprovalsOf = BoundedBTreeMap< AccountIdOf, Option>, ::ApprovalsLimit, >; - -pub(super) type ItemDetailsFor = ItemDetails, BalanceOf, ApprovalsOf>; -pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; - -/// Information concerning the ownership of a single unique item. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ItemDetails { - /// The owner of this item. - pub owner: AccountId, - /// The approved transferrer of this item, if one is set. - pub approvals: Approvals, - /// The amount held in the pallet's default account for this item. Free-hold items will have - /// this as zero. - pub deposit: Deposit, -} -/// Information about the reserved item deposit. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ItemDeposit { - /// A depositor account. - account: AccountId, - /// An amount that gets reserved. - amount: DepositBalance, -} -/// Information about a collection. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct CollectionDetails { - /// Collection's owner. - pub owner: AccountId, - /// The total balance deposited by the owner for all the storage data associated with this - /// collection. Used by `destroy`. - pub owner_deposit: DepositBalance, - /// The total number of outstanding items of this collection. - pub items: u32, - /// The total number of outstanding item metadata of this collection. - pub item_metadatas: u32, - /// The total number of outstanding item configs of this collection. - pub item_configs: u32, - /// The total number of attributes for this collection. - pub attributes: u32, -} +// TODO: Multi-instances. +pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; +pub(super) type CollectionDetailsFor = + CollectionDetails, BalanceOf>; +pub(super) type ItemDetailsFor = + ItemDetails, ItemDepositOf, ApprovalsOf>; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index f51de192..6fe483f1 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,6 +34,11 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.owner) } + /// Get the total number of items in the collection, if the collection exists. + pub fn collection_items(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.items) + } + /// Validates the signature of the given data with the provided signer's account ID. /// /// # Errors @@ -46,7 +51,7 @@ impl, I: 'static> Pallet { signer: &T::AccountId, ) -> DispatchResult { if signature.verify(&**data, &signer) { - return Ok(()) + return Ok(()); } // NOTE: for security reasons modern UIs implicitly wrap the data requested to sign into diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ad5d93c2..f626a9fe 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -65,7 +65,6 @@ impl, I: 'static> Pallet { if let Some(check_origin) = maybe_check_origin { ensure!(check_origin == details.owner, Error::::NoPermission); } - let now = frame_system::Pallet::::block_number(); let deadline = maybe_deadline.map(|d| d.saturating_add(now)); @@ -74,15 +73,13 @@ impl, I: 'static> Pallet { .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; Item::::insert(&collection, &item, &details); - Self::deposit_event(Event::TransferApproved { collection, - item, + item: Some(item), owner: details.owner, delegate, deadline, }); - Ok(()) } @@ -129,7 +126,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::ApprovalCancelled { collection, - item, + item: Some(item), owner: details.owner, delegate, }); @@ -173,4 +170,82 @@ impl, I: 'static> Pallet { Ok(()) } + + pub(crate) fn do_approve_transfer_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + let collection_owner = + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == collection_owner, Error::::NoPermission); + } + + Allowances::::mutate((&collection, &collection_owner, &delegate), |allowance| { + *allowance = true; + }); + + Self::deposit_event(Event::TransferApproved { + collection, + item: None, + owner: collection_owner, + delegate, + deadline: None, + }); + Ok(()) + } + + pub(crate) fn do_cancel_approval_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + let collection_owner = + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == collection_owner, Error::::NoPermission); + } + + Allowances::::remove((&collection, &collection_owner, &delegate)); + + Self::deposit_event(Event::ApprovalCancelled { + collection, + owner: collection_owner, + item: None, + delegate, + }); + + Ok(()) + } + + pub fn allowance( + collection: T::CollectionId, + item: Option, + owner: T::AccountId, + delegate: T::AccountId, + ) -> Option { + // Check if a `delegate` has a permission to spend the collection. + if Allowances::::get((&collection, &owner, &delegate)) { + return Some(true); + } + // Check if a `delegate` has a permission to spend the collection item. + item.map(|item| { + Item::::get(&collection, &item) + .map(|detail| detail.approvals.contains_key(&delegate)) + }) + .unwrap_or_default() + } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..2ea5cd73 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -137,6 +137,9 @@ impl, I: 'static> Pallet { } } + let _ = + AccountBalance::::clear_prefix((collection,), collection_details.items, None); + let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); CollectionConfigOf::::remove(&collection); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9843b2e..036a63b7 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,6 +69,9 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); + AccountBalance::::mutate((collection, &mint_to), |balance| { + balance.saturating_inc(); + }); let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config @@ -263,6 +266,9 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); ItemAttributesApprovalsOf::::remove(&collection, &item); + AccountBalance::::mutate((collection, &owner), |balance| { + balance.saturating_dec(); + }); if remove_config { ItemConfigOf::::remove(&collection, &item); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index b7223a7c..0aa83fe8 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -87,6 +87,14 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; + // Update account balances. + AccountBalance::::mutate((collection, &details.owner), |balance| { + balance.saturating_dec(); + }); + AccountBalance::::mutate((collection, &dest), |balance| { + balance.saturating_dec(); + }); + // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 89bfb963..9f4d3aed 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -402,6 +402,36 @@ pub mod pallet { pub type CollectionConfigOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; + /// Number of collection items that accounts own. + #[pallet::storage] + pub type AccountBalance, I: 'static = ()> = StorageNMap< + _, + ( + // Collection Id. + NMapKey, + // Collection Owner Id. + NMapKey, + ), + u32, + ValueQuery, + >; + + /// Permission for the delegate to transfer all owner's items within a collection. + #[pallet::storage] + pub type Allowances, I: 'static = ()> = StorageNMap< + _, + ( + // Collection ID. + NMapKey, + // Collection Owner Id. + NMapKey, + // Delegate Id. + NMapKey, + ), + bool, + ValueQuery, + >; + /// Config of an item. #[pallet::storage] pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< @@ -460,7 +490,7 @@ pub mod pallet { /// a `delegate`. TransferApproved { collection: T::CollectionId, - item: T::ItemId, + item: Option, owner: T::AccountId, delegate: T::AccountId, deadline: Option>, @@ -469,7 +499,7 @@ pub mod pallet { /// `collection` was cancelled by its `owner`. ApprovalCancelled { collection: T::CollectionId, - item: T::ItemId, + item: Option, owner: T::AccountId, delegate: T::AccountId, }, @@ -1931,6 +1961,60 @@ pub mod pallet { Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } + + /// Approve an item to be transferred by a delegated third-party account. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `item`. + /// + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `item`: The item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer the item. + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(39)] + #[pallet::weight(T::WeightInfo::approve_transfer())] + pub fn approve_transfer_collection( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate) + } + + /// Cancel one of the transfer approvals for a specific item. + /// + /// Origin must be either: + /// - the `Force` origin; + /// - `Signed` with the signer being the Owner of the `item`; + /// + /// Arguments: + /// - `collection`: The collection of the item of whose approval will be cancelled. + /// - `item`: The item of the collection of whose approval will be cancelled. + /// - `delegate`: The account that is going to loose their approval. + /// + /// Emits `ApprovalCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(40)] + #[pallet::weight(T::WeightInfo::cancel_approval())] + pub fn cancel_approval_collection( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate) + } } } From 0ad3e31366e21fdaa2d4b61dd26f5cd8f73f4119 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 16 Oct 2024 22:30:14 +0700 Subject: [PATCH 06/64] feat: check allowance --- pallets/api/src/nonfungibles/mod.rs | 102 +++++++------------------ pallets/nfts/src/features/approvals.rs | 28 ++++--- pallets/nfts/src/features/transfer.rs | 6 +- pallets/nfts/src/lib.rs | 94 ++++++----------------- pallets/nfts/src/tests.rs | 93 +++++++++++++--------- 5 files changed, 128 insertions(+), 195 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index cf2b14e7..bc728ac8 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -62,7 +62,7 @@ pub mod pallet { pub enum ReadResult { OwnerOf(Option>), CollectionOwner(Option>), - TotalSupply(u32), + TotalSupply(u128), BalanceOf(u32), Collection(Option>), Item(Option>), @@ -99,25 +99,18 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event emitted when allowance by `owner` to `spender` canceled. - CancelApproval { - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - /// The beneficiary of the allowance. - spender: AccountIdOf, - }, - /// Event emitted when allowance by `owner` to `spender` changes. + /// Event emitted when allowance by `owner` to `operator` changes. Approval { /// The collection ID. collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, /// The owner providing the allowance. owner: AccountIdOf, /// The beneficiary of the allowance. - spender: AccountIdOf, + operator: AccountIdOf, + /// The item which is (dis)approved. `None` for all owner's items. + item: Option>, + /// Whether allowance is set or removed. + approved: bool, }, /// Event emitted when new item is minted to the account. Mint { @@ -150,12 +143,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Create a new non-fungible token to the collection. - /// - /// # Parameters - /// - `to` - The owner of the collection item. - /// - `collection` - The collection ID. - /// - `item` - The item ID. #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -169,11 +156,6 @@ pub mod pallet { Ok(()) } - /// Destroy a new non-fungible token to the collection. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. #[pallet::call_index(1)] #[pallet::weight(NftsWeightInfoOf::::burn())] pub fn burn( @@ -186,12 +168,6 @@ pub mod pallet { Ok(()) } - /// Transfer a token from one account to the another account. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `to` - The recipient account. #[pallet::call_index(2)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( @@ -206,53 +182,33 @@ pub mod pallet { Ok(()) } - /// Delegate a permission to perform actions on the collection item to an account. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `spender` - The account that is allowed to transfer the collection item. #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] pub fn approve( origin: OriginFor, collection: CollectionIdOf, - item: ItemIdOf, - spender: AccountIdOf, + item: Option>, + operator: AccountIdOf, + approved: bool, ) -> DispatchResult { let owner = ensure_signed(origin.clone())?; - NftsOf::::approve_transfer( - origin, - collection, - item, - T::Lookup::unlookup(spender.clone()), - None, - )?; - Self::deposit_event(Event::Approval { collection, item, spender, owner }); - Ok(()) - } - - /// Cancel one of the transfer approvals for a specific item. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `spender` - The account that is revoked permission to transfer the collection item. - #[pallet::call_index(4)] - #[pallet::weight(NftsWeightInfoOf::::cancel_approval())] - pub fn cancel_approval( - origin: OriginFor, - collection: CollectionIdOf, - item: ItemIdOf, - spender: AccountIdOf, - ) -> DispatchResult { - NftsOf::::cancel_approval( - origin, - collection, - item, - T::Lookup::unlookup(spender.clone()), - )?; - Self::deposit_event(Event::CancelApproval { collection, item, spender }); + if approved { + NftsOf::::approve_transfer( + origin, + collection, + item, + T::Lookup::unlookup(operator.clone()), + None, + )?; + } else { + NftsOf::::cancel_approval( + origin, + collection, + item, + T::Lookup::unlookup(operator.clone()), + )?; + } + Self::deposit_event(Event::Approval { collection, item, operator, owner, approved }); Ok(()) } } @@ -284,14 +240,14 @@ pub mod pallet { CollectionOwner(collection) => ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default(), + NftsOf::::collection_items(collection).unwrap_or_default().into(), ), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( - NftsOf::::allowance(collection, item, owner, operator).unwrap_or(false), + NftsOf::::allowance(&collection, &item, &owner, &operator).is_ok(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index f626a9fe..979035fa 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -232,20 +232,26 @@ impl, I: 'static> Pallet { } pub fn allowance( - collection: T::CollectionId, - item: Option, - owner: T::AccountId, - delegate: T::AccountId, - ) -> Option { + collection: &T::CollectionId, + item: &Option, + owner: &T::AccountId, + delegate: &T::AccountId, + ) -> Result<(), DispatchError> { // Check if a `delegate` has a permission to spend the collection. if Allowances::::get((&collection, &owner, &delegate)) { - return Some(true); + return Ok(()); } // Check if a `delegate` has a permission to spend the collection item. - item.map(|item| { - Item::::get(&collection, &item) - .map(|detail| detail.approvals.contains_key(&delegate)) - }) - .unwrap_or_default() + if let Some(item) = item { + let details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + let deadline = details.approvals.get(&delegate).ok_or(Error::::NoPermission)?; + if let Some(d) = deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *d, Error::::ApprovalExpired); + } + }; + Ok(()) } } diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 0aa83fe8..04d9f4fe 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -92,7 +92,7 @@ impl, I: 'static> Pallet { balance.saturating_dec(); }); AccountBalance::::mutate((collection, &dest), |balance| { - balance.saturating_dec(); + balance.saturating_inc(); }); // Update account ownership information. @@ -145,7 +145,7 @@ impl, I: 'static> Pallet { // Check if the `origin` is the current owner of the collection. ensure!(origin == details.owner, Error::::NoPermission); if details.owner == new_owner { - return Ok(()) + return Ok(()); } // Move the deposit to the new owner. @@ -220,7 +220,7 @@ impl, I: 'static> Pallet { Collection::::try_mutate(collection, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; if details.owner == owner { - return Ok(()) + return Ok(()); } // Move the deposit to the new owner. diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 9f4d3aed..14689293 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1060,12 +1060,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - let deadline = - details.approvals.get(&origin).ok_or(Error::::NoPermission)?; - if let Some(d) = deadline { - let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *d, Error::::ApprovalExpired); - } + Self::allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1120,10 +1115,10 @@ pub mod pallet { if T::Currency::reserve(&details.deposit.account, deposit - old).is_err() { // NOTE: No alterations made to collection_details in this iteration so far, // so this is OK to do. - continue + continue; } } else { - continue + continue; } details.deposit.amount = deposit; Item::::insert(&collection, &item, &details); @@ -1322,7 +1317,7 @@ pub mod pallet { pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1330,13 +1325,17 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ) + match maybe_item { + Some(item) => Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ), + None => + Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate), + } } /// Cancel one of the transfer approvals for a specific item. @@ -1358,14 +1357,19 @@ pub mod pallet { pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) + match maybe_item { + Some(item) => + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), + None => + Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate), + } } /// Cancel all the approvals of a specific item. @@ -1961,60 +1965,6 @@ pub mod pallet { Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } - - /// Approve an item to be transferred by a delegated third-party account. - /// - /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// `item`. - /// - /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `item`: The item to be approved for delegated transfer. - /// - `delegate`: The account to delegate permission to transfer the item. - /// - /// Emits `TransferApproved` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(39)] - #[pallet::weight(T::WeightInfo::approve_transfer())] - pub fn approve_transfer_collection( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - let maybe_check_origin = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate) - } - - /// Cancel one of the transfer approvals for a specific item. - /// - /// Origin must be either: - /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item`; - /// - /// Arguments: - /// - `collection`: The collection of the item of whose approval will be cancelled. - /// - `item`: The item of the collection of whose approval will be cancelled. - /// - `delegate`: The account that is going to loose their approval. - /// - /// Emits `ApprovalCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(40)] - #[pallet::weight(T::WeightInfo::cancel_approval())] - pub fn cancel_approval_collection( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - let maybe_check_origin = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate) - } } } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 44f2f32a..4002c48e 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -487,7 +487,7 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - 42, + Some(42), account(2), None )); @@ -1777,7 +1777,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); @@ -1791,7 +1791,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(2), None )); @@ -1819,7 +1819,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - 1, + Some(1), account(2), None ), @@ -1847,30 +1847,35 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, Some(42), account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3) + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), Error::::NotDelegate ); @@ -1887,18 +1892,23 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, Some(42), account(3)), Error::::NoPermission ); System::set_block_number(current_block + 3); // 5 can cancel the approval since the deadline has passed. - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(5)), + 0, + Some(42), + account(3) + )); assert_eq!(approvals(0, 69), vec![]); }); } @@ -1924,21 +1934,21 @@ fn approving_multiple_accounts_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(4), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(5), Some(2) )); @@ -1979,14 +1989,20 @@ fn approvals_limit_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(i), None )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), + Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(14), + None + ), Error::::ReachedApprovalLimit ); }); @@ -2015,7 +2031,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); @@ -2034,7 +2050,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(6), Some(4) )); @@ -2063,26 +2079,31 @@ fn cancel_approval_works_with_admin() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3) + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(1)), Error::::NotDelegate ); }); @@ -2107,26 +2128,26 @@ fn cancel_approval_works_with_force() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, Some(42), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(43), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(1)), Error::::NotDelegate ); }); @@ -2151,14 +2172,14 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(4), None )); @@ -3169,7 +3190,7 @@ fn pallet_level_feature_flags_should_work() { Nfts::approve_transfer( RuntimeOrigin::signed(user_id.clone()), collection_id, - item_id, + Some(item_id), account(2), None ), From cf363a2f60cf454f8b15d605a00e4b5b93cf2054 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:03:43 +0700 Subject: [PATCH 07/64] test(nfts): check account balance & test total supply --- pallets/nfts/src/tests.rs | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4002c48e..f75c25d8 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,6 +164,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -173,6 +174,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); + assert_eq!(AccountBalance::::get((1, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } @@ -204,6 +206,7 @@ fn lifecycle_should_work() { account(10), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(10))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 6); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), @@ -212,8 +215,10 @@ fn lifecycle_should_work() { account(20), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(20))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 7); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); @@ -221,6 +226,8 @@ fn lifecycle_should_work() { assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); + assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -238,6 +245,7 @@ fn lifecycle_should_work() { Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), Error::::CollectionNotEmpty ); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(account(1)), @@ -248,7 +256,9 @@ fn lifecycle_should_work() { bvec![0], )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); + assert_eq!(AccountBalance::::get((0, account(10))), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); + assert_eq!(AccountBalance::::get((0, account(10))), 0); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -256,6 +266,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -305,6 +316,7 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -323,6 +335,7 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -337,6 +350,7 @@ fn mint_should_work() { default_collection_config() )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -402,6 +416,7 @@ fn mint_should_work() { account(2), Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -440,6 +455,7 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); + assert_eq!(AccountBalance::::get((1, account(2))), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -478,6 +494,8 @@ fn transfer_should_work() { )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_eq!(AccountBalance::::get((0, account(2))), 0); + assert_eq!(AccountBalance::::get((0, account(3))), 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -492,7 +510,9 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - + assert_eq!(AccountBalance::::get((0, account(2))), 0); + assert_eq!(AccountBalance::::get((0, account(3))), 0); + assert_eq!(AccountBalance::::get((0, account(4))), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1746,15 +1766,17 @@ fn burn_works() { account(5), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(5))), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), Error::::NoPermission ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); + assert_eq!(AccountBalance::::get((0, account(5))), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); + assert_eq!(AccountBalance::::get((0, account(5))), 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2209,6 +2231,36 @@ fn clear_all_transfer_approvals_works() { }); } +#[test] +fn total_supply_should_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = account(1); + let total_items = 10; + + // no collection. + assert_eq!(Nfts::collection_items(collection_id), None); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + + // mint items and validate the total supply. + (0..total_items).into_iter().for_each(|i| { + assert_ok!(Nfts::force_mint( + RuntimeOrigin::root(), + collection_id, + i, + user_id.clone(), + ItemConfig::default() + )); + }); + assert_eq!(Nfts::collection_items(collection_id), Some(total_items)); + }); +} + #[test] fn max_supply_should_work() { new_test_ext().execute_with(|| { @@ -2545,6 +2597,7 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -2912,6 +2965,8 @@ fn claim_swap_should_work() { default_item_config(), )); + assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3002,6 +3057,8 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); + assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); From 24495972ec2e4d17de9acc256f92635186cd35c3 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:39:53 +0700 Subject: [PATCH 08/64] test(nfts): allowance works --- pallets/api/src/nonfungibles/mod.rs | 2 +- pallets/nfts/src/features/approvals.rs | 8 +++- pallets/nfts/src/lib.rs | 2 +- pallets/nfts/src/tests.rs | 57 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index bc728ac8..4b6558e9 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -247,7 +247,7 @@ pub mod pallet { Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( - NftsOf::::allowance(&collection, &item, &owner, &operator).is_ok(), + NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 979035fa..89b8fc6a 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -231,7 +231,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub fn allowance( + pub fn check_allowance( collection: &T::CollectionId, item: &Option, owner: &T::AccountId, @@ -239,6 +239,9 @@ impl, I: 'static> Pallet { ) -> Result<(), DispatchError> { // Check if a `delegate` has a permission to spend the collection. if Allowances::::get((&collection, &owner, &delegate)) { + if let Some(item) = item { + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + }; return Ok(()); } // Check if a `delegate` has a permission to spend the collection item. @@ -251,7 +254,8 @@ impl, I: 'static> Pallet { let block_number = frame_system::Pallet::::block_number(); ensure!(block_number <= *d, Error::::ApprovalExpired); } + return Ok(()); }; - Ok(()) + Err(Error::::NoPermission.into()) } } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 14689293..c7d826b5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1060,7 +1060,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::allowance(&collection, &Some(item), &details.owner, &origin)?; + Self::check_allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index f75c25d8..5ad13e6e 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1850,6 +1850,63 @@ fn approval_lifecycle_works() { }); } +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(2), + None + )); + + // collection transfer approved. + assert_noop!( + Nfts::check_allowance(&0, &Some(43), &account(1), &account(2)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(1), &account(3)), + Error::::NoPermission + ); + assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(2))); + assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(1), &account(2))); + + // collection item transfer approved. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3), + None + )); + + assert_noop!( + Nfts::check_allowance(&0, &Some(43), &account(2), &account(3)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(2), &account(4)), + Error::::NoPermission + ); + assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(2), &account(3))); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { From 9de384ea091145b9e4b1563be0bc473c4f28640f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:40:34 +0700 Subject: [PATCH 09/64] refactor(test): check_allowance_works --- pallets/nfts/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 5ad13e6e..9c3cce0d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1851,7 +1851,7 @@ fn approval_lifecycle_works() { } #[test] -fn allowance_works() { +fn check_allowance_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), From 58d4c92587fc85ae6291044302846aa12737c018 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:18:49 +0700 Subject: [PATCH 10/64] fix(nfts): cancel / approve collection transfer --- pallets/nfts/src/features/approvals.rs | 27 ++++------ pallets/nfts/src/tests.rs | 72 ++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 89b8fc6a..05696fee 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -180,27 +180,24 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let collection_owner = - Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - + if !Collection::::contains_key(collection) { + return Err(Error::::UnknownCollection.into()); + } let collection_config = Self::get_collection_config(&collection)?; ensure!( collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == collection_owner, Error::::NoPermission); - } - - Allowances::::mutate((&collection, &collection_owner, &delegate), |allowance| { + let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; + Allowances::::mutate((&collection, &origin, &delegate), |allowance| { *allowance = true; }); Self::deposit_event(Event::TransferApproved { collection, item: None, - owner: collection_owner, + owner: origin, delegate, deadline: None, }); @@ -212,18 +209,16 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let collection_owner = - Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == collection_owner, Error::::NoPermission); + if !Collection::::contains_key(collection) { + return Err(Error::::UnknownCollection.into()); } - Allowances::::remove((&collection, &collection_owner, &delegate)); + let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; + Allowances::::remove((&collection, &origin, &delegate)); Self::deposit_event(Event::ApprovalCancelled { collection, - owner: collection_owner, + owner: origin, item: None, delegate, }); diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 9c3cce0d..07f2a74d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1876,12 +1876,12 @@ fn check_allowance_works() { // collection transfer approved. assert_noop!( - Nfts::check_allowance(&0, &Some(43), &account(1), &account(2)), - Error::::UnknownItem + Nfts::check_allowance(&1, &None, &account(1), &account(2)), + Error::::NoPermission ); assert_noop!( - Nfts::check_allowance(&0, &Some(42), &account(1), &account(3)), - Error::::NoPermission + Nfts::check_allowance(&1, &Some(43), &account(1), &account(2)), + Error::::UnknownItem ); assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(2))); assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(1), &account(2))); @@ -1992,6 +1992,43 @@ fn cancel_approval_works() { }); } +#[test] +fn cancel_approval_collection_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + None, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), + Error::::NoPermission + ); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -2087,6 +2124,33 @@ fn approvals_limit_works() { }); } +#[test] +fn approval_collection_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(3), + None + )); + assert_eq!(Allowances::::get((0, account(1), account(3))), true); + }); +} + #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { From df1f6a6537217d5ec19b028945f763f085c72382 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:17:38 +0700 Subject: [PATCH 11/64] test(nfts): cancel approval collection --- pallets/nfts/src/tests.rs | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 07f2a74d..4fbec4de 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2021,6 +2021,13 @@ fn cancel_approval_collection_works() { ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: 0, + item: None, + owner: account(2), + delegate: account(3) + })); + assert_eq!(Allowances::::get((0, account(2), account(3))), false); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2127,6 +2134,11 @@ fn approvals_limit_works() { #[test] fn approval_collection_works() { new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2140,14 +2152,47 @@ fn approval_collection_works() { default_item_config() )); - assert_ok!(Nfts::approve_transfer( + // Error::ItemsNonTransferable. + assert_ok!(Nfts::lock_collection( RuntimeOrigin::signed(account(1)), + 1, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), + Error::::ItemsNonTransferable + ); + + // Error::MethodDisabled. + Features::set(&PalletFeatures::from_disabled(PalletFeature::Approvals.into())); + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), + Error::::MethodDisabled + ); + Features::set(&PalletFeatures::all_enabled()); + + // Error::UnknownCollection. + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), 0, None, account(3), None )); - assert_eq!(Allowances::::get((0, account(1), account(3))), true); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: account(2), + delegate: account(3), + deadline: None + })); + assert_eq!(Allowances::::get((0, account(2), account(3))), true); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } From fea02597f558c0a6369fdd14c49a9fed2a87123a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:23:23 +0700 Subject: [PATCH 12/64] test(nfts): update approval test cases --- pallets/nfts/src/tests.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4fbec4de..10c95bd6 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1993,7 +1993,7 @@ fn cancel_approval_works() { } #[test] -fn cancel_approval_collection_works() { +fn cancel_approval_collection_works_with_admin() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2132,7 +2132,7 @@ fn approvals_limit_works() { } #[test] -fn approval_collection_works() { +fn approval_collection_works_with_admin() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2163,14 +2163,6 @@ fn approval_collection_works() { Error::::ItemsNonTransferable ); - // Error::MethodDisabled. - Features::set(&PalletFeatures::from_disabled(PalletFeature::Approvals.into())); - assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), - Error::::MethodDisabled - ); - Features::set(&PalletFeatures::all_enabled()); - // Error::UnknownCollection. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), From 84a7fe340dae20ac1e3e214de899975ba2e97a17 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:18:20 +0700 Subject: [PATCH 13/64] feat(nfts): get attribute read method --- pallets/api/src/nonfungibles/mod.rs | 105 ++++++++++++++++++-------- pallets/api/src/nonfungibles/types.rs | 6 +- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 4b6558e9..83d23585 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -14,10 +14,11 @@ mod types; pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; + use pallet_nfts::MintWitness; use sp_std::vec::Vec; use types::{ - AccountIdOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, NftsOf, - NftsWeightInfoOf, + AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, + ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -54,6 +55,14 @@ pub mod pallet { operator: AccountIdOf, item: Option>, }, + /// Returns the attribute of `item` for the given `key`. + #[codec(index = 6)] + GetAttribute { + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + }, } /// Results of state reads for the non-fungibles API. @@ -67,6 +76,7 @@ pub mod pallet { Collection(Option>), Item(Option>), Allowance(bool), + GetAttribute(Option>), } impl ReadResult { @@ -81,6 +91,7 @@ pub mod pallet { Collection(result) => result.encode(), Item(result) => result.encode(), Allowance(result) => result.encode(), + GetAttribute(result) => result.encode(), } } } @@ -103,46 +114,46 @@ pub mod pallet { Approval { /// The collection ID. collection: CollectionIdOf, + /// The item which is (dis)approved. `None` for all owner's items. + item: Option>, /// The owner providing the allowance. owner: AccountIdOf, /// The beneficiary of the allowance. operator: AccountIdOf, - /// The item which is (dis)approved. `None` for all owner's items. - item: Option>, /// Whether allowance is set or removed. approved: bool, }, - /// Event emitted when new item is minted to the account. - Mint { - /// The owner of the item. - to: AccountIdOf, - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - }, - /// Event emitted when item is burned. - Burn { - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - }, - /// Event emitted when an item transfer occurs. + /// Event emitted when a token transfer occurs. + // Differing style: event name abides by the PSP22 standard. Transfer { /// The collection ID. collection: CollectionIdOf, - /// the item ID. + /// The collection item ID. item: ItemIdOf, - /// The source of the transfer. - from: AccountIdOf, - /// The recipient of the transfer. - to: AccountIdOf, + /// The source of the transfer. `None` when minting. + from: Option>, + /// The recipient of the transfer. `None` when burning. + to: Option>, + /// The amount minted. + value: Option>, }, } #[pallet::call] impl Pallet { + #[pallet::call_index(20)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn create(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + + // TODO: Fix weight + #[pallet::call_index(21)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn destroy(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -150,9 +161,24 @@ pub mod pallet { to: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf, + mint_price: Option>, ) -> DispatchResult { - NftsOf::::mint(origin, collection, item, T::Lookup::unlookup(to.clone()), None)?; - Self::deposit_event(Event::Mint { to, collection, item }); + let account = ensure_signed(origin.clone())?; + let witness_data = MintWitness { mint_price, owned_item: Some(item) }; + NftsOf::::mint( + origin, + collection, + item, + T::Lookup::unlookup(to.clone()), + Some(witness_data), + )?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: None, + to: Some(account), + value: mint_price, + }); Ok(()) } @@ -163,8 +189,15 @@ pub mod pallet { collection: CollectionIdOf, item: ItemIdOf, ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; NftsOf::::burn(origin, collection, item)?; - Self::deposit_event(Event::Burn { collection, item }); + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(account), + to: None, + value: None, + }); Ok(()) } @@ -178,12 +211,18 @@ pub mod pallet { ) -> DispatchResult { let from = ensure_signed(origin.clone())?; NftsOf::::transfer(origin, collection, item, T::Lookup::unlookup(to.clone()))?; - Self::deposit_event(Event::Transfer { from, to, collection, item }); + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(from), + to: Some(to), + value: None, + }); Ok(()) } #[pallet::call_index(3)] - #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] + #[pallet::weight(NftsWeightInfoOf::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( origin: OriginFor, collection: CollectionIdOf, @@ -252,6 +291,10 @@ pub mod pallet { BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), ), + GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( + pallet_nfts::Attribute::::get((collection, item, namespace, key)) + .map(|attribute| attribute.0), + ), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index f81ea535..da949171 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,6 +1,6 @@ use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; +use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails}; use sp_runtime::BoundedBTreeMap; // Type aliases for pallet-nfts. @@ -15,14 +15,16 @@ pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -type ApprovalsOf = BoundedBTreeMap< +pub(super) type ApprovalsOf = BoundedBTreeMap< AccountIdOf, Option>, ::ApprovalsLimit, >; +pub(super) type ItemPriceOf = BalanceOf; // TODO: Multi-instances. pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; pub(super) type ItemDetailsFor = ItemDetails, ItemDepositOf, ApprovalsOf>; +pub(super) type AttributeNamespaceOf = AttributeNamespace>; From 1bb5a98b1f96e0c11e84b95329c5137fa2aeef2a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:45:16 +0700 Subject: [PATCH 14/64] feat(nonfungibles + nfts): add new methods to manage attributes --- Cargo.lock | 8 +- pallets/api/src/nonfungibles/mod.rs | 198 ++++++++++++++---- pallets/api/src/nonfungibles/types.rs | 17 +- pallets/nfts/src/features/approvals.rs | 4 +- .../src/features/create_delete_collection.rs | 4 +- .../nfts/src/features/create_delete_item.rs | 4 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/lib.rs | 18 +- pallets/nfts/src/tests.rs | 66 +++--- 9 files changed, 228 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed534195..48f7b34c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "Inflector" @@ -822,7 +822,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.36.4", + "object 0.36.0", "rustc-demangle", ] @@ -7195,9 +7195,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 83d23585..efef2386 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -14,11 +14,14 @@ mod types; pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; - use pallet_nfts::MintWitness; + use pallet_nfts::{ + CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, + MintSettings, MintWitness, + }; use sp_std::vec::Vec; use types::{ AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, + CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -29,24 +32,12 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Returns the owner of an item. - #[codec(index = 0)] - OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Returns the owner of a collection. - #[codec(index = 1)] - CollectionOwner(CollectionIdOf), /// Number of items existing in a concrete collection. #[codec(index = 2)] TotalSupply(CollectionIdOf), /// Returns the total number of items in the collection owned by the account. #[codec(index = 3)] BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, - /// Returns the details of a collection. - #[codec(index = 4)] - Collection(CollectionIdOf), - /// Returns the details of an item. - #[codec(index = 5)] - Item { collection: CollectionIdOf, item: ItemIdOf }, /// Whether a spender is allowed to transfer an item or items from owner. #[codec(index = 6)] Allowance { @@ -55,6 +46,9 @@ pub mod pallet { operator: AccountIdOf, item: Option>, }, + /// Returns the owner of an item. + #[codec(index = 0)] + OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, /// Returns the attribute of `item` for the given `key`. #[codec(index = 6)] GetAttribute { @@ -63,20 +57,29 @@ pub mod pallet { namespace: AttributeNamespaceOf, key: BoundedVec, }, + /// Returns the owner of a collection. + #[codec(index = 1)] + CollectionOwner(CollectionIdOf), + /// Returns the details of a collection. + #[codec(index = 4)] + Collection(CollectionIdOf), + /// Returns the details of an item. + #[codec(index = 5)] + Item { collection: CollectionIdOf, item: ItemIdOf }, } /// Results of state reads for the non-fungibles API. #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { - OwnerOf(Option>), - CollectionOwner(Option>), TotalSupply(u128), BalanceOf(u32), - Collection(Option>), - Item(Option>), Allowance(bool), + OwnerOf(Option>), GetAttribute(Option>), + CollectionOwner(Option>), + Collection(Option>), + Item(Option>), } impl ReadResult { @@ -141,19 +144,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(20)] - #[pallet::weight(NftsWeightInfoOf::::create())] - pub fn create(_origin: OriginFor) -> DispatchResult { - Ok(()) - } - - // TODO: Fix weight - #[pallet::call_index(21)] - #[pallet::weight(NftsWeightInfoOf::::create())] - pub fn destroy(_origin: OriginFor) -> DispatchResult { - Ok(()) - } - #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -250,6 +240,131 @@ pub mod pallet { Self::deposit_event(Event::Approval { collection, item, operator, owner, approved }); Ok(()) } + + #[pallet::call_index(4)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn create( + origin: OriginFor, + admin: AccountIdOf, + config: CreateCollectionConfigFor, + ) -> DispatchResult { + let collection_config = CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: config.max_supply, + mint_settings: MintSettings { + mint_type: config.mint_type, + start_block: config.start_block, + end_block: config.end_block, + ..MintSettings::default() + }, + }; + NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::weight(NftsWeightInfoOf::::destroy( + witness.item_metadatas, + witness.item_configs, + witness.attributes, + ))] + pub fn destroy( + origin: OriginFor, + collection: CollectionIdOf, + witness: DestroyWitness, + ) -> DispatchResultWithPostInfo { + NftsOf::::destroy(origin, collection, witness) + } + + #[pallet::call_index(6)] + #[pallet::weight(NftsWeightInfoOf::::set_attribute())] + pub fn set_attribute( + origin: OriginFor, + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + NftsOf::::set_attribute(origin, collection, item, namespace, key, value) + } + + #[pallet::call_index(7)] + #[pallet::weight(NftsWeightInfoOf::::clear_attribute())] + pub fn clear_attribute( + origin: OriginFor, + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + ) -> DispatchResult { + NftsOf::::clear_attribute(origin, collection, item, namespace, key) + } + + #[pallet::call_index(8)] + #[pallet::weight(NftsWeightInfoOf::::set_metadata())] + pub fn set_metadata( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + data: BoundedVec, + ) -> DispatchResult { + NftsOf::::set_metadata(origin, collection, item, data) + } + + #[pallet::call_index(9)] + #[pallet::weight(NftsWeightInfoOf::::clear_metadata())] + pub fn clear_metadata( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::clear_metadata(origin, collection, item) + } + + #[pallet::call_index(10)] + #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] + pub fn approve_item_attributes( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + delegate: AccountIdOf, + ) -> DispatchResult { + NftsOf::::approve_item_attributes( + origin, + collection, + item, + T::Lookup::unlookup(delegate.clone()), + ) + } + + #[pallet::call_index(11)] + #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] + pub fn cancel_item_attributes_approval( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + delegate: AccountIdOf, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + NftsOf::::cancel_item_attributes_approval( + origin, + collection, + item, + T::Lookup::unlookup(delegate.clone()), + witness, + ) + } + + #[pallet::call_index(12)] + #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] + pub fn set_max_supply( + origin: OriginFor, + collection: CollectionIdOf, + max_supply: u32, + ) -> DispatchResult { + NftsOf::::set_collection_max_supply(origin, collection, max_supply) + } } impl crate::Read for Pallet { @@ -274,27 +389,26 @@ pub mod pallet { fn read(value: Self::Read) -> Self::Result { use Read::*; match value { - OwnerOf { collection, item } => - ReadResult::OwnerOf(NftsOf::::owner(collection, item)), - CollectionOwner(collection) => - ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), TotalSupply(collection) => ReadResult::TotalSupply( NftsOf::::collection_items(collection).unwrap_or_default().into(), ), - Collection(collection) => - ReadResult::Collection(pallet_nfts::Collection::::get(collection)), - Item { collection, item } => - ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + BalanceOf { collection, owner } => + ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), - BalanceOf { collection, owner } => ReadResult::BalanceOf( - pallet_nfts::AccountBalance::::get((collection, owner)), - ), + OwnerOf { collection, item } => + ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( pallet_nfts::Attribute::::get((collection, item, namespace, key)) .map(|attribute| attribute.0), ), + CollectionOwner(collection) => + ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), + Collection(collection) => + ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + Item { collection, item } => + ReadResult::Item(pallet_nfts::Item::::get(collection, item)), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index da949171..8c53ffd3 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,7 +1,9 @@ +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails}; -use sp_runtime::BoundedBTreeMap; +use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails, MintType}; +use scale_info::TypeInfo; +use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; @@ -28,3 +30,14 @@ pub(super) type CollectionDetailsFor = pub(super) type ItemDetailsFor = ItemDetails, ItemDepositOf, ApprovalsOf>; pub(super) type AttributeNamespaceOf = AttributeNamespace>; +pub(super) type CreateCollectionConfigFor = + CreateCollectionConfig, BlockNumberFor, CollectionIdOf>; + +#[derive(Clone, Copy, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct CreateCollectionConfig { + pub max_supply: Option, + pub mint_type: MintType, + pub price: Option, + pub start_block: Option, + pub end_block: Option, +} diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 05696fee..6d71c1a2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -171,7 +171,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(crate) fn do_approve_transfer_collection( + pub(crate) fn do_approve_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, @@ -204,7 +204,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(crate) fn do_cancel_approval_collection( + pub(crate) fn do_cancel_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 2ea5cd73..b7efd03a 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -137,8 +137,10 @@ impl, I: 'static> Pallet { } } + // TODO: Do we need another storage item to keep track of number of holders of a + // collection let _ = - AccountBalance::::clear_prefix((collection,), collection_details.items, None); + AccountBalance::::clear_prefix(collection, collection_details.items, None); let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 036a63b7..cc29f8da 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,7 +69,7 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); - AccountBalance::::mutate((collection, &mint_to), |balance| { + AccountBalance::::mutate(collection, &mint_to, |balance| { balance.saturating_inc(); }); @@ -266,7 +266,7 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); ItemAttributesApprovalsOf::::remove(&collection, &item); - AccountBalance::::mutate((collection, &owner), |balance| { + AccountBalance::::mutate(collection, &owner, |balance| { balance.saturating_dec(); }); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 04d9f4fe..3b25b014 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -88,10 +88,10 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balances. - AccountBalance::::mutate((collection, &details.owner), |balance| { + AccountBalance::::mutate(collection, &details.owner, |balance| { balance.saturating_dec(); }); - AccountBalance::::mutate((collection, &dest), |balance| { + AccountBalance::::mutate(collection, &dest, |balance| { balance.saturating_inc(); }); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index c7d826b5..bc8b67b6 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -404,14 +404,12 @@ pub mod pallet { /// Number of collection items that accounts own. #[pallet::storage] - pub type AccountBalance, I: 'static = ()> = StorageNMap< + pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< _, - ( - // Collection Id. - NMapKey, - // Collection Owner Id. - NMapKey, - ), + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, u32, ValueQuery, >; @@ -1333,8 +1331,7 @@ pub mod pallet { delegate, maybe_deadline, ), - None => - Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate), + None => Self::do_approve_collection(maybe_check_origin, collection, delegate), } } @@ -1367,8 +1364,7 @@ pub mod pallet { match maybe_item { Some(item) => Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), - None => - Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate), + None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), } } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 10c95bd6..397a715c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,7 +164,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -174,7 +174,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); - assert_eq!(AccountBalance::::get((1, account(1))), 1); + assert_eq!(AccountBalance::::get(1, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } @@ -206,7 +206,7 @@ fn lifecycle_should_work() { account(10), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(10))), 1); + assert_eq!(AccountBalance::::get(0, account(10)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 6); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), @@ -215,10 +215,10 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(20))), 1); + assert_eq!(AccountBalance::::get(0, account(20)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 7); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); @@ -226,8 +226,8 @@ fn lifecycle_should_work() { assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); - assert_eq!(AccountBalance::::get((0, account(1))), 0); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 0); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -245,7 +245,7 @@ fn lifecycle_should_work() { Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), Error::::CollectionNotEmpty ); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(account(1)), @@ -256,9 +256,9 @@ fn lifecycle_should_work() { bvec![0], )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); - assert_eq!(AccountBalance::::get((0, account(10))), 0); + assert_eq!(AccountBalance::::get(0, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert_eq!(AccountBalance::::get((0, account(10))), 0); + assert_eq!(AccountBalance::::get(0, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -266,7 +266,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -316,7 +316,14 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + None, + account(3), + None + )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -335,7 +342,8 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::iter_prefix(0).count(), 0); + assert_eq!(Allowances::::iter_prefix((0,)).count(), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -350,7 +358,7 @@ fn mint_should_work() { default_collection_config() )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -416,7 +424,7 @@ fn mint_should_work() { account(2), Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -455,7 +463,7 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); - assert_eq!(AccountBalance::::get((1, account(2))), 1); + assert_eq!(AccountBalance::::get(1, account(2)), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -494,8 +502,8 @@ fn transfer_should_work() { )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); - assert_eq!(AccountBalance::::get((0, account(2))), 0); - assert_eq!(AccountBalance::::get((0, account(3))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(AccountBalance::::get(0, account(3)), 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -510,9 +518,9 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - assert_eq!(AccountBalance::::get((0, account(2))), 0); - assert_eq!(AccountBalance::::get((0, account(3))), 0); - assert_eq!(AccountBalance::::get((0, account(4))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(AccountBalance::::get(0, account(3)), 0); + assert_eq!(AccountBalance::::get(0, account(4)), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1766,7 +1774,7 @@ fn burn_works() { account(5), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(5))), 2); + assert_eq!(AccountBalance::::get(0, account(5)), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1774,9 +1782,9 @@ fn burn_works() { Error::::NoPermission ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); - assert_eq!(AccountBalance::::get((0, account(5))), 1); + assert_eq!(AccountBalance::::get(0, account(5)), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); - assert_eq!(AccountBalance::::get((0, account(5))), 0); + assert_eq!(AccountBalance::::get(0, account(5)), 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2755,7 +2763,7 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 1); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -3123,8 +3131,8 @@ fn claim_swap_should_work() { default_item_config(), )); - assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); + assert_eq!(AccountBalance::::get(collection_id, user_1.clone()), 2); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 3); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3215,8 +3223,8 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); - assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); + assert_eq!(AccountBalance::::get(collection_id, user_1.clone()), 2); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); From 7bc9a1176cd5700655414fe886c042cc1b9f6ed3 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:04:01 +0700 Subject: [PATCH 15/64] refactor(nfts): toml lock file --- Cargo.lock | 20 ++++++++++---------- pallets/nfts/Cargo.toml | 7 +++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48f7b34c..71903ca0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -8240,39 +8240,39 @@ dependencies = [ [[package]] name = "pallet-nfts" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" +version = "0.1.0" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", - "sp-std", ] [[package]] name = "pallet-nfts" -version = "31.0.0" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-keystore", "sp-runtime", + "sp-std", ] [[package]] @@ -10857,7 +10857,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -11002,7 +11002,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 7644a35b..60b3b746 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -6,8 +6,7 @@ homepage = "https://substrate.io" license.workspace = true name = "pallet-nfts" readme = "README.md" -repository.workspace = true -version = "31.0.0" +version = "0.1.0" [package.metadata.docs.rs] targets = [ "x86_64-unknown-linux-gnu" ] @@ -27,8 +26,8 @@ sp-io.workspace = true sp-runtime.workspace = true [dev-dependencies] -pallet-balances = { default-features = true, workspace = true } -sp-keystore = { default-features = true, workspace = true } +pallet-balances.workspace = true +sp-keystore.workspace = true [features] default = [ "std" ] From 9a6aca06387427398ca18624ad19beae0b6bdf34 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:06:00 +0700 Subject: [PATCH 16/64] fix(pallet-api): propagate try-runtime feature --- pallets/api/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/api/Cargo.toml b/pallets/api/Cargo.toml index 5d398724..31ccc076 100644 --- a/pallets/api/Cargo.toml +++ b/pallets/api/Cargo.toml @@ -60,5 +60,6 @@ std = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-nfts/try-runtime", "sp-runtime/try-runtime", ] From ba9162959dfa79801938a72817f6780f06069570 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:36:29 +0700 Subject: [PATCH 17/64] fix(api/nonfungibles): unit tests --- pallets/api/src/nonfungibles/mod.rs | 4 +- pallets/api/src/nonfungibles/tests.rs | 407 ++++++++++++++------------ 2 files changed, 225 insertions(+), 186 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index efef2386..9655bbea 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -72,7 +72,7 @@ pub mod pallet { #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { - TotalSupply(u128), + TotalSupply(u32), BalanceOf(u32), Allowance(bool), OwnerOf(Option>), @@ -390,7 +390,7 @@ pub mod pallet { use Read::*; match value { TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default().into(), + NftsOf::::collection_items(collection).unwrap_or_default(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 54d85516..d757508a 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,184 +1,223 @@ -// TODO -// use codec::Encode; -// use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; -// use frame_system::pallet_prelude::BlockNumberFor; -// use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; - -// use super::types::*; -// use crate::{ -// mock::*, -// nonfungibles::{Event, Read::*}, -// }; - -// const ITEM: u32 = 1; - -// #[test] -// fn mint_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let collection = create_collection(owner.clone()); -// // Successfully mint a new collection item. -// assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); -// System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); -// }); -// } - -// #[test] -// fn burn_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully burn an existing new collection item. -// assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); -// System::assert_last_event(Event::Burn { collection, item }.into()); -// }); -// } - -// #[test] -// fn transfer() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let dest = account(BOB); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully burn an existing new collection item. -// assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); -// System::assert_last_event( -// Event::Transfer { collection, item, from: owner, to: dest }.into(), -// ); -// }); -// } - -// #[test] -// fn approve_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully approve `spender` to transfer the collection item. -// assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); -// System::assert_last_event( -// Event::Approval { collection, item, owner, spender: spender.clone() }.into(), -// ); -// // Successfully transfer the item by the delegated account `spender`. -// assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); -// }); -// } - -// #[test] -// fn cancel_approval_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = -// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); -// // Successfully cancel the transfer approval of `spender` by `owner`. -// assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); -// // Failed to transfer the item by `spender` without permission. -// assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); -// }); -// } - -// #[test] -// fn owner_of_works() {} - -// #[test] -// fn collection_owner_works() { -// new_test_ext().execute_with(|| { -// let collection = create_collection(account(ALICE)); -// assert_eq!( -// NonFungibles::read_state(CollectionOwner(collection)), -// Nfts::collection_owner(collection).encode() -// ); -// }); -// } - -// #[test] -// fn total_supply_works() { -// new_test_ext().execute_with(|| { -// let (collection, _) = create_collection_mint(account(ALICE), ITEM); -// assert_eq!( -// NonFungibles::read_state(TotalSupply(collection)), -// (Nfts::items(&collection).count() as u8).encode() -// ); -// }); -// } - -// #[test] -// fn collection_works() { -// new_test_ext().execute_with(|| { -// let (collection, _) = create_collection_mint(account(ALICE), ITEM); -// assert_eq!( -// NonFungibles::read_state(Collection(collection)), -// pallet_nfts::Collection::::get(&collection).encode(), -// ); -// }); -// } - -// #[test] -// fn balance_of_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let (collection, _) = create_collection_mint(owner.clone(), ITEM); -// assert_eq!( -// NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), -// (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() -// ); -// }); -// } - -// #[test] -// fn allowance_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = -// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); -// assert_eq!( -// NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), -// super::Pallet::::allowance(collection, item, spender).encode() -// ); -// }); -// } - -// fn signed(account: AccountId) -> RuntimeOrigin { -// RuntimeOrigin::signed(account) -// } - -// fn create_collection_mint_and_approve( -// owner: AccountIdOf, -// item: ItemIdOf, -// spender: AccountIdOf, -// ) -> (u32, u32) { -// let (collection, item) = create_collection_mint(owner.clone(), item); -// assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); -// (collection, item) -// } - -// fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { -// let collection = create_collection(owner.clone()); -// assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); -// (collection, item) -// } - -// fn create_collection(owner: AccountIdOf) -> u32 { -// let next_id = next_collection_id(); -// assert_ok!(Nfts::create( -// signed(owner.clone()), -// owner.clone(), -// collection_config_with_all_settings_enabled() -// )); -// next_id -// } - -// fn next_collection_id() -> u32 { -// pallet_nfts::NextCollectionId::::get().unwrap_or_default() -// } - -// fn collection_config_with_all_settings_enabled( -// ) -> CollectionConfig, CollectionIdOf> { -// CollectionConfig { -// settings: CollectionSettings::all_enabled(), -// max_supply: None, -// mint_settings: MintSettings::default(), -// } -// } +use codec::Encode; +use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; + +use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; +use crate::{ + mock::*, + nonfungibles::{Event, Read::*}, + Read, +}; + +const ITEM: u32 = 1; + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let collection = create_collection(owner.clone()); + // Successfully mint a new collection item. + assert_ok!(NonFungibles::mint( + signed(owner.clone()), + owner.clone(), + collection, + ITEM, + None + )); + System::assert_last_event( + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), value: None } + .into(), + ); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + System::assert_last_event( + Event::Transfer { collection, item, from: Some(owner), to: None, value: None }.into(), + ); + }); +} + +#[test] +fn transfer() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let dest = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + System::assert_last_event( + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), value: None } + .into(), + ); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let operator = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully approve `spender` to transfer the collection item. + assert_ok!(NonFungibles::approve( + signed(owner.clone()), + collection, + Some(item), + operator.clone(), + true + )); + System::assert_last_event( + Event::Approval { + collection, + item: Some(item), + owner, + operator: operator.clone(), + approved: true, + } + .into(), + ); + // Successfully transfer the item by the delegated account `spender`. + assert_ok!(Nfts::transfer(signed(operator.clone()), collection, item, operator)); + }); +} + +#[test] +fn cancel_approval_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + // Successfully cancel the transfer approval of `spender` by `owner`. + assert_ok!(NonFungibles::approve( + signed(owner), + collection, + Some(item), + spender.clone(), + false + )); + // Failed to transfer the item by `spender` without permission. + assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + }); +} + +#[test] +fn owner_of_works() {} + +#[test] +fn collection_owner_works() { + new_test_ext().execute_with(|| { + let collection = create_collection(account(ALICE)); + assert_eq!( + NonFungibles::read(CollectionOwner(collection)).encode(), + Nfts::collection_owner(collection).encode() + ); + }); +} + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + Nfts::collection_items(collection).unwrap_or_default().encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read(Collection(collection)).encode(), + pallet_nfts::Collection::::get(&collection).encode(), + ); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, _) = create_collection_mint(owner.clone(), ITEM); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: owner.clone() }).encode(), + AccountBalance::::get(collection, owner).encode() + ); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let operator = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, operator.clone()); + assert_eq!( + NonFungibles::read(Allowance { + collection, + item: Some(item), + owner: owner.clone(), + operator: operator.clone(), + }) + .encode(), + Nfts::check_allowance(&collection, &Some(item), &owner, &operator) + .is_ok() + .encode() + ); + }); +} + +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) +} + +fn create_collection_mint_and_approve( + owner: AccountIdOf, + item: ItemIdOf, + spender: AccountIdOf, +) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner.clone(), item); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), spender, None)); + (collection, item) +} + +fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner.clone()); + assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); + (collection, item) +} + +fn create_collection(owner: AccountIdOf) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner.clone()), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + next_id +} + +fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() +} + +fn collection_config_with_all_settings_enabled( +) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} From 83d86c295690e0ed5a91169c8a4131fbac28f141 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:15:11 +0700 Subject: [PATCH 18/64] test(api/nonfungibles): encoding_read_result --- pallets/api/src/nonfungibles/mod.rs | 10 +-- pallets/api/src/nonfungibles/tests.rs | 109 ++++++++++++++++++++++++-- pallets/nfts/src/types.rs | 22 +++--- 3 files changed, 120 insertions(+), 21 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 9655bbea..eb88bfa6 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -137,8 +137,8 @@ pub mod pallet { from: Option>, /// The recipient of the transfer. `None` when burning. to: Option>, - /// The amount minted. - value: Option>, + /// The price of the collection item. + price: Option>, }, } @@ -167,7 +167,7 @@ pub mod pallet { item, from: None, to: Some(account), - value: mint_price, + price: mint_price, }); Ok(()) } @@ -186,7 +186,7 @@ pub mod pallet { item, from: Some(account), to: None, - value: None, + price: None, }); Ok(()) } @@ -206,7 +206,7 @@ pub mod pallet { item, from: Some(from), to: Some(to), - value: None, + price: None, }); Ok(()) } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index d757508a..063ceee3 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,23 +1,119 @@ use codec::Encode; -use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_support::assert_ok; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; use crate::{ mock::*, - nonfungibles::{Event, Read::*}, + nonfungibles::{Event, Read::*, ReadResult}, Read, }; const ITEM: u32 = 1; +mod encoding_read_result { + use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; + use sp_runtime::{BoundedBTreeMap, BoundedVec}; + + use super::*; + + #[test] + fn total_supply() { + let total_supply: u32 = 1_000_000; + assert_eq!(ReadResult::TotalSupply::(total_supply).encode(), total_supply.encode()); + } + + #[test] + fn balance_of() { + let balance: u32 = 100; + assert_eq!(ReadResult::BalanceOf::(balance).encode(), balance.encode()); + } + + #[test] + fn allowance() { + let allowance = false; + assert_eq!(ReadResult::Allowance::(allowance).encode(), allowance.encode()); + } + + #[test] + fn owner_of() { + let mut owner = Some(account(ALICE)); + assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); + owner = None; + assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); + } + + #[test] + fn get_attribute() { + let mut attribute = Some(BoundedVec::truncate_from("some attribute".as_bytes().to_vec())); + assert_eq!( + ReadResult::GetAttribute::(attribute.clone()).encode(), + attribute.encode() + ); + attribute = None; + assert_eq!( + ReadResult::GetAttribute::(attribute.clone()).encode(), + attribute.encode() + ); + } + + #[test] + fn collection_owner() { + let mut collection_owner = Some(account(ALICE)); + assert_eq!( + ReadResult::CollectionOwner::(collection_owner.clone()).encode(), + collection_owner.encode() + ); + collection_owner = None; + assert_eq!( + ReadResult::CollectionOwner::(collection_owner.clone()).encode(), + collection_owner.encode() + ); + } + + #[test] + fn collection() { + let mut collection_details = Some(CollectionDetails { + owner: account(ALICE), + owner_deposit: 0, + items: 0, + item_metadatas: 0, + item_configs: 0, + attributes: 0, + }); + assert_eq!( + ReadResult::Collection::(collection_details.clone()).encode(), + collection_details.encode() + ); + collection_details = None; + assert_eq!( + ReadResult::Collection::(collection_details.clone()).encode(), + collection_details.encode() + ); + } + + #[test] + fn item() { + let mut item_details = Some(ItemDetails { + owner: account(ALICE), + approvals: BoundedBTreeMap::default(), + deposit: ItemDeposit { amount: 0, account: account(BOB) }, + }); + assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); + item_details = None; + assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); + } +} + #[test] fn mint_works() { new_test_ext().execute_with(|| { let owner = account(ALICE); let collection = create_collection(owner.clone()); // Successfully mint a new collection item. + let balance_before_mint = AccountBalance::::get(collection.clone(), owner.clone()); + // assert_ok!(NonFungibles::mint( signed(owner.clone()), owner.clone(), @@ -25,8 +121,11 @@ fn mint_works() { ITEM, None )); + let balance_after_mint = AccountBalance::::get(collection.clone(), owner.clone()); + assert_eq!(balance_after_mint, 1); + assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), value: None } + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } .into(), ); }); @@ -40,7 +139,7 @@ fn burn_works() { // Successfully burn an existing new collection item. assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: None, value: None }.into(), + Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); }); } @@ -54,7 +153,7 @@ fn transfer() { // Successfully burn an existing new collection item. assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: Some(dest), value: None } + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } .into(), ); }); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index f08f1d09..061352c0 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,18 +94,18 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Collection's owner. - pub(super) owner: AccountId, + pub owner: AccountId, /// The total balance deposited by the owner for all the storage data associated with this /// collection. Used by `destroy`. - pub(super) owner_deposit: DepositBalance, + pub owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub(super) items: u32, + pub items: u32, /// The total number of outstanding item metadata of this collection. - pub(super) item_metadatas: u32, + pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. - pub(super) item_configs: u32, + pub item_configs: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + pub attributes: u32, } /// Witness data for the destroy transactions. @@ -145,21 +145,21 @@ pub struct MintWitness { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountId, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approvals: Approvals, + pub approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: Deposit, + pub deposit: Deposit, } /// Information about the reserved item deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub(super) account: AccountId, + pub account: AccountId, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + pub amount: DepositBalance, } /// Information about the collection's metadata. From cf9c69749e2a7e17ba3e61c03ab2384ffc75c545 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:51:50 +0700 Subject: [PATCH 19/64] refactor(api/nonfungibles): pallet tests --- pallets/api/src/nonfungibles/tests.rs | 243 +++++++++++++++----------- 1 file changed, 143 insertions(+), 100 deletions(-) diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 063ceee3..05c82f60 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,7 +1,11 @@ use codec::Encode; -use frame_support::assert_ok; +use frame_support::{assert_noop, assert_ok}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; +use pallet_nfts::{ + AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, + ItemDetails, MintSettings, +}; +use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; use crate::{ @@ -12,10 +16,9 @@ use crate::{ const ITEM: u32 = 1; -mod encoding_read_result { - use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; - use sp_runtime::{BoundedBTreeMap, BoundedVec}; +type NftsError = pallet_nfts::Error; +mod encoding_read_result { use super::*; #[test] @@ -107,53 +110,72 @@ mod encoding_read_result { } #[test] -fn mint_works() { +fn transfer() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let collection = create_collection(owner.clone()); - // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection.clone(), owner.clone()); - // - assert_ok!(NonFungibles::mint( - signed(owner.clone()), - owner.clone(), - collection, - ITEM, - None - )); - let balance_after_mint = AccountBalance::::get(collection.clone(), owner.clone()); - assert_eq!(balance_after_mint, 1); - assert_eq!(balance_after_mint - balance_before_mint, 1); + let owner = ALICE; + let dest = BOB; + + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + for origin in vec![root(), none()] { + assert_noop!( + NonFungibles::transfer(origin, collection, item, account(dest)), + BadOrigin + ); + } + // Successfully burn an existing new collection item. + let balance_before_transfer = AccountBalance::::get(collection, &account(dest)); + assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, account(dest))); + let balance_after_transfer = AccountBalance::::get(collection, &account(dest)); + assert_eq!(AccountBalance::::get(collection, &account(owner)), 0); + assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( - Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } - .into(), + Event::Transfer { + collection, + item, + from: Some(account(owner)), + to: Some(account(dest)), + price: None, + } + .into(), ); }); } #[test] -fn burn_works() { +fn mint_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + let owner = ALICE; + let collection = nfts::create_collection(owner); + + // Successfully mint a new collection item. + let balance_before_mint = AccountBalance::::get(collection, account(owner)); + assert_ok!(NonFungibles::mint(signed(owner), account(owner), collection, ITEM, None)); + let balance_after_mint = AccountBalance::::get(collection, account(owner)); + assert_eq!(balance_after_mint, 1); + assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), + Event::Transfer { + collection, + item: ITEM, + from: None, + to: Some(account(owner)), + price: None, + } + .into(), ); }); } #[test] -fn transfer() { +fn burn_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let dest = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); + let owner = ALICE; + // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } + Event::Transfer { collection, item, from: Some(account(owner)), to: None, price: None } .into(), ); }); @@ -162,59 +184,63 @@ fn transfer() { #[test] fn approve_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let operator = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully approve `spender` to transfer the collection item. + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully approve `oeprator` to transfer the collection item. assert_ok!(NonFungibles::approve( - signed(owner.clone()), + signed(owner), collection, Some(item), - operator.clone(), + account(operator), true )); System::assert_last_event( Event::Approval { collection, item: Some(item), - owner, - operator: operator.clone(), + owner: account(owner), + operator: account(operator), approved: true, } .into(), ); - // Successfully transfer the item by the delegated account `spender`. - assert_ok!(Nfts::transfer(signed(operator.clone()), collection, item, operator)); + // Successfully transfer the item by the delegated account `operator`. + assert_ok!(Nfts::transfer(signed(operator), collection, item, account(operator))); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - // Successfully cancel the transfer approval of `spender` by `owner`. + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); + // Successfully cancel the transfer approval of `operator` by `owner`. assert_ok!(NonFungibles::approve( signed(owner), collection, Some(item), - spender.clone(), + account(operator), false )); - // Failed to transfer the item by `spender` without permission. - assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + // Failed to transfer the item by `operator` without permission. + assert_noop!( + Nfts::transfer(signed(operator), collection, item, account(operator)), + NftsError::NoPermission + ); }); } #[test] -fn owner_of_works() {} +fn owner_of_works() { + unimplemented!() +} #[test] fn collection_owner_works() { new_test_ext().execute_with(|| { - let collection = create_collection(account(ALICE)); + let collection = nfts::create_collection(ALICE); assert_eq!( NonFungibles::read(CollectionOwner(collection)).encode(), Nfts::collection_owner(collection).encode() @@ -225,7 +251,7 @@ fn collection_owner_works() { #[test] fn total_supply_works() { new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(TotalSupply(collection)).encode(), Nfts::collection_items(collection).unwrap_or_default().encode() @@ -236,7 +262,7 @@ fn total_supply_works() { #[test] fn collection_works() { new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(Collection(collection)).encode(), pallet_nfts::Collection::::get(&collection).encode(), @@ -247,11 +273,11 @@ fn collection_works() { #[test] fn balance_of_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, _) = create_collection_mint(owner.clone(), ITEM); + let owner = ALICE; + let (collection, _) = nfts::create_collection_mint(owner, ITEM); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: owner.clone() }).encode(), - AccountBalance::::get(collection, owner).encode() + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + AccountBalance::::get(collection, account(owner)).encode() ); }); } @@ -259,64 +285,81 @@ fn balance_of_works() { #[test] fn allowance_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let operator = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, operator.clone()); + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( NonFungibles::read(Allowance { collection, item: Some(item), - owner: owner.clone(), - operator: operator.clone(), + owner: account(owner), + operator: account(operator), }) .encode(), - Nfts::check_allowance(&collection, &Some(item), &owner, &operator) + Nfts::check_allowance(&collection, &Some(item), &account(owner), &account(operator)) .is_ok() .encode() ); }); } -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) +fn signed(account_id: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(account(account_id)) } -fn create_collection_mint_and_approve( - owner: AccountIdOf, - item: ItemIdOf, - spender: AccountIdOf, -) -> (u32, u32) { - let (collection, item) = create_collection_mint(owner.clone(), item); - assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), spender, None)); - (collection, item) +fn root() -> RuntimeOrigin { + RuntimeOrigin::root() } -fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { - let collection = create_collection(owner.clone()); - assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); - (collection, item) +fn none() -> RuntimeOrigin { + RuntimeOrigin::none() } -fn create_collection(owner: AccountIdOf) -> u32 { - let next_id = next_collection_id(); - assert_ok!(Nfts::create( - signed(owner.clone()), - owner.clone(), - collection_config_with_all_settings_enabled() - )); - next_id -} +mod nfts { + use super::*; -fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() -} + pub(super) fn create_collection_mint_and_approve( + owner: u8, + item: ItemIdOf, + operator: u8, + ) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner, item); + assert_ok!(Nfts::approve_transfer( + signed(owner), + collection, + Some(item), + account(operator), + None + )); + (collection, item) + } + + pub(super) fn create_collection_mint(owner: u8, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner); + assert_ok!(Nfts::mint(signed(owner), collection, item, account(owner), None)); + (collection, item) + } + + pub(super) fn create_collection(owner: u8) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner), + account(owner), + collection_config_with_all_settings_enabled() + )); + next_id + } + + pub(super) fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() + } -fn collection_config_with_all_settings_enabled( -) -> CollectionConfig, CollectionIdOf> { - CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: None, - mint_settings: MintSettings::default(), + pub(super) fn collection_config_with_all_settings_enabled( + ) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } } } From b61c5f1c340b74dd338de55677a6528fe354797e Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:30:10 +0700 Subject: [PATCH 20/64] test(nonfungibles): add tests and remove collection owner read --- pallets/api/src/nonfungibles/mod.rs | 70 ++++--- pallets/api/src/nonfungibles/tests.rs | 267 +++++++++++++++++++++++--- pallets/api/src/nonfungibles/types.rs | 2 + 3 files changed, 286 insertions(+), 53 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index eb88bfa6..7377048f 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -12,7 +12,7 @@ mod types; #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::Incrementable}; use frame_system::pallet_prelude::*; use pallet_nfts::{ CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, @@ -21,7 +21,8 @@ pub mod pallet { use sp_std::vec::Vec; use types::{ AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, + CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NextCollectionIdOf, + NftsOf, NftsWeightInfoOf, }; use super::*; @@ -32,54 +33,62 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Number of items existing in a concrete collection. - #[codec(index = 2)] + /// Total item supply of a collection. + #[codec(index = 0)] TotalSupply(CollectionIdOf), - /// Returns the total number of items in the collection owned by the account. - #[codec(index = 3)] + /// Account balance for a specified collection. + #[codec(index = 1)] BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, - /// Whether a spender is allowed to transfer an item or items from owner. - #[codec(index = 6)] + /// Allowance for an operator approved by an owner, for a specified collection or item. + #[codec(index = 2)] Allowance { collection: CollectionIdOf, owner: AccountIdOf, operator: AccountIdOf, item: Option>, }, - /// Returns the owner of an item. - #[codec(index = 0)] + /// Owner of a specified collection item. + #[codec(index = 3)] OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Returns the attribute of `item` for the given `key`. - #[codec(index = 6)] + /// Attribute value of a collection item. + #[codec(index = 4)] GetAttribute { collection: CollectionIdOf, item: Option>, namespace: AttributeNamespaceOf, key: BoundedVec, }, - /// Returns the owner of a collection. - #[codec(index = 1)] - CollectionOwner(CollectionIdOf), - /// Returns the details of a collection. - #[codec(index = 4)] + /// Details of a collection. + #[codec(index = 6)] Collection(CollectionIdOf), - /// Returns the details of an item. - #[codec(index = 5)] + /// Details of a collection item. + #[codec(index = 7)] Item { collection: CollectionIdOf, item: ItemIdOf }, + /// Next collection ID. + #[codec(index = 8)] + NextCollectionId, } /// Results of state reads for the non-fungibles API. #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { + /// Total item supply of a collection. TotalSupply(u32), + /// Account balance for a specified collection. BalanceOf(u32), + /// Allowance for an operator approved by an owner, for a specified collection or item. Allowance(bool), + /// Owner of a specified collection owner. OwnerOf(Option>), + /// Attribute value of a collection item. GetAttribute(Option>), - CollectionOwner(Option>), + /// Details of a collection. Collection(Option>), + /// Details of a collection item. Item(Option>), + /// Next collection ID. + NextCollectionId(Option>), } impl ReadResult { @@ -88,13 +97,13 @@ pub mod pallet { use ReadResult::*; match self { OwnerOf(result) => result.encode(), - CollectionOwner(result) => result.encode(), TotalSupply(result) => result.encode(), BalanceOf(result) => result.encode(), Collection(result) => result.encode(), Item(result) => result.encode(), Allowance(result) => result.encode(), GetAttribute(result) => result.encode(), + NextCollectionId(result) => result.encode(), } } } @@ -140,6 +149,15 @@ pub mod pallet { /// The price of the collection item. price: Option>, }, + /// Event emitted when a collection is created. + Created { + /// The collection identifier. + id: CollectionIdOf, + /// The creator of the collection. + creator: AccountIdOf, + /// The administrator of the collection. + admin: AccountIdOf, + }, } #[pallet::call] @@ -248,6 +266,10 @@ pub mod pallet { admin: AccountIdOf, config: CreateCollectionConfigFor, ) -> DispatchResult { + let id = NextCollectionIdOf::::get() + .or(T::CollectionId::initial_value()) + .ok_or(pallet_nfts::Error::::UnknownCollection)?; + let creator = ensure_signed(origin.clone())?; let collection_config = CollectionConfig { settings: CollectionSettings::all_enabled(), max_supply: config.max_supply, @@ -259,6 +281,7 @@ pub mod pallet { }, }; NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } @@ -403,12 +426,13 @@ pub mod pallet { pallet_nfts::Attribute::::get((collection, item, namespace, key)) .map(|attribute| attribute.0), ), - CollectionOwner(collection) => - ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + NextCollectionId => ReadResult::NextCollectionId( + NextCollectionIdOf::::get().or(T::CollectionId::initial_value()), + ), } } } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 05c82f60..e89ba0bd 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,5 +1,5 @@ use codec::Encode; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, traits::Incrementable}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{ AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, @@ -7,7 +7,7 @@ use pallet_nfts::{ }; use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; -use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; +use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ mock::*, nonfungibles::{Event, Read::*, ReadResult}, @@ -61,20 +61,6 @@ mod encoding_read_result { ); } - #[test] - fn collection_owner() { - let mut collection_owner = Some(account(ALICE)); - assert_eq!( - ReadResult::CollectionOwner::(collection_owner.clone()).encode(), - collection_owner.encode() - ); - collection_owner = None; - assert_eq!( - ReadResult::CollectionOwner::(collection_owner.clone()).encode(), - collection_owner.encode() - ); - } - #[test] fn collection() { let mut collection_details = Some(CollectionDetails { @@ -107,6 +93,20 @@ mod encoding_read_result { item_details = None; assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); } + + #[test] + fn next_collection_id_works() { + let mut next_collection_id = Some(0); + assert_eq!( + ReadResult::NextCollectionId::(next_collection_id).encode(), + next_collection_id.encode() + ); + next_collection_id = None; + assert_eq!( + ReadResult::NextCollectionId::(next_collection_id).encode(), + next_collection_id.encode() + ); + } } #[test] @@ -232,33 +232,212 @@ fn cancel_approval_works() { }); } +#[test] +fn set_max_supply_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + assert_ok!(NonFungibles::set_max_supply(signed(owner), collection, 10)); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + }); + assert_noop!( + Nfts::mint(signed(owner), collection, 42, account(owner), None), + NftsError::MaxSupplyReached + ); + }); +} + #[test] fn owner_of_works() { - unimplemented!() + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(OwnerOf { collection, item }).encode(), + Nfts::owner(collection, item).encode() + ); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // No attribute set. + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute.clone() + }) + .encode(), + result.encode() + ); + // Successfully get an existing attribute. + result = Some(value.clone()); + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + value, + )); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute + }) + .encode(), + result.encode() + ); + }); } #[test] -fn collection_owner_works() { +fn clear_attribute_works() { new_test_ext().execute_with(|| { - let collection = nfts::create_collection(ALICE); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + BoundedVec::truncate_from("some value".as_bytes().to_vec()) + )); + // Successfully clear an attribute. + assert_ok!(Nfts::clear_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + )); assert_eq!( - NonFungibles::read(CollectionOwner(collection)).encode(), - Nfts::collection_owner(collection).encode() + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute + }) + .encode(), + result.encode() ); }); } #[test] -fn total_supply_works() { +fn approve_item_attribute_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // Successfully approve delegate to set attributes. + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + )); + result = Some(value); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::Account(account(BOB)), + key: attribute + }) + .encode(), + result.encode() + ); + }); +} + +#[test] +fn cancel_item_attribute_approval_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // Successfully approve delegate to set attributes. + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + )); + assert_ok!(Nfts::cancel_item_attributes_approval( + signed(ALICE), + collection, + item, + account(BOB), + pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } + )); + assert_noop!( + Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + ), + NftsError::NoPermission + ); + }); +} + +#[test] +fn next_collection_id_works() { + new_test_ext().execute_with(|| { + let _ = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - Nfts::collection_items(collection).unwrap_or_default().encode() + NonFungibles::read(NextCollectionId).encode(), + pallet_nfts::NextCollectionId::::get() + .or(CollectionIdOf::::initial_value()) + .encode(), ); }); } +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_eq!(NonFungibles::read(TotalSupply(collection)).encode(), (i + 1).encode()); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + Nfts::collection_items(collection).unwrap_or_default().encode() + ); + }); + }); +} + #[test] fn collection_works() { new_test_ext().execute_with(|| { @@ -271,23 +450,51 @@ fn collection_works() { } #[test] -fn balance_of_works() { +fn item_works() { new_test_ext().execute_with(|| { - let owner = ALICE; - let (collection, _) = nfts::create_collection_mint(owner, ITEM); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), - AccountBalance::::get(collection, account(owner)).encode() + NonFungibles::read(Item { collection, item }).encode(), + pallet_nfts::Item::::get(&collection, &item).encode(), ); }); } +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + (i + 1).encode() + ); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + AccountBalance::::get(collection, account(owner)).encode() + ); + }); + }); +} + #[test] fn allowance_works() { new_test_ext().execute_with(|| { let owner = ALICE; let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); + assert_eq!( + NonFungibles::read(Allowance { + collection, + item: Some(item), + owner: account(owner), + operator: account(operator), + }) + .encode(), + true.encode() + ); assert_eq!( NonFungibles::read(Allowance { collection, diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index 8c53ffd3..f57ee697 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -7,12 +7,14 @@ use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; +pub(super) type NftsErrorOf = pallet_nfts::Error; pub(super) type NftsWeightInfoOf = ::WeightInfo; // Type aliases for pallet-nfts storage items. pub(super) type AccountIdOf = ::AccountId; pub(super) type BalanceOf = <>::Currency as Currency< ::AccountId, >>::Balance; +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId; pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = From 86ff5d8cc080de0726aa124f9ad7bb3011628e29 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 12 Nov 2024 01:17:21 +0700 Subject: [PATCH 21/64] chore: update pallet & runtime --- pallets/api/src/fungibles/tests.rs | 286 ++++------- pallets/api/src/mock.rs | 61 ++- pallets/api/src/nonfungibles/mod.rs | 184 ++++--- pallets/api/src/nonfungibles/tests.rs | 285 +++++----- pallets/api/src/nonfungibles/types.rs | 30 +- pallets/nfts/Cargo.toml | 1 + pallets/nfts/src/benchmarking.rs | 12 +- pallets/nfts/src/common_functions.rs | 8 + pallets/nfts/src/features/approvals.rs | 31 +- pallets/nfts/src/tests.rs | 18 +- pallets/nfts/src/types.rs | 10 +- pallets/nfts/src/weights.rs | 685 +++++++++++++------------ runtime/devnet/src/config/api/mod.rs | 189 ++++++- runtime/devnet/src/config/assets.rs | 13 +- runtime/devnet/src/lib.rs | 5 +- 15 files changed, 964 insertions(+), 854 deletions(-) diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index 6e181a6f..f5c560bb 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -83,21 +83,17 @@ fn transfer_works() { let to = BOB; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer(origin, token, account(to), value), BadOrigin); + assert_noop!(Fungibles::transfer(origin, token, to, value), BadOrigin); } // Check error works for `Assets::transfer_keep_alive()`. - assert_noop!( - Fungibles::transfer(signed(from), token, account(to), value), - AssetsError::Unknown - ); + assert_noop!(Fungibles::transfer(signed(from), token, to, value), AssetsError::Unknown); assets::create_and_mint_to(from, token, from, value * 2); - let balance_before_transfer = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::transfer(signed(from), token, account(to), value)); - let balance_after_transfer = Assets::balance(token, &account(to)); + let balance_before_transfer = Assets::balance(token, &to); + assert_ok!(Fungibles::transfer(signed(from), token, to, value)); + let balance_after_transfer = Assets::balance(token, &to); assert_eq!(balance_after_transfer, balance_before_transfer + value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } - .into(), + Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), ); }); } @@ -112,36 +108,26 @@ fn transfer_from_works() { let spender = CHARLIE; for origin in vec![root(), none()] { - assert_noop!( - Fungibles::transfer_from(origin, token, account(from), account(to), value), - BadOrigin - ); + assert_noop!(Fungibles::transfer_from(origin, token, from, to, value), BadOrigin); } // Check error works for `Assets::transfer_approved()`. assert_noop!( - Fungibles::transfer_from(signed(spender), token, account(from), account(to), value), + Fungibles::transfer_from(signed(spender), token, from, to, value), AssetsError::Unknown ); // Approve `spender` to transfer up to `value`. assets::create_mint_and_approve(spender, token, from, value * 2, spender, value); // Successfully call transfer from. - let from_balance_before_transfer = Assets::balance(token, &account(from)); - let to_balance_before_transfer = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::transfer_from( - signed(spender), - token, - account(from), - account(to), - value - )); - let from_balance_after_transfer = Assets::balance(token, &account(from)); - let to_balance_after_transfer = Assets::balance(token, &account(to)); + let from_balance_before_transfer = Assets::balance(token, &from); + let to_balance_before_transfer = Assets::balance(token, &to); + assert_ok!(Fungibles::transfer_from(signed(spender), token, from, to, value)); + let from_balance_after_transfer = Assets::balance(token, &from); + let to_balance_after_transfer = Assets::balance(token, &to); // Check that `to` has received the `value` tokens from `from`. assert_eq!(to_balance_after_transfer, to_balance_before_transfer + value); assert_eq!(from_balance_after_transfer, from_balance_before_transfer - value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } - .into(), + Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), ); }); } @@ -158,7 +144,7 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, account(spender), value), + Fungibles::approve(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } @@ -175,20 +161,20 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, account(spender), value), + Fungibles::approve(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()` in `Greater` match arm. assert_noop!( - Fungibles::approve(signed(owner), token, account(spender), value), + Fungibles::approve(signed(owner), token, spender, value), AssetsError::Unknown.with_weight(WeightInfo::approve(1, 0)) ); assets::create_mint_and_approve(owner, token, owner, value, spender, value); // Check error works for `Assets::cancel_approval()` in `Less` match arm. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); @@ -207,61 +193,38 @@ mod approve { // Approves a value to spend that is higher than the current allowance. assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); + assert_eq!(Assets::allowance(token, &owner, &spender), 0); assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value), + Fungibles::approve(signed(owner), token, spender, value), Ok(Some(WeightInfo::approve(1, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); - System::assert_last_event( - Event::Approval { token, owner: account(owner), spender: account(spender), value } - .into(), - ); + assert_eq!(Assets::allowance(token, &owner, &spender), value); + System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); // Approves a value to spend that is lower than the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); // Approves a value to spend that is equal to the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); // Sets allowance to zero. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), 0), + Fungibles::approve(signed(owner), token, spender, 0), Ok(Some(WeightInfo::approve(0, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); - System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: 0, - } - .into(), - ); + assert_eq!(Assets::allowance(token, &owner, &spender), 0); + System::assert_last_event(Event::Approval { token, owner, spender, value: 0 }.into()); }); } } @@ -276,34 +239,25 @@ fn increase_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::increase_allowance(origin, token, account(spender), value), + Fungibles::increase_allowance(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()`. assert_noop!( - Fungibles::increase_allowance(signed(owner), token, account(spender), value), + Fungibles::increase_allowance(signed(owner), token, spender, value), AssetsError::Unknown.with_weight(AssetsWeightInfo::approve_transfer()) ); assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(0, Assets::allowance(token, &account(owner), &account(spender))); - assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); - System::assert_last_event( - Event::Approval { token, owner: account(owner), spender: account(spender), value } - .into(), - ); + assert_eq!(0, Assets::allowance(token, &owner, &spender)); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); + assert_eq!(Assets::allowance(token, &owner, &spender), value); + System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); // Additive. - assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value * 2); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); + assert_eq!(Assets::allowance(token, &owner, &spender), value * 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value * 2, - } - .into(), + Event::Approval { token, owner, spender, value: value * 2 }.into(), ); }); } @@ -318,46 +272,40 @@ fn decrease_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::decrease_allowance(origin, token, account(spender), 0), + Fungibles::decrease_allowance(origin, token, spender, 0), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } assets::create_mint_and_approve(owner, token, owner, value, spender, value); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + assert_eq!(Assets::allowance(token, &owner, &spender), value); // Check error works for `Assets::cancel_approval()`. No error test for `approve_transfer` // because it is not possible. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // Owner balance is not changed if decreased by zero. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), 0), + Fungibles::decrease_allowance(signed(owner), token, spender, 0), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + assert_eq!(Assets::allowance(token, &owner, &spender), value); // "Unapproved" error is returned if the current allowance is less than amount to decrease // with. assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value * 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value * 2), AssetsError::Unapproved ); // Decrease allowance successfully. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); }); } @@ -370,19 +318,14 @@ fn create_works() { let admin = ALICE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::create(origin, id, account(admin), 100), BadOrigin); + assert_noop!(Fungibles::create(origin, id, admin, 100), BadOrigin); } assert!(!Assets::asset_exists(id)); - assert_ok!(Fungibles::create(signed(creator), id, account(admin), 100)); + assert_ok!(Fungibles::create(signed(creator), id, admin, 100)); assert!(Assets::asset_exists(id)); - System::assert_last_event( - Event::Created { id, creator: account(creator), admin: account(admin) }.into(), - ); + System::assert_last_event(Event::Created { id, creator, admin }.into()); // Check error works for `Assets::create()`. - assert_noop!( - Fungibles::create(signed(creator), id, account(admin), 100), - AssetsError::InUse - ); + assert_noop!(Fungibles::create(signed(creator), id, admin, 100), AssetsError::InUse); }); } @@ -393,11 +336,11 @@ fn start_destroy_works() { // Check error works for `Assets::start_destroy()`. assert_noop!(Fungibles::start_destroy(signed(ALICE), token), AssetsError::Unknown); - assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); assert_ok!(Fungibles::start_destroy(signed(ALICE), token)); // Check that the token is not live after starting the destroy process. assert_noop!( - Assets::mint(signed(ALICE), token, account(ALICE), 10 * UNIT), + Assets::mint(signed(ALICE), token, ALICE, 10 * UNIT), AssetsError::AssetNotLive ); }); @@ -416,7 +359,7 @@ fn set_metadata_works() { Fungibles::set_metadata(signed(ALICE), token, name.clone(), symbol.clone(), decimals), AssetsError::Unknown ); - assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); assert_ok!(Fungibles::set_metadata( signed(ALICE), token, @@ -455,16 +398,16 @@ fn mint_works() { // Check error works for `Assets::mint()`. assert_noop!( - Fungibles::mint(signed(from), token, account(to), value), + Fungibles::mint(signed(from), token, to, value), sp_runtime::TokenError::UnknownAsset ); - assert_ok!(Assets::create(signed(from), token, account(from), 1)); - let balance_before_mint = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::mint(signed(from), token, account(to), value)); - let balance_after_mint = Assets::balance(token, &account(to)); + assert_ok!(Assets::create(signed(from), token, from, 1)); + let balance_before_mint = Assets::balance(token, &to); + assert_ok!(Fungibles::mint(signed(from), token, to, value)); + let balance_after_mint = Assets::balance(token, &to); assert_eq!(balance_after_mint, balance_before_mint + value); System::assert_last_event( - Event::Transfer { token, from: None, to: Some(account(to)), value }.into(), + Event::Transfer { token, from: None, to: Some(to), value }.into(), ); }); } @@ -480,30 +423,27 @@ fn burn_works() { // "BalanceLow" error is returned if token is not created. assert_noop!( - Fungibles::burn(signed(owner), token, account(from), value), + Fungibles::burn(signed(owner), token, from, value), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); assets::create_and_mint_to(owner, token, from, total_supply); assert_eq!(Assets::total_supply(TOKEN), total_supply); // Check error works for `Assets::burn()`. assert_ok!(Assets::freeze_asset(signed(owner), token)); - assert_noop!( - Fungibles::burn(signed(owner), token, account(from), value), - AssetsError::AssetNotLive - ); + assert_noop!(Fungibles::burn(signed(owner), token, from, value), AssetsError::AssetNotLive); assert_ok!(Assets::thaw_asset(signed(owner), token)); // "BalanceLow" error is returned if the balance is less than amount to burn. assert_noop!( - Fungibles::burn(signed(owner), token, account(from), total_supply * 2), + Fungibles::burn(signed(owner), token, from, total_supply * 2), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); - let balance_before_burn = Assets::balance(token, &account(from)); - assert_ok!(Fungibles::burn(signed(owner), token, account(from), value)); + let balance_before_burn = Assets::balance(token, &from); + assert_ok!(Fungibles::burn(signed(owner), token, from, value)); assert_eq!(Assets::total_supply(TOKEN), total_supply - value); - let balance_after_burn = Assets::balance(token, &account(from)); + let balance_after_burn = Assets::balance(token, &from); assert_eq!(balance_after_burn, balance_before_burn - value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: None, value }.into(), + Event::Transfer { token, from: Some(from), to: None, value }.into(), ); }); } @@ -530,17 +470,17 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), ReadResult::BalanceOf(Default::default()) ); assets::create_and_mint_to(ALICE, TOKEN, ALICE, value); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), ReadResult::BalanceOf(value) ); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }).encode(), - Assets::balance(TOKEN, account(ALICE)).encode(), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }).encode(), + Assets::balance(TOKEN, ALICE).encode(), ); }); } @@ -550,30 +490,17 @@ fn allowance_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), ReadResult::Allowance(Default::default()) ); assets::create_mint_and_approve(ALICE, TOKEN, ALICE, value * 2, BOB, value); assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), ReadResult::Allowance(value) ); assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }) - .encode(), - Assets::allowance(TOKEN, &account(ALICE), &account(BOB)).encode(), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }).encode(), + Assets::allowance(TOKEN, &ALICE, &BOB).encode(), ); }); } @@ -607,7 +534,7 @@ fn token_metadata_works() { fn token_exists_works() { new_test_ext().execute_with(|| { assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(false)); - assert_ok!(Assets::create(signed(ALICE), TOKEN, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), TOKEN, ALICE, 1)); assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(true)); assert_eq!( Fungibles::read(TokenExists(TOKEN)).encode(), @@ -616,8 +543,8 @@ fn token_exists_works() { }); } -fn signed(account_id: u8) -> RuntimeOrigin { - RuntimeOrigin::signed(account(account_id)) +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) } fn root() -> RuntimeOrigin { @@ -632,31 +559,36 @@ fn none() -> RuntimeOrigin { mod assets { use super::*; - pub(super) fn create_and_mint_to(owner: u8, token: TokenId, to: u8, value: Balance) { - assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); - assert_ok!(Assets::mint(signed(owner), token, account(to), value)); + pub(super) fn create_and_mint_to( + owner: AccountId, + token: TokenId, + to: AccountId, + value: Balance, + ) { + assert_ok!(Assets::create(signed(owner), token, owner, 1)); + assert_ok!(Assets::mint(signed(owner), token, to, value)); } pub(super) fn create_mint_and_approve( - owner: u8, + owner: AccountId, token: TokenId, - to: u8, + to: AccountId, mint: Balance, - spender: u8, + spender: AccountId, approve: Balance, ) { create_and_mint_to(owner, token, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), token, account(spender), approve,)); + assert_ok!(Assets::approve_transfer(signed(to), token, spender, approve,)); } pub(super) fn create_and_set_metadata( - owner: u8, + owner: AccountId, token: TokenId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); + assert_ok!(Assets::create(signed(owner), token, owner, 1)); assert_ok!(Assets::set_metadata(signed(owner), token, name, symbol, decimals)); } } @@ -681,11 +613,11 @@ mod read_weights { fn new() -> Self { Self { total_supply: Fungibles::weight(&TotalSupply(TOKEN)), - balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: account(ALICE) }), + balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: ALICE }), allowance: Fungibles::weight(&Allowance { token: TOKEN, - owner: account(ALICE), - spender: account(BOB), + owner: ALICE, + spender: BOB, }), token_name: Fungibles::weight(&TokenName(TOKEN)), token_symbol: Fungibles::weight(&TokenSymbol(TOKEN)), @@ -767,15 +699,15 @@ mod ensure_codec_indexes { [ (TotalSupply::(Default::default()), 0u8, "TotalSupply"), ( - BalanceOf:: { token: Default::default(), owner: account(Default::default()) }, + BalanceOf:: { token: Default::default(), owner: Default::default() }, 1, "BalanceOf", ), ( Allowance:: { token: Default::default(), - owner: account(Default::default()), - spender: account(Default::default()), + owner: Default::default(), + spender: Default::default(), }, 2, "Allowance", @@ -799,7 +731,7 @@ mod ensure_codec_indexes { ( transfer { token: Default::default(), - to: account(Default::default()), + to: Default::default(), value: Default::default(), }, 3u8, @@ -808,8 +740,8 @@ mod ensure_codec_indexes { ( transfer_from { token: Default::default(), - from: account(Default::default()), - to: account(Default::default()), + from: Default::default(), + to: Default::default(), value: Default::default(), }, 4, @@ -818,7 +750,7 @@ mod ensure_codec_indexes { ( approve { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 5, @@ -827,7 +759,7 @@ mod ensure_codec_indexes { ( increase_allowance { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 6, @@ -836,7 +768,7 @@ mod ensure_codec_indexes { ( decrease_allowance { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 7, @@ -845,7 +777,7 @@ mod ensure_codec_indexes { ( create { id: Default::default(), - admin: account(Default::default()), + admin: Default::default(), min_balance: Default::default(), }, 11, @@ -866,7 +798,7 @@ mod ensure_codec_indexes { ( mint { token: Default::default(), - account: account(Default::default()), + account: Default::default(), value: Default::default(), }, 19, @@ -875,7 +807,7 @@ mod ensure_codec_indexes { ( burn { token: Default::default(), - account: account(Default::default()), + account: Default::default(), value: Default::default(), }, 20, diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 920d590f..8a4ad27d 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -1,28 +1,28 @@ +use codec::{Decode, Encode}; use frame_support::{ derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; use pallet_nfts::PalletFeatures; +use scale_info::TypeInfo; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - BuildStorage, MultiSignature, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Lazy, Verify}, + BuildStorage, }; -pub(crate) const ALICE: u8 = 1; -pub(crate) const BOB: u8 = 2; -pub(crate) const CHARLIE: u8 = 3; +pub(crate) const ALICE: AccountId = 1; +pub(crate) const BOB: AccountId = 2; +pub(crate) const CHARLIE: AccountId = 3; pub(crate) const INIT_AMOUNT: Balance = 100_000_000 * UNIT; pub(crate) const UNIT: Balance = 10_000_000_000; type Block = frame_system::mocking::MockBlock; -pub(crate) type AccountId = ::AccountId; +pub(crate) type AccountId = u64; pub(crate) type Balance = u128; // For terminology in tests. pub(crate) type TokenId = u32; -type Signature = MultiSignature; -type AccountPublic = ::Signer; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -99,7 +99,7 @@ impl pallet_assets::Config for Test { type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type Extra = (); - type ForceOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; @@ -119,12 +119,35 @@ parameter_types! { pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); } +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] +pub struct Noop; + +impl IdentifyAccount for Noop { + type AccountId = AccountId; + + fn into_account(self) -> Self::AccountId { + 0 + } +} + +impl Verify for Noop { + type Signer = Noop; + + fn verify>( + &self, + _msg: L, + _signer: &::AccountId, + ) -> bool { + false + } +} + impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; type CollectionDeposit = ConstU128<2>; type CollectionId = u32; - type CreateOrigin = AsEnsureOriginWithArg>; + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type DepositPerByte = ConstU128<1>; type Features = Features; @@ -140,11 +163,8 @@ impl pallet_nfts::Config for Test { type MaxDeadlineDuration = ConstU64<10000>; type MaxTips = ConstU32<10>; type MetadataDepositBase = ConstU128<1>; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; - /// Off-chain = signature On-chain - therefore no conversion needed. - /// It needs to be From for benchmarking. - type OffchainSignature = Signature; + type OffchainPublic = Noop; + type OffchainSignature = Noop; type RuntimeEvent = RuntimeEvent; type StringLimit = ConstU32<50>; type ValueLimit = ConstU32<50>; @@ -155,22 +175,13 @@ impl crate::nonfungibles::Config for Test { type RuntimeEvent = RuntimeEvent; } -/// Initialize a new account ID. -pub(crate) fn account(id: u8) -> AccountId { - [id; 32].into() -} - pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default() .build_storage() .expect("Frame system builds valid default genesis config"); pallet_balances::GenesisConfig:: { - balances: vec![ - (account(ALICE), INIT_AMOUNT), - (account(BOB), INIT_AMOUNT), - (account(CHARLIE), INIT_AMOUNT), - ], + balances: vec![(ALICE, INIT_AMOUNT), (BOB, INIT_AMOUNT), (CHARLIE, INIT_AMOUNT)], } .assimilate_storage(&mut t) .expect("Pallet balances storage can be assimilated"); diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 7377048f..1a5b07b8 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -5,24 +5,22 @@ pub use pallet::*; use pallet_nfts::WeightInfo; use sp_runtime::traits::StaticLookup; +pub use types::*; #[cfg(test)] mod tests; -mod types; +pub mod types; #[frame_support::pallet] pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::Incrementable}; use frame_system::pallet_prelude::*; - use pallet_nfts::{ - CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, - MintSettings, MintWitness, - }; + use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness}; + use sp_runtime::BoundedVec; use sp_std::vec::Vec; use types::{ - AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NextCollectionIdOf, - NftsOf, NftsWeightInfoOf, + AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionConfigFor, CollectionDetailsFor, + CollectionIdOf, ItemIdOf, ItemPriceOf, NextCollectionIdOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -48,25 +46,24 @@ pub mod pallet { item: Option>, }, /// Owner of a specified collection item. - #[codec(index = 3)] + #[codec(index = 5)] OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Attribute value of a collection item. - #[codec(index = 4)] + /// Attribute value of a collection item. (Error: bounded collection is not partial) + #[codec(index = 6)] GetAttribute { collection: CollectionIdOf, - item: Option>, + item: ItemIdOf, namespace: AttributeNamespaceOf, key: BoundedVec, }, /// Details of a collection. - #[codec(index = 6)] + #[codec(index = 9)] Collection(CollectionIdOf), - /// Details of a collection item. - #[codec(index = 7)] - Item { collection: CollectionIdOf, item: ItemIdOf }, /// Next collection ID. - #[codec(index = 8)] + #[codec(index = 10)] NextCollectionId, + #[codec(index = 11)] + ItemMetadata { collection: CollectionIdOf, item: ItemIdOf }, } /// Results of state reads for the non-fungibles API. @@ -74,7 +71,7 @@ pub mod pallet { #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { /// Total item supply of a collection. - TotalSupply(u32), + TotalSupply(u128), /// Account balance for a specified collection. BalanceOf(u32), /// Allowance for an operator approved by an owner, for a specified collection or item. @@ -82,13 +79,13 @@ pub mod pallet { /// Owner of a specified collection owner. OwnerOf(Option>), /// Attribute value of a collection item. - GetAttribute(Option>), + GetAttribute(Option>), /// Details of a collection. Collection(Option>), - /// Details of a collection item. - Item(Option>), /// Next collection ID. NextCollectionId(Option>), + /// Collection item metadata. + ItemMetadata(Option>), } impl ReadResult { @@ -100,10 +97,10 @@ pub mod pallet { TotalSupply(result) => result.encode(), BalanceOf(result) => result.encode(), Collection(result) => result.encode(), - Item(result) => result.encode(), Allowance(result) => result.encode(), GetAttribute(result) => result.encode(), NextCollectionId(result) => result.encode(), + ItemMetadata(result) => result.encode(), } } } @@ -162,54 +159,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(NftsWeightInfoOf::::mint())] - pub fn mint( - origin: OriginFor, - to: AccountIdOf, - collection: CollectionIdOf, - item: ItemIdOf, - mint_price: Option>, - ) -> DispatchResult { - let account = ensure_signed(origin.clone())?; - let witness_data = MintWitness { mint_price, owned_item: Some(item) }; - NftsOf::::mint( - origin, - collection, - item, - T::Lookup::unlookup(to.clone()), - Some(witness_data), - )?; - Self::deposit_event(Event::Transfer { - collection, - item, - from: None, - to: Some(account), - price: mint_price, - }); - Ok(()) - } - - #[pallet::call_index(1)] - #[pallet::weight(NftsWeightInfoOf::::burn())] - pub fn burn( - origin: OriginFor, - collection: CollectionIdOf, - item: ItemIdOf, - ) -> DispatchResult { - let account = ensure_signed(origin.clone())?; - NftsOf::::burn(origin, collection, item)?; - Self::deposit_event(Event::Transfer { - collection, - item, - from: Some(account), - to: None, - price: None, - }); - Ok(()) - } - - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( origin: OriginFor, @@ -229,7 +179,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight(NftsWeightInfoOf::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( origin: OriginFor, @@ -259,33 +209,25 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(4)] + #[pallet::call_index(7)] #[pallet::weight(NftsWeightInfoOf::::create())] pub fn create( origin: OriginFor, admin: AccountIdOf, - config: CreateCollectionConfigFor, + config: CollectionConfigFor, ) -> DispatchResult { + // 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::::get() .or(T::CollectionId::initial_value()) .ok_or(pallet_nfts::Error::::UnknownCollection)?; let creator = ensure_signed(origin.clone())?; - let collection_config = CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: config.max_supply, - mint_settings: MintSettings { - mint_type: config.mint_type, - start_block: config.start_block, - end_block: config.end_block, - ..MintSettings::default() - }, - }; - NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), config)?; Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } - #[pallet::call_index(5)] + #[pallet::call_index(8)] #[pallet::weight(NftsWeightInfoOf::::destroy( witness.item_metadatas, witness.item_configs, @@ -299,7 +241,7 @@ pub mod pallet { NftsOf::::destroy(origin, collection, witness) } - #[pallet::call_index(6)] + #[pallet::call_index(12)] #[pallet::weight(NftsWeightInfoOf::::set_attribute())] pub fn set_attribute( origin: OriginFor, @@ -312,7 +254,7 @@ pub mod pallet { NftsOf::::set_attribute(origin, collection, item, namespace, key, value) } - #[pallet::call_index(7)] + #[pallet::call_index(13)] #[pallet::weight(NftsWeightInfoOf::::clear_attribute())] pub fn clear_attribute( origin: OriginFor, @@ -324,7 +266,7 @@ pub mod pallet { NftsOf::::clear_attribute(origin, collection, item, namespace, key) } - #[pallet::call_index(8)] + #[pallet::call_index(14)] #[pallet::weight(NftsWeightInfoOf::::set_metadata())] pub fn set_metadata( origin: OriginFor, @@ -335,7 +277,7 @@ pub mod pallet { NftsOf::::set_metadata(origin, collection, item, data) } - #[pallet::call_index(9)] + #[pallet::call_index(15)] #[pallet::weight(NftsWeightInfoOf::::clear_metadata())] pub fn clear_metadata( origin: OriginFor, @@ -345,7 +287,7 @@ pub mod pallet { NftsOf::::clear_metadata(origin, collection, item) } - #[pallet::call_index(10)] + #[pallet::call_index(16)] #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] pub fn approve_item_attributes( origin: OriginFor, @@ -361,7 +303,7 @@ pub mod pallet { ) } - #[pallet::call_index(11)] + #[pallet::call_index(17)] #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] pub fn cancel_item_attributes_approval( origin: OriginFor, @@ -379,7 +321,7 @@ pub mod pallet { ) } - #[pallet::call_index(12)] + #[pallet::call_index(18)] #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] pub fn set_max_supply( origin: OriginFor, @@ -388,6 +330,53 @@ pub mod pallet { ) -> DispatchResult { NftsOf::::set_collection_max_supply(origin, collection, max_supply) } + + #[pallet::call_index(19)] + #[pallet::weight(NftsWeightInfoOf::::mint())] + pub fn mint( + origin: OriginFor, + to: AccountIdOf, + collection: CollectionIdOf, + item: ItemIdOf, + witness: MintWitness, ItemPriceOf>, + ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; + let mint_price = witness.mint_price; + NftsOf::::mint( + origin, + collection, + item, + T::Lookup::unlookup(to.clone()), + Some(witness), + )?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: None, + to: Some(account), + price: mint_price, + }); + Ok(()) + } + + #[pallet::call_index(20)] + #[pallet::weight(NftsWeightInfoOf::::burn())] + pub fn burn( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; + NftsOf::::burn(origin, collection, item)?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(account), + to: None, + price: None, + }); + Ok(()) + } } impl crate::Read for Pallet { @@ -413,7 +402,7 @@ pub mod pallet { use Read::*; match value { TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default(), + NftsOf::::collection_items(collection).unwrap_or_default() as u128, ), BalanceOf { collection, owner } => ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), @@ -423,13 +412,14 @@ pub mod pallet { OwnerOf { collection, item } => ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( - pallet_nfts::Attribute::::get((collection, item, namespace, key)) - .map(|attribute| attribute.0), + pallet_nfts::Attribute::::get((collection, Some(item), namespace, key)) + .map(|attribute| attribute.0.into()), ), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), - Item { collection, item } => - ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + ItemMetadata { collection, item } => ReadResult::ItemMetadata( + NftsOf::::item_metadata(collection, item).map(|metadata| metadata.into()), + ), NextCollectionId => ReadResult::NextCollectionId( NextCollectionIdOf::::get().or(T::CollectionId::initial_value()), ), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index e89ba0bd..79d484a2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -2,10 +2,10 @@ use codec::Encode; use frame_support::{assert_noop, assert_ok, traits::Incrementable}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{ - AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, - ItemDetails, MintSettings, + AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, DestroyWitness, + MintSettings, MintWitness, }; -use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; +use sp_runtime::{BoundedVec, DispatchError::BadOrigin}; use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ @@ -23,7 +23,7 @@ mod encoding_read_result { #[test] fn total_supply() { - let total_supply: u32 = 1_000_000; + let total_supply: u128 = 1_000_000; assert_eq!(ReadResult::TotalSupply::(total_supply).encode(), total_supply.encode()); } @@ -41,7 +41,7 @@ mod encoding_read_result { #[test] fn owner_of() { - let mut owner = Some(account(ALICE)); + let mut owner = Some(ALICE); assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); owner = None; assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); @@ -49,7 +49,7 @@ mod encoding_read_result { #[test] fn get_attribute() { - let mut attribute = Some(BoundedVec::truncate_from("some attribute".as_bytes().to_vec())); + let mut attribute = Some("some attribute".as_bytes().to_vec()); assert_eq!( ReadResult::GetAttribute::(attribute.clone()).encode(), attribute.encode() @@ -64,7 +64,7 @@ mod encoding_read_result { #[test] fn collection() { let mut collection_details = Some(CollectionDetails { - owner: account(ALICE), + owner: ALICE, owner_deposit: 0, items: 0, item_metadatas: 0, @@ -82,18 +82,6 @@ mod encoding_read_result { ); } - #[test] - fn item() { - let mut item_details = Some(ItemDetails { - owner: account(ALICE), - approvals: BoundedBTreeMap::default(), - deposit: ItemDeposit { amount: 0, account: account(BOB) }, - }); - assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); - item_details = None; - assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); - } - #[test] fn next_collection_id_works() { let mut next_collection_id = Some(0); @@ -107,6 +95,14 @@ mod encoding_read_result { next_collection_id.encode() ); } + + #[test] + fn item_metadata_works() { + let mut data = Some("some metadata".as_bytes().to_vec()); + assert_eq!(ReadResult::ItemMetadata::(data.clone()).encode(), data.encode()); + data = None; + assert_eq!(ReadResult::ItemMetadata::(data.clone()).encode(), data.encode()); + } } #[test] @@ -117,26 +113,17 @@ fn transfer() { let (collection, item) = nfts::create_collection_mint(owner, ITEM); for origin in vec![root(), none()] { - assert_noop!( - NonFungibles::transfer(origin, collection, item, account(dest)), - BadOrigin - ); + assert_noop!(NonFungibles::transfer(origin, collection, item, dest), BadOrigin); } // Successfully burn an existing new collection item. - let balance_before_transfer = AccountBalance::::get(collection, &account(dest)); - assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, account(dest))); - let balance_after_transfer = AccountBalance::::get(collection, &account(dest)); - assert_eq!(AccountBalance::::get(collection, &account(owner)), 0); + let balance_before_transfer = AccountBalance::::get(collection, &dest); + assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, dest)); + let balance_after_transfer = AccountBalance::::get(collection, &dest); + assert_eq!(AccountBalance::::get(collection, &owner), 0); assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( - Event::Transfer { - collection, - item, - from: Some(account(owner)), - to: Some(account(dest)), - price: None, - } - .into(), + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } + .into(), ); }); } @@ -148,20 +135,20 @@ fn mint_works() { let collection = nfts::create_collection(owner); // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection, account(owner)); - assert_ok!(NonFungibles::mint(signed(owner), account(owner), collection, ITEM, None)); - let balance_after_mint = AccountBalance::::get(collection, account(owner)); + let balance_before_mint = AccountBalance::::get(collection, owner); + assert_ok!(NonFungibles::mint( + signed(owner), + owner, + collection, + ITEM, + MintWitness { mint_price: None, owned_item: None } + )); + let balance_after_mint = AccountBalance::::get(collection, owner); assert_eq!(balance_after_mint, 1); assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { - collection, - item: ITEM, - from: None, - to: Some(account(owner)), - price: None, - } - .into(), + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } + .into(), ); }); } @@ -175,8 +162,7 @@ fn burn_works() { let (collection, item) = nfts::create_collection_mint(owner, ITEM); assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(account(owner)), to: None, price: None } - .into(), + Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); }); } @@ -188,25 +174,13 @@ fn approve_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint(owner, ITEM); // Successfully approve `oeprator` to transfer the collection item. - assert_ok!(NonFungibles::approve( - signed(owner), - collection, - Some(item), - account(operator), - true - )); + assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, true)); System::assert_last_event( - Event::Approval { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - approved: true, - } - .into(), + Event::Approval { collection, item: Some(item), owner, operator, approved: true } + .into(), ); // Successfully transfer the item by the delegated account `operator`. - assert_ok!(Nfts::transfer(signed(operator), collection, item, account(operator))); + assert_ok!(Nfts::transfer(signed(operator), collection, item, operator)); }); } @@ -217,16 +191,10 @@ fn cancel_approval_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); // Successfully cancel the transfer approval of `operator` by `owner`. - assert_ok!(NonFungibles::approve( - signed(owner), - collection, - Some(item), - account(operator), - false - )); + assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, false)); // Failed to transfer the item by `operator` without permission. assert_noop!( - Nfts::transfer(signed(operator), collection, item, account(operator)), + Nfts::transfer(signed(operator), collection, item, operator), NftsError::NoPermission ); }); @@ -239,10 +207,10 @@ fn set_max_supply_works() { let collection = nfts::create_collection(owner); assert_ok!(NonFungibles::set_max_supply(signed(owner), collection, 10)); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); }); assert_noop!( - Nfts::mint(signed(owner), collection, 42, account(owner), None), + Nfts::mint(signed(owner), collection, 42, owner, None), NftsError::MaxSupplyReached ); }); @@ -263,15 +231,14 @@ fn owner_of_works() { fn get_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); let mut result: Option::ValueLimit>> = None; // No attribute set. assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute.clone() }) @@ -291,7 +258,7 @@ fn get_attribute_works() { assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute }) @@ -301,13 +268,44 @@ fn get_attribute_works() { }); } +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let value = BoundedVec::truncate_from("some metadata".as_bytes().to_vec()); + assert_ok!(NonFungibles::set_metadata(signed(ALICE), collection, item, value.clone())); + assert_eq!( + NonFungibles::read(ItemMetadata { collection, item }).encode(), + Some(value).encode() + ); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_ok!(NonFungibles::set_metadata( + signed(ALICE), + collection, + item, + BoundedVec::truncate_from("some metadata".as_bytes().to_vec()) + )); + assert_ok!(NonFungibles::clear_metadata(signed(ALICE), collection, item)); + assert_eq!( + NonFungibles::read(ItemMetadata { collection, item }).encode(), + ReadResult::::ItemMetadata(None).encode() + ); + }); +} + #[test] fn clear_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let result: Option::ValueLimit>> = None; assert_ok!(Nfts::set_attribute( signed(ALICE), collection, @@ -327,7 +325,7 @@ fn clear_attribute_works() { assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute }) @@ -342,25 +340,24 @@ fn approve_item_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; // Successfully approve delegate to set attributes. - assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, BOB)); assert_ok!(Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); - result = Some(value); + let result: Option::ValueLimit>> = Some(value); assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), - namespace: pallet_nfts::AttributeNamespace::Account(account(BOB)), + item, + namespace: pallet_nfts::AttributeNamespace::Account(BOB), key: attribute }) .encode(), @@ -374,16 +371,15 @@ fn cancel_item_attribute_approval_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; // Successfully approve delegate to set attributes. - assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, BOB)); assert_ok!(Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -391,7 +387,7 @@ fn cancel_item_attribute_approval_works() { signed(ALICE), collection, item, - account(BOB), + BOB, pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } )); assert_noop!( @@ -399,7 +395,7 @@ fn cancel_item_attribute_approval_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() ), @@ -428,34 +424,57 @@ fn total_supply_works() { let owner = ALICE; let collection = nfts::create_collection(owner); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); - assert_eq!(NonFungibles::read(TotalSupply(collection)).encode(), (i + 1).encode()); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + ((i + 1) as u128).encode() + ); assert_eq!( NonFungibles::read(TotalSupply(collection)).encode(), - Nfts::collection_items(collection).unwrap_or_default().encode() + (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() ); }); }); } #[test] -fn collection_works() { +fn create_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(Collection(collection)).encode(), - pallet_nfts::Collection::::get(&collection).encode(), - ); + let owner = ALICE; + let next_collection_id = pallet_nfts::NextCollectionId::::get().unwrap_or_default(); + assert_ok!(NonFungibles::create( + signed(owner), + owner, + CollectionConfig { + max_supply: None, + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled() + }, + )); + assert_eq!(Nfts::collection_owner(next_collection_id), Some(owner)); }); } #[test] -fn item_works() { +fn destroy_works() { new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let collection = nfts::create_collection(ALICE); + assert_ok!(NonFungibles::destroy( + signed(ALICE), + collection, + DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } + )); + assert_eq!(Nfts::collection_owner(collection), None); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( - NonFungibles::read(Item { collection, item }).encode(), - pallet_nfts::Item::::get(&collection, &item).encode(), + NonFungibles::read(Collection(collection)).encode(), + pallet_nfts::Collection::::get(&collection).encode(), ); }); } @@ -466,14 +485,14 @@ fn balance_of_works() { let owner = ALICE; let collection = nfts::create_collection(owner); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + NonFungibles::read(BalanceOf { collection, owner }).encode(), (i + 1).encode() ); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), - AccountBalance::::get(collection, account(owner)).encode() + NonFungibles::read(BalanceOf { collection, owner }).encode(), + AccountBalance::::get(collection, owner).encode() ); }); }); @@ -486,32 +505,22 @@ fn allowance_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( - NonFungibles::read(Allowance { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - }) - .encode(), + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) + .encode(), true.encode() ); assert_eq!( - NonFungibles::read(Allowance { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - }) - .encode(), - Nfts::check_allowance(&collection, &Some(item), &account(owner), &account(operator)) + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) + .encode(), + Nfts::check_allowance(&collection, &Some(item), &owner, &operator) .is_ok() .encode() ); }); } -fn signed(account_id: u8) -> RuntimeOrigin { - RuntimeOrigin::signed(account(account_id)) +fn signed(account_id: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account_id) } fn root() -> RuntimeOrigin { @@ -526,32 +535,26 @@ mod nfts { use super::*; pub(super) fn create_collection_mint_and_approve( - owner: u8, + owner: AccountId, item: ItemIdOf, - operator: u8, + operator: AccountId, ) -> (u32, u32) { let (collection, item) = create_collection_mint(owner, item); - assert_ok!(Nfts::approve_transfer( - signed(owner), - collection, - Some(item), - account(operator), - None - )); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), operator, None)); (collection, item) } - pub(super) fn create_collection_mint(owner: u8, item: ItemIdOf) -> (u32, u32) { + pub(super) fn create_collection_mint(owner: AccountId, item: ItemIdOf) -> (u32, u32) { let collection = create_collection(owner); - assert_ok!(Nfts::mint(signed(owner), collection, item, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, item, owner, None)); (collection, item) } - pub(super) fn create_collection(owner: u8) -> u32 { + pub(super) fn create_collection(owner: AccountId) -> u32 { let next_id = next_collection_id(); assert_ok!(Nfts::create( signed(owner), - account(owner), + owner, collection_config_with_all_settings_enabled() )); next_id diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index f57ee697..6e686389 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,13 +1,12 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails, MintType}; -use scale_info::TypeInfo; -use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; +pub use pallet_nfts::{ + AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, + DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, +}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; -pub(super) type NftsErrorOf = pallet_nfts::Error; pub(super) type NftsWeightInfoOf = ::WeightInfo; // Type aliases for pallet-nfts storage items. pub(super) type AccountIdOf = ::AccountId; @@ -19,27 +18,10 @@ pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -pub(super) type ApprovalsOf = BoundedBTreeMap< - AccountIdOf, - Option>, - ::ApprovalsLimit, ->; pub(super) type ItemPriceOf = BalanceOf; // TODO: Multi-instances. -pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; -pub(super) type ItemDetailsFor = - ItemDetails, ItemDepositOf, ApprovalsOf>; pub(super) type AttributeNamespaceOf = AttributeNamespace>; -pub(super) type CreateCollectionConfigFor = - CreateCollectionConfig, BlockNumberFor, CollectionIdOf>; - -#[derive(Clone, Copy, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub struct CreateCollectionConfig { - pub max_supply: Option, - pub mint_type: MintType, - pub price: Option, - pub start_block: Option, - pub end_block: Option, -} +pub(super) type CollectionConfigFor = + CollectionConfig, BlockNumberFor, CollectionIdOf>; diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 60b3b746..0a882d72 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -44,6 +44,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "scale-info/std", "sp-core/std", "sp-io/std", diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..ab66da26 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -578,9 +578,9 @@ benchmarks_instance_pallet! { let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let deadline = BlockNumberFor::::max_value(); - }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) + }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(deadline) }.into()); + assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); } cancel_approval { @@ -590,10 +590,10 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) + Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -603,7 +603,7 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 6fe483f1..89de1f05 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,6 +39,14 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.items) } + /// Get the metadata of the collection item. + pub fn item_metadata( + collection: T::CollectionId, + item: T::ItemId, + ) -> Option> { + ItemMetadataOf::::get(collection, item).map(|metadata| metadata.data) + } + /// Validates the signature of the given data with the provided signer's account ID. /// /// # Errors diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 6d71c1a2..e1e79ef4 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -180,24 +180,26 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - if !Collection::::contains_key(collection) { - return Err(Error::::UnknownCollection.into()); - } + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + let collection_config = Self::get_collection_config(&collection)?; ensure!( collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; - Allowances::::mutate((&collection, &origin, &delegate), |allowance| { + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + Allowances::::mutate((&collection, &owner, &delegate), |allowance| { *allowance = true; }); Self::deposit_event(Event::TransferApproved { collection, item: None, - owner: origin, + owner, delegate, deadline: None, }); @@ -209,19 +211,14 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - if !Collection::::contains_key(collection) { - return Err(Error::::UnknownCollection.into()); - } + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; - Allowances::::remove((&collection, &origin, &delegate)); + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + Allowances::::remove((&collection, &owner, &delegate)); - Self::deposit_event(Event::ApprovalCancelled { - collection, - owner: origin, - item: None, - delegate, - }); + Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); Ok(()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 397a715c..4d0f08c9 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -318,7 +318,7 @@ fn destroy_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), @@ -2017,22 +2017,22 @@ fn cancel_approval_collection_works_with_admin() { )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), Error::::UnknownCollection ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, item: None, - owner: account(2), + owner: account(1), delegate: account(3) })); assert_eq!(Allowances::::get((0, account(2), account(3))), false); @@ -2156,7 +2156,7 @@ fn approval_collection_works_with_admin() { RuntimeOrigin::signed(account(1)), 0, 42, - account(2), + account(1), default_item_config() )); @@ -2178,7 +2178,7 @@ fn approval_collection_works_with_admin() { ); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), @@ -2187,11 +2187,11 @@ fn approval_collection_works_with_admin() { assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, - owner: account(2), + owner: account(1), delegate: account(3), deadline: None })); - assert_eq!(Allowances::::get((0, account(2), account(3))), true); + assert_eq!(Allowances::::get((0, account(1), account(3))), true); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 061352c0..941da6ca 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -145,21 +145,21 @@ pub struct MintWitness { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub owner: AccountId, + pub(super) owner: AccountId, /// The approved transferrer of this item, if one is set. - pub approvals: Approvals, + pub(super) approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub deposit: Deposit, + pub(super) deposit: Deposit, } /// Information about the reserved item deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub account: AccountId, + pub(super) account: AccountId, /// An amount that gets reserved. - pub amount: DepositBalance, + pub(super) amount: DepositBalance, } /// Information about the collection's metadata. diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index c5fb60a2..c374d6db 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -1,30 +1,14 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. //! Autogenerated weights for `pallet_nfts` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 +//! DATE: 2024-10-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `R0GUE`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// ./target/release/pop-node // benchmark // pallet // --chain=dev @@ -34,12 +18,11 @@ // --no-storage-info // --no-median-slopes // --no-min-squares -// --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nfts/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./pallets/nfts/src/weights.rs +// --template=./scripts/pallet-weights-template.hbs +// --extrinsic= #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -107,10 +90,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `216` + // Measured: `105` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(27_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -126,10 +109,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -141,6 +124,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -152,15 +137,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` + // Measured: `32216 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1004_u64)) + // Minimum execution time: 982_000_000 picoseconds. + Weight::from_parts(937_587_516, 2523990) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1005_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -174,18 +163,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(42_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -195,18 +186,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -218,22 +211,24 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `564` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(59_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -245,6 +240,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -253,12 +250,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `593` - // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `605` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(83_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -269,12 +266,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `763 + i * (108 ±0)` + // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 20_022 + .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -286,10 +283,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -299,10 +296,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -312,10 +309,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -329,10 +326,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -342,10 +339,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `369` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -355,10 +352,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `238` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -368,10 +365,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `203` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -381,10 +378,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -400,10 +397,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -413,10 +410,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(19_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -430,30 +427,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Measured: `308` + // Estimated: `4466` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4466) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -461,12 +458,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Measured: `686 + n * (398 ±0)` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 4466) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -485,10 +482,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -502,10 +499,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -519,10 +516,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `398` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -536,10 +533,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` + // Measured: `643` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(29_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -549,10 +546,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `410` + // Measured: `337` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -560,10 +557,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -571,10 +568,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -582,10 +579,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -595,10 +592,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,10 +605,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `323` + // Measured: `250` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -625,10 +622,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `518` + // Measured: `478` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -644,28 +641,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `717` + // Estimated: `6068` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(45_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(390_532, 0) + // Standard Error: 84_277 + .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -673,10 +672,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `494` + // Measured: `421` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -686,10 +685,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `513` + // Measured: `440` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -705,18 +704,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:4) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `834` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(10_u64)) + // Minimum execution time: 75_000_000 picoseconds. + Weight::from_parts(77_000_000, 7662) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -726,6 +727,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -739,22 +742,22 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `629` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(107_476_765, 6078) + // Standard Error: 61_259 + .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) @@ -766,12 +769,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Measured: `514` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(57_358_180, 4466) + // Standard Error: 54_968 + .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -794,10 +797,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `216` + // Measured: `105` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(27_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -813,10 +816,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -828,6 +831,8 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -839,15 +844,19 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` + // Measured: `32216 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1004_u64)) + // Minimum execution time: 982_000_000 picoseconds. + Weight::from_parts(937_587_516, 2523990) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1005_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -861,18 +870,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(42_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -882,18 +893,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -905,22 +918,24 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `564` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(59_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -932,6 +947,8 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -940,12 +957,12 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `593` - // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `605` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(83_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -956,12 +973,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `763 + i * (108 ±0)` + // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 20_022 + .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -973,10 +990,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -986,10 +1003,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -999,10 +1016,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1016,10 +1033,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1029,10 +1046,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `369` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1042,10 +1059,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `238` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1055,10 +1072,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `203` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1068,10 +1085,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1087,10 +1104,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1100,10 +1117,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(19_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1117,30 +1134,30 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Measured: `308` + // Estimated: `4466` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4466) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1148,12 +1165,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Measured: `686 + n * (398 ±0)` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 4466) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1172,10 +1189,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1189,10 +1206,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1206,10 +1223,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `398` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1223,10 +1240,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` + // Measured: `643` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(29_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1236,10 +1253,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `410` + // Measured: `337` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1247,10 +1264,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1258,10 +1275,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1269,10 +1286,10 @@ impl WeightInfo for () { /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1282,10 +1299,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1295,10 +1312,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `323` + // Measured: `250` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1312,10 +1329,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `518` + // Measured: `478` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,28 +1348,30 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `717` + // Estimated: `6068` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(45_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(390_532, 0) + // Standard Error: 84_277 + .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1360,10 +1379,10 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `494` + // Measured: `421` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1373,10 +1392,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `513` + // Measured: `440` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1392,18 +1411,20 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:4) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `834` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(10_u64)) + // Minimum execution time: 75_000_000 picoseconds. + Weight::from_parts(77_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1413,6 +1434,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1426,22 +1449,22 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `629` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(107_476_765, 6078) + // Standard Error: 61_259 + .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) @@ -1453,16 +1476,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Measured: `514` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(57_358_180, 4466) + // Standard Error: 54_968 + .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } -} +} \ No newline at end of file diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 035a6014..93f4853f 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use codec::Decode; use cumulus_primitives_core::Weight; -use frame_support::traits::Contains; +use frame_support::traits::{ConstU32, Contains}; pub(crate) use pallet_api::Extension; use pallet_api::{extension::*, Read}; use sp_core::ConstU8; @@ -11,7 +11,9 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::TrustBackedAssetsInstance, fungibles, Runtime, RuntimeCall, RuntimeEvent, + config::{assets::TrustBackedAssetsInstance, xcm::LocalOriginToLocation}, + fungibles, nonfungibles, Balances, Ismp, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, TransactionByteFee, }; mod versioning; @@ -32,6 +34,9 @@ pub enum RuntimeRead { /// Fungible token queries. #[codec(index = 150)] Fungibles(fungibles::Read), + /// Non-fungible token queries. + #[codec(index = 151)] + NonFungibles(nonfungibles::Read), } impl Readable for RuntimeRead { @@ -43,6 +48,7 @@ impl Readable for RuntimeRead { fn weight(&self) -> Weight { match self { RuntimeRead::Fungibles(key) => fungibles::Pallet::weight(key), + RuntimeRead::NonFungibles(key) => nonfungibles::Pallet::weight(key), } } @@ -50,16 +56,20 @@ impl Readable for RuntimeRead { fn read(self) -> Self::Result { match self { RuntimeRead::Fungibles(key) => RuntimeResult::Fungibles(fungibles::Pallet::read(key)), + RuntimeRead::NonFungibles(key) => + RuntimeResult::NonFungibles(nonfungibles::Pallet::read(key)), } } } /// The result of a runtime state read. #[derive(Debug)] -#[cfg_attr(test, derive(PartialEq, Clone))] +#[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum RuntimeResult { /// Fungible token read results. Fungibles(fungibles::ReadResult), + /// Non-fungible token read results. + NonFungibles(nonfungibles::ReadResult), } impl RuntimeResult { @@ -67,6 +77,7 @@ impl RuntimeResult { fn encode(&self) -> Vec { match self { RuntimeResult::Fungibles(result) => result.encode(), + RuntimeResult::NonFungibles(result) => result.encode(), } } } @@ -77,6 +88,10 @@ impl fungibles::Config for Runtime { type WeightInfo = fungibles::weights::SubstrateWeight; } +impl nonfungibles::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + #[derive(Default)] pub struct Config; impl pallet_api::extension::Config for Config { @@ -130,8 +145,8 @@ pub struct Filter(PhantomData); impl> Contains for Filter { fn contains(c: &RuntimeCall) -> bool { - use fungibles::Call::*; - T::BaseCallFilter::contains(c) && + let contain_fungibles: bool = { + use fungibles::Call::*; matches!( c, RuntimeCall::Fungibles( @@ -142,26 +157,63 @@ impl> Contains f create { .. } | set_metadata { .. } | start_destroy { .. } | clear_metadata { .. } | - mint { .. } | burn { .. } + mint { .. } | burn { .. }, + ) + ) + }; + + let contain_nonfungibles: bool = { + use nonfungibles::Call::*; + matches!( + c, + RuntimeCall::NonFungibles( + transfer { .. } | + approve { .. } | create { .. } | + destroy { .. } | set_metadata { .. } | + clear_metadata { .. } | + set_attribute { .. } | + clear_attribute { .. } | + approve_item_attributes { .. } | + cancel_item_attributes_approval { .. } | + mint { .. } | burn { .. } | + set_max_supply { .. }, ) ) + }; + + T::BaseCallFilter::contains(c) && contain_fungibles | contain_nonfungibles } } impl Contains for Filter { fn contains(r: &RuntimeRead) -> bool { - use fungibles::Read::*; - matches!( - r, - RuntimeRead::Fungibles( - TotalSupply(..) | - BalanceOf { .. } | - Allowance { .. } | - TokenName(..) | TokenSymbol(..) | - TokenDecimals(..) | - TokenExists(..) + let contain_fungibles: bool = { + use fungibles::Read::*; + matches!( + r, + RuntimeRead::Fungibles( + TotalSupply(..) | + BalanceOf { .. } | Allowance { .. } | + TokenName(..) | TokenSymbol(..) | + TokenDecimals(..) | TokenExists(..), + ) + ) + }; + let contain_nonfungibles: bool = { + use nonfungibles::Read::*; + matches!( + r, + RuntimeRead::NonFungibles( + TotalSupply(..) | + BalanceOf { .. } | Allowance { .. } | + OwnerOf { .. } | GetAttribute { .. } | + Collection { .. } | NextCollectionId | + ItemMetadata { .. }, + ) ) - ) + }; + + contain_fungibles | contain_nonfungibles } } @@ -169,8 +221,9 @@ impl Contains for Filter { mod tests { use codec::Encode; use pallet_api::fungibles::Call::*; - use sp_core::crypto::AccountId32; - use RuntimeCall::{Balances, Fungibles}; + use pallet_nfts::MintWitness; + use sp_core::{bounded_vec, crypto::AccountId32}; + use RuntimeCall::{Balances, Fungibles, NonFungibles}; use super::*; @@ -181,6 +234,10 @@ mod tests { let value = 1_000; let result = fungibles::ReadResult::::TotalSupply(value); assert_eq!(RuntimeResult::Fungibles(result).encode(), value.encode()); + + let value = 1_000; + let result = nonfungibles::ReadResult::::TotalSupply(value); + assert_eq!(RuntimeResult::NonFungibles(result).encode(), value.encode()); } #[test] @@ -228,6 +285,71 @@ mod tests { } } + #[test] + fn filter_allows_nonfungibles_calls() { + use pallet_api::nonfungibles::{ + types::{CollectionConfig, CollectionSettings, MintSettings}, + Call::*, + }; + use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness}; + + for call in vec![ + NonFungibles(transfer { collection: 0, item: 0, to: ACCOUNT }), + NonFungibles(approve { + collection: 0, + item: Some(0), + operator: ACCOUNT, + approved: false, + }), + NonFungibles(create { + admin: ACCOUNT, + config: CollectionConfig { + max_supply: Some(0), + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled(), + }, + }), + NonFungibles(destroy { + collection: 0, + witness: DestroyWitness { attributes: 0, item_configs: 0, item_metadatas: 0 }, + }), + NonFungibles(set_attribute { + collection: 0, + item: Some(0), + namespace: pallet_nfts::AttributeNamespace::Pallet, + key: bounded_vec![], + value: bounded_vec![], + }), + NonFungibles(clear_attribute { + collection: 0, + item: Some(0), + namespace: pallet_nfts::AttributeNamespace::Pallet, + key: bounded_vec![], + }), + NonFungibles(set_metadata { collection: 0, item: 0, data: bounded_vec![] }), + NonFungibles(clear_metadata { collection: 0, item: 0 }), + NonFungibles(approve_item_attributes { collection: 0, item: 0, delegate: ACCOUNT }), + NonFungibles(cancel_item_attributes_approval { + collection: 0, + item: 0, + delegate: ACCOUNT, + witness: CancelAttributesApprovalWitness { account_attributes: 0 }, + }), + NonFungibles(set_max_supply { collection: 0, max_supply: 0 }), + NonFungibles(mint { + to: ACCOUNT, + collection: 0, + item: 0, + witness: MintWitness { mint_price: None, owned_item: None }, + }), + NonFungibles(burn { collection: 0, item: 0 }), + ] + .iter() + { + assert!(Filter::::contains(call)) + } + } + #[test] fn filter_allows_fungibles_reads() { use super::{fungibles::Read::*, RuntimeRead::*}; @@ -245,4 +367,33 @@ mod tests { assert!(Filter::::contains(&read)) } } + + #[test] + fn filter_allows_nonfungibles_reads() { + use super::{nonfungibles::Read::*, RuntimeRead::*}; + + for read in vec![ + NonFungibles(TotalSupply(1)), + NonFungibles(BalanceOf { collection: 1, owner: ACCOUNT }), + NonFungibles(Allowance { + collection: 1, + item: None, + owner: ACCOUNT, + operator: ACCOUNT, + }), + NonFungibles(OwnerOf { collection: 1, item: 1 }), + NonFungibles(GetAttribute { + collection: 0, + item: 0, + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: bounded_vec![], + }), + NonFungibles(Collection(1)), + NonFungibles(NextCollectionId), + ] + .iter() + { + assert!(Filter::::contains(read)) + } + } } diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 326b7e59..28a51d52 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -6,7 +6,7 @@ use frame_support::{ use frame_system::{EnsureRoot, EnsureSigned}; use pallet_nfts::PalletFeatures; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId, Signature}; -use sp_runtime::traits::Verify; +use sp_runtime::traits::{Get, Verify}; use crate::{ deposit, AccountId, Assets, Balance, Balances, BlockNumber, Nfts, Runtime, RuntimeEvent, @@ -37,6 +37,15 @@ parameter_types! { pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(PartialEq, Clone))] +pub struct KeyLimit; +impl Get for KeyLimit { + fn get() -> u32 { + N + } +} + impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; @@ -56,7 +65,7 @@ impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ItemId = ItemId; // TODO: source from primitives - type KeyLimit = ConstU32<64>; + type KeyLimit = KeyLimit<64>; type Locker = (); type MaxAttributesPerCall = ConstU32<10>; type MaxDeadlineDuration = NftsMaxDeadlineDuration; diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index f539cbde..1d860f62 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -39,7 +39,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use pallet_api::fungibles; +use pallet_api::{fungibles, nonfungibles}; use pallet_balances::Call as BalancesCall; use pallet_ismp::mmr::{Leaf, Proof, ProofKeys}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; @@ -637,6 +637,8 @@ mod runtime { // Pop API #[runtime::pallet_index(150)] pub type Fungibles = fungibles::Pallet; + #[runtime::pallet_index(151)] + pub type NonFungibles = nonfungibles::Pallet; } #[cfg(feature = "runtime-benchmarks")] @@ -648,6 +650,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] [pallet_message_queue, MessageQueue] + [pallet_nfts, Nfts] [pallet_sudo, Sudo] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] From a651c3ec66b9294a28d1635262d0ea7e63fafe66 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:42:12 +0700 Subject: [PATCH 22/64] fix: becnhmark helper --- pallets/api/src/mock.rs | 19 +++++++++++++++++++ runtime/devnet/src/config/api/mod.rs | 7 +++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 8a4ad27d..1e6216f5 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -142,6 +142,25 @@ impl Verify for Noop { } } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_nfts::pallet::BenchmarkHelper for () { + fn collection(i: u16) -> u32 { + i.into() + } + + fn item(i: u16) -> u32 { + i.into() + } + + fn signer() -> (Noop, u64) { + unimplemented!() + } + + fn sign(signer: &Noop, message: &[u8]) -> Noop { + unimplemented!() + } +} + impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 93f4853f..b7c33279 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use codec::Decode; use cumulus_primitives_core::Weight; -use frame_support::traits::{ConstU32, Contains}; +use frame_support::traits::Contains; pub(crate) use pallet_api::Extension; use pallet_api::{extension::*, Read}; use sp_core::ConstU8; @@ -11,9 +11,8 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::{assets::TrustBackedAssetsInstance, xcm::LocalOriginToLocation}, - fungibles, nonfungibles, Balances, Ismp, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, - RuntimeHoldReason, TransactionByteFee, + config::assets::TrustBackedAssetsInstance, fungibles, nonfungibles, Runtime, RuntimeCall, + RuntimeEvent, }; mod versioning; From ae9ef78ffff6e311913f82729a9107c92ec27477 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:39:46 +0700 Subject: [PATCH 23/64] feat: multi instances & function comments --- pallets/api/src/mock.rs | 7 +- pallets/api/src/nonfungibles/mod.rs | 172 ++++++++++++++++++++++---- pallets/api/src/nonfungibles/tests.rs | 52 ++++---- pallets/api/src/nonfungibles/types.rs | 27 ---- 4 files changed, 186 insertions(+), 72 deletions(-) delete mode 100644 pallets/api/src/nonfungibles/types.rs diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 1e6216f5..d11a8c98 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -32,7 +32,7 @@ frame_support::construct_runtime!( Assets: pallet_assets::, Balances: pallet_balances, Fungibles: crate::fungibles, - Nfts: pallet_nfts, + Nfts: pallet_nfts::, NonFungibles: crate::nonfungibles } ); @@ -161,7 +161,8 @@ impl pallet_nfts::pallet::BenchmarkHelper for () { } } -impl pallet_nfts::Config for Test { +type NftsInstance = pallet_nfts::Instance1; +impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; type CollectionDeposit = ConstU128<2>; @@ -191,7 +192,9 @@ impl pallet_nfts::Config for Test { } impl crate::nonfungibles::Config for Test { + type NftsInstance = NftsInstance; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 1a5b07b8..b3370a84 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -2,14 +2,40 @@ //! assets. The goal is to provide a simplified, consistent API that adheres to standards in the //! smart contract space. +use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; +use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; use pallet_nfts::WeightInfo; +pub use pallet_nfts::{ + AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, + DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, +}; use sp_runtime::traits::StaticLookup; -pub use types::*; #[cfg(test)] mod tests; -pub mod types; + +type AccountIdOf = ::AccountId; +type NftsOf = pallet_nfts::Pallet>; +type NftsErrorOf = pallet_nfts::Error>; +type NftsWeightInfoOf = >>::WeightInfo; +type NftsInstanceOf = ::NftsInstance; +type BalanceOf = <>>::Currency as Currency< + ::AccountId, +>>::Balance; +type CollectionIdOf = + as Inspect<::AccountId>>::CollectionId; +type ItemIdOf = as Inspect<::AccountId>>::ItemId; +type ItemPriceOf = BalanceOf; +type CollectionDetailsFor = CollectionDetails, BalanceOf>; +type AttributeNamespaceOf = AttributeNamespace>; +type CollectionConfigFor = + CollectionConfig, BlockNumberFor, CollectionIdOf>; +// Type aliases for storage items. +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; +pub(super) type AttributeOf = pallet_nfts::Attribute>; +pub(super) type CollectionOf = pallet_nfts::Collection>; #[frame_support::pallet] pub mod pallet { @@ -18,10 +44,6 @@ pub mod pallet { use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness}; use sp_runtime::BoundedVec; use sp_std::vec::Vec; - use types::{ - AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionConfigFor, CollectionDetailsFor, - CollectionIdOf, ItemIdOf, ItemPriceOf, NextCollectionIdOf, NftsOf, NftsWeightInfoOf, - }; use super::*; @@ -31,39 +53,64 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Total item supply of a collection. + /// Total item supply of a specified collection. #[codec(index = 0)] TotalSupply(CollectionIdOf), /// Account balance for a specified collection. #[codec(index = 1)] - BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, + BalanceOf { + // The collection. + collection: CollectionIdOf, + // The owner of the collection . + owner: AccountIdOf, + }, /// Allowance for an operator approved by an owner, for a specified collection or item. #[codec(index = 2)] Allowance { + // The collection. collection: CollectionIdOf, + // The collection item. + item: Option>, + // The owner of the collection item. owner: AccountIdOf, + // The delegated operator of collection item. operator: AccountIdOf, - item: Option>, }, /// Owner of a specified collection item. #[codec(index = 5)] - OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Attribute value of a collection item. (Error: bounded collection is not partial) + OwnerOf { + // The collection. + collection: CollectionIdOf, + // The collection item. + item: ItemIdOf, + }, + /// Attribute value of a specified collection item. (Error: bounded collection is not + /// partial) #[codec(index = 6)] GetAttribute { + // The collection. collection: CollectionIdOf, + // The collection item. item: ItemIdOf, + // The namespace of the attribute. namespace: AttributeNamespaceOf, + // The key of the attribute. key: BoundedVec, }, - /// Details of a collection. + /// Details of a specified collection. #[codec(index = 9)] Collection(CollectionIdOf), /// Next collection ID. #[codec(index = 10)] NextCollectionId, + /// Metadata of a specified collection item. #[codec(index = 11)] - ItemMetadata { collection: CollectionIdOf, item: ItemIdOf }, + ItemMetadata { + // The collection. + collection: CollectionIdOf, + // The collection item. + item: ItemIdOf, + }, } /// Results of state reads for the non-fungibles API. @@ -78,13 +125,13 @@ pub mod pallet { Allowance(bool), /// Owner of a specified collection owner. OwnerOf(Option>), - /// Attribute value of a collection item. + /// Attribute value of a specified collection item. GetAttribute(Option>), - /// Details of a collection. + /// Details of a specified collection. Collection(Option>), /// Next collection ID. NextCollectionId(Option>), - /// Collection item metadata. + /// Metadata of a specified collection item. ItemMetadata(Option>), } @@ -107,9 +154,13 @@ pub mod pallet { /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] - pub trait Config: frame_system::Config + pallet_nfts::Config { + pub trait Config: frame_system::Config + pallet_nfts::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The instance of pallet-nfts. + type NftsInstance; + /// Weight information for dispatchables in this pallet. + type WeightInfo: WeightInfo; } #[pallet::pallet] @@ -159,6 +210,12 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// 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. + /// - `to` - The recipient account. #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( @@ -179,6 +236,13 @@ pub mod pallet { 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. + /// - `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::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( @@ -209,6 +273,12 @@ pub mod pallet { Ok(()) } + /// 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::::create())] pub fn create( @@ -220,13 +290,19 @@ pub mod pallet { // issues for setting it to xcm's `Location`. This can easily be done differently. let id = NextCollectionIdOf::::get() .or(T::CollectionId::initial_value()) - .ok_or(pallet_nfts::Error::::UnknownCollection)?; + .ok_or(NftsErrorOf::::UnknownCollection)?; let creator = ensure_signed(origin.clone())?; NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), config)?; Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } + /// Destroy a collection of fungible items. + /// + /// # Parameters + /// - `collection` - The identifier of the collection to be destroyed. + /// - `witness` - Information on the items minted in the collection. This must be + /// correct. #[pallet::call_index(8)] #[pallet::weight(NftsWeightInfoOf::::destroy( witness.item_metadatas, @@ -241,6 +317,14 @@ pub mod pallet { NftsOf::::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::::set_attribute())] pub fn set_attribute( @@ -254,6 +338,13 @@ pub mod pallet { NftsOf::::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::::clear_attribute())] pub fn clear_attribute( @@ -266,6 +357,12 @@ pub mod pallet { NftsOf::::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::::set_metadata())] pub fn set_metadata( @@ -287,6 +384,12 @@ pub mod pallet { NftsOf::::clear_metadata(origin, collection, item) } + /// Approve item's attributes to be changed by a delegated third-party account. + /// + /// # Parameters + /// - `collection` - The collection of the item. + /// - `item` - The item that holds attributes. + /// - `delegate` - The account to delegate permission to change attributes of the item. #[pallet::call_index(16)] #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] pub fn approve_item_attributes( @@ -303,6 +406,14 @@ pub mod pallet { ) } + /// Cancel the previously provided approval to change item's attributes. + /// All the previously set attributes by the `delegate` will be removed. + /// + /// # Parameters + /// - `collection` - 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. #[pallet::call_index(17)] #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] pub fn cancel_item_attributes_approval( @@ -321,6 +432,11 @@ pub mod pallet { ) } + /// Set the maximum number of items a collection could have. + /// + /// # Parameters + /// - `collection` - The identifier of the collection to change. + /// - `max_supply` - The maximum number of items a collection could have. #[pallet::call_index(18)] #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] pub fn set_max_supply( @@ -331,6 +447,15 @@ pub mod pallet { NftsOf::::set_collection_max_supply(origin, collection, max_supply) } + /// Mint an item of a particular collection. + /// + /// # Parameters + /// - `collection` - The collection of the item to be minted. + /// - `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`. #[pallet::call_index(19)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -359,6 +484,11 @@ pub mod pallet { Ok(()) } + /// Destroy a single collection item. + /// + /// # Parameters + /// - `collection` - The collection of the item to be burned. + /// - `item` - The item to be burned. #[pallet::call_index(20)] #[pallet::weight(NftsWeightInfoOf::::burn())] pub fn burn( @@ -405,18 +535,18 @@ pub mod pallet { NftsOf::::collection_items(collection).unwrap_or_default() as u128, ), BalanceOf { collection, owner } => - ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), + ReadResult::BalanceOf(AccountBalanceOf::::get(collection, owner)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), OwnerOf { collection, item } => ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( - pallet_nfts::Attribute::::get((collection, Some(item), namespace, key)) + AttributeOf::::get((collection, Some(item), namespace, key)) .map(|attribute| attribute.0.into()), ), Collection(collection) => - ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + ReadResult::Collection(CollectionOf::::get(collection)), ItemMetadata { collection, item } => ReadResult::ItemMetadata( NftsOf::::item_metadata(collection, item).map(|metadata| metadata.into()), ), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 79d484a2..290f49f2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,22 +1,24 @@ use codec::Encode; -use frame_support::{assert_noop, assert_ok, traits::Incrementable}; -use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{ - AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, DestroyWitness, - MintSettings, MintWitness, +use frame_support::{ + assert_noop, assert_ok, + sp_runtime::{BoundedVec, DispatchError::BadOrigin}, + traits::Incrementable, }; -use sp_runtime::{BoundedVec, DispatchError::BadOrigin}; -use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ mock::*, - nonfungibles::{Event, Read::*, ReadResult}, + nonfungibles::{ + AccountBalanceOf, BlockNumberFor, CollectionConfig, CollectionDetails, CollectionIdOf, + CollectionOf, CollectionSettings, DestroyWitness, ItemIdOf, MintSettings, MintWitness, + NextCollectionIdOf, NftsInstanceOf, Read::*, ReadResult, + }, Read, }; const ITEM: u32 = 1; -type NftsError = pallet_nfts::Error; +type NftsError = pallet_nfts::Error>; +type Event = crate::nonfungibles::Event; mod encoding_read_result { use super::*; @@ -116,10 +118,10 @@ fn transfer() { assert_noop!(NonFungibles::transfer(origin, collection, item, dest), BadOrigin); } // Successfully burn an existing new collection item. - let balance_before_transfer = AccountBalance::::get(collection, &dest); + let balance_before_transfer = AccountBalanceOf::::get(collection, &dest); assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, dest)); - let balance_after_transfer = AccountBalance::::get(collection, &dest); - assert_eq!(AccountBalance::::get(collection, &owner), 0); + let balance_after_transfer = AccountBalanceOf::::get(collection, &dest); + assert_eq!(AccountBalanceOf::::get(collection, &owner), 0); assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } @@ -135,7 +137,7 @@ fn mint_works() { let collection = nfts::create_collection(owner); // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection, owner); + let balance_before_mint = AccountBalanceOf::::get(collection, owner); assert_ok!(NonFungibles::mint( signed(owner), owner, @@ -143,7 +145,7 @@ fn mint_works() { ITEM, MintWitness { mint_price: None, owned_item: None } )); - let balance_after_mint = AccountBalance::::get(collection, owner); + let balance_after_mint = AccountBalanceOf::::get(collection, owner); assert_eq!(balance_after_mint, 1); assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( @@ -233,7 +235,9 @@ fn get_attribute_works() { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; + let mut result: Option< + BoundedVec>>::ValueLimit>, + > = None; // No attribute set. assert_eq!( NonFungibles::read(GetAttribute { @@ -305,7 +309,9 @@ fn clear_attribute_works() { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let result: Option::ValueLimit>> = None; + let result: Option< + BoundedVec>>::ValueLimit>, + > = None; assert_ok!(Nfts::set_attribute( signed(ALICE), collection, @@ -352,7 +358,9 @@ fn approve_item_attribute_works() { attribute.clone(), value.clone() )); - let result: Option::ValueLimit>> = Some(value); + let result: Option< + BoundedVec>>::ValueLimit>, + > = Some(value); assert_eq!( NonFungibles::read(GetAttribute { collection, @@ -411,7 +419,7 @@ fn next_collection_id_works() { assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); assert_eq!( NonFungibles::read(NextCollectionId).encode(), - pallet_nfts::NextCollectionId::::get() + NextCollectionIdOf::::get() .or(CollectionIdOf::::initial_value()) .encode(), ); @@ -441,7 +449,7 @@ fn total_supply_works() { fn create_works() { new_test_ext().execute_with(|| { let owner = ALICE; - let next_collection_id = pallet_nfts::NextCollectionId::::get().unwrap_or_default(); + let next_collection_id = NextCollectionIdOf::::get().unwrap_or_default(); assert_ok!(NonFungibles::create( signed(owner), owner, @@ -474,7 +482,7 @@ fn collection_works() { let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(Collection(collection)).encode(), - pallet_nfts::Collection::::get(&collection).encode(), + CollectionOf::::get(&collection).encode(), ); }); } @@ -492,7 +500,7 @@ fn balance_of_works() { ); assert_eq!( NonFungibles::read(BalanceOf { collection, owner }).encode(), - AccountBalance::::get(collection, owner).encode() + AccountBalanceOf::::get(collection, owner).encode() ); }); }); @@ -561,7 +569,7 @@ mod nfts { } pub(super) fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() + NextCollectionIdOf::::get().unwrap_or_default() } pub(super) fn collection_config_with_all_settings_enabled( diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs deleted file mode 100644 index 6e686389..00000000 --- a/pallets/api/src/nonfungibles/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; -use frame_system::pallet_prelude::BlockNumberFor; -pub use pallet_nfts::{ - AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, - DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, -}; - -// Type aliases for pallet-nfts. -pub(super) type NftsOf = pallet_nfts::Pallet; -pub(super) type NftsWeightInfoOf = ::WeightInfo; -// Type aliases for pallet-nfts storage items. -pub(super) type AccountIdOf = ::AccountId; -pub(super) type BalanceOf = <>::Currency as Currency< - ::AccountId, ->>::Balance; -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId; -pub(super) type CollectionIdOf = - as Inspect<::AccountId>>::CollectionId; -pub(super) type ItemIdOf = - as Inspect<::AccountId>>::ItemId; -pub(super) type ItemPriceOf = BalanceOf; -// TODO: Multi-instances. -pub(super) type CollectionDetailsFor = - CollectionDetails, BalanceOf>; -pub(super) type AttributeNamespaceOf = AttributeNamespace>; -pub(super) type CollectionConfigFor = - CollectionConfig, BlockNumberFor, CollectionIdOf>; From 242e53bfd9ba33dfc7b6b74b366297c080232fcd Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:31:33 +0700 Subject: [PATCH 24/64] feat(devnet): pallet nfts instance configuration --- runtime/devnet/src/config/api/mod.rs | 9 ++++--- runtime/devnet/src/config/assets.rs | 8 +++--- runtime/devnet/src/config/proxy.rs | 38 ++++++++++++++-------------- runtime/devnet/src/lib.rs | 2 +- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index b7c33279..5ea1d923 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -11,8 +11,8 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::TrustBackedAssetsInstance, fungibles, nonfungibles, Runtime, RuntimeCall, - RuntimeEvent, + config::assets::{NftsInstance, TrustBackedAssetsInstance}, + fungibles, nonfungibles, Runtime, RuntimeCall, RuntimeEvent, }; mod versioning; @@ -88,7 +88,9 @@ impl fungibles::Config for Runtime { } impl nonfungibles::Config for Runtime { + type NftsInstance = NftsInstance; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } #[derive(Default)] @@ -287,8 +289,7 @@ mod tests { #[test] fn filter_allows_nonfungibles_calls() { use pallet_api::nonfungibles::{ - types::{CollectionConfig, CollectionSettings, MintSettings}, - Call::*, + Call::*, CollectionConfig, CollectionSettings, MintSettings, }; use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness}; diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 28a51d52..97c2a9e7 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -46,7 +46,9 @@ impl Get for KeyLimit { } } -impl pallet_nfts::Config for Runtime { +pub(crate) type NftsInstance = pallet_nfts::Instance1; +pub type NftsCall = pallet_nfts::Call; +impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; @@ -95,8 +97,8 @@ impl pallet_nft_fractionalization::Config for Runtime { type Deposit = AssetDeposit; type NewAssetName = NewAssetName; type NewAssetSymbol = NewAssetSymbol; - type NftCollectionId = ::CollectionId; - type NftId = ::ItemId; + type NftCollectionId = >::CollectionId; + type NftId = >::ItemId; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index ff70240e..161178dc 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -5,7 +5,7 @@ use pop_runtime_common::proxy::{ }; use sp_runtime::traits::BlakeTwo256; -use super::assets::TrustBackedAssetsCall; +use super::assets::{NftsCall, TrustBackedAssetsCall}; use crate::{Balances, Runtime, RuntimeCall, RuntimeEvent}; impl InstanceFilter for ProxyType { @@ -45,13 +45,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::create { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::destroy { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::redeposit { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::transfer_ownership { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_team { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_collection { .. }) | + RuntimeCall::Nfts(NftsCall::create { .. }) | + RuntimeCall::Nfts(NftsCall::destroy { .. }) | + RuntimeCall::Nfts(NftsCall::redeposit { .. }) | + RuntimeCall::Nfts(NftsCall::transfer_ownership { .. }) | + RuntimeCall::Nfts(NftsCall::set_team { .. }) | + RuntimeCall::Nfts(NftsCall::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(NftsCall::lock_collection { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -66,17 +66,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::force_mint { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::update_mint_settings { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::mint_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_properties { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_collection_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::force_mint { .. }) | + RuntimeCall::Nfts(NftsCall::update_mint_settings { .. }) | + RuntimeCall::Nfts(NftsCall::mint_pre_signed { .. }) | + RuntimeCall::Nfts(NftsCall::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(NftsCall::lock_item_transfer { .. }) | + RuntimeCall::Nfts(NftsCall::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(NftsCall::lock_item_properties { .. }) | + RuntimeCall::Nfts(NftsCall::set_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::clear_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::set_collection_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::clear_collection_metadata { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 1d860f62..839f819d 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -628,7 +628,7 @@ mod runtime { // Assets #[runtime::pallet_index(50)] - pub type Nfts = pallet_nfts::Pallet; + pub type Nfts = pallet_nfts::Pallet; #[runtime::pallet_index(51)] pub type NftFractionalization = pallet_nft_fractionalization::Pallet; #[runtime::pallet_index(52)] From c69dd85e23f43fa419fa7ecefb9c39bc6f30639b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:46:04 +0700 Subject: [PATCH 25/64] chore: resolve feedback --- pallets/nfts/Cargo.toml | 5 ++--- pallets/nfts/runtime-api/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index f23b50f0..cf69a164 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors.workspace = true -description = "Fork of FRAME NFTs pallet (polkadot v1.15.0)" +authors = [ "Parity Technologies ", "R0GUE " ] +description = "Fork of FRAME NFTs pallet" edition.workspace = true homepage = "https://substrate.io" license.workspace = true @@ -9,7 +9,6 @@ readme = "README.md" repository.workspace = true version = "31.0.0" - [package.metadata.docs.rs] targets = [ "x86_64-unknown-linux-gnu" ] diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml index 17fd68f2..503642ef 100644 --- a/pallets/nfts/runtime-api/Cargo.toml +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors.workspace = true -description = "Runtime API for the FRAME NFTs pallet. (polkadot v1.15.0)" +authors = [ "Parity Technologies ", "R0GUE " ] +description = "Runtime API for the FRAME NFTs pallet." edition.workspace = true homepage = "https://substrate.io" license = "Apache-2.0" From 5dccecb63e7e4dc3e47268f3549a51038704068a Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 17:53:09 +0700 Subject: [PATCH 26/64] feat(api/nonfungibles): destroy collection witness data & weights (#383) --- pallets/api/src/nonfungibles/benchmarking.rs | 110 +++ pallets/api/src/nonfungibles/mod.rs | 114 +-- pallets/api/src/nonfungibles/tests.rs | 674 ++++++++++++++---- pallets/api/src/nonfungibles/weights.rs | 217 ++++++ pallets/nfts/src/benchmarking.rs | 62 +- pallets/nfts/src/common_functions.rs | 5 + pallets/nfts/src/features/approvals.rs | 18 + .../src/features/create_delete_collection.rs | 11 +- .../nfts/src/features/create_delete_item.rs | 16 +- pallets/nfts/src/features/transfer.rs | 23 +- pallets/nfts/src/lib.rs | 9 +- pallets/nfts/src/migration.rs | 120 ---- pallets/nfts/src/tests.rs | 50 +- pallets/nfts/src/types.rs | 12 + pallets/nfts/src/weights.rs | 570 ++++++++------- runtime/devnet/src/config/api/mod.rs | 12 +- runtime/devnet/src/config/assets.rs | 10 +- runtime/devnet/src/lib.rs | 1 + 18 files changed, 1442 insertions(+), 592 deletions(-) create mode 100644 pallets/api/src/nonfungibles/benchmarking.rs create mode 100644 pallets/api/src/nonfungibles/weights.rs delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/api/src/nonfungibles/benchmarking.rs b/pallets/api/src/nonfungibles/benchmarking.rs new file mode 100644 index 00000000..45d9d5bd --- /dev/null +++ b/pallets/api/src/nonfungibles/benchmarking.rs @@ -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 + > as Inspect<::AccountId>>::ItemId: Zero, + > as Inspect<::AccountId>>::CollectionId: Zero, +)] +mod benchmarks { + use super::*; + + #[benchmark] + // Storage: `Collection` + fn total_supply() { + #[block] + { + Pallet::::read(Read::TotalSupply(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `AccountBalance` + fn balance_of() { + #[block] + { + Pallet::::read(Read::BalanceOf { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + }); + } + } + + #[benchmark] + // Storage: `Allowances`, `Item` + fn allowance() { + #[block] + { + Pallet::::read(Read::Allowance { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + operator: account("Bob", 0, SEED), + item: Some(ItemIdOf::::zero()), + }); + } + } + + #[benchmark] + // Storage: `Item` + fn owner_of() { + #[block] + { + Pallet::::read(Read::OwnerOf { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } + + #[benchmark] + // Storage: `Attribute` + fn get_attribute() { + #[block] + { + Pallet::::read(Read::GetAttribute { + key: BoundedVec::default(), + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + namespace: AttributeNamespace::CollectionOwner, + }); + } + } + + #[benchmark] + // Storage: `Collection` + fn collection() { + #[block] + { + Pallet::::read(Read::Collection(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `NextCollectionId` + fn next_collection_id() { + #[block] + { + Pallet::::read(Read::NextCollectionId); + } + } + + #[benchmark] + // Storage: `ItemMetadata` + fn item_metadata() { + #[block] + { + Pallet::::read(Read::ItemMetadata { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } +} diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index b3370a84..6da7de5f 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -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 = ::AccountId; type NftsOf = pallet_nfts::Pallet>; @@ -31,15 +36,19 @@ type CollectionDetailsFor = CollectionDetails, BalanceOf>; type AttributeNamespaceOf = AttributeNamespace>; type CollectionConfigFor = CollectionConfig, BlockNumberFor, CollectionIdOf>; -// Type aliases for storage items. -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +// Type aliases for pallet-nfts storage items. pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; pub(super) type AttributeOf = pallet_nfts::Attribute>; +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; pub(super) type CollectionOf = pallet_nfts::Collection>; #[frame_support::pallet] 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; @@ -59,42 +68,42 @@ pub mod pallet { /// Account balance for a specified collection. #[codec(index = 1)] BalanceOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The owner of the collection . + /// The owner of the collection . owner: AccountIdOf, }, /// Allowance for an operator approved by an owner, for a specified collection or item. #[codec(index = 2)] Allowance { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: Option>, - // The owner of the collection item. + /// The owner of the collection item. owner: AccountIdOf, - // The delegated operator of collection item. + /// The delegated operator of collection item. operator: AccountIdOf, }, /// Owner of a specified collection item. #[codec(index = 5)] OwnerOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, /// Attribute value of a specified collection item. (Error: bounded collection is not /// partial) #[codec(index = 6)] GetAttribute { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, - // The namespace of the attribute. + /// The namespace of the attribute. namespace: AttributeNamespaceOf, - // The key of the attribute. + /// The key of the attribute. key: BoundedVec, }, /// Details of a specified collection. @@ -106,9 +115,9 @@ pub mod pallet { /// Metadata of a specified collection item. #[codec(index = 11)] ItemMetadata { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, } @@ -213,8 +222,8 @@ pub mod pallet { /// 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::::transfer())] @@ -239,38 +248,49 @@ pub mod pallet { /// 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::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] + #[pallet::weight( + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) + + NftsWeightInfoOf::::cancel_approval(item.is_some() as u32) + )] pub fn approve( origin: OriginFor, collection: CollectionIdOf, item: Option>, operator: AccountIdOf, approved: bool, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let owner = ensure_signed(origin.clone())?; - if approved { + let weight = if approved { NftsOf::::approve_transfer( origin, collection, item, T::Lookup::unlookup(operator.clone()), None, - )?; + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::approve_transfer(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) } else { NftsOf::::cancel_approval( origin, collection, item, T::Lookup::unlookup(operator.clone()), - )?; - } + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::cancel_approval(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::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. @@ -286,21 +306,21 @@ pub mod pallet { admin: AccountIdOf, config: CollectionConfigFor, ) -> 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::::get() .or(T::CollectionId::initial_value()) .ok_or(NftsErrorOf::::UnknownCollection)?; - let creator = ensure_signed(origin.clone())?; NftsOf::::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)] @@ -308,6 +328,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -410,7 +432,7 @@ pub mod pallet { /// 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. @@ -450,9 +472,9 @@ pub mod pallet { /// 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`. @@ -487,8 +509,8 @@ pub mod pallet { /// 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::::burn())] pub fn burn( @@ -520,8 +542,18 @@ pub mod pallet { /// /// # Parameters /// - `request` - The read request. - fn weight(_request: &Self::Read) -> Weight { - Default::default() + fn weight(request: &Self::Read) -> Weight { + use Read::*; + match request { + TotalSupply(_) => ::WeightInfo::total_supply(), + BalanceOf { .. } => ::WeightInfo::balance_of(), + Allowance { .. } => ::WeightInfo::allowance(), + OwnerOf { .. } => ::WeightInfo::owner_of(), + GetAttribute { .. } => ::WeightInfo::get_attribute(), + Collection(_) => ::WeightInfo::collection(), + ItemMetadata { .. } => ::WeightInfo::item_metadata(), + NextCollectionId => ::WeightInfo::next_collection_id(), + } } /// Performs the requested read and returns the result. diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 290f49f2..e7866b03 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -2,19 +2,21 @@ use codec::Encode; use frame_support::{ assert_noop, assert_ok, sp_runtime::{BoundedVec, DispatchError::BadOrigin}, - traits::Incrementable, }; +use pallet_nfts::WeightInfo as NftsWeightInfoTrait; use crate::{ mock::*, nonfungibles::{ - AccountBalanceOf, BlockNumberFor, CollectionConfig, CollectionDetails, CollectionIdOf, + AccountBalanceOf, AttributeNamespace, AttributeOf, BlockNumberFor, + CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails, CollectionIdOf, CollectionOf, CollectionSettings, DestroyWitness, ItemIdOf, MintSettings, MintWitness, - NextCollectionIdOf, NftsInstanceOf, Read::*, ReadResult, + NextCollectionIdOf, NftsInstanceOf, NftsWeightInfoOf, Read::*, ReadResult, }, Read, }; +const COLLECTION: u32 = 0; const ITEM: u32 = 1; type NftsError = pallet_nfts::Error>; @@ -71,7 +73,9 @@ mod encoding_read_result { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }); assert_eq!( ReadResult::Collection::(collection_details.clone()).encode(), @@ -160,9 +164,14 @@ fn burn_works() { new_test_ext().execute_with(|| { let owner = ALICE; + // "UnknownItem" error is returned if collection item is not created. + assert_noop!(NonFungibles::burn(signed(owner), COLLECTION, ITEM), NftsError::UnknownItem); // Successfully burn an existing new collection item. let (collection, item) = nfts::create_collection_mint(owner, ITEM); + let balance_before_burn = AccountBalanceOf::::get(collection, owner); assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); + let balance_after_burn = AccountBalanceOf::::get(collection, owner); + assert_eq!(balance_after_burn, balance_before_burn - 1); System::assert_last_event( Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); @@ -175,8 +184,12 @@ fn approve_works() { let owner = ALICE; let operator = BOB; let (collection, item) = nfts::create_collection_mint(owner, ITEM); - // Successfully approve `oeprator` to transfer the collection item. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, true)); + // Successfully approve `operator` to transfer the collection item. + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer()).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &Some(item), &owner, &operator)); System::assert_last_event( Event::Approval { collection, item: Some(item), owner, operator, approved: true } .into(), @@ -186,6 +199,26 @@ fn approve_works() { }); } +#[test] +fn approve_collection_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully approve `operator` to transfer all items within the collection. + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer()).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &None, &owner, &operator)); + System::assert_last_event( + Event::Approval { collection, item: None, owner, operator, approved: true }.into(), + ); + // Successfully transfer the item by the delegated account `operator`. + assert_ok!(Nfts::transfer(signed(operator), collection, item, operator)); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { @@ -193,7 +226,38 @@ fn cancel_approval_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); // Successfully cancel the transfer approval of `operator` by `owner`. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, false)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval()).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &Some(item), &owner, &operator), + Err(NftsError::NoPermission.into()) + ); + // Failed to transfer the item by `operator` without permission. + assert_noop!( + Nfts::transfer(signed(operator), collection, item, operator), + NftsError::NoPermission + ); + }); +} + +#[test] +fn cancel_collection_approval_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully cancel the transfer collection approval of `operator` by `owner`. + assert_ok!(Nfts::approve_transfer(signed(owner), collection, None, operator, None)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval()).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &None, &owner, &operator), + Err(NftsError::NoPermission.into()) + ); // Failed to transfer the item by `operator` without permission. assert_noop!( Nfts::transfer(signed(operator), collection, item, operator), @@ -218,60 +282,6 @@ fn set_max_supply_works() { }); } -#[test] -fn owner_of_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(OwnerOf { collection, item }).encode(), - Nfts::owner(collection, item).encode() - ); - }); -} - -#[test] -fn get_attribute_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option< - BoundedVec>>::ValueLimit>, - > = None; - // No attribute set. - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute.clone() - }) - .encode(), - result.encode() - ); - // Successfully get an existing attribute. - result = Some(value.clone()); - assert_ok!(Nfts::set_attribute( - signed(ALICE), - collection, - Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, - attribute.clone(), - value, - )); - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute - }) - .encode(), - result.encode() - ); - }); -} - #[test] fn set_metadata_works() { new_test_ext().execute_with(|| { @@ -316,7 +326,7 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), BoundedVec::truncate_from("some value".as_bytes().to_vec()) )); @@ -325,14 +335,14 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), )); assert_eq!( NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + namespace: AttributeNamespace::CollectionOwner, key: attribute }) .encode(), @@ -354,7 +364,7 @@ fn approve_item_attribute_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -365,7 +375,7 @@ fn approve_item_attribute_works() { NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::Account(BOB), + namespace: AttributeNamespace::Account(BOB), key: attribute }) .encode(), @@ -387,7 +397,7 @@ fn cancel_item_attribute_approval_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -396,14 +406,14 @@ fn cancel_item_attribute_approval_works() { collection, item, BOB, - pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } + CancelAttributesApprovalWitness { account_attributes: 1 } )); assert_noop!( Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() ), @@ -412,78 +422,79 @@ fn cancel_item_attribute_approval_works() { }); } -#[test] -fn next_collection_id_works() { - new_test_ext().execute_with(|| { - let _ = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - assert_eq!( - NonFungibles::read(NextCollectionId).encode(), - NextCollectionIdOf::::get() - .or(CollectionIdOf::::initial_value()) - .encode(), - ); - }); -} - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let owner = ALICE; - let collection = nfts::create_collection(owner); - (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - ((i + 1) as u128).encode() - ); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() - ); - }); - }); -} - #[test] fn create_works() { new_test_ext().execute_with(|| { - let owner = ALICE; + let creator = ALICE; + let admin = ALICE; let next_collection_id = NextCollectionIdOf::::get().unwrap_or_default(); + for origin in vec![root(), none()] { + assert_noop!( + NonFungibles::create( + origin, + admin, + CollectionConfig { + max_supply: None, + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled() + }, + ), + BadOrigin + ); + } assert_ok!(NonFungibles::create( - signed(owner), - owner, + signed(creator), + admin, CollectionConfig { max_supply: None, mint_settings: MintSettings::default(), settings: CollectionSettings::all_enabled() }, )); - assert_eq!(Nfts::collection_owner(next_collection_id), Some(owner)); + assert_eq!(Nfts::collection_owner(next_collection_id), Some(creator)); + System::assert_last_event(Event::Created { id: next_collection_id, creator, admin }.into()); }); } #[test] fn destroy_works() { new_test_ext().execute_with(|| { - let collection = nfts::create_collection(ALICE); - assert_ok!(NonFungibles::destroy( - signed(ALICE), - collection, - DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } - )); + let collection = COLLECTION; + let witness = DestroyWitness { + item_metadatas: 0, + item_configs: 0, + item_holders: 0, + attributes: 0, + allowances: 0, + }; + // Check error works for `Nfts::destroy()`. + assert_noop!( + NonFungibles::destroy(signed(ALICE), collection, witness), + NftsError::UnknownCollection + ); + nfts::create_collection(ALICE); + assert_ok!(NonFungibles::destroy(signed(ALICE), collection, witness)); assert_eq!(Nfts::collection_owner(collection), None); }); } #[test] -fn collection_works() { +fn total_supply_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(Collection(collection)).encode(), - CollectionOf::::get(&collection).encode(), - ); + let owner = ALICE; + let collection = nfts::create_collection(owner); + assert_eq!(NonFungibles::read(TotalSupply(collection)), ReadResult::TotalSupply(0)); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); + assert_eq!( + NonFungibles::read(TotalSupply(collection)), + ReadResult::TotalSupply((i + 1).into()) + ); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() + ); + }); }); } @@ -492,11 +503,15 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let owner = ALICE; let collection = nfts::create_collection(owner); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(Default::default()) + ); (0..10).into_iter().for_each(|i| { assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner }).encode(), - (i + 1).encode() + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(i + 1) ); assert_eq!( NonFungibles::read(BalanceOf { collection, owner }).encode(), @@ -513,9 +528,8 @@ fn allowance_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( - NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) - .encode(), - true.encode() + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }), + ReadResult::Allowance(true) ); assert_eq!( NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) @@ -527,6 +541,131 @@ fn allowance_works() { }); } +#[test] +fn owner_of_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(Some(ALICE)) + ); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }).encode(), + Nfts::owner(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let raw_value = "some value".as_bytes().to_vec(); + let value = BoundedVec::truncate_from(raw_value.clone()); + let namespace = AttributeNamespace::CollectionOwner; + // No attribute set. + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(None) + ); + // Successfully get an existing attribute. + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + namespace.clone(), + attribute.clone(), + value, + )); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(Some(raw_value)) + ); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }) + .encode(), + AttributeOf::::get((collection, Some(item), namespace, attribute)) + .map(|result| result.0) + .encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(Collection(COLLECTION)), ReadResult::Collection(None),); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)), + ReadResult::Collection(CollectionOf::::get(COLLECTION)), + ); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)).encode(), + CollectionOf::::get(COLLECTION).encode(), + ); + }); +} + +#[test] +fn item_metadata_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + let value = "some metadata".as_bytes().to_vec(); + assert_ok!(NonFungibles::set_metadata( + signed(ALICE), + COLLECTION, + ITEM, + BoundedVec::truncate_from(value.clone()) + )); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(Some(value)) + ); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }).encode(), + Nfts::item_metadata(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn next_collection_id_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(0))); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(1))); + assert_eq!( + NonFungibles::read(NextCollectionId).encode(), + Some(NextCollectionIdOf::::get().unwrap_or_default()).encode(), + ); + }); +} + fn signed(account_id: AccountId) -> RuntimeOrigin { RuntimeOrigin::signed(account_id) } @@ -539,6 +678,7 @@ fn none() -> RuntimeOrigin { RuntimeOrigin::none() } +// Helper functions for interacting with pallet-nfts. mod nfts { use super::*; @@ -559,7 +699,7 @@ mod nfts { } pub(super) fn create_collection(owner: AccountId) -> u32 { - let next_id = next_collection_id(); + let next_id = NextCollectionIdOf::::get().unwrap_or_default(); assert_ok!(Nfts::create( signed(owner), owner, @@ -568,10 +708,6 @@ mod nfts { next_id } - pub(super) fn next_collection_id() -> u32 { - NextCollectionIdOf::::get().unwrap_or_default() - } - pub(super) fn collection_config_with_all_settings_enabled( ) -> CollectionConfig, CollectionIdOf> { CollectionConfig { @@ -581,3 +717,287 @@ mod nfts { } } } + +mod read_weights { + use frame_support::weights::Weight; + + use super::*; + use crate::nonfungibles::{weights::WeightInfo, Config}; + + struct ReadWeightInfo { + total_supply: Weight, + balance_of: Weight, + allowance: Weight, + owner_of: Weight, + get_attribute: Weight, + collection: Weight, + next_collection_id: Weight, + item_metadata: Weight, + } + + impl ReadWeightInfo { + fn new() -> Self { + Self { + total_supply: NonFungibles::weight(&TotalSupply(COLLECTION)), + balance_of: NonFungibles::weight(&BalanceOf { + collection: COLLECTION, + owner: ALICE, + }), + allowance: NonFungibles::weight(&Allowance { + collection: COLLECTION, + item: Some(ITEM), + owner: ALICE, + operator: BOB, + }), + owner_of: NonFungibles::weight(&OwnerOf { collection: COLLECTION, item: ITEM }), + get_attribute: NonFungibles::weight(&GetAttribute { + collection: COLLECTION, + item: ITEM, + namespace: AttributeNamespace::CollectionOwner, + key: BoundedVec::default(), + }), + collection: NonFungibles::weight(&Collection(COLLECTION)), + next_collection_id: NonFungibles::weight(&NextCollectionId), + item_metadata: NonFungibles::weight(&ItemMetadata { + collection: COLLECTION, + item: ITEM, + }), + } + } + } + + #[test] + fn ensure_read_matches_benchmarks() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + assert_eq!(total_supply, ::WeightInfo::total_supply()); + assert_eq!(balance_of, ::WeightInfo::balance_of()); + assert_eq!(allowance, ::WeightInfo::allowance()); + assert_eq!(owner_of, ::WeightInfo::owner_of()); + assert_eq!(get_attribute, ::WeightInfo::get_attribute()); + assert_eq!(collection, ::WeightInfo::collection()); + assert_eq!(next_collection_id, ::WeightInfo::next_collection_id()); + assert_eq!(item_metadata, ::WeightInfo::item_metadata()); + } + + // These types read from the `Collection` storage. + #[test] + fn ensure_collection_variants_match() { + let ReadWeightInfo { total_supply, collection, .. } = ReadWeightInfo::new(); + + assert_eq!(total_supply, collection); + } + + // Proof size is based on `MaxEncodedLen`, not hardware. + // This test ensures that the data structure sizes do not change with upgrades. + #[test] + fn ensure_expected_proof_size_does_not_change() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + // These values come from `weights.rs`. + assert_eq!(total_supply.proof_size(), 3557); + assert_eq!(balance_of.proof_size(), 3529); + assert_eq!(allowance.proof_size(), 4326); + assert_eq!(owner_of.proof_size(), 4326); + assert_eq!(get_attribute.proof_size(), 3944); + assert_eq!(collection.proof_size(), 3557); + assert_eq!(next_collection_id.proof_size(), 1489); + assert_eq!(item_metadata.proof_size(), 3812); + } +} + +mod ensure_codec_indexes { + use super::{Encode, *}; + use crate::{mock::RuntimeCall::NonFungibles, nonfungibles}; + + #[test] + fn ensure_read_variant_indexes() { + [ + (TotalSupply::(Default::default()), 0u8, "TotalSupply"), + ( + BalanceOf:: { collection: Default::default(), owner: Default::default() }, + 1, + "BalanceOf", + ), + ( + Allowance:: { + collection: Default::default(), + item: Default::default(), + owner: Default::default(), + operator: Default::default(), + }, + 2, + "Allowance", + ), + ( + OwnerOf:: { collection: Default::default(), item: Default::default() }, + 5, + "OwnerOf", + ), + ( + GetAttribute:: { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 6, + "GetAttribute", + ), + (Collection::(Default::default()), 9, "Collection"), + (NextCollectionId, 10, "NextCollectionId"), + ( + ItemMetadata { collection: Default::default(), item: Default::default() }, + 11, + "ItemMetadata", + ), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!(variant.encode()[0], *expected_index, "{name} variant index changed"); + }) + } + + #[test] + fn ensure_dispatchable_indexes() { + use nonfungibles::Call::*; + + [ + ( + transfer { + collection: Default::default(), + item: Default::default(), + to: Default::default(), + }, + 3u8, + "transfer", + ), + ( + approve { + collection: Default::default(), + item: Default::default(), + operator: Default::default(), + approved: Default::default(), + }, + 4, + "approve", + ), + (create { admin: Default::default(), config: Default::default() }, 7, "create"), + ( + destroy { + collection: Default::default(), + witness: DestroyWitness { + item_metadatas: Default::default(), + item_configs: Default::default(), + item_holders: Default::default(), + attributes: Default::default(), + allowances: Default::default(), + }, + }, + 8, + "destroy", + ), + ( + set_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + value: Default::default(), + }, + 12, + "set_attribute", + ), + ( + clear_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 13, + "clear_attribute", + ), + ( + set_metadata { + collection: Default::default(), + item: Default::default(), + data: Default::default(), + }, + 14, + "set_metadata", + ), + ( + clear_metadata { collection: Default::default(), item: Default::default() }, + 15, + "clear_metadata", + ), + ( + approve_item_attributes { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + }, + 16, + "approve_item_attributes", + ), + ( + cancel_item_attributes_approval { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + witness: CancelAttributesApprovalWitness { + account_attributes: Default::default(), + }, + }, + 17, + "cancel_item_attributes_approval", + ), + ( + set_max_supply { collection: Default::default(), max_supply: Default::default() }, + 18, + "set_max_supply", + ), + ( + mint { + to: Default::default(), + collection: Default::default(), + item: Default::default(), + witness: MintWitness { + owned_item: Default::default(), + mint_price: Default::default(), + }, + }, + 19, + "mint", + ), + (burn { collection: Default::default(), item: Default::default() }, 20, "burn"), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!( + NonFungibles(variant.to_owned()).encode()[1], + *expected_index, + "{name} dispatchable index changed" + ); + }) + } +} diff --git a/pallets/api/src/nonfungibles/weights.rs b/pallets/api/src/nonfungibles/weights.rs new file mode 100644 index 00000000..f0b8fa83 --- /dev/null +++ b/pallets/api/src/nonfungibles/weights.rs @@ -0,0 +1,217 @@ + +//! Autogenerated weights for `nonfungibles` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `R0GUE`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/pop-node +// benchmark +// pallet +// --chain=dev +// --wasm-execution=compiled +// --pallet=nonfungibles +// --steps=50 +// --repeat=20 +// --json +// --template +// ./scripts/pallet-weights-template.hbs +// --output=./pallets/api/src/nonfungibles/weights.rs +// --extrinsic= + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `nonfungibles`. +pub trait WeightInfo { + fn total_supply() -> Weight; + fn balance_of() -> Weight; + fn allowance() -> Weight; + fn owner_of() -> Weight; + fn get_attribute() -> Weight; + fn collection() -> Weight; + fn next_collection_id() -> Weight; + fn item_metadata() -> Weight; +} + +/// Weights for `nonfungibles` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } +} + diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index ab66da26..58209b8b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -64,6 +64,27 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account (caller, caller_lookup) } +fn approve_collection, I: 'static>( + index: u32, +) -> (T::AccountId, AccountIdLookupOf) { + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; + if caller != whitelisted_caller() { + whitelist_account!(caller); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let delegate: T::AccountId = account("delegate", 0, SEED + index); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + assert_ok!(Nfts::::approve_transfer( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + None, + delegate_lookup.clone(), + Some(deadline), + )); + (caller, caller_lookup) +} + fn mint_item, I: 'static>( index: u16, ) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { @@ -77,7 +98,7 @@ fn mint_item, I: 'static>( let item_exists = Item::::contains_key(&collection, &item); let item_config = ItemConfigOf::::get(&collection, &item); if item_exists { - return (item, caller, caller_lookup) + return (item, caller, caller_lookup); } else if let Some(item_config) = item_config { assert_ok!(Nfts::::force_mint( SystemOrigin::Signed(caller.clone()).into(), @@ -250,6 +271,8 @@ benchmarks_instance_pallet! { let m in 0 .. 1_000; let c in 0 .. 1_000; let a in 0 .. 1_000; + let h in 0 .. 1_000; + let l in 0 .. 1_000; let (collection, caller, _) = create_collection::(); add_collection_metadata::(); @@ -267,6 +290,13 @@ benchmarks_instance_pallet! { for i in 0..a { add_collection_attribute::(i as u16); } + for i in 0..h { + mint_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..l { + approve_collection::(i as u32); + } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { @@ -573,27 +603,45 @@ benchmarks_instance_pallet! { } approve_transfer { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup, Some(deadline)) + let maybe_deadline = if i == 0 { + None + } else { + Some(BlockNumberFor::::max_value()) + }; + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, maybe_deadline) verify { - assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); + assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); } cancel_approval { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup) + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 89de1f05..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,6 +39,11 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.items) } + /// Get the allowances to spend items within the collection. + pub fn collection_allowances(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.allowances) + } + /// Get the metadata of the collection item. pub fn item_metadata( collection: T::CollectionId, diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index e1e79ef4..2647492c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -195,6 +195,15 @@ impl, I: 'static> Pallet { Allowances::::mutate((&collection, &owner, &delegate), |allowance| { *allowance = true; }); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_inc(); + Ok(()) + }, + )?; Self::deposit_event(Event::TransferApproved { collection, @@ -217,6 +226,15 @@ impl, I: 'static> Pallet { ensure!(check_origin == owner, Error::::NoPermission); } Allowances::::remove((&collection, &owner, &delegate)); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_dec(); + Ok(()) + }, + )?; Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index b7efd03a..1d08cd1b 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,7 +54,9 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }, ); CollectionRoleOf::::insert( @@ -119,6 +121,11 @@ impl, I: 'static> Pallet { collection_details.item_configs == witness.item_configs, Error::::BadWitness ); + ensure!( + collection_details.item_holders == witness.item_holders, + Error::::BadWitness + ); + ensure!(collection_details.allowances == witness.allowances, Error::::BadWitness); for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { if let Some(depositor) = metadata.deposit.account { @@ -137,8 +144,6 @@ impl, I: 'static> Pallet { } } - // TODO: Do we need another storage item to keep track of number of holders of a - // collection let _ = AccountBalance::::clear_prefix(collection, collection_details.items, None); let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); @@ -152,7 +157,9 @@ impl, I: 'static> Pallet { Ok(DestroyWitness { item_metadatas: collection_details.item_metadatas, item_configs: collection_details.item_configs, + item_holders: collection_details.item_holders, attributes: collection_details.attributes, + allowances: collection_details.allowances, }) }) } diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index cc29f8da..a7b7ddf3 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,9 +69,15 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); - AccountBalance::::mutate(collection, &mint_to, |balance| { - balance.saturating_inc(); - }); + + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + balance.clone() + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config @@ -257,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 3b25b014..dbe6f3b0 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -54,7 +54,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult, ) -> DispatchResult { // Retrieve collection details. - let collection_details = + let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,13 +87,23 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balances. - AccountBalance::::mutate(collection, &details.owner, |balance| { - balance.saturating_dec(); - }); - AccountBalance::::mutate(collection, &dest, |balance| { + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + balance.clone() + }); + if owner_balance == 0 { + collection_details.item_holders.saturating_dec(); + } + // Update account balance of the destination account. + let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { balance.saturating_inc(); + balance.clone() }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); @@ -108,6 +118,7 @@ impl, I: 'static> Pallet { // Update item details. Item::::insert(&collection, &item, &details); + Collection::::insert(&collection, &collection_details); ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index bc8b67b6..37e8b29c 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,7 +30,6 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -832,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -847,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1311,7 +1314,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer())] + #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, @@ -1350,7 +1353,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::cancel_approval())] + #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs deleted file mode 100644 index af611bf1..00000000 --- a/pallets/nfts/src/migration.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use frame_support::traits::OnRuntimeUpgrade; -use log; -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; - -use super::*; - -pub mod v1 { - use frame_support::{pallet_prelude::*, weights::Weight}; - - use super::*; - - #[derive(Decode)] - pub struct OldCollectionDetails { - pub owner: AccountId, - pub owner_deposit: DepositBalance, - pub items: u32, - pub item_metadatas: u32, - pub attributes: u32, - } - - impl OldCollectionDetails { - /// Migrates the old collection details to the new v1 format. - fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { - CollectionDetails { - owner: self.owner, - owner_deposit: self.owner_deposit, - items: self.items, - item_metadatas: self.item_metadatas, - item_configs, - attributes: self.attributes, - } - } - } - - /// A migration utility to update the storage version from v0 to v1 for the pallet. - pub struct MigrateToV1(core::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { - fn on_runtime_upgrade() -> Weight { - let in_code_version = Pallet::::in_code_storage_version(); - let on_chain_version = Pallet::::on_chain_storage_version(); - - log::info!( - target: LOG_TARGET, - "Running migration with in-code storage version {:?} / onchain {:?}", - in_code_version, - on_chain_version - ); - - if on_chain_version == 0 && in_code_version == 1 { - let mut translated = 0u64; - let mut configs_iterated = 0u64; - Collection::::translate::< - OldCollectionDetails>, - _, - >(|key, old_value| { - let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; - configs_iterated += item_configs as u64; - translated.saturating_inc(); - Some(old_value.migrate_to_v1(item_configs)) - }); - - in_code_version.put::>(); - - log::info!( - target: LOG_TARGET, - "Upgraded {} records, storage to version {:?}", - translated, - in_code_version - ); - T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) - } else { - log::info!( - target: LOG_TARGET, - "Migration did not execute. This probably should be removed" - ); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let prev_count = Collection::::iter().count(); - Ok((prev_count as u32).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(prev_count: Vec) -> Result<(), TryRuntimeError> { - let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( - "the state parameter should be something that was generated by pre_upgrade", - ); - let post_count = Collection::::iter().count() as u32; - ensure!( - prev_count == post_count, - "the records count before and after the migration should be the same" - ); - - ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); - - Ok(()) - } - } -} diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4d0f08c9..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -165,6 +165,7 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -175,10 +176,37 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); assert_eq!(AccountBalance::::get(1, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } +#[test] +fn collection_item_holders_should_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + let total = 5; + for i in 0..total { + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, i, account(1), None)); + } + assert_eq!(AccountBalance::::get(0, account(1)), total); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, total, account(2), None)); + assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, total)); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + }); +} + #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { @@ -223,6 +251,7 @@ fn lifecycle_should_work() { assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); assert_eq!(Collection::::get(0).unwrap().item_configs, 3); + assert_eq!(Collection::::get(0).unwrap().item_holders, 3); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); @@ -317,6 +346,7 @@ fn destroy_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), 0, @@ -360,6 +390,7 @@ fn mint_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -425,6 +456,7 @@ fn mint_should_work() { Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -464,6 +496,7 @@ fn mint_should_work() { Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); assert_eq!(AccountBalance::::get(1, account(2)), 1); + assert_eq!(Collection::::get(1).unwrap().item_holders, 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -500,10 +533,11 @@ fn transfer_should_work() { account(2), default_item_config() )); - + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -521,6 +555,7 @@ fn transfer_should_work() { assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 0); assert_eq!(AccountBalance::::get(0, account(4)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1775,6 +1810,7 @@ fn burn_works() { default_item_config() )); assert_eq!(AccountBalance::::get(0, account(5)), 2); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1783,8 +1819,10 @@ fn burn_works() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); assert_eq!(AccountBalance::::get(0, account(5)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); assert_eq!(AccountBalance::::get(0, account(5)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2036,6 +2074,7 @@ fn cancel_approval_collection_works_with_admin() { delegate: account(3) })); assert_eq!(Allowances::::get((0, account(2), account(3))), false); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 0); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2192,6 +2231,7 @@ fn approval_collection_works_with_admin() { deadline: None })); assert_eq!(Allowances::::get((0, account(1), account(3))), true); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -4114,7 +4154,13 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0 } + DestroyWitness { + item_configs: 0, + item_metadatas: 0, + attributes: 0, + allowances: 0, + item_holders: 0 + } )); assert_eq!(Collection::::get(0), None); assert_eq!(Balances::reserved_balance(&account(1)), 10); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 941da6ca..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -104,8 +104,12 @@ pub struct CollectionDetails { pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. pub attributes: u32, + /// The total number of allowances to spend all items within collections. + pub allowances: u32, } /// Witness data for the destroy transactions. @@ -117,9 +121,15 @@ pub struct DestroyWitness { /// The total number of outstanding item configs of this collection. #[codec(compact)] pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + #[codec(compact)] + pub item_holders: u32, /// The total number of attributes for this collection. #[codec(compact)] pub attributes: u32, + /// The total number of allowances to spend all items within collections. + #[codec(compact)] + pub allowances: u32, } impl CollectionDetails { @@ -127,7 +137,9 @@ impl CollectionDetails { DestroyWitness { item_metadatas: self.item_metadatas, item_configs: self.item_configs, + item_holders: self.item_holders, attributes: self.attributes, + allowances: self.allowances, } } } diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index c374d6db..b3307503 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 -//! DATE: 2024-10-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `R0GUE`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -36,7 +36,7 @@ use core::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(m: u32, c: u32, a: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, h: u32, l: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -59,8 +59,8 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer() -> Weight; - fn cancel_approval() -> Weight; + fn approve_transfer(i: u32, ) -> Weight; + fn cancel_approval(i: u32, ) -> Weight; fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -91,16 +91,16 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -110,14 +110,14 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -126,6 +126,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -137,19 +139,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1006_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -160,7 +160,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -171,10 +171,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,7 +183,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -194,10 +194,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -206,7 +206,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -223,15 +223,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -250,15 +250,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -266,12 +266,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -285,7 +285,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -298,35 +298,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -334,12 +334,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -347,28 +347,28 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,7 +386,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -397,20 +397,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -424,13 +424,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -462,8 +462,8 @@ impl WeightInfo for SubstrateWeight { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -473,7 +473,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -482,7 +482,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -494,15 +494,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,32 +511,32 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,25 +544,37 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -582,20 +594,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,7 +620,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -624,8 +636,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -633,8 +645,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -649,12 +661,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -662,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -674,8 +686,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -687,7 +699,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -696,8 +708,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -712,12 +724,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -726,7 +738,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -742,12 +754,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -761,7 +773,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -769,12 +781,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -788,7 +800,7 @@ impl WeightInfo for () { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -798,16 +810,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -817,14 +829,14 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -833,6 +845,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -844,19 +858,17 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1006_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -867,7 +879,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -878,10 +890,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -890,7 +902,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -901,10 +913,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -913,7 +925,7 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -930,15 +942,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -957,15 +969,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -973,12 +985,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -992,7 +1004,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1005,35 +1017,35 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -1041,12 +1053,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -1054,28 +1066,28 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1093,7 +1105,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1104,20 +1116,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -1131,13 +1143,13 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1169,8 +1181,8 @@ impl WeightInfo for () { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1180,7 +1192,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1189,7 +1201,7 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -1201,15 +1213,15 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1218,32 +1230,32 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1251,25 +1263,37 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1289,20 +1313,20 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1315,7 +1339,7 @@ impl WeightInfo for () { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,8 +1355,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1340,8 +1364,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1356,12 +1380,12 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -1369,9 +1393,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1381,8 +1405,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1394,7 +1418,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1403,8 +1427,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1419,12 +1443,12 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1433,7 +1457,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -1449,12 +1473,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -1468,7 +1492,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1476,16 +1500,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } -} \ No newline at end of file +} diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 5ea1d923..d96fd85b 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -11,7 +11,7 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::{NftsInstance, TrustBackedAssetsInstance}, + config::assets::{TrustBackedAssetsInstance, TrustBackedNftsInstance}, fungibles, nonfungibles, Runtime, RuntimeCall, RuntimeEvent, }; @@ -88,7 +88,7 @@ impl fungibles::Config for Runtime { } impl nonfungibles::Config for Runtime { - type NftsInstance = NftsInstance; + type NftsInstance = TrustBackedNftsInstance; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -311,7 +311,13 @@ mod tests { }), NonFungibles(destroy { collection: 0, - witness: DestroyWitness { attributes: 0, item_configs: 0, item_metadatas: 0 }, + witness: DestroyWitness { + attributes: 0, + item_configs: 0, + item_metadatas: 0, + item_holders: 0, + allowances: 0, + }, }), NonFungibles(set_attribute { collection: 0, diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 97c2a9e7..43f88990 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -46,9 +46,9 @@ impl Get for KeyLimit { } } -pub(crate) type NftsInstance = pallet_nfts::Instance1; -pub type NftsCall = pallet_nfts::Call; -impl pallet_nfts::Config for Runtime { +pub(crate) type TrustBackedNftsInstance = pallet_nfts::Instance1; +pub type NftsCall = pallet_nfts::Call; +impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; @@ -97,8 +97,8 @@ impl pallet_nft_fractionalization::Config for Runtime { type Deposit = AssetDeposit; type NewAssetName = NewAssetName; type NewAssetSymbol = NewAssetSymbol; - type NftCollectionId = >::CollectionId; - type NftId = >::ItemId; + type NftCollectionId = >::CollectionId; + type NftId = >::ItemId; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 839f819d..736f0be7 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -646,6 +646,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [fungibles, Fungibles] + [nonfungibles, NonFungibles] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] From 488be7575d47ee5006394f7746ce0c83f37da7db Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 23:00:22 +0700 Subject: [PATCH 27/64] chore: rename nfts instance --- Cargo.lock | 20 +++++++-------- runtime/devnet/src/config/assets.rs | 2 +- runtime/devnet/src/config/proxy.rs | 38 ++++++++++++++--------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71903ca0..48f7b34c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -8240,39 +8240,39 @@ dependencies = [ [[package]] name = "pallet-nfts" -version = "0.1.0" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-keystore", "sp-runtime", + "sp-std", ] [[package]] name = "pallet-nfts" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" +version = "31.0.0" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", - "sp-std", ] [[package]] @@ -10857,7 +10857,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -11002,7 +11002,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 43f88990..65405ea4 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -47,7 +47,7 @@ impl Get for KeyLimit { } pub(crate) type TrustBackedNftsInstance = pallet_nfts::Instance1; -pub type NftsCall = pallet_nfts::Call; +pub type TrustBackedNftsCall = pallet_nfts::Call; impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index 161178dc..48653027 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -5,7 +5,7 @@ use pop_runtime_common::proxy::{ }; use sp_runtime::traits::BlakeTwo256; -use super::assets::{NftsCall, TrustBackedAssetsCall}; +use super::assets::{TrustBackedAssetsCall, TrustBackedNftsCall}; use crate::{Balances, Runtime, RuntimeCall, RuntimeEvent}; impl InstanceFilter for ProxyType { @@ -45,13 +45,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(NftsCall::create { .. }) | - RuntimeCall::Nfts(NftsCall::destroy { .. }) | - RuntimeCall::Nfts(NftsCall::redeposit { .. }) | - RuntimeCall::Nfts(NftsCall::transfer_ownership { .. }) | - RuntimeCall::Nfts(NftsCall::set_team { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(NftsCall::lock_collection { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::create { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::destroy { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::redeposit { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::transfer_ownership { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_team { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_collection { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -66,17 +66,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(NftsCall::force_mint { .. }) | - RuntimeCall::Nfts(NftsCall::update_mint_settings { .. }) | - RuntimeCall::Nfts(NftsCall::mint_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_properties { .. }) | - RuntimeCall::Nfts(NftsCall::set_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::force_mint { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::update_mint_settings { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::mint_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_properties { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_collection_metadata { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), From 5dbc1b701fafeabe24cbbe6228a29c600f160a06 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 17:53:09 +0700 Subject: [PATCH 28/64] feat(api/nonfungibles): destroy collection witness data & weights (#383) chore: rename nfts instance feat(api/nonfungibles): destroy collection witness data & weights (#383) chore: rename nfts instance fix(api/nonfungibles): pallet weight testing --- Cargo.lock | 20 +- pallets/api/src/nonfungibles/benchmarking.rs | 110 +++ pallets/api/src/nonfungibles/mod.rs | 114 +-- pallets/api/src/nonfungibles/tests.rs | 674 ++++++++++++++---- pallets/api/src/nonfungibles/weights.rs | 217 ++++++ pallets/nfts/src/benchmarking.rs | 62 +- pallets/nfts/src/common_functions.rs | 5 + pallets/nfts/src/features/approvals.rs | 18 + .../src/features/create_delete_collection.rs | 11 +- .../nfts/src/features/create_delete_item.rs | 16 +- pallets/nfts/src/features/transfer.rs | 23 +- pallets/nfts/src/lib.rs | 9 +- pallets/nfts/src/migration.rs | 120 ---- pallets/nfts/src/tests.rs | 50 +- pallets/nfts/src/types.rs | 12 + pallets/nfts/src/weights.rs | 570 ++++++++------- runtime/devnet/src/config/api/mod.rs | 12 +- runtime/devnet/src/config/assets.rs | 10 +- runtime/devnet/src/config/proxy.rs | 38 +- runtime/devnet/src/lib.rs | 1 + 20 files changed, 1471 insertions(+), 621 deletions(-) create mode 100644 pallets/api/src/nonfungibles/benchmarking.rs create mode 100644 pallets/api/src/nonfungibles/weights.rs delete mode 100644 pallets/nfts/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index 71903ca0..48f7b34c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -8240,39 +8240,39 @@ dependencies = [ [[package]] name = "pallet-nfts" -version = "0.1.0" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-keystore", "sp-runtime", + "sp-std", ] [[package]] name = "pallet-nfts" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" +version = "31.0.0" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", - "sp-std", ] [[package]] @@ -10857,7 +10857,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -11002,7 +11002,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/pallets/api/src/nonfungibles/benchmarking.rs b/pallets/api/src/nonfungibles/benchmarking.rs new file mode 100644 index 00000000..45d9d5bd --- /dev/null +++ b/pallets/api/src/nonfungibles/benchmarking.rs @@ -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 + > as Inspect<::AccountId>>::ItemId: Zero, + > as Inspect<::AccountId>>::CollectionId: Zero, +)] +mod benchmarks { + use super::*; + + #[benchmark] + // Storage: `Collection` + fn total_supply() { + #[block] + { + Pallet::::read(Read::TotalSupply(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `AccountBalance` + fn balance_of() { + #[block] + { + Pallet::::read(Read::BalanceOf { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + }); + } + } + + #[benchmark] + // Storage: `Allowances`, `Item` + fn allowance() { + #[block] + { + Pallet::::read(Read::Allowance { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + operator: account("Bob", 0, SEED), + item: Some(ItemIdOf::::zero()), + }); + } + } + + #[benchmark] + // Storage: `Item` + fn owner_of() { + #[block] + { + Pallet::::read(Read::OwnerOf { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } + + #[benchmark] + // Storage: `Attribute` + fn get_attribute() { + #[block] + { + Pallet::::read(Read::GetAttribute { + key: BoundedVec::default(), + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + namespace: AttributeNamespace::CollectionOwner, + }); + } + } + + #[benchmark] + // Storage: `Collection` + fn collection() { + #[block] + { + Pallet::::read(Read::Collection(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `NextCollectionId` + fn next_collection_id() { + #[block] + { + Pallet::::read(Read::NextCollectionId); + } + } + + #[benchmark] + // Storage: `ItemMetadata` + fn item_metadata() { + #[block] + { + Pallet::::read(Read::ItemMetadata { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } +} diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index b3370a84..6da7de5f 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -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 = ::AccountId; type NftsOf = pallet_nfts::Pallet>; @@ -31,15 +36,19 @@ type CollectionDetailsFor = CollectionDetails, BalanceOf>; type AttributeNamespaceOf = AttributeNamespace>; type CollectionConfigFor = CollectionConfig, BlockNumberFor, CollectionIdOf>; -// Type aliases for storage items. -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +// Type aliases for pallet-nfts storage items. pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; pub(super) type AttributeOf = pallet_nfts::Attribute>; +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; pub(super) type CollectionOf = pallet_nfts::Collection>; #[frame_support::pallet] 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; @@ -59,42 +68,42 @@ pub mod pallet { /// Account balance for a specified collection. #[codec(index = 1)] BalanceOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The owner of the collection . + /// The owner of the collection . owner: AccountIdOf, }, /// Allowance for an operator approved by an owner, for a specified collection or item. #[codec(index = 2)] Allowance { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: Option>, - // The owner of the collection item. + /// The owner of the collection item. owner: AccountIdOf, - // The delegated operator of collection item. + /// The delegated operator of collection item. operator: AccountIdOf, }, /// Owner of a specified collection item. #[codec(index = 5)] OwnerOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, /// Attribute value of a specified collection item. (Error: bounded collection is not /// partial) #[codec(index = 6)] GetAttribute { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, - // The namespace of the attribute. + /// The namespace of the attribute. namespace: AttributeNamespaceOf, - // The key of the attribute. + /// The key of the attribute. key: BoundedVec, }, /// Details of a specified collection. @@ -106,9 +115,9 @@ pub mod pallet { /// Metadata of a specified collection item. #[codec(index = 11)] ItemMetadata { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, } @@ -213,8 +222,8 @@ pub mod pallet { /// 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::::transfer())] @@ -239,38 +248,49 @@ pub mod pallet { /// 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::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] + #[pallet::weight( + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) + + NftsWeightInfoOf::::cancel_approval(item.is_some() as u32) + )] pub fn approve( origin: OriginFor, collection: CollectionIdOf, item: Option>, operator: AccountIdOf, approved: bool, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let owner = ensure_signed(origin.clone())?; - if approved { + let weight = if approved { NftsOf::::approve_transfer( origin, collection, item, T::Lookup::unlookup(operator.clone()), None, - )?; + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::approve_transfer(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) } else { NftsOf::::cancel_approval( origin, collection, item, T::Lookup::unlookup(operator.clone()), - )?; - } + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::cancel_approval(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::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. @@ -286,21 +306,21 @@ pub mod pallet { admin: AccountIdOf, config: CollectionConfigFor, ) -> 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::::get() .or(T::CollectionId::initial_value()) .ok_or(NftsErrorOf::::UnknownCollection)?; - let creator = ensure_signed(origin.clone())?; NftsOf::::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)] @@ -308,6 +328,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -410,7 +432,7 @@ pub mod pallet { /// 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. @@ -450,9 +472,9 @@ pub mod pallet { /// 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`. @@ -487,8 +509,8 @@ pub mod pallet { /// 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::::burn())] pub fn burn( @@ -520,8 +542,18 @@ pub mod pallet { /// /// # Parameters /// - `request` - The read request. - fn weight(_request: &Self::Read) -> Weight { - Default::default() + fn weight(request: &Self::Read) -> Weight { + use Read::*; + match request { + TotalSupply(_) => ::WeightInfo::total_supply(), + BalanceOf { .. } => ::WeightInfo::balance_of(), + Allowance { .. } => ::WeightInfo::allowance(), + OwnerOf { .. } => ::WeightInfo::owner_of(), + GetAttribute { .. } => ::WeightInfo::get_attribute(), + Collection(_) => ::WeightInfo::collection(), + ItemMetadata { .. } => ::WeightInfo::item_metadata(), + NextCollectionId => ::WeightInfo::next_collection_id(), + } } /// Performs the requested read and returns the result. diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 290f49f2..68260ab2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -2,19 +2,21 @@ use codec::Encode; use frame_support::{ assert_noop, assert_ok, sp_runtime::{BoundedVec, DispatchError::BadOrigin}, - traits::Incrementable, }; +use pallet_nfts::WeightInfo as NftsWeightInfoTrait; use crate::{ mock::*, nonfungibles::{ - AccountBalanceOf, BlockNumberFor, CollectionConfig, CollectionDetails, CollectionIdOf, + AccountBalanceOf, AttributeNamespace, AttributeOf, BlockNumberFor, + CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails, CollectionIdOf, CollectionOf, CollectionSettings, DestroyWitness, ItemIdOf, MintSettings, MintWitness, - NextCollectionIdOf, NftsInstanceOf, Read::*, ReadResult, + NextCollectionIdOf, NftsInstanceOf, NftsWeightInfoOf, Read::*, ReadResult, }, Read, }; +const COLLECTION: u32 = 0; const ITEM: u32 = 1; type NftsError = pallet_nfts::Error>; @@ -71,7 +73,9 @@ mod encoding_read_result { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }); assert_eq!( ReadResult::Collection::(collection_details.clone()).encode(), @@ -160,9 +164,14 @@ fn burn_works() { new_test_ext().execute_with(|| { let owner = ALICE; + // "UnknownItem" error is returned if collection item is not created. + assert_noop!(NonFungibles::burn(signed(owner), COLLECTION, ITEM), NftsError::UnknownItem); // Successfully burn an existing new collection item. let (collection, item) = nfts::create_collection_mint(owner, ITEM); + let balance_before_burn = AccountBalanceOf::::get(collection, owner); assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); + let balance_after_burn = AccountBalanceOf::::get(collection, owner); + assert_eq!(balance_after_burn, balance_before_burn - 1); System::assert_last_event( Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); @@ -175,8 +184,12 @@ fn approve_works() { let owner = ALICE; let operator = BOB; let (collection, item) = nfts::create_collection_mint(owner, ITEM); - // Successfully approve `oeprator` to transfer the collection item. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, true)); + // Successfully approve `operator` to transfer the collection item. + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer(1)).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &Some(item), &owner, &operator)); System::assert_last_event( Event::Approval { collection, item: Some(item), owner, operator, approved: true } .into(), @@ -186,6 +199,26 @@ fn approve_works() { }); } +#[test] +fn approve_collection_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully approve `operator` to transfer all items within the collection. + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer(0)).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &None, &owner, &operator)); + System::assert_last_event( + Event::Approval { collection, item: None, owner, operator, approved: true }.into(), + ); + // Successfully transfer the item by the delegated account `operator`. + assert_ok!(Nfts::transfer(signed(operator), collection, item, operator)); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { @@ -193,7 +226,38 @@ fn cancel_approval_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); // Successfully cancel the transfer approval of `operator` by `owner`. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, false)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval(1)).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &Some(item), &owner, &operator), + Err(NftsError::NoPermission.into()) + ); + // Failed to transfer the item by `operator` without permission. + assert_noop!( + Nfts::transfer(signed(operator), collection, item, operator), + NftsError::NoPermission + ); + }); +} + +#[test] +fn cancel_collection_approval_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully cancel the transfer collection approval of `operator` by `owner`. + assert_ok!(Nfts::approve_transfer(signed(owner), collection, None, operator, None)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval(0)).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &None, &owner, &operator), + Err(NftsError::NoPermission.into()) + ); // Failed to transfer the item by `operator` without permission. assert_noop!( Nfts::transfer(signed(operator), collection, item, operator), @@ -218,60 +282,6 @@ fn set_max_supply_works() { }); } -#[test] -fn owner_of_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(OwnerOf { collection, item }).encode(), - Nfts::owner(collection, item).encode() - ); - }); -} - -#[test] -fn get_attribute_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option< - BoundedVec>>::ValueLimit>, - > = None; - // No attribute set. - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute.clone() - }) - .encode(), - result.encode() - ); - // Successfully get an existing attribute. - result = Some(value.clone()); - assert_ok!(Nfts::set_attribute( - signed(ALICE), - collection, - Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, - attribute.clone(), - value, - )); - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute - }) - .encode(), - result.encode() - ); - }); -} - #[test] fn set_metadata_works() { new_test_ext().execute_with(|| { @@ -316,7 +326,7 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), BoundedVec::truncate_from("some value".as_bytes().to_vec()) )); @@ -325,14 +335,14 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), )); assert_eq!( NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + namespace: AttributeNamespace::CollectionOwner, key: attribute }) .encode(), @@ -354,7 +364,7 @@ fn approve_item_attribute_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -365,7 +375,7 @@ fn approve_item_attribute_works() { NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::Account(BOB), + namespace: AttributeNamespace::Account(BOB), key: attribute }) .encode(), @@ -387,7 +397,7 @@ fn cancel_item_attribute_approval_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -396,14 +406,14 @@ fn cancel_item_attribute_approval_works() { collection, item, BOB, - pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } + CancelAttributesApprovalWitness { account_attributes: 1 } )); assert_noop!( Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() ), @@ -412,78 +422,79 @@ fn cancel_item_attribute_approval_works() { }); } -#[test] -fn next_collection_id_works() { - new_test_ext().execute_with(|| { - let _ = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - assert_eq!( - NonFungibles::read(NextCollectionId).encode(), - NextCollectionIdOf::::get() - .or(CollectionIdOf::::initial_value()) - .encode(), - ); - }); -} - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let owner = ALICE; - let collection = nfts::create_collection(owner); - (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - ((i + 1) as u128).encode() - ); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() - ); - }); - }); -} - #[test] fn create_works() { new_test_ext().execute_with(|| { - let owner = ALICE; + let creator = ALICE; + let admin = ALICE; let next_collection_id = NextCollectionIdOf::::get().unwrap_or_default(); + for origin in vec![root(), none()] { + assert_noop!( + NonFungibles::create( + origin, + admin, + CollectionConfig { + max_supply: None, + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled() + }, + ), + BadOrigin + ); + } assert_ok!(NonFungibles::create( - signed(owner), - owner, + signed(creator), + admin, CollectionConfig { max_supply: None, mint_settings: MintSettings::default(), settings: CollectionSettings::all_enabled() }, )); - assert_eq!(Nfts::collection_owner(next_collection_id), Some(owner)); + assert_eq!(Nfts::collection_owner(next_collection_id), Some(creator)); + System::assert_last_event(Event::Created { id: next_collection_id, creator, admin }.into()); }); } #[test] fn destroy_works() { new_test_ext().execute_with(|| { - let collection = nfts::create_collection(ALICE); - assert_ok!(NonFungibles::destroy( - signed(ALICE), - collection, - DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } - )); + let collection = COLLECTION; + let witness = DestroyWitness { + item_metadatas: 0, + item_configs: 0, + item_holders: 0, + attributes: 0, + allowances: 0, + }; + // Check error works for `Nfts::destroy()`. + assert_noop!( + NonFungibles::destroy(signed(ALICE), collection, witness), + NftsError::UnknownCollection + ); + nfts::create_collection(ALICE); + assert_ok!(NonFungibles::destroy(signed(ALICE), collection, witness)); assert_eq!(Nfts::collection_owner(collection), None); }); } #[test] -fn collection_works() { +fn total_supply_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(Collection(collection)).encode(), - CollectionOf::::get(&collection).encode(), - ); + let owner = ALICE; + let collection = nfts::create_collection(owner); + assert_eq!(NonFungibles::read(TotalSupply(collection)), ReadResult::TotalSupply(0)); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); + assert_eq!( + NonFungibles::read(TotalSupply(collection)), + ReadResult::TotalSupply((i + 1).into()) + ); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() + ); + }); }); } @@ -492,11 +503,15 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let owner = ALICE; let collection = nfts::create_collection(owner); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(Default::default()) + ); (0..10).into_iter().for_each(|i| { assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner }).encode(), - (i + 1).encode() + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(i + 1) ); assert_eq!( NonFungibles::read(BalanceOf { collection, owner }).encode(), @@ -513,9 +528,8 @@ fn allowance_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( - NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) - .encode(), - true.encode() + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }), + ReadResult::Allowance(true) ); assert_eq!( NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) @@ -527,6 +541,131 @@ fn allowance_works() { }); } +#[test] +fn owner_of_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(Some(ALICE)) + ); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }).encode(), + Nfts::owner(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let raw_value = "some value".as_bytes().to_vec(); + let value = BoundedVec::truncate_from(raw_value.clone()); + let namespace = AttributeNamespace::CollectionOwner; + // No attribute set. + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(None) + ); + // Successfully get an existing attribute. + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + namespace.clone(), + attribute.clone(), + value, + )); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(Some(raw_value)) + ); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }) + .encode(), + AttributeOf::::get((collection, Some(item), namespace, attribute)) + .map(|result| result.0) + .encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(Collection(COLLECTION)), ReadResult::Collection(None),); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)), + ReadResult::Collection(CollectionOf::::get(COLLECTION)), + ); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)).encode(), + CollectionOf::::get(COLLECTION).encode(), + ); + }); +} + +#[test] +fn item_metadata_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + let value = "some metadata".as_bytes().to_vec(); + assert_ok!(NonFungibles::set_metadata( + signed(ALICE), + COLLECTION, + ITEM, + BoundedVec::truncate_from(value.clone()) + )); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(Some(value)) + ); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }).encode(), + Nfts::item_metadata(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn next_collection_id_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(0))); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(1))); + assert_eq!( + NonFungibles::read(NextCollectionId).encode(), + Some(NextCollectionIdOf::::get().unwrap_or_default()).encode(), + ); + }); +} + fn signed(account_id: AccountId) -> RuntimeOrigin { RuntimeOrigin::signed(account_id) } @@ -539,6 +678,7 @@ fn none() -> RuntimeOrigin { RuntimeOrigin::none() } +// Helper functions for interacting with pallet-nfts. mod nfts { use super::*; @@ -559,7 +699,7 @@ mod nfts { } pub(super) fn create_collection(owner: AccountId) -> u32 { - let next_id = next_collection_id(); + let next_id = NextCollectionIdOf::::get().unwrap_or_default(); assert_ok!(Nfts::create( signed(owner), owner, @@ -568,10 +708,6 @@ mod nfts { next_id } - pub(super) fn next_collection_id() -> u32 { - NextCollectionIdOf::::get().unwrap_or_default() - } - pub(super) fn collection_config_with_all_settings_enabled( ) -> CollectionConfig, CollectionIdOf> { CollectionConfig { @@ -581,3 +717,287 @@ mod nfts { } } } + +mod read_weights { + use frame_support::weights::Weight; + + use super::*; + use crate::nonfungibles::{weights::WeightInfo, Config}; + + struct ReadWeightInfo { + total_supply: Weight, + balance_of: Weight, + allowance: Weight, + owner_of: Weight, + get_attribute: Weight, + collection: Weight, + next_collection_id: Weight, + item_metadata: Weight, + } + + impl ReadWeightInfo { + fn new() -> Self { + Self { + total_supply: NonFungibles::weight(&TotalSupply(COLLECTION)), + balance_of: NonFungibles::weight(&BalanceOf { + collection: COLLECTION, + owner: ALICE, + }), + allowance: NonFungibles::weight(&Allowance { + collection: COLLECTION, + item: Some(ITEM), + owner: ALICE, + operator: BOB, + }), + owner_of: NonFungibles::weight(&OwnerOf { collection: COLLECTION, item: ITEM }), + get_attribute: NonFungibles::weight(&GetAttribute { + collection: COLLECTION, + item: ITEM, + namespace: AttributeNamespace::CollectionOwner, + key: BoundedVec::default(), + }), + collection: NonFungibles::weight(&Collection(COLLECTION)), + next_collection_id: NonFungibles::weight(&NextCollectionId), + item_metadata: NonFungibles::weight(&ItemMetadata { + collection: COLLECTION, + item: ITEM, + }), + } + } + } + + #[test] + fn ensure_read_matches_benchmarks() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + assert_eq!(total_supply, ::WeightInfo::total_supply()); + assert_eq!(balance_of, ::WeightInfo::balance_of()); + assert_eq!(allowance, ::WeightInfo::allowance()); + assert_eq!(owner_of, ::WeightInfo::owner_of()); + assert_eq!(get_attribute, ::WeightInfo::get_attribute()); + assert_eq!(collection, ::WeightInfo::collection()); + assert_eq!(next_collection_id, ::WeightInfo::next_collection_id()); + assert_eq!(item_metadata, ::WeightInfo::item_metadata()); + } + + // These types read from the `Collection` storage. + #[test] + fn ensure_collection_variants_match() { + let ReadWeightInfo { total_supply, collection, .. } = ReadWeightInfo::new(); + + assert_eq!(total_supply, collection); + } + + // Proof size is based on `MaxEncodedLen`, not hardware. + // This test ensures that the data structure sizes do not change with upgrades. + #[test] + fn ensure_expected_proof_size_does_not_change() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + // These values come from `weights.rs`. + assert_eq!(total_supply.proof_size(), 3557); + assert_eq!(balance_of.proof_size(), 3529); + assert_eq!(allowance.proof_size(), 4326); + assert_eq!(owner_of.proof_size(), 4326); + assert_eq!(get_attribute.proof_size(), 3944); + assert_eq!(collection.proof_size(), 3557); + assert_eq!(next_collection_id.proof_size(), 1489); + assert_eq!(item_metadata.proof_size(), 3812); + } +} + +mod ensure_codec_indexes { + use super::{Encode, *}; + use crate::{mock::RuntimeCall::NonFungibles, nonfungibles}; + + #[test] + fn ensure_read_variant_indexes() { + [ + (TotalSupply::(Default::default()), 0u8, "TotalSupply"), + ( + BalanceOf:: { collection: Default::default(), owner: Default::default() }, + 1, + "BalanceOf", + ), + ( + Allowance:: { + collection: Default::default(), + item: Default::default(), + owner: Default::default(), + operator: Default::default(), + }, + 2, + "Allowance", + ), + ( + OwnerOf:: { collection: Default::default(), item: Default::default() }, + 5, + "OwnerOf", + ), + ( + GetAttribute:: { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 6, + "GetAttribute", + ), + (Collection::(Default::default()), 9, "Collection"), + (NextCollectionId, 10, "NextCollectionId"), + ( + ItemMetadata { collection: Default::default(), item: Default::default() }, + 11, + "ItemMetadata", + ), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!(variant.encode()[0], *expected_index, "{name} variant index changed"); + }) + } + + #[test] + fn ensure_dispatchable_indexes() { + use nonfungibles::Call::*; + + [ + ( + transfer { + collection: Default::default(), + item: Default::default(), + to: Default::default(), + }, + 3u8, + "transfer", + ), + ( + approve { + collection: Default::default(), + item: Default::default(), + operator: Default::default(), + approved: Default::default(), + }, + 4, + "approve", + ), + (create { admin: Default::default(), config: Default::default() }, 7, "create"), + ( + destroy { + collection: Default::default(), + witness: DestroyWitness { + item_metadatas: Default::default(), + item_configs: Default::default(), + item_holders: Default::default(), + attributes: Default::default(), + allowances: Default::default(), + }, + }, + 8, + "destroy", + ), + ( + set_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + value: Default::default(), + }, + 12, + "set_attribute", + ), + ( + clear_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 13, + "clear_attribute", + ), + ( + set_metadata { + collection: Default::default(), + item: Default::default(), + data: Default::default(), + }, + 14, + "set_metadata", + ), + ( + clear_metadata { collection: Default::default(), item: Default::default() }, + 15, + "clear_metadata", + ), + ( + approve_item_attributes { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + }, + 16, + "approve_item_attributes", + ), + ( + cancel_item_attributes_approval { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + witness: CancelAttributesApprovalWitness { + account_attributes: Default::default(), + }, + }, + 17, + "cancel_item_attributes_approval", + ), + ( + set_max_supply { collection: Default::default(), max_supply: Default::default() }, + 18, + "set_max_supply", + ), + ( + mint { + to: Default::default(), + collection: Default::default(), + item: Default::default(), + witness: MintWitness { + owned_item: Default::default(), + mint_price: Default::default(), + }, + }, + 19, + "mint", + ), + (burn { collection: Default::default(), item: Default::default() }, 20, "burn"), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!( + NonFungibles(variant.to_owned()).encode()[1], + *expected_index, + "{name} dispatchable index changed" + ); + }) + } +} diff --git a/pallets/api/src/nonfungibles/weights.rs b/pallets/api/src/nonfungibles/weights.rs new file mode 100644 index 00000000..f0b8fa83 --- /dev/null +++ b/pallets/api/src/nonfungibles/weights.rs @@ -0,0 +1,217 @@ + +//! Autogenerated weights for `nonfungibles` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `R0GUE`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/pop-node +// benchmark +// pallet +// --chain=dev +// --wasm-execution=compiled +// --pallet=nonfungibles +// --steps=50 +// --repeat=20 +// --json +// --template +// ./scripts/pallet-weights-template.hbs +// --output=./pallets/api/src/nonfungibles/weights.rs +// --extrinsic= + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `nonfungibles`. +pub trait WeightInfo { + fn total_supply() -> Weight; + fn balance_of() -> Weight; + fn allowance() -> Weight; + fn owner_of() -> Weight; + fn get_attribute() -> Weight; + fn collection() -> Weight; + fn next_collection_id() -> Weight; + fn item_metadata() -> Weight; +} + +/// Weights for `nonfungibles` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } +} + diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index ab66da26..58209b8b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -64,6 +64,27 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account (caller, caller_lookup) } +fn approve_collection, I: 'static>( + index: u32, +) -> (T::AccountId, AccountIdLookupOf) { + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; + if caller != whitelisted_caller() { + whitelist_account!(caller); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let delegate: T::AccountId = account("delegate", 0, SEED + index); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + assert_ok!(Nfts::::approve_transfer( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + None, + delegate_lookup.clone(), + Some(deadline), + )); + (caller, caller_lookup) +} + fn mint_item, I: 'static>( index: u16, ) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { @@ -77,7 +98,7 @@ fn mint_item, I: 'static>( let item_exists = Item::::contains_key(&collection, &item); let item_config = ItemConfigOf::::get(&collection, &item); if item_exists { - return (item, caller, caller_lookup) + return (item, caller, caller_lookup); } else if let Some(item_config) = item_config { assert_ok!(Nfts::::force_mint( SystemOrigin::Signed(caller.clone()).into(), @@ -250,6 +271,8 @@ benchmarks_instance_pallet! { let m in 0 .. 1_000; let c in 0 .. 1_000; let a in 0 .. 1_000; + let h in 0 .. 1_000; + let l in 0 .. 1_000; let (collection, caller, _) = create_collection::(); add_collection_metadata::(); @@ -267,6 +290,13 @@ benchmarks_instance_pallet! { for i in 0..a { add_collection_attribute::(i as u16); } + for i in 0..h { + mint_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..l { + approve_collection::(i as u32); + } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { @@ -573,27 +603,45 @@ benchmarks_instance_pallet! { } approve_transfer { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup, Some(deadline)) + let maybe_deadline = if i == 0 { + None + } else { + Some(BlockNumberFor::::max_value()) + }; + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, maybe_deadline) verify { - assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); + assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); } cancel_approval { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup) + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 89de1f05..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,6 +39,11 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.items) } + /// Get the allowances to spend items within the collection. + pub fn collection_allowances(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.allowances) + } + /// Get the metadata of the collection item. pub fn item_metadata( collection: T::CollectionId, diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index e1e79ef4..2647492c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -195,6 +195,15 @@ impl, I: 'static> Pallet { Allowances::::mutate((&collection, &owner, &delegate), |allowance| { *allowance = true; }); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_inc(); + Ok(()) + }, + )?; Self::deposit_event(Event::TransferApproved { collection, @@ -217,6 +226,15 @@ impl, I: 'static> Pallet { ensure!(check_origin == owner, Error::::NoPermission); } Allowances::::remove((&collection, &owner, &delegate)); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_dec(); + Ok(()) + }, + )?; Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index b7efd03a..1d08cd1b 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,7 +54,9 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }, ); CollectionRoleOf::::insert( @@ -119,6 +121,11 @@ impl, I: 'static> Pallet { collection_details.item_configs == witness.item_configs, Error::::BadWitness ); + ensure!( + collection_details.item_holders == witness.item_holders, + Error::::BadWitness + ); + ensure!(collection_details.allowances == witness.allowances, Error::::BadWitness); for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { if let Some(depositor) = metadata.deposit.account { @@ -137,8 +144,6 @@ impl, I: 'static> Pallet { } } - // TODO: Do we need another storage item to keep track of number of holders of a - // collection let _ = AccountBalance::::clear_prefix(collection, collection_details.items, None); let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); @@ -152,7 +157,9 @@ impl, I: 'static> Pallet { Ok(DestroyWitness { item_metadatas: collection_details.item_metadatas, item_configs: collection_details.item_configs, + item_holders: collection_details.item_holders, attributes: collection_details.attributes, + allowances: collection_details.allowances, }) }) } diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index cc29f8da..a7b7ddf3 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,9 +69,15 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); - AccountBalance::::mutate(collection, &mint_to, |balance| { - balance.saturating_inc(); - }); + + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + balance.clone() + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config @@ -257,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 3b25b014..dbe6f3b0 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -54,7 +54,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult, ) -> DispatchResult { // Retrieve collection details. - let collection_details = + let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,13 +87,23 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balances. - AccountBalance::::mutate(collection, &details.owner, |balance| { - balance.saturating_dec(); - }); - AccountBalance::::mutate(collection, &dest, |balance| { + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + balance.clone() + }); + if owner_balance == 0 { + collection_details.item_holders.saturating_dec(); + } + // Update account balance of the destination account. + let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { balance.saturating_inc(); + balance.clone() }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); @@ -108,6 +118,7 @@ impl, I: 'static> Pallet { // Update item details. Item::::insert(&collection, &item, &details); + Collection::::insert(&collection, &collection_details); ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index bc8b67b6..37e8b29c 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,7 +30,6 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -832,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -847,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1311,7 +1314,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer())] + #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, @@ -1350,7 +1353,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::cancel_approval())] + #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs deleted file mode 100644 index af611bf1..00000000 --- a/pallets/nfts/src/migration.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use frame_support::traits::OnRuntimeUpgrade; -use log; -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; - -use super::*; - -pub mod v1 { - use frame_support::{pallet_prelude::*, weights::Weight}; - - use super::*; - - #[derive(Decode)] - pub struct OldCollectionDetails { - pub owner: AccountId, - pub owner_deposit: DepositBalance, - pub items: u32, - pub item_metadatas: u32, - pub attributes: u32, - } - - impl OldCollectionDetails { - /// Migrates the old collection details to the new v1 format. - fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { - CollectionDetails { - owner: self.owner, - owner_deposit: self.owner_deposit, - items: self.items, - item_metadatas: self.item_metadatas, - item_configs, - attributes: self.attributes, - } - } - } - - /// A migration utility to update the storage version from v0 to v1 for the pallet. - pub struct MigrateToV1(core::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { - fn on_runtime_upgrade() -> Weight { - let in_code_version = Pallet::::in_code_storage_version(); - let on_chain_version = Pallet::::on_chain_storage_version(); - - log::info!( - target: LOG_TARGET, - "Running migration with in-code storage version {:?} / onchain {:?}", - in_code_version, - on_chain_version - ); - - if on_chain_version == 0 && in_code_version == 1 { - let mut translated = 0u64; - let mut configs_iterated = 0u64; - Collection::::translate::< - OldCollectionDetails>, - _, - >(|key, old_value| { - let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; - configs_iterated += item_configs as u64; - translated.saturating_inc(); - Some(old_value.migrate_to_v1(item_configs)) - }); - - in_code_version.put::>(); - - log::info!( - target: LOG_TARGET, - "Upgraded {} records, storage to version {:?}", - translated, - in_code_version - ); - T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) - } else { - log::info!( - target: LOG_TARGET, - "Migration did not execute. This probably should be removed" - ); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let prev_count = Collection::::iter().count(); - Ok((prev_count as u32).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(prev_count: Vec) -> Result<(), TryRuntimeError> { - let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( - "the state parameter should be something that was generated by pre_upgrade", - ); - let post_count = Collection::::iter().count() as u32; - ensure!( - prev_count == post_count, - "the records count before and after the migration should be the same" - ); - - ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); - - Ok(()) - } - } -} diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4d0f08c9..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -165,6 +165,7 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -175,10 +176,37 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); assert_eq!(AccountBalance::::get(1, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } +#[test] +fn collection_item_holders_should_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + let total = 5; + for i in 0..total { + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, i, account(1), None)); + } + assert_eq!(AccountBalance::::get(0, account(1)), total); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, total, account(2), None)); + assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, total)); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + }); +} + #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { @@ -223,6 +251,7 @@ fn lifecycle_should_work() { assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); assert_eq!(Collection::::get(0).unwrap().item_configs, 3); + assert_eq!(Collection::::get(0).unwrap().item_holders, 3); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); @@ -317,6 +346,7 @@ fn destroy_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), 0, @@ -360,6 +390,7 @@ fn mint_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -425,6 +456,7 @@ fn mint_should_work() { Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -464,6 +496,7 @@ fn mint_should_work() { Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); assert_eq!(AccountBalance::::get(1, account(2)), 1); + assert_eq!(Collection::::get(1).unwrap().item_holders, 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -500,10 +533,11 @@ fn transfer_should_work() { account(2), default_item_config() )); - + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -521,6 +555,7 @@ fn transfer_should_work() { assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 0); assert_eq!(AccountBalance::::get(0, account(4)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1775,6 +1810,7 @@ fn burn_works() { default_item_config() )); assert_eq!(AccountBalance::::get(0, account(5)), 2); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1783,8 +1819,10 @@ fn burn_works() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); assert_eq!(AccountBalance::::get(0, account(5)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); assert_eq!(AccountBalance::::get(0, account(5)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2036,6 +2074,7 @@ fn cancel_approval_collection_works_with_admin() { delegate: account(3) })); assert_eq!(Allowances::::get((0, account(2), account(3))), false); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 0); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2192,6 +2231,7 @@ fn approval_collection_works_with_admin() { deadline: None })); assert_eq!(Allowances::::get((0, account(1), account(3))), true); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -4114,7 +4154,13 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0 } + DestroyWitness { + item_configs: 0, + item_metadatas: 0, + attributes: 0, + allowances: 0, + item_holders: 0 + } )); assert_eq!(Collection::::get(0), None); assert_eq!(Balances::reserved_balance(&account(1)), 10); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 941da6ca..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -104,8 +104,12 @@ pub struct CollectionDetails { pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. pub attributes: u32, + /// The total number of allowances to spend all items within collections. + pub allowances: u32, } /// Witness data for the destroy transactions. @@ -117,9 +121,15 @@ pub struct DestroyWitness { /// The total number of outstanding item configs of this collection. #[codec(compact)] pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + #[codec(compact)] + pub item_holders: u32, /// The total number of attributes for this collection. #[codec(compact)] pub attributes: u32, + /// The total number of allowances to spend all items within collections. + #[codec(compact)] + pub allowances: u32, } impl CollectionDetails { @@ -127,7 +137,9 @@ impl CollectionDetails { DestroyWitness { item_metadatas: self.item_metadatas, item_configs: self.item_configs, + item_holders: self.item_holders, attributes: self.attributes, + allowances: self.allowances, } } } diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index c374d6db..b3307503 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 -//! DATE: 2024-10-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `R0GUE`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -36,7 +36,7 @@ use core::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(m: u32, c: u32, a: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, h: u32, l: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -59,8 +59,8 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer() -> Weight; - fn cancel_approval() -> Weight; + fn approve_transfer(i: u32, ) -> Weight; + fn cancel_approval(i: u32, ) -> Weight; fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -91,16 +91,16 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -110,14 +110,14 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -126,6 +126,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -137,19 +139,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1006_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -160,7 +160,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -171,10 +171,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,7 +183,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -194,10 +194,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -206,7 +206,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -223,15 +223,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -250,15 +250,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -266,12 +266,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -285,7 +285,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -298,35 +298,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -334,12 +334,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -347,28 +347,28 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,7 +386,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -397,20 +397,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -424,13 +424,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -462,8 +462,8 @@ impl WeightInfo for SubstrateWeight { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -473,7 +473,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -482,7 +482,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -494,15 +494,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,32 +511,32 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,25 +544,37 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -582,20 +594,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,7 +620,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -624,8 +636,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -633,8 +645,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -649,12 +661,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -662,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -674,8 +686,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -687,7 +699,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -696,8 +708,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -712,12 +724,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -726,7 +738,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -742,12 +754,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -761,7 +773,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -769,12 +781,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -788,7 +800,7 @@ impl WeightInfo for () { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -798,16 +810,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -817,14 +829,14 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -833,6 +845,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -844,19 +858,17 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1006_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -867,7 +879,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -878,10 +890,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -890,7 +902,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -901,10 +913,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -913,7 +925,7 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -930,15 +942,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -957,15 +969,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -973,12 +985,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -992,7 +1004,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1005,35 +1017,35 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -1041,12 +1053,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -1054,28 +1066,28 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1093,7 +1105,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1104,20 +1116,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -1131,13 +1143,13 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1169,8 +1181,8 @@ impl WeightInfo for () { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1180,7 +1192,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1189,7 +1201,7 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -1201,15 +1213,15 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1218,32 +1230,32 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1251,25 +1263,37 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1289,20 +1313,20 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1315,7 +1339,7 @@ impl WeightInfo for () { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,8 +1355,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1340,8 +1364,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1356,12 +1380,12 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -1369,9 +1393,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1381,8 +1405,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1394,7 +1418,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1403,8 +1427,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1419,12 +1443,12 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1433,7 +1457,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -1449,12 +1473,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -1468,7 +1492,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1476,16 +1500,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } -} \ No newline at end of file +} diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 5ea1d923..d96fd85b 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -11,7 +11,7 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::{NftsInstance, TrustBackedAssetsInstance}, + config::assets::{TrustBackedAssetsInstance, TrustBackedNftsInstance}, fungibles, nonfungibles, Runtime, RuntimeCall, RuntimeEvent, }; @@ -88,7 +88,7 @@ impl fungibles::Config for Runtime { } impl nonfungibles::Config for Runtime { - type NftsInstance = NftsInstance; + type NftsInstance = TrustBackedNftsInstance; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -311,7 +311,13 @@ mod tests { }), NonFungibles(destroy { collection: 0, - witness: DestroyWitness { attributes: 0, item_configs: 0, item_metadatas: 0 }, + witness: DestroyWitness { + attributes: 0, + item_configs: 0, + item_metadatas: 0, + item_holders: 0, + allowances: 0, + }, }), NonFungibles(set_attribute { collection: 0, diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 97c2a9e7..65405ea4 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -46,9 +46,9 @@ impl Get for KeyLimit { } } -pub(crate) type NftsInstance = pallet_nfts::Instance1; -pub type NftsCall = pallet_nfts::Call; -impl pallet_nfts::Config for Runtime { +pub(crate) type TrustBackedNftsInstance = pallet_nfts::Instance1; +pub type TrustBackedNftsCall = pallet_nfts::Call; +impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; @@ -97,8 +97,8 @@ impl pallet_nft_fractionalization::Config for Runtime { type Deposit = AssetDeposit; type NewAssetName = NewAssetName; type NewAssetSymbol = NewAssetSymbol; - type NftCollectionId = >::CollectionId; - type NftId = >::ItemId; + type NftCollectionId = >::CollectionId; + type NftId = >::ItemId; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index 161178dc..48653027 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -5,7 +5,7 @@ use pop_runtime_common::proxy::{ }; use sp_runtime::traits::BlakeTwo256; -use super::assets::{NftsCall, TrustBackedAssetsCall}; +use super::assets::{TrustBackedAssetsCall, TrustBackedNftsCall}; use crate::{Balances, Runtime, RuntimeCall, RuntimeEvent}; impl InstanceFilter for ProxyType { @@ -45,13 +45,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(NftsCall::create { .. }) | - RuntimeCall::Nfts(NftsCall::destroy { .. }) | - RuntimeCall::Nfts(NftsCall::redeposit { .. }) | - RuntimeCall::Nfts(NftsCall::transfer_ownership { .. }) | - RuntimeCall::Nfts(NftsCall::set_team { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(NftsCall::lock_collection { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::create { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::destroy { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::redeposit { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::transfer_ownership { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_team { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_collection { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -66,17 +66,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(NftsCall::force_mint { .. }) | - RuntimeCall::Nfts(NftsCall::update_mint_settings { .. }) | - RuntimeCall::Nfts(NftsCall::mint_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_properties { .. }) | - RuntimeCall::Nfts(NftsCall::set_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::force_mint { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::update_mint_settings { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::mint_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_properties { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_collection_metadata { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 839f819d..736f0be7 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -646,6 +646,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [fungibles, Fungibles] + [nonfungibles, NonFungibles] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] From c5532616dbbfa1cb5d7d5a10800eb2ea87ee0a7a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:14:46 +0700 Subject: [PATCH 29/64] chore: clippy --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/features/create_delete_item.rs | 2 +- pallets/nfts/src/features/transfer.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 58209b8b..d8876d52 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -295,7 +295,7 @@ benchmarks_instance_pallet! { burn_item::(i as u16); } for i in 0..l { - approve_collection::(i as u32); + approve_collection::(i); } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index a7b7ddf3..08cf5f95 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -73,7 +73,7 @@ impl, I: 'static> Pallet { let account_balance = AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { balance.saturating_inc(); - balance.clone() + *balance }); if account_balance == 1 { collection_details.item_holders.saturating_inc(); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index dbe6f3b0..3f2dae3b 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -91,7 +91,7 @@ impl, I: 'static> Pallet { let owner_balance = AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { balance.saturating_dec(); - balance.clone() + *balance }); if owner_balance == 0 { collection_details.item_holders.saturating_dec(); @@ -99,7 +99,7 @@ impl, I: 'static> Pallet { // Update account balance of the destination account. let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { balance.saturating_inc(); - balance.clone() + *balance }); if dest_balance == 1 { collection_details.item_holders.saturating_inc(); From c5ecbd8ebd4724d22f32921eb97a5e594312f533 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:23:51 +0700 Subject: [PATCH 30/64] chore: forked pallet nfts --- pallets/nfts/src/migration.rs | 120 ++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs new file mode 100644 index 00000000..8f82e092 --- /dev/null +++ b/pallets/nfts/src/migration.rs @@ -0,0 +1,120 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use frame_support::traits::OnRuntimeUpgrade; +use log; + +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; + +pub mod v1 { + use frame_support::{pallet_prelude::*, weights::Weight}; + + use super::*; + + #[derive(Decode)] + pub struct OldCollectionDetails { + pub owner: AccountId, + pub owner_deposit: DepositBalance, + pub items: u32, + pub item_metadatas: u32, + pub attributes: u32, + } + + impl OldCollectionDetails { + /// Migrates the old collection details to the new v1 format. + fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { + CollectionDetails { + owner: self.owner, + owner_deposit: self.owner_deposit, + items: self.items, + item_metadatas: self.item_metadatas, + item_configs, + attributes: self.attributes, + } + } + } + + /// A migration utility to update the storage version from v0 to v1 for the pallet. + pub struct MigrateToV1(core::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let in_code_version = Pallet::::in_code_storage_version(); + let on_chain_version = Pallet::::on_chain_storage_version(); + + log::info!( + target: LOG_TARGET, + "Running migration with in-code storage version {:?} / onchain {:?}", + in_code_version, + on_chain_version + ); + + if on_chain_version == 0 && in_code_version == 1 { + let mut translated = 0u64; + let mut configs_iterated = 0u64; + Collection::::translate::< + OldCollectionDetails>, + _, + >(|key, old_value| { + let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; + configs_iterated += item_configs as u64; + translated.saturating_inc(); + Some(old_value.migrate_to_v1(item_configs)) + }); + + in_code_version.put::>(); + + log::info!( + target: LOG_TARGET, + "Upgraded {} records, storage to version {:?}", + translated, + in_code_version + ); + T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) + } else { + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let prev_count = Collection::::iter().count(); + Ok((prev_count as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev_count: Vec) -> Result<(), TryRuntimeError> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + let post_count = Collection::::iter().count() as u32; + ensure!( + prev_count == post_count, + "the records count before and after the migration should be the same" + ); + + ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); + + Ok(()) + } + } +} From 9fd921a1cd3bbe5b8e1838d5f57c3f4a7d1b449a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:36:36 +0700 Subject: [PATCH 31/64] feat: add nonfungibles api + integration tests --- pop-api/Cargo.toml | 3 + pop-api/integration-tests/Cargo.toml | 3 + .../contracts/nonfungibles/Cargo.toml | 21 + .../contracts/nonfungibles/lib.rs | 244 +++++++++++ .../integration-tests/src/fungibles/utils.rs | 33 -- pop-api/integration-tests/src/lib.rs | 9 +- .../integration-tests/src/nonfungibles/mod.rs | 409 ++++++++++++++++++ .../src/nonfungibles/utils.rs | 328 ++++++++++++++ pop-api/integration-tests/src/utils.rs | 34 ++ pop-api/src/lib.rs | 3 + pop-api/src/macros.rs | 53 +++ pop-api/src/primitives.rs | 3 +- pop-api/src/v0/mod.rs | 3 + pop-api/src/v0/nonfungibles/errors.rs | 35 ++ pop-api/src/v0/nonfungibles/events.rs | 50 +++ pop-api/src/v0/nonfungibles/mod.rs | 300 +++++++++++++ pop-api/src/v0/nonfungibles/traits.rs | 85 ++++ pop-api/src/v0/nonfungibles/types.rs | 192 ++++++++ 18 files changed, 1771 insertions(+), 37 deletions(-) create mode 100644 pop-api/integration-tests/contracts/nonfungibles/Cargo.toml create mode 100644 pop-api/integration-tests/contracts/nonfungibles/lib.rs create mode 100644 pop-api/integration-tests/src/nonfungibles/mod.rs create mode 100644 pop-api/integration-tests/src/nonfungibles/utils.rs create mode 100644 pop-api/integration-tests/src/utils.rs create mode 100644 pop-api/src/macros.rs create mode 100644 pop-api/src/v0/nonfungibles/errors.rs create mode 100644 pop-api/src/v0/nonfungibles/events.rs create mode 100644 pop-api/src/v0/nonfungibles/mod.rs create mode 100644 pop-api/src/v0/nonfungibles/traits.rs create mode 100644 pop-api/src/v0/nonfungibles/types.rs diff --git a/pop-api/Cargo.toml b/pop-api/Cargo.toml index 4caf8eaa..c9d0c4f5 100644 --- a/pop-api/Cargo.toml +++ b/pop-api/Cargo.toml @@ -6,6 +6,8 @@ name = "pop-api" version = "0.0.0" [dependencies] +bitflags = { version = "1.3.2" } +enumflags2 = "0.7.9" ink = { version = "5.0.0", default-features = false } pop-primitives = { path = "../primitives", default-features = false } sp-io = { version = "37.0.0", default-features = false, features = [ @@ -22,4 +24,5 @@ path = "src/lib.rs" [features] default = [ "std" ] fungibles = [ ] +nonfungibles = [ ] std = [ "ink/std", "pop-primitives/std", "sp-io/std" ] diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index 482a214f..f87cdddb 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -16,8 +16,10 @@ log = "0.4.22" pallet-assets = { version = "37.0.0", default-features = false } pallet-balances = { version = "37.0.0", default-features = false } pallet-contracts = { version = "35.0.0", default-features = false } +pallet-nfts = { path = "../../pallets/nfts", default-features = false } pop-api = { path = "../../pop-api", default-features = false, features = [ "fungibles", + "nonfungibles", ] } pop-primitives = { path = "../../primitives", default-features = false } pop-runtime-devnet = { path = "../../runtime/devnet", default-features = false } @@ -39,6 +41,7 @@ std = [ "pallet-assets/std", "pallet-balances/std", "pallet-contracts/std", + "pallet-nfts/std", "pop-api/std", "pop-primitives/std", "pop-runtime-devnet/std", diff --git a/pop-api/integration-tests/contracts/nonfungibles/Cargo.toml b/pop-api/integration-tests/contracts/nonfungibles/Cargo.toml new file mode 100644 index 00000000..9c8bda79 --- /dev/null +++ b/pop-api/integration-tests/contracts/nonfungibles/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = [ "R0GUE " ] +edition = "2021" +name = "nonfungibles" +version = "0.1.0" + +[dependencies] +ink = { version = "5.0.0", default-features = false } +pop-api = { path = "../../../../pop-api", default-features = false, features = [ "nonfungibles" ] } + +[lib] +path = "lib.rs" + +[features] +default = [ "std" ] +e2e-tests = [ ] +ink-as-dependency = [ ] +std = [ + "ink/std", + "pop-api/std", +] diff --git a/pop-api/integration-tests/contracts/nonfungibles/lib.rs b/pop-api/integration-tests/contracts/nonfungibles/lib.rs new file mode 100644 index 00000000..13446791 --- /dev/null +++ b/pop-api/integration-tests/contracts/nonfungibles/lib.rs @@ -0,0 +1,244 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +/// 1. PSP-34 +/// 2. PSP-34 Metadata +/// 3. Management +/// 4. PSP-34 Mintable & Burnable +use ink::prelude::vec::Vec; +use pop_api::{ + nonfungibles::{ + self as api, + events::{Approval, AttributeSet, Transfer}, + AttributeNamespace, CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails, + CollectionId, DestroyWitness, ItemId, MintWitness, + }, + StatusCode, +}; + +pub type Result = core::result::Result; + +#[ink::contract] +mod nonfungibles { + use super::*; + + #[ink(storage)] + #[derive(Default)] + pub struct NonFungibles; + + impl NonFungibles { + #[ink(constructor, payable)] + pub fn new() -> Self { + ink::env::debug_println!("PopApiNonFungiblesExample::new"); + Default::default() + } + + /// 1. PSP-34 Interface: + /// - total_supply + /// - balance_of + /// - allowance + /// - transfer + /// - approve + /// - owner_of + + #[ink(message)] + pub fn total_supply(&self, collection: CollectionId) -> Result { + api::total_supply(collection) + } + + #[ink(message)] + pub fn balance_of(&self, collection: CollectionId, owner: AccountId) -> Result { + api::balance_of(collection, owner) + } + + #[ink(message)] + pub fn allowance( + &self, + collection: CollectionId, + owner: AccountId, + operator: AccountId, + item: Option, + ) -> Result { + api::allowance(collection, owner, operator, item) + } + + #[ink(message)] + pub fn transfer( + &mut self, + collection: CollectionId, + item: ItemId, + to: AccountId, + ) -> Result<()> { + api::transfer(collection, item, to)?; + self.env().emit_event(Transfer { + from: Some(self.env().account_id()), + to: Some(to), + item, + }); + Ok(()) + } + + #[ink(message)] + pub fn approve( + &mut self, + collection: CollectionId, + item: Option, + operator: AccountId, + approved: bool, + ) -> Result<()> { + api::approve(collection, item, operator, approved)?; + self.env().emit_event(Approval { + owner: self.env().account_id(), + operator, + item, + approved, + }); + Ok(()) + } + + #[ink(message)] + pub fn owner_of( + &self, + collection: CollectionId, + item: ItemId, + ) -> Result> { + api::owner_of(collection, item) + } + + /// 2. PSP-34 Metadata Interface: + /// - get_attribute + + #[ink(message)] + pub fn get_attribute( + &self, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, + ) -> Result>> { + api::get_attribute(collection, item, namespace, key) + } + + /// 3. Asset Management: + /// - create + /// - destroy + /// - collection + /// - set_attribute + /// - clear_attribute + /// - set_metadata + /// - clear_metadata + /// - approve_item_attributes + /// - cancel_item_attributes_approval + /// - set_max_supply + /// - item_metadata + + #[ink(message)] + pub fn create(&mut self, admin: AccountId, config: CollectionConfig) -> Result<()> { + api::create(admin, config) + } + + #[ink(message)] + pub fn destroy(&mut self, collection: CollectionId, witness: DestroyWitness) -> Result<()> { + api::destroy(collection, witness) + } + + #[ink(message)] + pub fn collection(&self, collection: CollectionId) -> Result> { + api::collection(collection) + } + + #[ink(message)] + pub fn set_attribute( + &mut self, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, + value: Vec, + ) -> Result<()> { + api::set_attribute(collection, item, namespace, key.clone(), value.clone())?; + self.env().emit_event(AttributeSet { item, key, data: value }); + Ok(()) + } + + #[ink(message)] + pub fn clear_attribute( + &mut self, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, + ) -> Result<()> { + api::clear_attribute(collection, item, namespace, key) + } + + #[ink(message)] + pub fn set_metadata( + &mut self, + collection: CollectionId, + item: ItemId, + data: Vec, + ) -> Result<()> { + api::set_metadata(collection, item, data) + } + + #[ink(message)] + pub fn clear_metadata(&mut self, collection: CollectionId, item: ItemId) -> Result<()> { + api::clear_metadata(collection, item) + } + + #[ink(message)] + pub fn approve_item_attributes( + &mut self, + collection: CollectionId, + item: ItemId, + delegate: AccountId, + ) -> Result<()> { + api::approve_item_attributes(collection, item, delegate) + } + + #[ink(message)] + pub fn cancel_item_attributes_approval( + &mut self, + collection: CollectionId, + item: ItemId, + delegate: AccountId, + witness: CancelAttributesApprovalWitness, + ) -> Result<()> { + api::cancel_item_attributes_approval(collection, item, delegate, witness) + } + + #[ink(message)] + pub fn set_max_supply(&mut self, collection: CollectionId, max_supply: u32) -> Result<()> { + api::set_max_supply(collection, max_supply) + } + + #[ink(message)] + pub fn item_metadata( + &mut self, + collection: CollectionId, + item: ItemId, + ) -> Result>> { + api::item_metadata(collection, item) + } + + /// 4. PSP-22 Mintable & Burnable Interface: + /// - mint + /// - burn + + #[ink(message)] + pub fn mint( + &mut self, + to: AccountId, + collection: CollectionId, + item: ItemId, + witness: MintWitness, + ) -> Result<()> { + api::mint(to, collection, item, witness) + } + + #[ink(message)] + pub fn burn(&mut self, collection: CollectionId, item: ItemId) -> Result<()> { + api::burn(collection, item) + } + } +} diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 07be866e..018c6cfc 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -1,16 +1,5 @@ use super::*; -fn do_bare_call(function: &str, addr: &AccountId32, params: Vec) -> ExecReturnValue { - let function = function_selector(function); - let params = [function, params].concat(); - bare_call(addr.clone(), params, 0).expect("should work") -} - -// TODO - issue #263 - why result.data[1..] -pub(super) fn decoded(result: ExecReturnValue) -> Result { - ::decode(&mut &result.data[1..]).map_err(|_| result) -} - pub(super) fn total_supply(addr: &AccountId32, token_id: TokenId) -> Result { let result = do_bare_call("total_supply", addr, token_id.encode()); decoded::>(result.clone()) @@ -340,25 +329,3 @@ pub(super) fn instantiate_and_create_fungible( .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) .map(|_| address) } - -/// Get the last event from pallet contracts. -pub(super) fn last_contract_event() -> Vec { - let events = System::read_events_for_pallet::>(); - let contract_events = events - .iter() - .filter_map(|event| match event { - pallet_contracts::Event::::ContractEmitted { data, .. } => - Some(data.as_slice()), - _ => None, - }) - .collect::>(); - contract_events.last().unwrap().to_vec() -} - -/// Decodes a byte slice into an `AccountId` as defined in `primitives`. -/// -/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the -/// contract environment. -pub fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { - pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") -} diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index 58641889..4738d010 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -9,13 +9,16 @@ use frame_support::{ }; use pallet_contracts::{Code, CollectEvents, Determinism, ExecReturnValue}; #[cfg(feature = "devnet")] -use pop_runtime_devnet::{Assets, Contracts, Runtime, RuntimeOrigin, System, UNIT}; +use pop_runtime_devnet::{Assets, Contracts, Nfts, Runtime, RuntimeOrigin, System, UNIT}; #[cfg(feature = "testnet")] -use pop_runtime_testnet::{Assets, Contracts, Runtime, RuntimeOrigin, System, UNIT}; +use pop_runtime_testnet::{Assets, Contracts, Nfts, Runtime, RuntimeOrigin, System, UNIT}; use scale::{Decode, Encode}; use sp_runtime::{AccountId32, BuildStorage, DispatchError}; +use utils::*; mod fungibles; +mod nonfungibles; +mod utils; type Balance = u128; @@ -23,7 +26,7 @@ const ALICE: AccountId32 = AccountId32::new([1_u8; 32]); const BOB: AccountId32 = AccountId32::new([2_u8; 32]); const DEBUG_OUTPUT: pallet_contracts::DebugInfo = pallet_contracts::DebugInfo::UnsafeDebug; const FERDIE: AccountId32 = AccountId32::new([3_u8; 32]); -const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); +const GAS_LIMIT: Weight = Weight::from_parts(500_000_000_000, 3 * 1024 * 1024); const INIT_AMOUNT: Balance = 100_000_000 * UNIT; const INIT_VALUE: Balance = 100 * UNIT; diff --git a/pop-api/integration-tests/src/nonfungibles/mod.rs b/pop-api/integration-tests/src/nonfungibles/mod.rs new file mode 100644 index 00000000..c92652c0 --- /dev/null +++ b/pop-api/integration-tests/src/nonfungibles/mod.rs @@ -0,0 +1,409 @@ +use frame_support::BoundedVec; +use pop_api::{ + nonfungibles::{ + events::{Approval, AttributeSet, Transfer}, + types::*, + }, + primitives::BlockNumber, +}; +use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*}; +use utils::*; + +use super::*; + +mod utils; + +const COLLECTION_ID: CollectionId = 0; +const ITEM_ID: ItemId = 1; +const CONTRACT: &str = "contracts/nonfungibles/target/ink/nonfungibles.wasm"; + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!( + total_supply(&addr, COLLECTION_ID), + Ok(Nfts::collection_items(COLLECTION_ID).unwrap_or_default() as u128) + ); + assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(0)); + + // Tokens in circulation. + nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); + assert_eq!( + total_supply(&addr, COLLECTION_ID), + Ok(Nfts::collection_items(COLLECTION_ID).unwrap_or_default() as u128) + ); + assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(1)); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!( + balance_of(&addr, COLLECTION_ID, ALICE), + Ok(nfts::balance_of(COLLECTION_ID, ALICE)), + ); + assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(0)); + + // Tokens in circulation. + nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); + assert_eq!( + balance_of(&addr, COLLECTION_ID, ALICE), + Ok(nfts::balance_of(COLLECTION_ID, ALICE)), + ); + assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(1)); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + // No tokens in circulation. + assert_eq!( + allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, None), + Ok(!Nfts::check_allowance(&COLLECTION_ID, &None, &addr, &ALICE).is_err()), + ); + assert_eq!(allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, None), Ok(false)); + + let (_, item) = + nfts::create_collection_mint_and_approve(&addr, &addr, ITEM_ID, &addr, &ALICE); + assert_eq!( + allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, Some(item)), + Ok(Nfts::check_allowance(&COLLECTION_ID, &Some(item), &addr.clone(), &ALICE).is_ok()), + ); + assert_eq!( + allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, Some(item)), + Ok(true) + ); + }); +} + +#[test] +fn transfer_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let before_transfer_balance = nfts::balance_of(COLLECTION_ID, ALICE); + assert_ok!(transfer(&addr, collection, item, ALICE)); + let after_transfer_balance = nfts::balance_of(COLLECTION_ID, ALICE); + assert_eq!(after_transfer_balance - before_transfer_balance, 1); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(approve(&addr, collection, Some(item), ALICE, true)); + assert!(Nfts::check_allowance(&collection, &Some(item), &addr.clone(), &ALICE).is_ok(),); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(ALICE), collection, item, BOB.into())); + }); +} + +#[test] +fn owner_of_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); + assert_eq!(owner_of(&addr, collection, item), Ok(ALICE)); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(addr.clone()), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + BoundedVec::truncate_from("some attribute".as_bytes().to_vec()), + BoundedVec::truncate_from("some value".as_bytes().to_vec()), + )); + assert_eq!( + get_attribute( + &addr.clone(), + collection, + item, + AttributeNamespace::CollectionOwner, + "some attribute".as_bytes().to_vec(), + ), + Ok(Some("some value".as_bytes().to_vec())) + ); + }); +} + +#[test] +fn set_attribute_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + + assert_ok!(set_attribute( + &addr.clone(), + collection, + item, + AttributeNamespace::CollectionOwner, + "some attribute".as_bytes().to_vec(), + "some value".as_bytes().to_vec(), + )); + + assert_eq!( + pallet_nfts::Attribute::::get(( + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + )) + .map(|attribute| attribute.0), + Some(AttributeValue::truncate_from("some value".as_bytes().to_vec())) + ); + }); +} + +#[test] +fn clear_attribute_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(addr.clone()), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + BoundedVec::truncate_from("some attribute".as_bytes().to_vec()), + BoundedVec::truncate_from("some value".as_bytes().to_vec()), + )); + assert_ok!(clear_attribute( + &addr.clone(), + collection, + item, + AttributeNamespace::CollectionOwner, + "some attribute".as_bytes().to_vec() + )); + assert_eq!( + pallet_nfts::Attribute::::get(( + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + )) + .map(|attribute| attribute.0), + None + ); + }); +} + +#[test] +fn approve_item_attributes_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(approve_item_attributes(&addr.clone(), collection, item, ALICE)); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(ALICE), + BoundedVec::truncate_from("some attribute".as_bytes().to_vec()), + BoundedVec::truncate_from("some value".as_bytes().to_vec()), + )); + assert_eq!( + pallet_nfts::Attribute::::get(( + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(ALICE), + AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + )) + .map(|attribute| attribute.0), + Some(AttributeValue::truncate_from("some value".as_bytes().to_vec())) + ); + }); +} + +#[test] +fn cancel_item_attributes_approval_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(addr.clone()), + collection, + item, + ALICE.into() + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(ALICE), + BoundedVec::truncate_from("some attribute".as_bytes().to_vec()), + BoundedVec::truncate_from("some value".as_bytes().to_vec()), + )); + assert_ok!(cancel_item_attributes_approval( + &addr.clone(), + collection, + item, + ALICE, + CancelAttributesApprovalWitness { account_attributes: 1 } + )); + assert!(Nfts::set_attribute( + RuntimeOrigin::signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(ALICE), + BoundedVec::truncate_from("some attribute".as_bytes().to_vec()), + BoundedVec::truncate_from("some value".as_bytes().to_vec()), + ) + .is_err()); + }); +} + +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(set_metadata(&addr.clone(), collection, item, vec![])); + assert_eq!(Nfts::item_metadata(collection, item), Some(MetadataData::default())); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(Nfts::set_metadata( + RuntimeOrigin::signed(addr.clone()), + collection, + item, + MetadataData::default() + )); + assert_ok!(clear_metadata(&addr.clone(), collection, item)); + assert_eq!(Nfts::item_metadata(collection, item), None); + }); +} + +#[test] +fn create_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let collection = nfts::next_collection_id(); + assert_ok!(create( + &addr.clone(), + addr.clone(), + CollectionConfig { + max_supply: Some(100), + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled(), + } + )); + assert_eq!( + pallet_nfts::Collection::::get(collection), + Some(pallet_nfts::CollectionDetails { + owner: addr.clone(), + owner_deposit: 100000000000, + items: 0, + item_metadatas: 0, + item_configs: 0, + attributes: 0, + }) + ); + }); +} + +#[test] +fn destroy_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let collection = nfts::create_collection(&addr, &addr); + assert_ok!(destroy( + &addr.clone(), + collection, + DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } + )); + assert_eq!(pallet_nfts::Collection::::get(collection), None); + }); +} + +#[test] +fn set_max_supply_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let value = 10; + + let collection = nfts::create_collection(&addr, &addr); + assert_ok!(set_max_supply(&addr.clone(), collection, value)); + + (0..value).into_iter().for_each(|i| { + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(addr.clone()), + collection, + i, + ALICE.into(), + None + )); + }); + assert!(Nfts::mint( + RuntimeOrigin::signed(addr.clone()), + collection, + value + 1, + ALICE.into(), + None + ) + .is_err()); + }); +} + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let value = 10; + + let collection = nfts::create_collection(&addr, &addr); + assert_ok!(mint( + &addr.clone(), + ALICE, + collection, + ITEM_ID, + MintWitness { mint_price: None, owned_item: None } + )); + assert_eq!(nfts::balance_of(COLLECTION_ID, ALICE), 1); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + assert_ok!(burn(&addr.clone(), collection, ITEM_ID,)); + assert_eq!(nfts::balance_of(COLLECTION_ID, addr), 0); + }); +} diff --git a/pop-api/integration-tests/src/nonfungibles/utils.rs b/pop-api/integration-tests/src/nonfungibles/utils.rs new file mode 100644 index 00000000..0c1c3c19 --- /dev/null +++ b/pop-api/integration-tests/src/nonfungibles/utils.rs @@ -0,0 +1,328 @@ +use super::*; + +pub(super) type AttributeKey = BoundedVec::KeyLimit>; +pub(super) type AttributeValue = BoundedVec::ValueLimit>; +pub(super) type MetadataData = BoundedVec::StringLimit>; + +pub(super) fn total_supply(addr: &AccountId32, collection: CollectionId) -> Result { + let result = do_bare_call("total_supply", addr, collection.encode()); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn balance_of( + addr: &AccountId32, + collection: CollectionId, + owner: AccountId32, +) -> Result { + let params = [collection.encode(), owner.encode()].concat(); + let result = do_bare_call("balance_of", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn allowance( + addr: &AccountId32, + collection: CollectionId, + owner: AccountId32, + operator: AccountId32, + item: Option, +) -> Result { + let params = [collection.encode(), owner.encode(), operator.encode(), item.encode()].concat(); + let result = do_bare_call("allowance", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn transfer( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + to: AccountId32, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode(), to.encode()].concat(); + let result = do_bare_call("transfer", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn approve( + addr: &AccountId32, + collection: CollectionId, + item: Option, + operator: AccountId32, + approved: bool, +) -> Result<(), Error> { + let params = + [collection.encode(), item.encode(), operator.encode(), approved.encode()].concat(); + let result = do_bare_call("approve", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn owner_of( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, +) -> Result { + let params = [collection.encode(), item.encode()].concat(); + let result = do_bare_call("owner_of", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn get_attribute( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, +) -> Result>, Error> { + let params = [ + collection.encode(), + item.encode(), + namespace.encode(), + AttributeKey::truncate_from(key).encode(), + ] + .concat(); + let result = do_bare_call("get_attribute", &addr, params); + decoded::, Error>>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) + .map(|value| value.map(|v| v.to_vec())) +} + +pub(super) fn create( + addr: &AccountId32, + admin: AccountId32, + config: CollectionConfig, +) -> Result<(), Error> { + let params = [admin.encode(), config.encode()].concat(); + let result = do_bare_call("create", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn destroy( + addr: &AccountId32, + collection: CollectionId, + witness: DestroyWitness, +) -> Result<(), Error> { + let params = [collection.encode(), witness.encode()].concat(); + let result = do_bare_call("destroy", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn collection( + addr: &AccountId32, + collection: CollectionId, +) -> Result, Error> { + let result = do_bare_call("collection", &addr, collection.encode()); + decoded::, Error>>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn set_attribute( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, + value: Vec, +) -> Result<(), Error> { + let params = [ + collection.encode(), + item.encode(), + namespace.encode(), + AttributeKey::truncate_from(key).encode(), + AttributeValue::truncate_from(value).encode(), + ] + .concat(); + let result = do_bare_call("set_attribute", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn clear_attribute( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode(), namespace.encode(), key.encode()].concat(); + let result = do_bare_call("clear_attribute", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn set_metadata( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + data: Vec, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode(), data.encode()].concat(); + let result = do_bare_call("set_metadata", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn clear_metadata( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode()].concat(); + let result = do_bare_call("clear_metadata", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn approve_item_attributes( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + delegate: AccountId32, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode(), delegate.encode()].concat(); + let result = do_bare_call("approve_item_attributes", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn cancel_item_attributes_approval( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, + delegate: AccountId32, + witness: CancelAttributesApprovalWitness, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode(), delegate.encode(), witness.encode()].concat(); + let result = do_bare_call("cancel_item_attributes_approval", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn set_max_supply( + addr: &AccountId32, + collection: CollectionId, + max_supply: u32, +) -> Result<(), Error> { + let params = [collection.encode(), max_supply.encode()].concat(); + let result = do_bare_call("set_max_supply", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn item_metadata( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, +) -> Result>, Error> { + let params = [collection.encode(), item.encode()].concat(); + let result = do_bare_call("item_metadata", &addr, params); + decoded::>, Error>>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) + .map(|value| value.map(|v| v.to_vec())) +} + +pub(super) fn mint( + addr: &AccountId32, + to: AccountId32, + collection: CollectionId, + item: ItemId, + witness: MintWitness, +) -> Result<(), Error> { + let params = [to.encode(), collection.encode(), item.encode(), witness.encode()].concat(); + let result = do_bare_call("mint", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) fn burn( + addr: &AccountId32, + collection: CollectionId, + item: ItemId, +) -> Result<(), Error> { + let params = [collection.encode(), item.encode()].concat(); + let result = do_bare_call("burn", &addr, params); + decoded::>(result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) +} + +pub(super) mod nfts { + use super::*; + + pub(crate) fn create_collection_and_mint_to( + owner: &AccountId32, + admin: &AccountId32, + to: &AccountId32, + item: ItemId, + ) -> (CollectionId, ItemId) { + let collection = create_collection(owner, admin); + mint(collection, item, owner, to); + (collection, item) + } + + pub(crate) fn create_collection_mint_and_approve( + owner: &AccountId32, + admin: &AccountId32, + item: ItemId, + to: &AccountId32, + operator: &AccountId32, + ) -> (u32, u32) { + let (collection, item) = create_collection_and_mint_to(&owner.clone(), admin, to, item); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(to.clone()), + collection, + Some(item), + operator.clone().into(), + None + )); + (collection, item) + } + + pub(crate) fn create_collection(owner: &AccountId32, admin: &AccountId32) -> CollectionId { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(owner.clone()), + admin.clone().into(), + collection_config_with_all_settings_enabled() + )); + next_id + } + + pub(crate) fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() + } + + pub(crate) fn mint( + collection: CollectionId, + item: ItemId, + owner: &AccountId32, + to: &AccountId32, + ) -> ItemId { + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection, + item, + to.clone().into(), + None + )); + item + } + + pub(crate) fn balance_of(collection: CollectionId, owner: AccountId32) -> u32 { + pallet_nfts::AccountBalance::::get(collection, owner) + } + + pub(super) fn collection_config_with_all_settings_enabled( + ) -> pallet_nfts::CollectionConfig { + pallet_nfts::CollectionConfig { + settings: pallet_nfts::CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: pallet_nfts::MintSettings::default(), + } + } +} diff --git a/pop-api/integration-tests/src/utils.rs b/pop-api/integration-tests/src/utils.rs new file mode 100644 index 00000000..9b2131fd --- /dev/null +++ b/pop-api/integration-tests/src/utils.rs @@ -0,0 +1,34 @@ +use super::*; + +/// Get the last event from pallet contracts. +pub(super) fn last_contract_event() -> Vec { + let events = System::read_events_for_pallet::>(); + let contract_events = events + .iter() + .filter_map(|event| match event { + pallet_contracts::Event::::ContractEmitted { data, .. } => + Some(data.as_slice()), + _ => None, + }) + .collect::>(); + contract_events.last().unwrap().to_vec() +} + +/// Decodes a byte slice into an `AccountId` as defined in `primitives`. +/// +/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the +/// contract environment. +pub(super) fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { + pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") +} + +pub(super) fn do_bare_call(function: &str, addr: &AccountId32, params: Vec) -> ExecReturnValue { + let function = function_selector(function); + let params = [function, params].concat(); + bare_call(addr.clone(), params, 0).expect("should work") +} + +// TODO - issue #263 - why result.data[1..] +pub(super) fn decoded(result: ExecReturnValue) -> Result { + ::decode(&mut &result.data[1..]).map_err(|_| result) +} diff --git a/pop-api/src/lib.rs b/pop-api/src/lib.rs index b9dbf634..9a4172f8 100644 --- a/pop-api/src/lib.rs +++ b/pop-api/src/lib.rs @@ -12,6 +12,8 @@ use constants::DECODING_FAILED; use ink::env::chain_extension::{ChainExtensionMethod, FromStatusCode}; pub use v0::*; +/// Module providing macros. +pub mod macros; /// Module providing primitives types. pub mod primitives; /// The first version of the API. @@ -73,6 +75,7 @@ mod constants { pub(crate) const ASSETS: u8 = 52; pub(crate) const BALANCES: u8 = 10; pub(crate) const FUNGIBLES: u8 = 150; + pub(crate) const NONFUNGIBLES: u8 = 151; } // Helper method to build a dispatch call or a call to read state. diff --git a/pop-api/src/macros.rs b/pop-api/src/macros.rs new file mode 100644 index 00000000..7a9fd34d --- /dev/null +++ b/pop-api/src/macros.rs @@ -0,0 +1,53 @@ +/// Implements encoding and decoding traits for a wrapper type that represents +/// bitflags. The wrapper type should contain a field of type `$size`, where +/// `$size` is an integer type (e.g., u8, u16, u32) that can represent the bitflags. +/// The `$bitflag_enum` type is the enumeration type that defines the individual bitflags. +/// +/// This macro provides implementations for the following traits: +/// - `MaxEncodedLen`: Calculates the maximum encoded length for the wrapper type. +/// - `Encode`: Encodes the wrapper type using the provided encoding function. +/// - `EncodeLike`: Trait indicating the type can be encoded as is. +/// - `Decode`: Decodes the wrapper type from the input. +/// - `TypeInfo`: Provides type information for the wrapper type. +macro_rules! impl_codec_bitflags { + ($wrapper:ty, $size:ty, $bitflag_enum:ty) => { + impl ink::scale::MaxEncodedLen for $wrapper { + fn max_encoded_len() -> usize { + <$size>::max_encoded_len() + } + } + impl ink::scale::Encode for $wrapper { + fn using_encoded R>(&self, f: F) -> R { + self.0.bits().using_encoded(f) + } + } + impl ink::scale::EncodeLike for $wrapper {} + impl ink::scale::Decode for $wrapper { + fn decode( + input: &mut I, + ) -> ::core::result::Result { + let field = <$size>::decode(input)?; + Ok(Self(BitFlags::from_bits(field as $size).map_err(|_| "invalid value")?)) + } + } + + #[cfg(feature = "std")] + impl ink::scale_info::TypeInfo for $wrapper { + type Identity = Self; + + fn type_info() -> ink::scale_info::Type { + ink::scale_info::Type::builder() + .path(ink::scale_info::Path::new("BitFlags", module_path!())) + .type_params(vec![ink::scale_info::TypeParameter::new( + "T", + Some(ink::scale_info::meta_type::<$bitflag_enum>()), + )]) + .composite( + ink::scale_info::build::Fields::unnamed() + .field(|f| f.ty::<$size>().type_name(stringify!($bitflag_enum))), + ) + } + } + }; +} +pub(crate) use impl_codec_bitflags; diff --git a/pop-api/src/primitives.rs b/pop-api/src/primitives.rs index 2fcb8a95..ce396fc8 100644 --- a/pop-api/src/primitives.rs +++ b/pop-api/src/primitives.rs @@ -3,4 +3,5 @@ pub use pop_primitives::*; // Public due to integration tests crate. pub type AccountId = ::AccountId; -pub(crate) type Balance = ::Balance; +pub type Balance = ::Balance; +pub type BlockNumber = ::BlockNumber; diff --git a/pop-api/src/v0/mod.rs b/pop-api/src/v0/mod.rs index c6153892..2f12f5f4 100644 --- a/pop-api/src/v0/mod.rs +++ b/pop-api/src/v0/mod.rs @@ -8,6 +8,9 @@ use crate::{ /// APIs for fungible tokens. #[cfg(feature = "fungibles")] pub mod fungibles; +/// APIs for nonfungible tokens. +#[cfg(feature = "nonfungibles")] +pub mod nonfungibles; pub(crate) const V0: u8 = 0; diff --git a/pop-api/src/v0/nonfungibles/errors.rs b/pop-api/src/v0/nonfungibles/errors.rs new file mode 100644 index 00000000..c955bf60 --- /dev/null +++ b/pop-api/src/v0/nonfungibles/errors.rs @@ -0,0 +1,35 @@ +//! A set of errors for use in smart contracts that interact with the nonfungibles api. This +//! includes errors compliant to standards. + +use ink::prelude::string::{String, ToString}; + +use super::*; + +/// The PSP34 error. +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub enum Psp34Error { + /// Custom error type for cases if writer of traits added own restrictions + Custom(String), + /// Returned if owner approves self + SelfApprove, + /// Returned if the caller doesn't have allowance for transferring. + NotApproved, + /// Returned if the owner already own the token. + TokenExists, + /// Returned if the token doesn't exist + TokenNotExists, + /// Returned if safe transfer check fails + SafeTransferCheckFailed(String), +} + +impl From for Psp34Error { + /// Converts a `StatusCode` to a `PSP22Error`. + fn from(value: StatusCode) -> Self { + let encoded = value.0.to_le_bytes(); + match encoded { + // TODO: Handle conversion. + _ => Psp34Error::Custom(value.0.to_string()), + } + } +} diff --git a/pop-api/src/v0/nonfungibles/events.rs b/pop-api/src/v0/nonfungibles/events.rs new file mode 100644 index 00000000..3c409868 --- /dev/null +++ b/pop-api/src/v0/nonfungibles/events.rs @@ -0,0 +1,50 @@ +//! A set of events for use in smart contracts interacting with the nonfungibles API. +//! +//! The `Transfer` and `Approval` events conform to the PSP-34 standard. +//! +//! These events are not emitted by the API itself but can be used in your contracts to +//! track token operations. Be mindful of the costs associated with emitting events. +//! +//! For more details, refer to [ink! events](https://use.ink/basics/events). + +use super::*; + +/// Event emitted when a token transfer occurs. +#[ink::event] +pub struct Transfer { + /// The source of the transfer. `None` when minting. + #[ink(topic)] + pub from: Option, + /// The recipient of the transfer. `None` when burning. + #[ink(topic)] + pub to: Option, + /// The item transferred (or minted/burned). + pub item: ItemId, +} + +/// Event emitted when a token approve occurs. +#[ink::event] +pub struct Approval { + /// The owner providing the allowance. + #[ink(topic)] + pub owner: AccountId, + /// The beneficiary of the allowance. + #[ink(topic)] + pub operator: AccountId, + /// The item which is (dis)approved. `None` for all owner's items. + pub item: Option, + /// Whether allowance is set or removed. + pub approved: bool, +} + +/// Event emitted when an attribute is set for a token. +#[ink::event] +pub struct AttributeSet { + /// The item which attribute is set. + #[ink(topic)] + pub item: ItemId, + /// The key for the attribute. + pub key: Vec, + /// The data for the attribute. + pub data: Vec, +} diff --git a/pop-api/src/v0/nonfungibles/mod.rs b/pop-api/src/v0/nonfungibles/mod.rs new file mode 100644 index 00000000..7b2bd187 --- /dev/null +++ b/pop-api/src/v0/nonfungibles/mod.rs @@ -0,0 +1,300 @@ +//! The `nonfungibles` module provides an API for interacting and managing nonfungible tokens. +//! +//! The API includes the following interfaces: +//! 1. PSP-34 +//! 2. PSP-34 Metadata +//! 3. PSP-22 Mintable & Burnable + +use constants::*; +pub use errors::*; +pub use events::*; +use ink::prelude::vec::Vec; +pub use traits::*; +pub use types::*; + +use crate::{ + constants::NONFUNGIBLES, + primitives::{AccountId, BlockNumber}, + ChainExtensionMethodApi, Result, StatusCode, +}; + +pub mod errors; +pub mod events; +pub mod traits; +pub mod types; + +#[inline] +pub fn total_supply(collection: CollectionId) -> Result { + build_read_state(TOTAL_SUPPLY) + .input::() + .output::, true>() + .handle_error_code::() + .call(&(collection)) +} + +#[inline] +pub fn balance_of(collection: CollectionId, owner: AccountId) -> Result { + build_read_state(BALANCE_OF) + .input::<(CollectionId, AccountId)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, owner)) +} + +#[inline] +pub fn allowance( + collection: CollectionId, + owner: AccountId, + operator: AccountId, + item: Option, +) -> Result { + build_read_state(ALLOWANCE) + .input::<(CollectionId, AccountId, AccountId, Option)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, owner, operator, item)) +} + +#[inline] +pub fn transfer(collection: CollectionId, item: ItemId, to: AccountId) -> Result<()> { + build_dispatch(TRANSFER) + .input::<(CollectionId, ItemId, AccountId)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item, to)) +} + +#[inline] +pub fn approve( + collection: CollectionId, + item: Option, + operator: AccountId, + approved: bool, +) -> Result<()> { + build_dispatch(APPROVE) + .input::<(CollectionId, Option, AccountId, bool)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item, operator, approved)) +} + +#[inline] +pub fn owner_of(collection: CollectionId, item: ItemId) -> Result> { + build_read_state(OWNER_OF) + .input::<(CollectionId, ItemId)>() + .output::>, true>() + .handle_error_code::() + .call(&(collection, item)) +} + +#[inline] +pub fn get_attribute( + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, +) -> Result>> { + build_read_state(GET_ATTRIBUTE) + .input::<(CollectionId, ItemId, AttributeNamespace, Vec)>() + .output::>>, true>() + .handle_error_code::() + .call(&(collection, item, namespace, key)) +} + +#[inline] +pub fn create(admin: AccountId, config: CollectionConfig) -> Result<()> { + build_dispatch(CREATE) + .input::<(AccountId, CollectionConfig)>() + .output::, true>() + .handle_error_code::() + .call(&(admin, config))?; + Ok(()) +} + +#[inline] +pub fn destroy(collection: CollectionId, witness: DestroyWitness) -> Result<()> { + build_dispatch(DESTROY) + .input::<(CollectionId, DestroyWitness)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, witness)) +} + +#[inline] +pub fn collection(collection: CollectionId) -> Result> { + build_read_state(COLLECTION) + .input::() + .output::>, true>() + .handle_error_code::() + .call(&(collection)) +} + +#[inline] +pub fn item_metadata(collection: CollectionId, item: ItemId) -> Result>> { + build_read_state(ITEM_METADATA) + .input::<(CollectionId, ItemId)>() + .output::>>, true>() + .handle_error_code::() + .call(&(collection, item)) +} + +#[inline] +pub fn set_attribute( + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, + value: Vec, +) -> Result<()> { + build_dispatch(SET_ATTRIBUTE) + .input::<(CollectionId, Option, AttributeNamespace, Vec, Vec)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, Some(item), namespace, key, value)) +} + +#[inline] +pub fn clear_attribute( + collection: CollectionId, + item: ItemId, + namespace: AttributeNamespace, + key: Vec, +) -> Result<()> { + build_dispatch(CLEAR_ATTRIBUTE) + .input::<(CollectionId, Option, AttributeNamespace, Vec)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, Some(item), namespace, key)) +} + +#[inline] +pub fn set_metadata(collection: CollectionId, item: ItemId, data: Vec) -> Result<()> { + build_dispatch(SET_METADATA) + .input::<(CollectionId, ItemId, Vec)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item, data)) +} + +#[inline] +pub fn clear_metadata(collection: CollectionId, item: ItemId) -> Result<()> { + build_dispatch(CLEAR_METADATA) + .input::<(CollectionId, ItemId)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item)) +} + +#[inline] +pub fn approve_item_attributes( + collection: CollectionId, + item: ItemId, + delegate: AccountId, +) -> Result<()> { + build_dispatch(APPROVE_ITEM_ATTRIBUTES) + .input::<(CollectionId, ItemId, AccountId)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item, delegate)) +} + +#[inline] +pub fn cancel_item_attributes_approval( + collection: CollectionId, + item: ItemId, + delegate: AccountId, + witness: CancelAttributesApprovalWitness, +) -> Result<()> { + build_dispatch(CANCEL_ITEM_ATTRIBUTES_APPROVAL) + .input::<(CollectionId, ItemId, AccountId, CancelAttributesApprovalWitness)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item, delegate, witness)) +} + +#[inline] +pub fn set_max_supply(collection: CollectionId, max_supply: u32) -> Result<()> { + build_dispatch(SET_MAX_SUPPLY) + .input::<(CollectionId, u32)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, max_supply)) +} + +#[inline] +pub fn mint( + to: AccountId, + collection: CollectionId, + item: ItemId, + witness: MintWitness, +) -> Result<()> { + build_dispatch(MINT) + .input::<(AccountId, CollectionId, ItemId, MintWitness)>() + .output::, true>() + .handle_error_code::() + .call(&(to, collection, item, witness)) +} + +#[inline] +pub fn burn(collection: CollectionId, item: ItemId) -> Result<()> { + build_dispatch(BURN) + .input::<(CollectionId, ItemId)>() + .output::, true>() + .handle_error_code::() + .call(&(collection, item)) +} + +#[inline] +pub fn next_collection_id() -> Result { + build_read_state(NEXT_COLLECTION_ID) + .output::, true>() + .handle_error_code::() + .call(&()) +} + +mod constants { + /// 1. PSP-34 + pub(super) const TOTAL_SUPPLY: u8 = 0; + pub(super) const BALANCE_OF: u8 = 1; + pub(super) const ALLOWANCE: u8 = 2; + pub(super) const TRANSFER: u8 = 3; + pub(super) const APPROVE: u8 = 4; + pub(super) const OWNER_OF: u8 = 5; + + /// 2. PSP-34 Metadata + pub(super) const GET_ATTRIBUTE: u8 = 6; + + /// 3. Management + pub(super) const CREATE: u8 = 7; + pub(super) const DESTROY: u8 = 8; + pub(super) const COLLECTION: u8 = 9; + pub(super) const NEXT_COLLECTION_ID: u8 = 10; + pub(super) const ITEM_METADATA: u8 = 11; + pub(super) const SET_ATTRIBUTE: u8 = 12; + pub(super) const CLEAR_ATTRIBUTE: u8 = 13; + pub(super) const SET_METADATA: u8 = 14; + pub(super) const CLEAR_METADATA: u8 = 15; + pub(super) const APPROVE_ITEM_ATTRIBUTES: u8 = 16; + pub(super) const CANCEL_ITEM_ATTRIBUTES_APPROVAL: u8 = 17; + pub(super) const SET_MAX_SUPPLY: u8 = 18; + + /// 4. PSP-34 Mintable & Burnable + pub(super) const MINT: u8 = 19; + pub(super) const BURN: u8 = 20; +} + +// Helper method to build a dispatch call. +// +// Parameters: +// - 'dispatchable': The index of the dispatchable function within the module. +fn build_dispatch(dispatchable: u8) -> ChainExtensionMethodApi { + crate::v0::build_dispatch(NONFUNGIBLES, dispatchable) +} + +// Helper method to build a call to read state. +// +// Parameters: +// - 'state_query': The index of the runtime state query. +fn build_read_state(state_query: u8) -> ChainExtensionMethodApi { + crate::v0::build_read_state(NONFUNGIBLES, state_query) +} diff --git a/pop-api/src/v0/nonfungibles/traits.rs b/pop-api/src/v0/nonfungibles/traits.rs new file mode 100644 index 00000000..c9e3ad04 --- /dev/null +++ b/pop-api/src/v0/nonfungibles/traits.rs @@ -0,0 +1,85 @@ +//! Traits that can be used by contracts. Including standard compliant traits. + +use core::result::Result; + +use super::*; + +#[ink::trait_definition] +pub trait Psp34 { + /// Returns the collection `Id`. + #[ink(message, selector = 0xffa27a5f)] + fn collection_id(&self) -> ItemId; + + // Returns the current total supply of the NFT. + #[ink(message, selector = 0x628413fe)] + fn total_supply(&self) -> u128; + + /// Returns the amount of items the owner has within a collection. + /// + /// # Parameters + /// - `owner` - The account whose balance is being queried. + #[ink(message, selector = 0xcde7e55f)] + fn balance_of(&self, owner: AccountId) -> u32; + + /// Returns whether the operator is approved by the owner to withdraw `item`. If `item` is + /// `None`, it returns whether the operator is approved to withdraw all owner's items for the + /// given collection. + /// + /// # Parameters + /// * `owner` - The account that owns the item(s). + /// * `operator` - the account that is allowed to withdraw the item(s). + /// * `item` - The item. If `None`, it is regarding all owner's items in collection. + #[ink(message, selector = 0x4790f55a)] + fn allowance(&self, owner: AccountId, operator: AccountId, id: Option) -> bool; + + /// Transfers an owned or approved item to the specified recipient. + /// + /// # Parameters + /// * `to` - The recipient account. + /// * `item` - The item. + /// - `data` - Additional data in unspecified format. + #[ink(message, selector = 0x3128d61b)] + fn transfer(&mut self, to: AccountId, id: ItemId, data: Vec) -> Result<(), Psp34Error>; + + /// Approves operator to withdraw item(s) from the contract's account. + /// + /// # Parameters + /// * `operator` - The account that is allowed to withdraw the item. + /// * `item` - Optional item. `None` means all items owned in the specified collection. + /// * `approved` - Whether the operator is given or removed the right to withdraw the item(s). + #[ink(message, selector = 0x1932a8b0)] + fn approve( + &mut self, + operator: AccountId, + id: Option, + approved: bool, + ) -> Result<(), Psp34Error>; + + /// Returns the owner of an item within a specified collection, if any. + /// + /// # Parameters + /// * `item` - The item. + #[ink(message, selector = 0x1168624d)] + fn owner_of(&self, id: ItemId) -> Option; +} + +#[ink::trait_definition] +pub trait Psp34Metadata { + /// Returns the attribute of `item` for the given `key`. + /// + /// # Parameters + /// * `item` - The item. If `None` the attributes for the collection are queried. + /// * `namespace` - The attribute's namespace. + /// * `key` - The key of the attribute. + #[ink(message, selector = 0xf19d48d1)] + fn get_attribute(&self, id: ItemId, key: Vec) -> Option>; +} + +#[ink::trait_definition] +pub trait Psp34Enumerable { + #[ink(message, selector = 0x3bcfb511)] + fn owners_token_by_index(&self, owner: AccountId, index: u128) -> Result; + + #[ink(message, selector = 0xcd0340d0)] + fn token_by_index(&self, index: u128) -> Result; +} diff --git a/pop-api/src/v0/nonfungibles/types.rs b/pop-api/src/v0/nonfungibles/types.rs new file mode 100644 index 00000000..c630f04b --- /dev/null +++ b/pop-api/src/v0/nonfungibles/types.rs @@ -0,0 +1,192 @@ +use enumflags2::{bitflags, BitFlags}; + +use super::*; +use crate::{macros::impl_codec_bitflags, primitives::AccountId}; + +pub type ItemId = u32; +pub type CollectionId = u32; +pub(super) type Balance = u32; + +/// Information about a collection. +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct CollectionDetails { + /// Collection's owner. + pub owner: AccountId, + /// The total balance deposited by the owner for all the storage data associated with this + /// collection. Used by `destroy`. + pub owner_deposit: Balance, + /// The total number of outstanding items of this collection. + pub items: u32, + /// The total number of outstanding item metadata of this collection. + pub item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + pub item_configs: u32, + /// The total number of attributes for this collection. + pub attributes: u32, +} + +/// Attribute namespaces for non-fungible tokens. +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub enum AttributeNamespace { + /// An attribute set by collection's owner. + #[codec(index = 1)] + CollectionOwner, + /// An attribute set by item's owner. + #[codec(index = 2)] + ItemOwner, + /// An attribute set by a pre-approved account. + #[codec(index = 3)] + Account(AccountId), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub enum MintType { + /// Only an `Issuer` could mint items. + Issuer, + /// Anyone could mint items. + Public, + /// Only holders of items in specified collection could mint new items. + HolderOf(CollectionId), +} + +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct CancelAttributesApprovalWitness { + /// An amount of attributes previously created by account. + pub account_attributes: u32, +} + +/// Witness data for the destroy transactions. +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct DestroyWitness { + /// The total number of items in this collection that have outstanding item metadata. + #[codec(compact)] + pub item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + #[codec(compact)] + pub item_configs: u32, + /// The total number of attributes for this collection. + #[codec(compact)] + pub attributes: u32, +} + +/// Witness data for items mint transactions. +#[derive(Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct MintWitness { + /// Provide the id of the item in a required collection. + pub owned_item: Option, + /// The price specified in mint settings. + pub mint_price: Option, +} + +/// Collection's configuration. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct CollectionConfig { + /// Collection's settings. + pub settings: CollectionSettings, + /// Collection's max supply. + pub max_supply: Option, + /// Default settings each item will get during the mint. + pub mint_settings: MintSettings, +} + +/// Support for up to 64 user-enabled features on a collection. +#[bitflags] +#[repr(u64)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub enum CollectionSetting { + /// Items in this collection are transferable. + TransferableItems, + /// The metadata of this collection can be modified. + UnlockedMetadata, + /// Attributes of this collection can be modified. + UnlockedAttributes, + /// The supply of this collection can be modified. + UnlockedMaxSupply, + /// When this isn't set then the deposit is required to hold the items of this collection. + DepositRequired, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CollectionSettings(pub BitFlags); + +impl CollectionSettings { + pub fn from_disabled(settings: BitFlags) -> Self { + Self(settings) + } + + #[cfg(feature = "std")] + pub fn all_enabled() -> Self { + Self(BitFlags::EMPTY) + } +} + +impl_codec_bitflags!(CollectionSettings, u64, CollectionSetting); + +/// Support for up to 64 user-enabled features on an item. +#[bitflags] +#[repr(u64)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub enum ItemSetting { + /// This item is transferable. + Transferable, + /// The metadata of this item can be modified. + UnlockedMetadata, + /// Attributes of this item can be modified. + UnlockedAttributes, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ItemSettings(pub BitFlags); + +impl ItemSettings { + pub fn all_enabled() -> Self { + Self(BitFlags::EMPTY) + } + + #[cfg(feature = "std")] + pub fn from_disabled(settings: BitFlags) -> Self { + Self(settings) + } +} + +impl_codec_bitflags!(ItemSettings, u64, ItemSetting); + +/// Holds the information about minting. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[ink::scale_derive(Encode, Decode, TypeInfo)] +pub struct MintSettings { + /// Whether anyone can mint or if minters are restricted to some subset. + pub mint_type: MintType, + /// An optional price per mint. + pub price: Option, + /// When the mint starts. + pub start_block: Option, + /// When the mint ends. + pub end_block: Option, + /// Default settings each item will get during the mint. + pub default_item_settings: ItemSettings, +} + +#[cfg(feature = "std")] +impl Default for MintSettings { + fn default() -> Self { + Self { + mint_type: MintType::Issuer, + price: None, + start_block: None, + end_block: None, + default_item_settings: ItemSettings::all_enabled(), + } + } +} From 325e8d31f7b4f39e7f0386d98b00b7560e9126d4 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:26:45 +0700 Subject: [PATCH 32/64] chore: delete migration.rs --- pallets/nfts/src/migration.rs | 120 ---------------------------------- 1 file changed, 120 deletions(-) delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs deleted file mode 100644 index 8f82e092..00000000 --- a/pallets/nfts/src/migration.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use frame_support::traits::OnRuntimeUpgrade; -use log; - -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; - -pub mod v1 { - use frame_support::{pallet_prelude::*, weights::Weight}; - - use super::*; - - #[derive(Decode)] - pub struct OldCollectionDetails { - pub owner: AccountId, - pub owner_deposit: DepositBalance, - pub items: u32, - pub item_metadatas: u32, - pub attributes: u32, - } - - impl OldCollectionDetails { - /// Migrates the old collection details to the new v1 format. - fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { - CollectionDetails { - owner: self.owner, - owner_deposit: self.owner_deposit, - items: self.items, - item_metadatas: self.item_metadatas, - item_configs, - attributes: self.attributes, - } - } - } - - /// A migration utility to update the storage version from v0 to v1 for the pallet. - pub struct MigrateToV1(core::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { - fn on_runtime_upgrade() -> Weight { - let in_code_version = Pallet::::in_code_storage_version(); - let on_chain_version = Pallet::::on_chain_storage_version(); - - log::info!( - target: LOG_TARGET, - "Running migration with in-code storage version {:?} / onchain {:?}", - in_code_version, - on_chain_version - ); - - if on_chain_version == 0 && in_code_version == 1 { - let mut translated = 0u64; - let mut configs_iterated = 0u64; - Collection::::translate::< - OldCollectionDetails>, - _, - >(|key, old_value| { - let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; - configs_iterated += item_configs as u64; - translated.saturating_inc(); - Some(old_value.migrate_to_v1(item_configs)) - }); - - in_code_version.put::>(); - - log::info!( - target: LOG_TARGET, - "Upgraded {} records, storage to version {:?}", - translated, - in_code_version - ); - T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) - } else { - log::info!( - target: LOG_TARGET, - "Migration did not execute. This probably should be removed" - ); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let prev_count = Collection::::iter().count(); - Ok((prev_count as u32).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(prev_count: Vec) -> Result<(), TryRuntimeError> { - let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( - "the state parameter should be something that was generated by pre_upgrade", - ); - let post_count = Collection::::iter().count() as u32; - ensure!( - prev_count == post_count, - "the records count before and after the migration should be the same" - ); - - ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); - - Ok(()) - } - } -} From f205909f6a752ac48a2489516805d404d5fcbcee Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:36:59 +0700 Subject: [PATCH 33/64] chore: fork pallet nfts --- pallets/nfts/Cargo.toml | 8 ++++---- pallets/nfts/runtime-api/Cargo.toml | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index bef584b8..791db0a7 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = [ "Parity Technologies ", "R0GUE " ] +authors = ["Parity Technologies ", "R0GUE "] description = "Fork of FRAME NFTs pallet" edition.workspace = true homepage = "https://substrate.io" @@ -10,13 +10,13 @@ repository.workspace = true version = "31.0.0" [package.metadata.docs.rs] -targets = [ "x86_64-unknown-linux-gnu" ] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } enumflags2 = { workspace = true } log = { workspace = true } -scale-info = { features = [ "derive" ], workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -31,7 +31,7 @@ pallet-balances.workspace = true sp-keystore.workspace = true [features] -default = [ "std" ] +default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml index 503642ef..d9a748d6 100644 --- a/pallets/nfts/runtime-api/Cargo.toml +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = [ "Parity Technologies ", "R0GUE " ] +authors = ["Parity Technologies ", "R0GUE "] description = "Runtime API for the FRAME NFTs pallet." edition.workspace = true homepage = "https://substrate.io" @@ -13,13 +13,13 @@ version = "23.0.0" workspace = true [package.metadata.docs.rs] -targets = [ "x86_64-unknown-linux-gnu" ] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { features = [ "derive" ], workspace = true } +codec = { features = ["derive"], workspace = true } pallet-nfts.workspace = true sp-api.workspace = true [features] -default = [ "std" ] -std = [ "codec/std", "pallet-nfts/std", "sp-api/std" ] +default = ["std"] +std = ["codec/std", "pallet-nfts/std", "sp-api/std"] From 9cc20fe147fb1a2ba5d560f363dea3f168c546e9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:23:51 +0700 Subject: [PATCH 34/64] chore: forked pallet nfts --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/common_functions.rs | 4 +- pallets/nfts/src/features/approvals.rs | 3 +- pallets/nfts/src/features/atomic_swap.rs | 4 +- pallets/nfts/src/features/attributes.rs | 3 +- pallets/nfts/src/features/buy_sell.rs | 3 +- .../src/features/create_delete_collection.rs | 3 +- .../nfts/src/features/create_delete_item.rs | 3 +- pallets/nfts/src/features/lock.rs | 4 +- pallets/nfts/src/features/metadata.rs | 4 +- pallets/nfts/src/features/roles.rs | 4 +- pallets/nfts/src/features/settings.rs | 3 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/impl_nonfungibles.rs | 9 ++-- pallets/nfts/src/lib.rs | 10 ++-- pallets/nfts/src/migration.rs | 4 +- pallets/nfts/src/mock.rs | 48 +++++++++---------- pallets/nfts/src/tests.rs | 3 +- pallets/nfts/src/types.rs | 24 +--------- 19 files changed, 49 insertions(+), 93 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..bc81096b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -19,6 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] +use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -31,7 +32,6 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; use sp_runtime::traits::{Bounded, One}; -use super::*; use crate::Pallet as Nfts; const SEED: u32 = 0; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index f51de192..2c4778c1 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -17,12 +17,10 @@ //! Various pieces of common functionality. +use crate::*; use alloc::vec::Vec; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ad5d93c2..053fa671 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,9 +19,8 @@ //! The bitflag [`PalletFeature::Approvals`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Approves the transfer of an item to a delegate. diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 31c93fba..830283b7 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -20,13 +20,12 @@ //! The bitflag [`PalletFeature::Swaps`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. +use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement::KeepAlive}, }; -use crate::*; - impl, I: 'static> Pallet { /// Creates a new swap offer for the specified item. /// @@ -102,7 +101,6 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the specified swap offer. /// /// This function is used to cancel the specified swap offer created by the `caller` account. If diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index ab0cdc68..28f7bd2c 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -20,9 +20,8 @@ //! The bitflag [`PalletFeature::Attributes`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Sets the attribute of an item or a collection. diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index 8cf86f79..d6ec6f50 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -20,13 +20,12 @@ //! The bitflag [`PalletFeature::Trading`] needs to be set in the [`Config::Features`] for NFTs //! to have the functionality defined in this module. +use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, }; -use crate::*; - impl, I: 'static> Pallet { /// Pays the specified tips to the corresponding receivers. /// diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..f03df7fd 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform functionality associated with creating and //! destroying collections for the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Create a new collection with the given `collection`, `owner`, `admin`, `config`, `deposit`, diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9843b2e..37f64ae1 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform functionality associated with minting and burning //! items for the NFTs pallet. -use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; - use crate::*; +use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; impl, I: 'static> Pallet { /// Mint a new unique item with the given `collection`, `item`, and other minting configuration diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs index 4649f4a0..1c3c9c86 100644 --- a/pallets/nfts/src/features/lock.rs +++ b/pallets/nfts/src/features/lock.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to configure locks on collections and items for the NFTs //! pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Locks a collection with specified settings. @@ -30,6 +29,7 @@ impl, I: 'static> Pallet { /// /// Note: it's possible only to lock the setting, but not to unlock it after. + /// /// - `origin`: The origin of the transaction, representing the account attempting to lock the /// collection. /// - `collection`: The identifier of the collection to be locked. diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index b3d16b12..26006160 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -17,12 +17,10 @@ //! This module contains helper methods to configure the metadata of collections and items. +use crate::*; use alloc::vec::Vec; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Sets the metadata for a specific item within a collection. /// diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs index 053eaf0b..aa6394f7 100644 --- a/pallets/nfts/src/features/roles.rs +++ b/pallets/nfts/src/features/roles.rs @@ -17,12 +17,10 @@ //! This module contains helper methods to configure account roles for existing collections. +use crate::*; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; - use frame_support::pallet_prelude::*; -use crate::*; - impl, I: 'static> Pallet { /// Set the team roles for a specific collection. /// diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs index 9c7ac7ca..d4f7533f 100644 --- a/pallets/nfts/src/features/settings.rs +++ b/pallets/nfts/src/features/settings.rs @@ -17,9 +17,8 @@ //! This module provides helper methods to configure collection settings for the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Forcefully change the configuration of a collection. diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index b7223a7c..bba83448 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,9 +18,8 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use frame_support::pallet_prelude::*; - use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Transfer an NFT to the specified destination account. @@ -161,7 +160,6 @@ impl, I: 'static> Pallet { Ok(()) }) } - /// Set or unset the ownership acceptance for an account regarding a specific collection. /// /// - `who`: The account for which to set or unset the ownership acceptance. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index 362cccd9..c90655aa 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -17,6 +17,7 @@ //! Implementations for `nonfungibles` traits. +use super::*; use frame_support::{ ensure, storage::KeyPrefixIterator, @@ -25,11 +26,9 @@ use frame_support::{ }; use sp_runtime::{DispatchError, DispatchResult}; -use super::*; - impl, I: 'static> Inspect<::AccountId> for Pallet { - type CollectionId = T::CollectionId; type ItemId = T::ItemId; + type CollectionId = T::CollectionId; fn owner( collection: &Self::CollectionId, @@ -141,11 +140,9 @@ impl, I: 'static> InspectRole<::AccountId> for P fn is_issuer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Issuer) } - fn is_admin(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Admin) } - fn is_freezer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Freezer) } @@ -472,9 +469,9 @@ impl, I: 'static> Trading> for Pallet impl, I: 'static> InspectEnumerable for Pallet { type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; type ItemsIterator = KeyPrefixIterator<>::ItemId>; - type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; type OwnedIterator = KeyPrefixIterator<(>::CollectionId, >::ItemId)>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; /// Returns an iterator of the collections in existence. /// diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 89bfb963..4e5493a3 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -51,18 +51,18 @@ pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; - use codec::{Decode, Encode}; use frame_support::traits::{ tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, }; use frame_system::Config as SystemConfig; -pub use pallet::*; use sp_runtime::{ traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; + +pub use pallet::*; pub use types::*; pub use weights::WeightInfo; @@ -74,11 +74,10 @@ type AccountIdLookupOf = <::Lookup as StaticLookup>::Sourc #[frame_support::pallet] pub mod pallet { + use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; - use super::*; - /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -109,17 +108,14 @@ pub mod pallet { fn collection(i: u16) -> CollectionId { i.into() } - fn item(i: u16) -> ItemId { i.into() } - fn signer() -> (sp_runtime::MultiSigner, sp_runtime::AccountId32) { let public = sp_io::crypto::sr25519_generate(0.into(), None); let account = sp_runtime::MultiSigner::Sr25519(public).into_account(); (public.into(), account) } - fn sign(signer: &sp_runtime::MultiSigner, message: &[u8]) -> sp_runtime::MultiSignature { sp_runtime::MultiSignature::Sr25519( sp_io::crypto::sr25519_sign(0.into(), &signer.clone().try_into().unwrap(), message) diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index af611bf1..8f82e092 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::*; use frame_support::traits::OnRuntimeUpgrade; use log; + #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -use super::*; - pub mod v1 { use frame_support::{pallet_prelude::*, weights::Weight}; diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index 5532be8f..5b589f59 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -17,6 +17,9 @@ //! Test environment for Nfts pallet. +use super::*; +use crate as pallet_nfts; + use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, @@ -27,9 +30,6 @@ use sp_runtime::{ BuildStorage, MultiSignature, }; -use super::*; -use crate as pallet_nfts; - type Block = frame_system::mocking::MockBlock; construct_runtime!( @@ -47,10 +47,10 @@ pub type AccountId = ::AccountId; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { - type AccountData = pallet_balances::AccountData; type AccountId = AccountId; - type Block = Block; type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] @@ -63,35 +63,35 @@ parameter_types! { } impl Config for Test { - type ApprovalsLimit = ConstU32<10>; - type AttributeDepositBase = ConstU64<1>; - type CollectionDeposit = ConstU64<2>; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; - type CreateOrigin = AsEnsureOriginWithArg>; + type ItemId = u32; type Currency = Balances; - type DepositPerByte = ConstU64<1>; - type Features = Features; + type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type ItemAttributesApprovalsLimit = ConstU32<2>; + type Locker = (); + type CollectionDeposit = ConstU64<2>; type ItemDeposit = ConstU64<1>; - type ItemId = u32; + type MetadataDepositBase = ConstU64<1>; + type AttributeDepositBase = ConstU64<1>; + type DepositPerByte = ConstU64<1>; + type StringLimit = ConstU32<50>; type KeyLimit = ConstU32<50>; - type Locker = (); - type MaxAttributesPerCall = ConstU32<2>; - type MaxDeadlineDuration = ConstU64<10000>; + type ValueLimit = ConstU32<50>; + type ApprovalsLimit = ConstU32<10>; + type ItemAttributesApprovalsLimit = ConstU32<2>; type MaxTips = ConstU32<10>; - type MetadataDepositBase = ConstU64<1>; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxAttributesPerCall = ConstU32<2>; + type Features = Features; /// Off-chain = signature On-chain - therefore no conversion needed. /// It needs to be From for benchmarking. type OffchainSignature = Signature; - type RuntimeEvent = RuntimeEvent; - type StringLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 44f2f32a..e1b598ca 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -17,6 +17,7 @@ //! Tests for Nfts pallet. +use crate::{mock::*, Event, SystemConfig, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, @@ -32,8 +33,6 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; -use crate::{mock::*, Event, SystemConfig, *}; - type AccountIdOf = ::AccountId; fn account(id: u8) -> AccountIdOf { diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index f08f1d09..1687a035 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -17,8 +17,9 @@ //! This module contains various basic types and data structures used in the NFTs pallet. +use super::*; +use crate::macros::*; use alloc::{vec, vec::Vec}; - use codec::EncodeLike; use enumflags2::{bitflags, BitFlags}; use frame_support::{ @@ -29,9 +30,6 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; -use super::*; -use crate::macros::*; - /// A type alias for handling balance deposits. pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -278,15 +276,12 @@ impl CollectionSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn get_disabled(&self) -> BitFlags { self.0 } - pub fn is_disabled(&self, setting: CollectionSetting) -> bool { self.0.contains(setting) } - pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -382,15 +377,12 @@ impl CollectionConfig bool { !self.settings.is_disabled(setting) } - pub fn has_disabled_setting(&self, setting: CollectionSetting) -> bool { self.settings.is_disabled(setting) } - pub fn enable_setting(&mut self, setting: CollectionSetting) { self.settings.0.remove(setting); } - pub fn disable_setting(&mut self, setting: CollectionSetting) { self.settings.0.insert(setting); } @@ -417,15 +409,12 @@ impl ItemSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn get_disabled(&self) -> BitFlags { self.0 } - pub fn is_disabled(&self, setting: ItemSetting) -> bool { self.0.contains(setting) } - pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -446,19 +435,15 @@ impl ItemConfig { pub fn is_setting_enabled(&self, setting: ItemSetting) -> bool { !self.settings.is_disabled(setting) } - pub fn has_disabled_setting(&self, setting: ItemSetting) -> bool { self.settings.is_disabled(setting) } - pub fn has_disabled_settings(&self) -> bool { !self.settings.get_disabled().is_empty() } - pub fn enable_setting(&mut self, setting: ItemSetting) { self.settings.0.remove(setting); } - pub fn disable_setting(&mut self, setting: ItemSetting) { self.settings.0.insert(setting); } @@ -487,11 +472,9 @@ impl PalletFeatures { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } - pub fn from_disabled(features: BitFlags) -> Self { Self(features) } - pub fn is_enabled(&self, feature: PalletFeature) -> bool { !self.0.contains(feature) } @@ -519,15 +502,12 @@ impl CollectionRoles { pub fn none() -> Self { Self(BitFlags::EMPTY) } - pub fn has_role(&self, role: CollectionRole) -> bool { self.0.contains(role) } - pub fn add_role(&mut self, role: CollectionRole) { self.0.insert(role); } - pub fn max_roles() -> u8 { let all: BitFlags = BitFlags::all(); all.len() as u8 From 707bd809d32356c56dc83d53e91d555199c15519 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:24:10 +0700 Subject: [PATCH 35/64] fix: formatting --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/common_functions.rs | 4 +- pallets/nfts/src/features/approvals.rs | 3 +- pallets/nfts/src/features/atomic_swap.rs | 4 +- pallets/nfts/src/features/attributes.rs | 3 +- pallets/nfts/src/features/buy_sell.rs | 3 +- .../src/features/create_delete_collection.rs | 3 +- .../nfts/src/features/create_delete_item.rs | 3 +- pallets/nfts/src/features/lock.rs | 4 +- pallets/nfts/src/features/metadata.rs | 4 +- pallets/nfts/src/features/roles.rs | 4 +- pallets/nfts/src/features/settings.rs | 3 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/impl_nonfungibles.rs | 9 ++-- pallets/nfts/src/lib.rs | 10 ++-- pallets/nfts/src/migration.rs | 4 +- pallets/nfts/src/mock.rs | 48 +++++++++---------- pallets/nfts/src/tests.rs | 3 +- pallets/nfts/src/types.rs | 24 +++++++++- 19 files changed, 93 insertions(+), 49 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index bc81096b..8fa87557 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -19,7 +19,6 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -32,6 +31,7 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; use sp_runtime::traits::{Bounded, One}; +use super::*; use crate::Pallet as Nfts; const SEED: u32 = 0; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 2c4778c1..f51de192 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -17,10 +17,12 @@ //! Various pieces of common functionality. -use crate::*; use alloc::vec::Vec; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 053fa671..ad5d93c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,9 +19,10 @@ //! The bitflag [`PalletFeature::Approvals`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Approves the transfer of an item to a delegate. /// diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 830283b7..31c93fba 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -20,12 +20,13 @@ //! The bitflag [`PalletFeature::Swaps`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement::KeepAlive}, }; +use crate::*; + impl, I: 'static> Pallet { /// Creates a new swap offer for the specified item. /// @@ -101,6 +102,7 @@ impl, I: 'static> Pallet { Ok(()) } + /// Cancels the specified swap offer. /// /// This function is used to cancel the specified swap offer created by the `caller` account. If diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index 28f7bd2c..ab0cdc68 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -20,9 +20,10 @@ //! The bitflag [`PalletFeature::Attributes`] needs to be set in [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Sets the attribute of an item or a collection. /// diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index d6ec6f50..8cf86f79 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -20,12 +20,13 @@ //! The bitflag [`PalletFeature::Trading`] needs to be set in the [`Config::Features`] for NFTs //! to have the functionality defined in this module. -use crate::*; use frame_support::{ pallet_prelude::*, traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, }; +use crate::*; + impl, I: 'static> Pallet { /// Pays the specified tips to the corresponding receivers. /// diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index f03df7fd..348ec6b9 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform functionality associated with creating and //! destroying collections for the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Create a new collection with the given `collection`, `owner`, `admin`, `config`, `deposit`, /// and `event`. diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 37f64ae1..e9843b2e 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform functionality associated with minting and burning //! items for the NFTs pallet. -use crate::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; +use crate::*; + impl, I: 'static> Pallet { /// Mint a new unique item with the given `collection`, `item`, and other minting configuration /// details. diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs index 1c3c9c86..4649f4a0 100644 --- a/pallets/nfts/src/features/lock.rs +++ b/pallets/nfts/src/features/lock.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to configure locks on collections and items for the NFTs //! pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Locks a collection with specified settings. /// @@ -29,7 +30,6 @@ impl, I: 'static> Pallet { /// /// Note: it's possible only to lock the setting, but not to unlock it after. - /// /// - `origin`: The origin of the transaction, representing the account attempting to lock the /// collection. /// - `collection`: The identifier of the collection to be locked. diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index 26006160..b3d16b12 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -17,10 +17,12 @@ //! This module contains helper methods to configure the metadata of collections and items. -use crate::*; use alloc::vec::Vec; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Sets the metadata for a specific item within a collection. /// diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs index aa6394f7..053eaf0b 100644 --- a/pallets/nfts/src/features/roles.rs +++ b/pallets/nfts/src/features/roles.rs @@ -17,10 +17,12 @@ //! This module contains helper methods to configure account roles for existing collections. -use crate::*; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; + use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Set the team roles for a specific collection. /// diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs index d4f7533f..9c7ac7ca 100644 --- a/pallets/nfts/src/features/settings.rs +++ b/pallets/nfts/src/features/settings.rs @@ -17,9 +17,10 @@ //! This module provides helper methods to configure collection settings for the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Forcefully change the configuration of a collection. /// diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index bba83448..b7223a7c 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,9 +18,10 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use crate::*; use frame_support::pallet_prelude::*; +use crate::*; + impl, I: 'static> Pallet { /// Transfer an NFT to the specified destination account. /// @@ -160,6 +161,7 @@ impl, I: 'static> Pallet { Ok(()) }) } + /// Set or unset the ownership acceptance for an account regarding a specific collection. /// /// - `who`: The account for which to set or unset the ownership acceptance. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index c90655aa..362cccd9 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -17,7 +17,6 @@ //! Implementations for `nonfungibles` traits. -use super::*; use frame_support::{ ensure, storage::KeyPrefixIterator, @@ -26,9 +25,11 @@ use frame_support::{ }; use sp_runtime::{DispatchError, DispatchResult}; +use super::*; + impl, I: 'static> Inspect<::AccountId> for Pallet { - type ItemId = T::ItemId; type CollectionId = T::CollectionId; + type ItemId = T::ItemId; fn owner( collection: &Self::CollectionId, @@ -140,9 +141,11 @@ impl, I: 'static> InspectRole<::AccountId> for P fn is_issuer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Issuer) } + fn is_admin(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Admin) } + fn is_freezer(collection: &Self::CollectionId, who: &::AccountId) -> bool { Self::has_role(collection, who, CollectionRole::Freezer) } @@ -469,9 +472,9 @@ impl, I: 'static> Trading> for Pallet impl, I: 'static> InspectEnumerable for Pallet { type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; type ItemsIterator = KeyPrefixIterator<>::ItemId>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; type OwnedIterator = KeyPrefixIterator<(>::CollectionId, >::ItemId)>; - type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; /// Returns an iterator of the collections in existence. /// diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 4e5493a3..89bfb963 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -51,18 +51,18 @@ pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; + use codec::{Decode, Encode}; use frame_support::traits::{ tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, }; use frame_system::Config as SystemConfig; +pub use pallet::*; use sp_runtime::{ traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; - -pub use pallet::*; pub use types::*; pub use weights::WeightInfo; @@ -74,10 +74,11 @@ type AccountIdLookupOf = <::Lookup as StaticLookup>::Sourc #[frame_support::pallet] pub mod pallet { - use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; + use super::*; + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -108,14 +109,17 @@ pub mod pallet { fn collection(i: u16) -> CollectionId { i.into() } + fn item(i: u16) -> ItemId { i.into() } + fn signer() -> (sp_runtime::MultiSigner, sp_runtime::AccountId32) { let public = sp_io::crypto::sr25519_generate(0.into(), None); let account = sp_runtime::MultiSigner::Sr25519(public).into_account(); (public.into(), account) } + fn sign(signer: &sp_runtime::MultiSigner, message: &[u8]) -> sp_runtime::MultiSignature { sp_runtime::MultiSignature::Sr25519( sp_io::crypto::sr25519_sign(0.into(), &signer.clone().try_into().unwrap(), message) diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index 8f82e092..af611bf1 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::*; use frame_support::traits::OnRuntimeUpgrade; use log; - #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +use super::*; + pub mod v1 { use frame_support::{pallet_prelude::*, weights::Weight}; diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index 5b589f59..5532be8f 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -17,9 +17,6 @@ //! Test environment for Nfts pallet. -use super::*; -use crate as pallet_nfts; - use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, @@ -30,6 +27,9 @@ use sp_runtime::{ BuildStorage, MultiSignature, }; +use super::*; +use crate as pallet_nfts; + type Block = frame_system::mocking::MockBlock; construct_runtime!( @@ -47,10 +47,10 @@ pub type AccountId = ::AccountId; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { + type AccountData = pallet_balances::AccountData; type AccountId = AccountId; - type Lookup = IdentityLookup; type Block = Block; - type AccountData = pallet_balances::AccountData; + type Lookup = IdentityLookup; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] @@ -63,35 +63,35 @@ parameter_types! { } impl Config for Test { - type RuntimeEvent = RuntimeEvent; + type ApprovalsLimit = ConstU32<10>; + type AttributeDepositBase = ConstU64<1>; + type CollectionDeposit = ConstU64<2>; type CollectionId = u32; - type ItemId = u32; - type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = ConstU64<1>; + type Features = Features; type ForceOrigin = frame_system::EnsureRoot; - type Locker = (); - type CollectionDeposit = ConstU64<2>; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<2>; type ItemDeposit = ConstU64<1>; - type MetadataDepositBase = ConstU64<1>; - type AttributeDepositBase = ConstU64<1>; - type DepositPerByte = ConstU64<1>; - type StringLimit = ConstU32<50>; + type ItemId = u32; type KeyLimit = ConstU32<50>; - type ValueLimit = ConstU32<50>; - type ApprovalsLimit = ConstU32<10>; - type ItemAttributesApprovalsLimit = ConstU32<2>; - type MaxTips = ConstU32<10>; - type MaxDeadlineDuration = ConstU64<10000>; + type Locker = (); type MaxAttributesPerCall = ConstU32<2>; - type Features = Features; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxTips = ConstU32<10>; + type MetadataDepositBase = ConstU64<1>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; /// Off-chain = signature On-chain - therefore no conversion needed. /// It needs to be From for benchmarking. type OffchainSignature = Signature; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index e1b598ca..44f2f32a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -17,7 +17,6 @@ //! Tests for Nfts pallet. -use crate::{mock::*, Event, SystemConfig, *}; use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, @@ -33,6 +32,8 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; +use crate::{mock::*, Event, SystemConfig, *}; + type AccountIdOf = ::AccountId; fn account(id: u8) -> AccountIdOf { diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 1687a035..f08f1d09 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -17,9 +17,8 @@ //! This module contains various basic types and data structures used in the NFTs pallet. -use super::*; -use crate::macros::*; use alloc::{vec, vec::Vec}; + use codec::EncodeLike; use enumflags2::{bitflags, BitFlags}; use frame_support::{ @@ -30,6 +29,9 @@ use frame_support::{ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; +use super::*; +use crate::macros::*; + /// A type alias for handling balance deposits. pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -276,12 +278,15 @@ impl CollectionSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn get_disabled(&self) -> BitFlags { self.0 } + pub fn is_disabled(&self, setting: CollectionSetting) -> bool { self.0.contains(setting) } + pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -377,12 +382,15 @@ impl CollectionConfig bool { !self.settings.is_disabled(setting) } + pub fn has_disabled_setting(&self, setting: CollectionSetting) -> bool { self.settings.is_disabled(setting) } + pub fn enable_setting(&mut self, setting: CollectionSetting) { self.settings.0.remove(setting); } + pub fn disable_setting(&mut self, setting: CollectionSetting) { self.settings.0.insert(setting); } @@ -409,12 +417,15 @@ impl ItemSettings { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn get_disabled(&self) -> BitFlags { self.0 } + pub fn is_disabled(&self, setting: ItemSetting) -> bool { self.0.contains(setting) } + pub fn from_disabled(settings: BitFlags) -> Self { Self(settings) } @@ -435,15 +446,19 @@ impl ItemConfig { pub fn is_setting_enabled(&self, setting: ItemSetting) -> bool { !self.settings.is_disabled(setting) } + pub fn has_disabled_setting(&self, setting: ItemSetting) -> bool { self.settings.is_disabled(setting) } + pub fn has_disabled_settings(&self) -> bool { !self.settings.get_disabled().is_empty() } + pub fn enable_setting(&mut self, setting: ItemSetting) { self.settings.0.remove(setting); } + pub fn disable_setting(&mut self, setting: ItemSetting) { self.settings.0.insert(setting); } @@ -472,9 +487,11 @@ impl PalletFeatures { pub fn all_enabled() -> Self { Self(BitFlags::EMPTY) } + pub fn from_disabled(features: BitFlags) -> Self { Self(features) } + pub fn is_enabled(&self, feature: PalletFeature) -> bool { !self.0.contains(feature) } @@ -502,12 +519,15 @@ impl CollectionRoles { pub fn none() -> Self { Self(BitFlags::EMPTY) } + pub fn has_role(&self, role: CollectionRole) -> bool { self.0.contains(role) } + pub fn add_role(&mut self, role: CollectionRole) { self.0.insert(role); } + pub fn max_roles() -> u8 { let all: BitFlags = BitFlags::all(); all.len() as u8 From 7f5cec544415f9e42a9f9e77adbc49fff62c799f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:47:40 +0700 Subject: [PATCH 36/64] feat: add nonfungibles implementation --- Cargo.lock | 1 + pallets/api/Cargo.toml | 3 + pallets/api/src/fungibles/tests.rs | 286 ++++++++++++++++---------- pallets/api/src/lib.rs | 1 + pallets/api/src/mock.rs | 74 ++++++- pallets/api/src/nonfungibles/mod.rs | 260 +++++++++++++++++++++++ pallets/api/src/nonfungibles/tests.rs | 183 ++++++++++++++++ pallets/api/src/nonfungibles/types.rs | 61 ++++++ 8 files changed, 750 insertions(+), 119 deletions(-) create mode 100644 pallets/api/src/nonfungibles/mod.rs create mode 100644 pallets/api/src/nonfungibles/tests.rs create mode 100644 pallets/api/src/nonfungibles/types.rs diff --git a/Cargo.lock b/Cargo.lock index d2bf2ace..6f98f910 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,6 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", + "pallet-nfts", "parity-scale-codec", "pop-chain-extension", "scale-info", diff --git a/pallets/api/Cargo.toml b/pallets/api/Cargo.toml index 55a00789..5d398724 100644 --- a/pallets/api/Cargo.toml +++ b/pallets/api/Cargo.toml @@ -22,6 +22,7 @@ frame-benchmarking.workspace = true frame-support.workspace = true frame-system.workspace = true pallet-assets.workspace = true +pallet-nfts.workspace = true sp-runtime.workspace = true sp-std.workspace = true @@ -37,6 +38,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-assets/runtime-benchmarks", + "pallet-nfts/runtime-benchmarks", "pop-chain-extension/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -47,6 +49,7 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-balances/std", + "pallet-nfts/std", "pop-chain-extension/std", "scale-info/std", "sp-core/std", diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index f5c560bb..6e181a6f 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -83,17 +83,21 @@ fn transfer_works() { let to = BOB; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer(origin, token, to, value), BadOrigin); + assert_noop!(Fungibles::transfer(origin, token, account(to), value), BadOrigin); } // Check error works for `Assets::transfer_keep_alive()`. - assert_noop!(Fungibles::transfer(signed(from), token, to, value), AssetsError::Unknown); + assert_noop!( + Fungibles::transfer(signed(from), token, account(to), value), + AssetsError::Unknown + ); assets::create_and_mint_to(from, token, from, value * 2); - let balance_before_transfer = Assets::balance(token, &to); - assert_ok!(Fungibles::transfer(signed(from), token, to, value)); - let balance_after_transfer = Assets::balance(token, &to); + let balance_before_transfer = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::transfer(signed(from), token, account(to), value)); + let balance_after_transfer = Assets::balance(token, &account(to)); assert_eq!(balance_after_transfer, balance_before_transfer + value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), + Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } + .into(), ); }); } @@ -108,26 +112,36 @@ fn transfer_from_works() { let spender = CHARLIE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer_from(origin, token, from, to, value), BadOrigin); + assert_noop!( + Fungibles::transfer_from(origin, token, account(from), account(to), value), + BadOrigin + ); } // Check error works for `Assets::transfer_approved()`. assert_noop!( - Fungibles::transfer_from(signed(spender), token, from, to, value), + Fungibles::transfer_from(signed(spender), token, account(from), account(to), value), AssetsError::Unknown ); // Approve `spender` to transfer up to `value`. assets::create_mint_and_approve(spender, token, from, value * 2, spender, value); // Successfully call transfer from. - let from_balance_before_transfer = Assets::balance(token, &from); - let to_balance_before_transfer = Assets::balance(token, &to); - assert_ok!(Fungibles::transfer_from(signed(spender), token, from, to, value)); - let from_balance_after_transfer = Assets::balance(token, &from); - let to_balance_after_transfer = Assets::balance(token, &to); + let from_balance_before_transfer = Assets::balance(token, &account(from)); + let to_balance_before_transfer = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::transfer_from( + signed(spender), + token, + account(from), + account(to), + value + )); + let from_balance_after_transfer = Assets::balance(token, &account(from)); + let to_balance_after_transfer = Assets::balance(token, &account(to)); // Check that `to` has received the `value` tokens from `from`. assert_eq!(to_balance_after_transfer, to_balance_before_transfer + value); assert_eq!(from_balance_after_transfer, from_balance_before_transfer - value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), + Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } + .into(), ); }); } @@ -144,7 +158,7 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, spender, value), + Fungibles::approve(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } @@ -161,20 +175,20 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, spender, value), + Fungibles::approve(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()` in `Greater` match arm. assert_noop!( - Fungibles::approve(signed(owner), token, spender, value), + Fungibles::approve(signed(owner), token, account(spender), value), AssetsError::Unknown.with_weight(WeightInfo::approve(1, 0)) ); assets::create_mint_and_approve(owner, token, owner, value, spender, value); // Check error works for `Assets::cancel_approval()` in `Less` match arm. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); @@ -193,38 +207,61 @@ mod approve { // Approves a value to spend that is higher than the current allowance. assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(Assets::allowance(token, &owner, &spender), 0); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); assert_eq!( - Fungibles::approve(signed(owner), token, spender, value), + Fungibles::approve(signed(owner), token, account(spender), value), Ok(Some(WeightInfo::approve(1, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value); - System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + System::assert_last_event( + Event::Approval { token, owner: account(owner), spender: account(spender), value } + .into(), + ); // Approves a value to spend that is lower than the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); // Approves a value to spend that is equal to the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, spender, value / 2), + Fungibles::approve(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); // Sets allowance to zero. assert_eq!( - Fungibles::approve(signed(owner), token, spender, 0), + Fungibles::approve(signed(owner), token, account(spender), 0), Ok(Some(WeightInfo::approve(0, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), 0); - System::assert_last_event(Event::Approval { token, owner, spender, value: 0 }.into()); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); + System::assert_last_event( + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: 0, + } + .into(), + ); }); } } @@ -239,25 +276,34 @@ fn increase_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::increase_allowance(origin, token, spender, value), + Fungibles::increase_allowance(origin, token, account(spender), value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()`. assert_noop!( - Fungibles::increase_allowance(signed(owner), token, spender, value), + Fungibles::increase_allowance(signed(owner), token, account(spender), value), AssetsError::Unknown.with_weight(AssetsWeightInfo::approve_transfer()) ); assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(0, Assets::allowance(token, &owner, &spender)); - assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); - assert_eq!(Assets::allowance(token, &owner, &spender), value); - System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); + assert_eq!(0, Assets::allowance(token, &account(owner), &account(spender))); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + System::assert_last_event( + Event::Approval { token, owner: account(owner), spender: account(spender), value } + .into(), + ); // Additive. - assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); - assert_eq!(Assets::allowance(token, &owner, &spender), value * 2); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value * 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value * 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value * 2, + } + .into(), ); }); } @@ -272,40 +318,46 @@ fn decrease_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::decrease_allowance(origin, token, spender, 0), + Fungibles::decrease_allowance(origin, token, account(spender), 0), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } assets::create_mint_and_approve(owner, token, owner, value, spender, value); - assert_eq!(Assets::allowance(token, &owner, &spender), value); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); // Check error works for `Assets::cancel_approval()`. No error test for `approve_transfer` // because it is not possible. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // Owner balance is not changed if decreased by zero. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, spender, 0), + Fungibles::decrease_allowance(signed(owner), token, account(spender), 0), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); // "Unapproved" error is returned if the current allowance is less than amount to decrease // with. assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, spender, value * 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value * 2), AssetsError::Unapproved ); // Decrease allowance successfully. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), + Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); + assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); System::assert_last_event( - Event::Approval { token, owner, spender, value: value / 2 }.into(), + Event::Approval { + token, + owner: account(owner), + spender: account(spender), + value: value / 2, + } + .into(), ); }); } @@ -318,14 +370,19 @@ fn create_works() { let admin = ALICE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::create(origin, id, admin, 100), BadOrigin); + assert_noop!(Fungibles::create(origin, id, account(admin), 100), BadOrigin); } assert!(!Assets::asset_exists(id)); - assert_ok!(Fungibles::create(signed(creator), id, admin, 100)); + assert_ok!(Fungibles::create(signed(creator), id, account(admin), 100)); assert!(Assets::asset_exists(id)); - System::assert_last_event(Event::Created { id, creator, admin }.into()); + System::assert_last_event( + Event::Created { id, creator: account(creator), admin: account(admin) }.into(), + ); // Check error works for `Assets::create()`. - assert_noop!(Fungibles::create(signed(creator), id, admin, 100), AssetsError::InUse); + assert_noop!( + Fungibles::create(signed(creator), id, account(admin), 100), + AssetsError::InUse + ); }); } @@ -336,11 +393,11 @@ fn start_destroy_works() { // Check error works for `Assets::start_destroy()`. assert_noop!(Fungibles::start_destroy(signed(ALICE), token), AssetsError::Unknown); - assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); assert_ok!(Fungibles::start_destroy(signed(ALICE), token)); // Check that the token is not live after starting the destroy process. assert_noop!( - Assets::mint(signed(ALICE), token, ALICE, 10 * UNIT), + Assets::mint(signed(ALICE), token, account(ALICE), 10 * UNIT), AssetsError::AssetNotLive ); }); @@ -359,7 +416,7 @@ fn set_metadata_works() { Fungibles::set_metadata(signed(ALICE), token, name.clone(), symbol.clone(), decimals), AssetsError::Unknown ); - assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); assert_ok!(Fungibles::set_metadata( signed(ALICE), token, @@ -398,16 +455,16 @@ fn mint_works() { // Check error works for `Assets::mint()`. assert_noop!( - Fungibles::mint(signed(from), token, to, value), + Fungibles::mint(signed(from), token, account(to), value), sp_runtime::TokenError::UnknownAsset ); - assert_ok!(Assets::create(signed(from), token, from, 1)); - let balance_before_mint = Assets::balance(token, &to); - assert_ok!(Fungibles::mint(signed(from), token, to, value)); - let balance_after_mint = Assets::balance(token, &to); + assert_ok!(Assets::create(signed(from), token, account(from), 1)); + let balance_before_mint = Assets::balance(token, &account(to)); + assert_ok!(Fungibles::mint(signed(from), token, account(to), value)); + let balance_after_mint = Assets::balance(token, &account(to)); assert_eq!(balance_after_mint, balance_before_mint + value); System::assert_last_event( - Event::Transfer { token, from: None, to: Some(to), value }.into(), + Event::Transfer { token, from: None, to: Some(account(to)), value }.into(), ); }); } @@ -423,27 +480,30 @@ fn burn_works() { // "BalanceLow" error is returned if token is not created. assert_noop!( - Fungibles::burn(signed(owner), token, from, value), + Fungibles::burn(signed(owner), token, account(from), value), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); assets::create_and_mint_to(owner, token, from, total_supply); assert_eq!(Assets::total_supply(TOKEN), total_supply); // Check error works for `Assets::burn()`. assert_ok!(Assets::freeze_asset(signed(owner), token)); - assert_noop!(Fungibles::burn(signed(owner), token, from, value), AssetsError::AssetNotLive); + assert_noop!( + Fungibles::burn(signed(owner), token, account(from), value), + AssetsError::AssetNotLive + ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // "BalanceLow" error is returned if the balance is less than amount to burn. assert_noop!( - Fungibles::burn(signed(owner), token, from, total_supply * 2), + Fungibles::burn(signed(owner), token, account(from), total_supply * 2), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); - let balance_before_burn = Assets::balance(token, &from); - assert_ok!(Fungibles::burn(signed(owner), token, from, value)); + let balance_before_burn = Assets::balance(token, &account(from)); + assert_ok!(Fungibles::burn(signed(owner), token, account(from), value)); assert_eq!(Assets::total_supply(TOKEN), total_supply - value); - let balance_after_burn = Assets::balance(token, &from); + let balance_after_burn = Assets::balance(token, &account(from)); assert_eq!(balance_after_burn, balance_before_burn - value); System::assert_last_event( - Event::Transfer { token, from: Some(from), to: None, value }.into(), + Event::Transfer { token, from: Some(account(from)), to: None, value }.into(), ); }); } @@ -470,17 +530,17 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), ReadResult::BalanceOf(Default::default()) ); assets::create_and_mint_to(ALICE, TOKEN, ALICE, value); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), ReadResult::BalanceOf(value) ); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }).encode(), - Assets::balance(TOKEN, ALICE).encode(), + Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }).encode(), + Assets::balance(TOKEN, account(ALICE)).encode(), ); }); } @@ -490,17 +550,30 @@ fn allowance_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }), ReadResult::Allowance(Default::default()) ); assets::create_mint_and_approve(ALICE, TOKEN, ALICE, value * 2, BOB, value); assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }), ReadResult::Allowance(value) ); assert_eq!( - Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }).encode(), - Assets::allowance(TOKEN, &ALICE, &BOB).encode(), + Fungibles::read(Allowance { + token: TOKEN, + owner: account(ALICE), + spender: account(BOB) + }) + .encode(), + Assets::allowance(TOKEN, &account(ALICE), &account(BOB)).encode(), ); }); } @@ -534,7 +607,7 @@ fn token_metadata_works() { fn token_exists_works() { new_test_ext().execute_with(|| { assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(false)); - assert_ok!(Assets::create(signed(ALICE), TOKEN, ALICE, 1)); + assert_ok!(Assets::create(signed(ALICE), TOKEN, account(ALICE), 1)); assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(true)); assert_eq!( Fungibles::read(TokenExists(TOKEN)).encode(), @@ -543,8 +616,8 @@ fn token_exists_works() { }); } -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) +fn signed(account_id: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(account(account_id)) } fn root() -> RuntimeOrigin { @@ -559,36 +632,31 @@ fn none() -> RuntimeOrigin { mod assets { use super::*; - pub(super) fn create_and_mint_to( - owner: AccountId, - token: TokenId, - to: AccountId, - value: Balance, - ) { - assert_ok!(Assets::create(signed(owner), token, owner, 1)); - assert_ok!(Assets::mint(signed(owner), token, to, value)); + pub(super) fn create_and_mint_to(owner: u8, token: TokenId, to: u8, value: Balance) { + assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); + assert_ok!(Assets::mint(signed(owner), token, account(to), value)); } pub(super) fn create_mint_and_approve( - owner: AccountId, + owner: u8, token: TokenId, - to: AccountId, + to: u8, mint: Balance, - spender: AccountId, + spender: u8, approve: Balance, ) { create_and_mint_to(owner, token, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), token, spender, approve,)); + assert_ok!(Assets::approve_transfer(signed(to), token, account(spender), approve,)); } pub(super) fn create_and_set_metadata( - owner: AccountId, + owner: u8, token: TokenId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), token, owner, 1)); + assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); assert_ok!(Assets::set_metadata(signed(owner), token, name, symbol, decimals)); } } @@ -613,11 +681,11 @@ mod read_weights { fn new() -> Self { Self { total_supply: Fungibles::weight(&TotalSupply(TOKEN)), - balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: ALICE }), + balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: account(ALICE) }), allowance: Fungibles::weight(&Allowance { token: TOKEN, - owner: ALICE, - spender: BOB, + owner: account(ALICE), + spender: account(BOB), }), token_name: Fungibles::weight(&TokenName(TOKEN)), token_symbol: Fungibles::weight(&TokenSymbol(TOKEN)), @@ -699,15 +767,15 @@ mod ensure_codec_indexes { [ (TotalSupply::(Default::default()), 0u8, "TotalSupply"), ( - BalanceOf:: { token: Default::default(), owner: Default::default() }, + BalanceOf:: { token: Default::default(), owner: account(Default::default()) }, 1, "BalanceOf", ), ( Allowance:: { token: Default::default(), - owner: Default::default(), - spender: Default::default(), + owner: account(Default::default()), + spender: account(Default::default()), }, 2, "Allowance", @@ -731,7 +799,7 @@ mod ensure_codec_indexes { ( transfer { token: Default::default(), - to: Default::default(), + to: account(Default::default()), value: Default::default(), }, 3u8, @@ -740,8 +808,8 @@ mod ensure_codec_indexes { ( transfer_from { token: Default::default(), - from: Default::default(), - to: Default::default(), + from: account(Default::default()), + to: account(Default::default()), value: Default::default(), }, 4, @@ -750,7 +818,7 @@ mod ensure_codec_indexes { ( approve { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 5, @@ -759,7 +827,7 @@ mod ensure_codec_indexes { ( increase_allowance { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 6, @@ -768,7 +836,7 @@ mod ensure_codec_indexes { ( decrease_allowance { token: Default::default(), - spender: Default::default(), + spender: account(Default::default()), value: Default::default(), }, 7, @@ -777,7 +845,7 @@ mod ensure_codec_indexes { ( create { id: Default::default(), - admin: Default::default(), + admin: account(Default::default()), min_balance: Default::default(), }, 11, @@ -798,7 +866,7 @@ mod ensure_codec_indexes { ( mint { token: Default::default(), - account: Default::default(), + account: account(Default::default()), value: Default::default(), }, 19, @@ -807,7 +875,7 @@ mod ensure_codec_indexes { ( burn { token: Default::default(), - account: Default::default(), + account: account(Default::default()), value: Default::default(), }, 20, diff --git a/pallets/api/src/lib.rs b/pallets/api/src/lib.rs index d94d1978..e3d706e2 100644 --- a/pallets/api/src/lib.rs +++ b/pallets/api/src/lib.rs @@ -7,6 +7,7 @@ pub mod extension; pub mod fungibles; #[cfg(test)] mod mock; +pub mod nonfungibles; /// Trait for performing reads of runtime state. pub trait Read { diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 42c8bf0e..920d590f 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -1,25 +1,28 @@ use frame_support::{ derive_impl, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; +use pallet_nfts::PalletFeatures; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, MultiSignature, }; -pub(crate) const ALICE: AccountId = 1; -pub(crate) const BOB: AccountId = 2; -pub(crate) const CHARLIE: AccountId = 3; +pub(crate) const ALICE: u8 = 1; +pub(crate) const BOB: u8 = 2; +pub(crate) const CHARLIE: u8 = 3; pub(crate) const INIT_AMOUNT: Balance = 100_000_000 * UNIT; pub(crate) const UNIT: Balance = 10_000_000_000; type Block = frame_system::mocking::MockBlock; -pub(crate) type AccountId = u64; +pub(crate) type AccountId = ::AccountId; pub(crate) type Balance = u128; // For terminology in tests. pub(crate) type TokenId = u32; +type Signature = MultiSignature; +type AccountPublic = ::Signer; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -29,6 +32,8 @@ frame_support::construct_runtime!( Assets: pallet_assets::, Balances: pallet_balances, Fungibles: crate::fungibles, + Nfts: pallet_nfts, + NonFungibles: crate::nonfungibles } ); @@ -91,10 +96,10 @@ impl pallet_assets::Config for Test { #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); type CallbackHandle = (); - type CreateOrigin = AsEnsureOriginWithArg>; + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type Extra = (); - type ForceOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; @@ -110,13 +115,62 @@ impl crate::fungibles::Config for Test { type WeightInfo = (); } +parameter_types! { + pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); +} + +impl pallet_nfts::Config for Test { + type ApprovalsLimit = ConstU32<10>; + type AttributeDepositBase = ConstU128<1>; + type CollectionDeposit = ConstU128<2>; + type CollectionId = u32; + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = ConstU128<1>; + type Features = Features; + type ForceOrigin = frame_system::EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<2>; + type ItemDeposit = ConstU128<1>; + type ItemId = u32; + type KeyLimit = ConstU32<50>; + type Locker = (); + type MaxAttributesPerCall = ConstU32<2>; + type MaxDeadlineDuration = ConstU64<10000>; + type MaxTips = ConstU32<10>; + type MetadataDepositBase = ConstU128<1>; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; + /// Off-chain = signature On-chain - therefore no conversion needed. + /// It needs to be From for benchmarking. + type OffchainSignature = Signature; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; + type WeightInfo = (); +} + +impl crate::nonfungibles::Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +/// Initialize a new account ID. +pub(crate) fn account(id: u8) -> AccountId { + [id; 32].into() +} + pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default() .build_storage() .expect("Frame system builds valid default genesis config"); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, INIT_AMOUNT), (BOB, INIT_AMOUNT), (CHARLIE, INIT_AMOUNT)], + balances: vec![ + (account(ALICE), INIT_AMOUNT), + (account(BOB), INIT_AMOUNT), + (account(CHARLIE), INIT_AMOUNT), + ], } .assimilate_storage(&mut t) .expect("Pallet balances storage can be assimilated"); diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs new file mode 100644 index 00000000..cac0cbba --- /dev/null +++ b/pallets/api/src/nonfungibles/mod.rs @@ -0,0 +1,260 @@ +//! The non-fungibles pallet offers a streamlined interface for interacting with non-fungible +//! assets. The goal is to provide a simplified, consistent API that adheres to standards in the +//! smart contract space. + +use frame_support::traits::nonfungibles_v2::InspectEnumerable; +pub use pallet::*; +use pallet_nfts::WeightInfo; +use sp_runtime::traits::StaticLookup; + +#[cfg(test)] +mod tests; +mod types; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use sp_std::vec::Vec; + use types::{AccountIdOf, CollectionIdOf, ItemDetails, ItemIdOf, NftsOf, NftsWeightInfoOf}; + + use super::*; + + /// State reads for the fungibles API with required input. + #[derive(Encode, Decode, Debug, MaxEncodedLen)] + #[repr(u8)] + #[allow(clippy::unnecessary_cast)] + pub enum Read { + /// Returns the owner of an item. + #[codec(index = 0)] + OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, + /// Returns the owner of a collection. + #[codec(index = 1)] + CollectionOwner(CollectionIdOf), + /// Number of items existing in a concrete collection. + #[codec(index = 2)] + TotalSupply(CollectionIdOf), + /// Returns the total number of items in the collection owned by the account. + #[codec(index = 3)] + BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, + /// Returns the details of a collection. + #[codec(index = 4)] + Collection(CollectionIdOf), + /// Returns the details of an item. + #[codec(index = 5)] + Item { collection: CollectionIdOf, item: ItemIdOf }, + /// Whether a spender is allowed to transfer an item or items from owner. + #[codec(index = 6)] + Allowance { spender: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf }, + } + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config + pallet_nfts::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// The events that can be emitted. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Event emitted when allowance by `owner` to `spender` canceled. + CancelApproval { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The beneficiary of the allowance. + spender: AccountIdOf, + }, + /// Event emitted when allowance by `owner` to `spender` changes. + Approval { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The owner providing the allowance. + owner: AccountIdOf, + /// The beneficiary of the allowance. + spender: AccountIdOf, + }, + /// Event emitted when new item is minted to the account. + Mint { + /// The owner of the item. + to: AccountIdOf, + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + }, + /// Event emitted when item is burned. + Burn { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + }, + /// Event emitted when an item transfer occurs. + Transfer { + /// The collection ID. + collection: CollectionIdOf, + /// the item ID. + item: ItemIdOf, + /// The source of the transfer. + from: AccountIdOf, + /// The recipient of the transfer. + to: AccountIdOf, + }, + } + + #[pallet::call] + impl Pallet { + /// Create a new non-fungible token to the collection. + /// + /// # Parameters + /// - `to` - The owner of the collection item. + /// - `collection` - The collection ID. + /// - `item` - The item ID. + #[pallet::call_index(0)] + #[pallet::weight(NftsWeightInfoOf::::mint())] + pub fn mint( + origin: OriginFor, + to: AccountIdOf, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::mint(origin, collection, item, T::Lookup::unlookup(to.clone()), None)?; + Self::deposit_event(Event::Mint { to, collection, item }); + Ok(()) + } + + /// Destroy a new non-fungible token to the collection. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + #[pallet::call_index(1)] + #[pallet::weight(NftsWeightInfoOf::::burn())] + pub fn burn( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::burn(origin, collection, item)?; + Self::deposit_event(Event::Burn { collection, item }); + Ok(()) + } + + /// Transfer a token from one account to the another account. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `to` - The recipient account. + #[pallet::call_index(2)] + #[pallet::weight(NftsWeightInfoOf::::transfer())] + pub fn transfer( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + to: AccountIdOf, + ) -> DispatchResult { + let from = ensure_signed(origin.clone())?; + NftsOf::::transfer(origin, collection, item, T::Lookup::unlookup(to.clone()))?; + Self::deposit_event(Event::Transfer { from, to, collection, item }); + Ok(()) + } + + /// Delegate a permission to perform actions on the collection item to an account. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `spender` - The account that is allowed to transfer the collection item. + #[pallet::call_index(3)] + #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] + pub fn approve( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> DispatchResult { + let owner = ensure_signed(origin.clone())?; + NftsOf::::approve_transfer( + origin, + collection, + item, + T::Lookup::unlookup(spender.clone()), + None, + )?; + Self::deposit_event(Event::Approval { collection, item, spender, owner }); + Ok(()) + } + + /// Cancel one of the transfer approvals for a specific item. + /// + /// # Parameters + /// - `collection` - The collection ID. + /// - `item` - The item ID. + /// - `spender` - The account that is revoked permission to transfer the collection item. + #[pallet::call_index(4)] + #[pallet::weight(NftsWeightInfoOf::::cancel_approval())] + pub fn cancel_approval( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> DispatchResult { + NftsOf::::cancel_approval( + origin, + collection, + item, + T::Lookup::unlookup(spender.clone()), + )?; + Self::deposit_event(Event::CancelApproval { collection, item, spender }); + Ok(()) + } + } + + impl Pallet { + /// Reads fungible asset state based on the provided value. + /// + /// This function matches the value to determine the type of state query and returns the + /// encoded result. + /// + /// # Parameter + /// - `value` - An instance of `Read`, which specifies the type of state query and the + /// associated parameters. + pub fn read_state(value: Read) -> Vec { + use Read::*; + match value { + OwnerOf { collection, item } => NftsOf::::owner(collection, item).encode(), + CollectionOwner(collection) => NftsOf::::collection_owner(collection).encode(), + TotalSupply(collection) => (NftsOf::::items(&collection).count() as u8).encode(), + Collection(collection) => pallet_nfts::Collection::::get(&collection).encode(), + Item { collection, item } => pallet_nfts::Item::::get(collection, item).encode(), + Allowance { collection, item, spender } => + Self::allowance(collection, item, spender).encode(), + BalanceOf { collection, owner } => + (NftsOf::::owned_in_collection(&collection, &owner).count() as u8).encode(), + } + } + + /// Check if the `spender` is approved to transfer the collection item + pub(super) fn allowance( + collection: CollectionIdOf, + item: ItemIdOf, + spender: AccountIdOf, + ) -> bool { + let data = pallet_nfts::Item::::get(collection, item).encode(); + if let Ok(detail) = ItemDetails::::decode(&mut data.as_slice()) { + return detail.approvals.contains_key(&spender); + } + false + } + } +} diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs new file mode 100644 index 00000000..9e9da5c2 --- /dev/null +++ b/pallets/api/src/nonfungibles/tests.rs @@ -0,0 +1,183 @@ +use codec::Encode; +use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; + +use super::types::*; +use crate::{ + mock::*, + nonfungibles::{Event, Read::*}, +}; + +const ITEM: u32 = 1; + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let collection = create_collection(owner.clone()); + // Successfully mint a new collection item. + assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); + System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + System::assert_last_event(Event::Burn { collection, item }.into()); + }); +} + +#[test] +fn transfer() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let dest = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + System::assert_last_event( + Event::Transfer { collection, item, from: owner, to: dest }.into(), + ); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully approve `spender` to transfer the collection item. + assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); + System::assert_last_event( + Event::Approval { collection, item, owner, spender: spender.clone() }.into(), + ); + // Successfully transfer the item by the delegated account `spender`. + assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); + }); +} + +#[test] +fn cancel_approval_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + // Successfully cancel the transfer approval of `spender` by `owner`. + assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); + // Failed to transfer the item by `spender` without permission. + assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + }); +} + +#[test] +fn owner_of_works() {} + +#[test] +fn collection_owner_works() { + new_test_ext().execute_with(|| { + let collection = create_collection(account(ALICE)); + assert_eq!( + NonFungibles::read_state(CollectionOwner(collection)), + Nfts::collection_owner(collection).encode() + ); + }); +} + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read_state(TotalSupply(collection)), + (Nfts::items(&collection).count() as u8).encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read_state(Collection(collection)), + pallet_nfts::Collection::::get(&collection).encode(), + ); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, _) = create_collection_mint(owner.clone(), ITEM); + assert_eq!( + NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), + (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() + ); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + assert_eq!( + NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), + super::Pallet::::allowance(collection, item, spender).encode() + ); + }); +} + +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) +} + +fn create_collection_mint_and_approve( + owner: AccountIdOf, + item: ItemIdOf, + spender: AccountIdOf, +) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner.clone(), item); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); + (collection, item) +} + +fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner.clone()); + assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); + (collection, item) +} + +fn create_collection(owner: AccountIdOf) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner.clone()), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + next_id +} + +fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() +} + +fn collection_config_with_all_settings_enabled( +) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs new file mode 100644 index 00000000..0174ef77 --- /dev/null +++ b/pallets/api/src/nonfungibles/types.rs @@ -0,0 +1,61 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; +use frame_system::pallet_prelude::BlockNumberFor; +use scale_info::TypeInfo; +use sp_runtime::BoundedBTreeMap; + +use super::Config; + +pub(super) type AccountIdOf = ::AccountId; + +pub(super) type NftsOf = pallet_nfts::Pallet; + +/// Weight information for extrinsics in this pallet. +pub(super) type NftsWeightInfoOf = ::WeightInfo; + +/// A type alias for the collection ID. +pub(super) type CollectionIdOf = + as Inspect<::AccountId>>::CollectionId; + +/// A type alias for the collection item ID. +pub(super) type ItemIdOf = + as Inspect<::AccountId>>::ItemId; + +// TODO: Even though this serves the `allowance` method, it creates the maintenance cost. + +/// A type that holds the deposit for a single item. +pub(super) type ItemDepositOf = + ItemDeposit, ::AccountId>; + +/// A type alias for handling balance deposits. +pub(super) type DepositBalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +/// A type alias for keeping track of approvals used by a single item. +pub(super) type ApprovalsOf = BoundedBTreeMap< + AccountIdOf, + Option>, + ::ApprovalsLimit, +>; + +/// Information concerning the ownership of a single unique item. +#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub(super) struct ItemDetails { + /// The owner of this item. + pub(super) owner: AccountIdOf, + /// The approved transferrer of this item, if one is set. + pub(super) approvals: ApprovalsOf, + /// The amount held in the pallet's default account for this item. Free-hold items will have + /// this as zero. + pub(super) deposit: ItemDepositOf, +} + +/// Information about the reserved item deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub struct ItemDeposit { + /// A depositor account. + pub(super) account: AccountId, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} From cd84ed81053765a8894cf34be28da52eb07292e8 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:12:39 +0700 Subject: [PATCH 37/64] chore: add nfts pallet --- Cargo.lock | 2 +- pallets/api/src/nonfungibles/mod.rs | 171 +++++++++--- pallets/api/src/nonfungibles/tests.rs | 367 +++++++++++++------------- pallets/api/src/nonfungibles/types.rs | 57 ++-- 4 files changed, 357 insertions(+), 240 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f98f910..ed534195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index cac0cbba..c5e8cffb 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -2,10 +2,9 @@ //! assets. The goal is to provide a simplified, consistent API that adheres to standards in the //! smart contract space. -use frame_support::traits::nonfungibles_v2::InspectEnumerable; pub use pallet::*; use pallet_nfts::WeightInfo; -use sp_runtime::traits::StaticLookup; +use sp_runtime::{traits::StaticLookup, RuntimeDebug}; #[cfg(test)] mod tests; @@ -16,12 +15,16 @@ pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_std::vec::Vec; - use types::{AccountIdOf, CollectionIdOf, ItemDetails, ItemIdOf, NftsOf, NftsWeightInfoOf}; + use types::{ + AccountIdOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, + NftsOf, NftsWeightInfoOf, + }; use super::*; - /// State reads for the fungibles API with required input. + /// State reads for the non-fungibles API with required input. #[derive(Encode, Decode, Debug, MaxEncodedLen)] + #[cfg_attr(feature = "std", derive(PartialEq, Clone))] #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { @@ -45,7 +48,41 @@ pub mod pallet { Item { collection: CollectionIdOf, item: ItemIdOf }, /// Whether a spender is allowed to transfer an item or items from owner. #[codec(index = 6)] - Allowance { spender: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf }, + Allowance { + collection: CollectionIdOf, + owner: AccountIdOf, + operator: AccountIdOf, + item: Option>, + }, + } + + /// Results of state reads for the non-fungibles API. + #[derive(Debug)] + #[cfg_attr(feature = "std", derive(PartialEq, Clone))] + pub enum ReadResult { + OwnerOf(Option>), + CollectionOwner(Option>), + TotalSupply(u32), + BalanceOf(BalanceOf), + Collection(Option>), + Item(Option>), + Allowance(bool), + } + + impl ReadResult { + /// Encodes the result. + pub fn encode(&self) -> Vec { + use ReadResult::*; + match self { + OwnerOf(result) => result.encode(), + CollectionOwner(result) => result.encode(), + TotalSupply(result) => result.encode(), + BalanceOf(result) => result.encode(), + Collection(result) => result.encode(), + Item(result) => result.encode(), + Allowance(result) => result.encode(), + } + } } /// Configure the pallet by specifying the parameters and types on which it depends. @@ -55,6 +92,32 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } + #[pallet::storage] + type AccountBalance = StorageNMap< + Key = ( + // Collection ID + NMapKey>, + // Collection Owner ID + NMapKey>, + ), + Value = BalanceOf, + QueryKind = ValueQuery, + >; + + #[pallet::storage] + type Allowances = StorageNMap< + Key = ( + // Collection ID + NMapKey>, + // Collection Owner ID + NMapKey>, + // Collection Operator ID + NMapKey>, + ), + Value = bool, + QueryKind = ValueQuery, + >; + #[pallet::pallet] pub struct Pallet(_); @@ -221,40 +284,86 @@ pub mod pallet { } impl Pallet { - /// Reads fungible asset state based on the provided value. - /// - /// This function matches the value to determine the type of state query and returns the - /// encoded result. - /// - /// # Parameter - /// - `value` - An instance of `Read`, which specifies the type of state query and the - /// associated parameters. - pub fn read_state(value: Read) -> Vec { - use Read::*; - match value { - OwnerOf { collection, item } => NftsOf::::owner(collection, item).encode(), - CollectionOwner(collection) => NftsOf::::collection_owner(collection).encode(), - TotalSupply(collection) => (NftsOf::::items(&collection).count() as u8).encode(), - Collection(collection) => pallet_nfts::Collection::::get(&collection).encode(), - Item { collection, item } => pallet_nfts::Item::::get(collection, item).encode(), - Allowance { collection, item, spender } => - Self::allowance(collection, item, spender).encode(), - BalanceOf { collection, owner } => - (NftsOf::::owned_in_collection(&collection, &owner).count() as u8).encode(), - } + /// Check if the `spender` is approved to transfer the collection item. + pub(super) fn allowance( + collection: CollectionIdOf, + owner: AccountIdOf, + operator: AccountIdOf, + maybe_item: Option>, + ) -> bool { + // Check if has a permission to transfer all collection items. + Allowances::::get((collection, owner, operator.clone())) || + maybe_item + .and_then(|item| Some(Self::allowance_item(collection, operator, item))) + .unwrap_or(false) } - /// Check if the `spender` is approved to transfer the collection item - pub(super) fn allowance( + // Check the permission for the single item. + pub(super) fn allowance_item( collection: CollectionIdOf, + operator: AccountIdOf, item: ItemIdOf, - spender: AccountIdOf, ) -> bool { let data = pallet_nfts::Item::::get(collection, item).encode(); - if let Ok(detail) = ItemDetails::::decode(&mut data.as_slice()) { - return detail.approvals.contains_key(&spender); + if let Ok(detail) = ItemDetailsFor::::decode(&mut data.as_slice()) { + return detail.approvals.contains_key(&operator); } false } } + + impl crate::Read for Pallet { + /// The type of read requested. + type Read = Read; + /// The type or result returned. + type Result = ReadResult; + + /// Determines the weight of the requested read, used to charge the appropriate weight + /// before the read is performed. + /// + /// # Parameters + /// - `request` - The read request. + fn weight(_request: &Self::Read) -> Weight { + Default::default() + } + + /// Performs the requested read and returns the result. + /// + /// # Parameters + /// - `request` - The read request. + fn read(value: Self::Read) -> Self::Result { + use Read::*; + match value { + OwnerOf { collection, item } => + ReadResult::OwnerOf(NftsOf::::owner(collection, item)), + CollectionOwner(collection) => + ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), + TotalSupply(collection) => { + let data = pallet_nfts::Collection::::get(collection).encode(); + ReadResult::TotalSupply( + CollectionDetailsFor::::decode(&mut data.as_slice()) + .map(|detail| detail.items) + .unwrap_or_default(), + ) + }, + Collection(collection) => { + let data = pallet_nfts::Collection::::get(collection).encode(); + ReadResult::Collection( + Option::>::decode(&mut data.as_slice()) + .unwrap_or(None), + ) + }, + Item { collection, item } => { + let data = pallet_nfts::Item::::get(collection, item).encode(); + ReadResult::Item( + Option::>::decode(&mut data.as_slice()).unwrap_or(None), + ) + }, + Allowance { collection, owner, operator, item } => + ReadResult::Allowance(Self::allowance(collection, owner, operator, item)), + BalanceOf { collection, owner } => + ReadResult::BalanceOf(AccountBalance::::get((collection, owner))), + } + } + } } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 9e9da5c2..54d85516 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,183 +1,184 @@ -use codec::Encode; -use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; -use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; - -use super::types::*; -use crate::{ - mock::*, - nonfungibles::{Event, Read::*}, -}; - -const ITEM: u32 = 1; - -#[test] -fn mint_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let collection = create_collection(owner.clone()); - // Successfully mint a new collection item. - assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); - System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); - }); -} - -#[test] -fn burn_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); - System::assert_last_event(Event::Burn { collection, item }.into()); - }); -} - -#[test] -fn transfer() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let dest = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); - System::assert_last_event( - Event::Transfer { collection, item, from: owner, to: dest }.into(), - ); - }); -} - -#[test] -fn approve_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully approve `spender` to transfer the collection item. - assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); - System::assert_last_event( - Event::Approval { collection, item, owner, spender: spender.clone() }.into(), - ); - // Successfully transfer the item by the delegated account `spender`. - assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); - }); -} - -#[test] -fn cancel_approval_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - // Successfully cancel the transfer approval of `spender` by `owner`. - assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); - // Failed to transfer the item by `spender` without permission. - assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); - }); -} - -#[test] -fn owner_of_works() {} - -#[test] -fn collection_owner_works() { - new_test_ext().execute_with(|| { - let collection = create_collection(account(ALICE)); - assert_eq!( - NonFungibles::read_state(CollectionOwner(collection)), - Nfts::collection_owner(collection).encode() - ); - }); -} - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); - assert_eq!( - NonFungibles::read_state(TotalSupply(collection)), - (Nfts::items(&collection).count() as u8).encode() - ); - }); -} - -#[test] -fn collection_works() { - new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); - assert_eq!( - NonFungibles::read_state(Collection(collection)), - pallet_nfts::Collection::::get(&collection).encode(), - ); - }); -} - -#[test] -fn balance_of_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, _) = create_collection_mint(owner.clone(), ITEM); - assert_eq!( - NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), - (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() - ); - }); -} - -#[test] -fn allowance_works() { - new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - assert_eq!( - NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), - super::Pallet::::allowance(collection, item, spender).encode() - ); - }); -} - -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) -} - -fn create_collection_mint_and_approve( - owner: AccountIdOf, - item: ItemIdOf, - spender: AccountIdOf, -) -> (u32, u32) { - let (collection, item) = create_collection_mint(owner.clone(), item); - assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); - (collection, item) -} - -fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { - let collection = create_collection(owner.clone()); - assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); - (collection, item) -} - -fn create_collection(owner: AccountIdOf) -> u32 { - let next_id = next_collection_id(); - assert_ok!(Nfts::create( - signed(owner.clone()), - owner.clone(), - collection_config_with_all_settings_enabled() - )); - next_id -} - -fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() -} - -fn collection_config_with_all_settings_enabled( -) -> CollectionConfig, CollectionIdOf> { - CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: None, - mint_settings: MintSettings::default(), - } -} +// TODO +// use codec::Encode; +// use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +// use frame_system::pallet_prelude::BlockNumberFor; +// use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; + +// use super::types::*; +// use crate::{ +// mock::*, +// nonfungibles::{Event, Read::*}, +// }; + +// const ITEM: u32 = 1; + +// #[test] +// fn mint_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let collection = create_collection(owner.clone()); +// // Successfully mint a new collection item. +// assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); +// System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); +// }); +// } + +// #[test] +// fn burn_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully burn an existing new collection item. +// assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); +// System::assert_last_event(Event::Burn { collection, item }.into()); +// }); +// } + +// #[test] +// fn transfer() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let dest = account(BOB); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully burn an existing new collection item. +// assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); +// System::assert_last_event( +// Event::Transfer { collection, item, from: owner, to: dest }.into(), +// ); +// }); +// } + +// #[test] +// fn approve_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = create_collection_mint(owner.clone(), ITEM); +// // Successfully approve `spender` to transfer the collection item. +// assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); +// System::assert_last_event( +// Event::Approval { collection, item, owner, spender: spender.clone() }.into(), +// ); +// // Successfully transfer the item by the delegated account `spender`. +// assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); +// }); +// } + +// #[test] +// fn cancel_approval_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = +// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); +// // Successfully cancel the transfer approval of `spender` by `owner`. +// assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); +// // Failed to transfer the item by `spender` without permission. +// assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); +// }); +// } + +// #[test] +// fn owner_of_works() {} + +// #[test] +// fn collection_owner_works() { +// new_test_ext().execute_with(|| { +// let collection = create_collection(account(ALICE)); +// assert_eq!( +// NonFungibles::read_state(CollectionOwner(collection)), +// Nfts::collection_owner(collection).encode() +// ); +// }); +// } + +// #[test] +// fn total_supply_works() { +// new_test_ext().execute_with(|| { +// let (collection, _) = create_collection_mint(account(ALICE), ITEM); +// assert_eq!( +// NonFungibles::read_state(TotalSupply(collection)), +// (Nfts::items(&collection).count() as u8).encode() +// ); +// }); +// } + +// #[test] +// fn collection_works() { +// new_test_ext().execute_with(|| { +// let (collection, _) = create_collection_mint(account(ALICE), ITEM); +// assert_eq!( +// NonFungibles::read_state(Collection(collection)), +// pallet_nfts::Collection::::get(&collection).encode(), +// ); +// }); +// } + +// #[test] +// fn balance_of_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let (collection, _) = create_collection_mint(owner.clone(), ITEM); +// assert_eq!( +// NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), +// (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() +// ); +// }); +// } + +// #[test] +// fn allowance_works() { +// new_test_ext().execute_with(|| { +// let owner = account(ALICE); +// let spender = account(BOB); +// let (collection, item) = +// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); +// assert_eq!( +// NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), +// super::Pallet::::allowance(collection, item, spender).encode() +// ); +// }); +// } + +// fn signed(account: AccountId) -> RuntimeOrigin { +// RuntimeOrigin::signed(account) +// } + +// fn create_collection_mint_and_approve( +// owner: AccountIdOf, +// item: ItemIdOf, +// spender: AccountIdOf, +// ) -> (u32, u32) { +// let (collection, item) = create_collection_mint(owner.clone(), item); +// assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); +// (collection, item) +// } + +// fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { +// let collection = create_collection(owner.clone()); +// assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); +// (collection, item) +// } + +// fn create_collection(owner: AccountIdOf) -> u32 { +// let next_id = next_collection_id(); +// assert_ok!(Nfts::create( +// signed(owner.clone()), +// owner.clone(), +// collection_config_with_all_settings_enabled() +// )); +// next_id +// } + +// fn next_collection_id() -> u32 { +// pallet_nfts::NextCollectionId::::get().unwrap_or_default() +// } + +// fn collection_config_with_all_settings_enabled( +// ) -> CollectionConfig, CollectionIdOf> { +// CollectionConfig { +// settings: CollectionSettings::all_enabled(), +// max_supply: None, +// mint_settings: MintSettings::default(), +// } +// } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index 0174ef77..a55a8ec2 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -4,34 +4,22 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; use sp_runtime::BoundedBTreeMap; -use super::Config; +use super::*; pub(super) type AccountIdOf = ::AccountId; - pub(super) type NftsOf = pallet_nfts::Pallet; - /// Weight information for extrinsics in this pallet. pub(super) type NftsWeightInfoOf = ::WeightInfo; - /// A type alias for the collection ID. pub(super) type CollectionIdOf = - as Inspect<::AccountId>>::CollectionId; - + as Inspect<::AccountId>>::CollectionId; /// A type alias for the collection item ID. pub(super) type ItemIdOf = - as Inspect<::AccountId>>::ItemId; - -// TODO: Even though this serves the `allowance` method, it creates the maintenance cost. - -/// A type that holds the deposit for a single item. -pub(super) type ItemDepositOf = - ItemDeposit, ::AccountId>; - + as Inspect<::AccountId>>::ItemId; /// A type alias for handling balance deposits. -pub(super) type DepositBalanceOf = <::Currency as Currency< +pub(super) type BalanceOf = <::Currency as Currency< ::AccountId, >>::Balance; - /// A type alias for keeping track of approvals used by a single item. pub(super) type ApprovalsOf = BoundedBTreeMap< AccountIdOf, @@ -39,23 +27,42 @@ pub(super) type ApprovalsOf = BoundedBTreeMap< ::ApprovalsLimit, >; +pub(super) type ItemDetailsFor = ItemDetails, BalanceOf, ApprovalsOf>; +pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; + /// Information concerning the ownership of a single unique item. -#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] -pub(super) struct ItemDetails { +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountIdOf, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approvals: ApprovalsOf, + pub approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: ItemDepositOf, + pub deposit: Deposit, } - /// Information about the reserved item deposit. -#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub(super) account: AccountId, + account: AccountId, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + amount: DepositBalance, +} +/// Information about a collection. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectionDetails { + /// Collection's owner. + pub owner: AccountId, + /// The total balance deposited by the owner for all the storage data associated with this + /// collection. Used by `destroy`. + pub owner_deposit: DepositBalance, + /// The total number of outstanding items of this collection. + pub items: u32, + /// The total number of outstanding item metadata of this collection. + pub item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + pub item_configs: u32, + /// The total number of attributes for this collection. + pub attributes: u32, } From 3fad99499da309ab2a0729f423270eb845e6ff41 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:23:52 +0700 Subject: [PATCH 38/64] feat: add new storage items to pallet-nfts --- pallets/api/src/nonfungibles/mod.rs | 101 +++--------------- pallets/api/src/nonfungibles/types.rs | 68 +++--------- pallets/nfts/src/common_functions.rs | 7 +- pallets/nfts/src/features/approvals.rs | 85 ++++++++++++++- .../src/features/create_delete_collection.rs | 3 + .../nfts/src/features/create_delete_item.rs | 6 ++ pallets/nfts/src/features/transfer.rs | 8 ++ pallets/nfts/src/lib.rs | 88 ++++++++++++++- 8 files changed, 220 insertions(+), 146 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index c5e8cffb..cf2b14e7 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -4,7 +4,7 @@ pub use pallet::*; use pallet_nfts::WeightInfo; -use sp_runtime::{traits::StaticLookup, RuntimeDebug}; +use sp_runtime::traits::StaticLookup; #[cfg(test)] mod tests; @@ -16,8 +16,8 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_std::vec::Vec; use types::{ - AccountIdOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, - NftsOf, NftsWeightInfoOf, + AccountIdOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, NftsOf, + NftsWeightInfoOf, }; use super::*; @@ -63,7 +63,7 @@ pub mod pallet { OwnerOf(Option>), CollectionOwner(Option>), TotalSupply(u32), - BalanceOf(BalanceOf), + BalanceOf(u32), Collection(Option>), Item(Option>), Allowance(bool), @@ -92,32 +92,6 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } - #[pallet::storage] - type AccountBalance = StorageNMap< - Key = ( - // Collection ID - NMapKey>, - // Collection Owner ID - NMapKey>, - ), - Value = BalanceOf, - QueryKind = ValueQuery, - >; - - #[pallet::storage] - type Allowances = StorageNMap< - Key = ( - // Collection ID - NMapKey>, - // Collection Owner ID - NMapKey>, - // Collection Operator ID - NMapKey>, - ), - Value = bool, - QueryKind = ValueQuery, - >; - #[pallet::pallet] pub struct Pallet(_); @@ -283,35 +257,6 @@ pub mod pallet { } } - impl Pallet { - /// Check if the `spender` is approved to transfer the collection item. - pub(super) fn allowance( - collection: CollectionIdOf, - owner: AccountIdOf, - operator: AccountIdOf, - maybe_item: Option>, - ) -> bool { - // Check if has a permission to transfer all collection items. - Allowances::::get((collection, owner, operator.clone())) || - maybe_item - .and_then(|item| Some(Self::allowance_item(collection, operator, item))) - .unwrap_or(false) - } - - // Check the permission for the single item. - pub(super) fn allowance_item( - collection: CollectionIdOf, - operator: AccountIdOf, - item: ItemIdOf, - ) -> bool { - let data = pallet_nfts::Item::::get(collection, item).encode(); - if let Ok(detail) = ItemDetailsFor::::decode(&mut data.as_slice()) { - return detail.approvals.contains_key(&operator); - } - false - } - } - impl crate::Read for Pallet { /// The type of read requested. type Read = Read; @@ -338,31 +283,19 @@ pub mod pallet { ReadResult::OwnerOf(NftsOf::::owner(collection, item)), CollectionOwner(collection) => ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), - TotalSupply(collection) => { - let data = pallet_nfts::Collection::::get(collection).encode(); - ReadResult::TotalSupply( - CollectionDetailsFor::::decode(&mut data.as_slice()) - .map(|detail| detail.items) - .unwrap_or_default(), - ) - }, - Collection(collection) => { - let data = pallet_nfts::Collection::::get(collection).encode(); - ReadResult::Collection( - Option::>::decode(&mut data.as_slice()) - .unwrap_or(None), - ) - }, - Item { collection, item } => { - let data = pallet_nfts::Item::::get(collection, item).encode(); - ReadResult::Item( - Option::>::decode(&mut data.as_slice()).unwrap_or(None), - ) - }, - Allowance { collection, owner, operator, item } => - ReadResult::Allowance(Self::allowance(collection, owner, operator, item)), - BalanceOf { collection, owner } => - ReadResult::BalanceOf(AccountBalance::::get((collection, owner))), + TotalSupply(collection) => ReadResult::TotalSupply( + NftsOf::::collection_items(collection).unwrap_or_default(), + ), + Collection(collection) => + ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + Item { collection, item } => + ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + Allowance { collection, owner, operator, item } => ReadResult::Allowance( + NftsOf::::allowance(collection, item, owner, operator).unwrap_or(false), + ), + BalanceOf { collection, owner } => ReadResult::BalanceOf( + pallet_nfts::AccountBalance::::get((collection, owner)), + ), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index a55a8ec2..f81ea535 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,68 +1,28 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use scale_info::TypeInfo; +use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; use sp_runtime::BoundedBTreeMap; -use super::*; - -pub(super) type AccountIdOf = ::AccountId; +// Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; -/// Weight information for extrinsics in this pallet. pub(super) type NftsWeightInfoOf = ::WeightInfo; -/// A type alias for the collection ID. +// Type aliases for pallet-nfts storage items. +pub(super) type AccountIdOf = ::AccountId; +pub(super) type BalanceOf = <>::Currency as Currency< + ::AccountId, +>>::Balance; pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; -/// A type alias for the collection item ID. pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -/// A type alias for handling balance deposits. -pub(super) type BalanceOf = <::Currency as Currency< - ::AccountId, ->>::Balance; -/// A type alias for keeping track of approvals used by a single item. -pub(super) type ApprovalsOf = BoundedBTreeMap< +type ApprovalsOf = BoundedBTreeMap< AccountIdOf, Option>, ::ApprovalsLimit, >; - -pub(super) type ItemDetailsFor = ItemDetails, BalanceOf, ApprovalsOf>; -pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; - -/// Information concerning the ownership of a single unique item. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ItemDetails { - /// The owner of this item. - pub owner: AccountId, - /// The approved transferrer of this item, if one is set. - pub approvals: Approvals, - /// The amount held in the pallet's default account for this item. Free-hold items will have - /// this as zero. - pub deposit: Deposit, -} -/// Information about the reserved item deposit. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ItemDeposit { - /// A depositor account. - account: AccountId, - /// An amount that gets reserved. - amount: DepositBalance, -} -/// Information about a collection. -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct CollectionDetails { - /// Collection's owner. - pub owner: AccountId, - /// The total balance deposited by the owner for all the storage data associated with this - /// collection. Used by `destroy`. - pub owner_deposit: DepositBalance, - /// The total number of outstanding items of this collection. - pub items: u32, - /// The total number of outstanding item metadata of this collection. - pub item_metadatas: u32, - /// The total number of outstanding item configs of this collection. - pub item_configs: u32, - /// The total number of attributes for this collection. - pub attributes: u32, -} +// TODO: Multi-instances. +pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; +pub(super) type CollectionDetailsFor = + CollectionDetails, BalanceOf>; +pub(super) type ItemDetailsFor = + ItemDetails, ItemDepositOf, ApprovalsOf>; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index f51de192..6fe483f1 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,6 +34,11 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.owner) } + /// Get the total number of items in the collection, if the collection exists. + pub fn collection_items(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.items) + } + /// Validates the signature of the given data with the provided signer's account ID. /// /// # Errors @@ -46,7 +51,7 @@ impl, I: 'static> Pallet { signer: &T::AccountId, ) -> DispatchResult { if signature.verify(&**data, &signer) { - return Ok(()) + return Ok(()); } // NOTE: for security reasons modern UIs implicitly wrap the data requested to sign into diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ad5d93c2..f626a9fe 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -65,7 +65,6 @@ impl, I: 'static> Pallet { if let Some(check_origin) = maybe_check_origin { ensure!(check_origin == details.owner, Error::::NoPermission); } - let now = frame_system::Pallet::::block_number(); let deadline = maybe_deadline.map(|d| d.saturating_add(now)); @@ -74,15 +73,13 @@ impl, I: 'static> Pallet { .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; Item::::insert(&collection, &item, &details); - Self::deposit_event(Event::TransferApproved { collection, - item, + item: Some(item), owner: details.owner, delegate, deadline, }); - Ok(()) } @@ -129,7 +126,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::ApprovalCancelled { collection, - item, + item: Some(item), owner: details.owner, delegate, }); @@ -173,4 +170,82 @@ impl, I: 'static> Pallet { Ok(()) } + + pub(crate) fn do_approve_transfer_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + let collection_owner = + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == collection_owner, Error::::NoPermission); + } + + Allowances::::mutate((&collection, &collection_owner, &delegate), |allowance| { + *allowance = true; + }); + + Self::deposit_event(Event::TransferApproved { + collection, + item: None, + owner: collection_owner, + delegate, + deadline: None, + }); + Ok(()) + } + + pub(crate) fn do_cancel_approval_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + let collection_owner = + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == collection_owner, Error::::NoPermission); + } + + Allowances::::remove((&collection, &collection_owner, &delegate)); + + Self::deposit_event(Event::ApprovalCancelled { + collection, + owner: collection_owner, + item: None, + delegate, + }); + + Ok(()) + } + + pub fn allowance( + collection: T::CollectionId, + item: Option, + owner: T::AccountId, + delegate: T::AccountId, + ) -> Option { + // Check if a `delegate` has a permission to spend the collection. + if Allowances::::get((&collection, &owner, &delegate)) { + return Some(true); + } + // Check if a `delegate` has a permission to spend the collection item. + item.map(|item| { + Item::::get(&collection, &item) + .map(|detail| detail.approvals.contains_key(&delegate)) + }) + .unwrap_or_default() + } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..2ea5cd73 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -137,6 +137,9 @@ impl, I: 'static> Pallet { } } + let _ = + AccountBalance::::clear_prefix((collection,), collection_details.items, None); + let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); CollectionConfigOf::::remove(&collection); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9843b2e..036a63b7 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,6 +69,9 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); + AccountBalance::::mutate((collection, &mint_to), |balance| { + balance.saturating_inc(); + }); let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config @@ -263,6 +266,9 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); ItemAttributesApprovalsOf::::remove(&collection, &item); + AccountBalance::::mutate((collection, &owner), |balance| { + balance.saturating_dec(); + }); if remove_config { ItemConfigOf::::remove(&collection, &item); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index b7223a7c..0aa83fe8 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -87,6 +87,14 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; + // Update account balances. + AccountBalance::::mutate((collection, &details.owner), |balance| { + balance.saturating_dec(); + }); + AccountBalance::::mutate((collection, &dest), |balance| { + balance.saturating_dec(); + }); + // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 89bfb963..9f4d3aed 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -402,6 +402,36 @@ pub mod pallet { pub type CollectionConfigOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; + /// Number of collection items that accounts own. + #[pallet::storage] + pub type AccountBalance, I: 'static = ()> = StorageNMap< + _, + ( + // Collection Id. + NMapKey, + // Collection Owner Id. + NMapKey, + ), + u32, + ValueQuery, + >; + + /// Permission for the delegate to transfer all owner's items within a collection. + #[pallet::storage] + pub type Allowances, I: 'static = ()> = StorageNMap< + _, + ( + // Collection ID. + NMapKey, + // Collection Owner Id. + NMapKey, + // Delegate Id. + NMapKey, + ), + bool, + ValueQuery, + >; + /// Config of an item. #[pallet::storage] pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< @@ -460,7 +490,7 @@ pub mod pallet { /// a `delegate`. TransferApproved { collection: T::CollectionId, - item: T::ItemId, + item: Option, owner: T::AccountId, delegate: T::AccountId, deadline: Option>, @@ -469,7 +499,7 @@ pub mod pallet { /// `collection` was cancelled by its `owner`. ApprovalCancelled { collection: T::CollectionId, - item: T::ItemId, + item: Option, owner: T::AccountId, delegate: T::AccountId, }, @@ -1931,6 +1961,60 @@ pub mod pallet { Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } + + /// Approve an item to be transferred by a delegated third-party account. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `item`. + /// + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `item`: The item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer the item. + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(39)] + #[pallet::weight(T::WeightInfo::approve_transfer())] + pub fn approve_transfer_collection( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate) + } + + /// Cancel one of the transfer approvals for a specific item. + /// + /// Origin must be either: + /// - the `Force` origin; + /// - `Signed` with the signer being the Owner of the `item`; + /// + /// Arguments: + /// - `collection`: The collection of the item of whose approval will be cancelled. + /// - `item`: The item of the collection of whose approval will be cancelled. + /// - `delegate`: The account that is going to loose their approval. + /// + /// Emits `ApprovalCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(40)] + #[pallet::weight(T::WeightInfo::cancel_approval())] + pub fn cancel_approval_collection( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate) + } } } From bc2deee38e6ac4b1751cb1f9dc89aa73f65290b0 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 16 Oct 2024 22:30:14 +0700 Subject: [PATCH 39/64] feat: check allowance --- pallets/api/src/nonfungibles/mod.rs | 102 +++++++------------------ pallets/nfts/src/features/approvals.rs | 28 ++++--- pallets/nfts/src/features/transfer.rs | 6 +- pallets/nfts/src/lib.rs | 94 ++++++----------------- pallets/nfts/src/tests.rs | 93 +++++++++++++--------- 5 files changed, 128 insertions(+), 195 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index cf2b14e7..bc728ac8 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -62,7 +62,7 @@ pub mod pallet { pub enum ReadResult { OwnerOf(Option>), CollectionOwner(Option>), - TotalSupply(u32), + TotalSupply(u128), BalanceOf(u32), Collection(Option>), Item(Option>), @@ -99,25 +99,18 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event emitted when allowance by `owner` to `spender` canceled. - CancelApproval { - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - /// The beneficiary of the allowance. - spender: AccountIdOf, - }, - /// Event emitted when allowance by `owner` to `spender` changes. + /// Event emitted when allowance by `owner` to `operator` changes. Approval { /// The collection ID. collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, /// The owner providing the allowance. owner: AccountIdOf, /// The beneficiary of the allowance. - spender: AccountIdOf, + operator: AccountIdOf, + /// The item which is (dis)approved. `None` for all owner's items. + item: Option>, + /// Whether allowance is set or removed. + approved: bool, }, /// Event emitted when new item is minted to the account. Mint { @@ -150,12 +143,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Create a new non-fungible token to the collection. - /// - /// # Parameters - /// - `to` - The owner of the collection item. - /// - `collection` - The collection ID. - /// - `item` - The item ID. #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -169,11 +156,6 @@ pub mod pallet { Ok(()) } - /// Destroy a new non-fungible token to the collection. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. #[pallet::call_index(1)] #[pallet::weight(NftsWeightInfoOf::::burn())] pub fn burn( @@ -186,12 +168,6 @@ pub mod pallet { Ok(()) } - /// Transfer a token from one account to the another account. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `to` - The recipient account. #[pallet::call_index(2)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( @@ -206,53 +182,33 @@ pub mod pallet { Ok(()) } - /// Delegate a permission to perform actions on the collection item to an account. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `spender` - The account that is allowed to transfer the collection item. #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] pub fn approve( origin: OriginFor, collection: CollectionIdOf, - item: ItemIdOf, - spender: AccountIdOf, + item: Option>, + operator: AccountIdOf, + approved: bool, ) -> DispatchResult { let owner = ensure_signed(origin.clone())?; - NftsOf::::approve_transfer( - origin, - collection, - item, - T::Lookup::unlookup(spender.clone()), - None, - )?; - Self::deposit_event(Event::Approval { collection, item, spender, owner }); - Ok(()) - } - - /// Cancel one of the transfer approvals for a specific item. - /// - /// # Parameters - /// - `collection` - The collection ID. - /// - `item` - The item ID. - /// - `spender` - The account that is revoked permission to transfer the collection item. - #[pallet::call_index(4)] - #[pallet::weight(NftsWeightInfoOf::::cancel_approval())] - pub fn cancel_approval( - origin: OriginFor, - collection: CollectionIdOf, - item: ItemIdOf, - spender: AccountIdOf, - ) -> DispatchResult { - NftsOf::::cancel_approval( - origin, - collection, - item, - T::Lookup::unlookup(spender.clone()), - )?; - Self::deposit_event(Event::CancelApproval { collection, item, spender }); + if approved { + NftsOf::::approve_transfer( + origin, + collection, + item, + T::Lookup::unlookup(operator.clone()), + None, + )?; + } else { + NftsOf::::cancel_approval( + origin, + collection, + item, + T::Lookup::unlookup(operator.clone()), + )?; + } + Self::deposit_event(Event::Approval { collection, item, operator, owner, approved }); Ok(()) } } @@ -284,14 +240,14 @@ pub mod pallet { CollectionOwner(collection) => ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default(), + NftsOf::::collection_items(collection).unwrap_or_default().into(), ), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( - NftsOf::::allowance(collection, item, owner, operator).unwrap_or(false), + NftsOf::::allowance(&collection, &item, &owner, &operator).is_ok(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index f626a9fe..979035fa 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -232,20 +232,26 @@ impl, I: 'static> Pallet { } pub fn allowance( - collection: T::CollectionId, - item: Option, - owner: T::AccountId, - delegate: T::AccountId, - ) -> Option { + collection: &T::CollectionId, + item: &Option, + owner: &T::AccountId, + delegate: &T::AccountId, + ) -> Result<(), DispatchError> { // Check if a `delegate` has a permission to spend the collection. if Allowances::::get((&collection, &owner, &delegate)) { - return Some(true); + return Ok(()); } // Check if a `delegate` has a permission to spend the collection item. - item.map(|item| { - Item::::get(&collection, &item) - .map(|detail| detail.approvals.contains_key(&delegate)) - }) - .unwrap_or_default() + if let Some(item) = item { + let details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + let deadline = details.approvals.get(&delegate).ok_or(Error::::NoPermission)?; + if let Some(d) = deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *d, Error::::ApprovalExpired); + } + }; + Ok(()) } } diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 0aa83fe8..04d9f4fe 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -92,7 +92,7 @@ impl, I: 'static> Pallet { balance.saturating_dec(); }); AccountBalance::::mutate((collection, &dest), |balance| { - balance.saturating_dec(); + balance.saturating_inc(); }); // Update account ownership information. @@ -145,7 +145,7 @@ impl, I: 'static> Pallet { // Check if the `origin` is the current owner of the collection. ensure!(origin == details.owner, Error::::NoPermission); if details.owner == new_owner { - return Ok(()) + return Ok(()); } // Move the deposit to the new owner. @@ -220,7 +220,7 @@ impl, I: 'static> Pallet { Collection::::try_mutate(collection, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; if details.owner == owner { - return Ok(()) + return Ok(()); } // Move the deposit to the new owner. diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 9f4d3aed..14689293 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1060,12 +1060,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - let deadline = - details.approvals.get(&origin).ok_or(Error::::NoPermission)?; - if let Some(d) = deadline { - let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *d, Error::::ApprovalExpired); - } + Self::allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1120,10 +1115,10 @@ pub mod pallet { if T::Currency::reserve(&details.deposit.account, deposit - old).is_err() { // NOTE: No alterations made to collection_details in this iteration so far, // so this is OK to do. - continue + continue; } } else { - continue + continue; } details.deposit.amount = deposit; Item::::insert(&collection, &item, &details); @@ -1322,7 +1317,7 @@ pub mod pallet { pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1330,13 +1325,17 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ) + match maybe_item { + Some(item) => Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ), + None => + Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate), + } } /// Cancel one of the transfer approvals for a specific item. @@ -1358,14 +1357,19 @@ pub mod pallet { pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) + match maybe_item { + Some(item) => + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), + None => + Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate), + } } /// Cancel all the approvals of a specific item. @@ -1961,60 +1965,6 @@ pub mod pallet { Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } - - /// Approve an item to be transferred by a delegated third-party account. - /// - /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// `item`. - /// - /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `item`: The item to be approved for delegated transfer. - /// - `delegate`: The account to delegate permission to transfer the item. - /// - /// Emits `TransferApproved` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(39)] - #[pallet::weight(T::WeightInfo::approve_transfer())] - pub fn approve_transfer_collection( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - let maybe_check_origin = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate) - } - - /// Cancel one of the transfer approvals for a specific item. - /// - /// Origin must be either: - /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item`; - /// - /// Arguments: - /// - `collection`: The collection of the item of whose approval will be cancelled. - /// - `item`: The item of the collection of whose approval will be cancelled. - /// - `delegate`: The account that is going to loose their approval. - /// - /// Emits `ApprovalCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(40)] - #[pallet::weight(T::WeightInfo::cancel_approval())] - pub fn cancel_approval_collection( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - let maybe_check_origin = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate) - } } } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 44f2f32a..4002c48e 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -487,7 +487,7 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - 42, + Some(42), account(2), None )); @@ -1777,7 +1777,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); @@ -1791,7 +1791,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(2), None )); @@ -1819,7 +1819,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - 1, + Some(1), account(2), None ), @@ -1847,30 +1847,35 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, Some(42), account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3) + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), Error::::NotDelegate ); @@ -1887,18 +1892,23 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, Some(42), account(3)), Error::::NoPermission ); System::set_block_number(current_block + 3); // 5 can cancel the approval since the deadline has passed. - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(5)), + 0, + Some(42), + account(3) + )); assert_eq!(approvals(0, 69), vec![]); }); } @@ -1924,21 +1934,21 @@ fn approving_multiple_accounts_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(4), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(5), Some(2) )); @@ -1979,14 +1989,20 @@ fn approvals_limit_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(i), None )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), + Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(14), + None + ), Error::::ReachedApprovalLimit ); }); @@ -2015,7 +2031,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); @@ -2034,7 +2050,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(6), Some(4) )); @@ -2063,26 +2079,31 @@ fn cancel_approval_works_with_admin() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3) + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(1)), Error::::NotDelegate ); }); @@ -2107,26 +2128,26 @@ fn cancel_approval_works_with_force() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, Some(42), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(43), account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(1)), Error::::NotDelegate ); }); @@ -2151,14 +2172,14 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(4), None )); @@ -3169,7 +3190,7 @@ fn pallet_level_feature_flags_should_work() { Nfts::approve_transfer( RuntimeOrigin::signed(user_id.clone()), collection_id, - item_id, + Some(item_id), account(2), None ), From 1946b15479f55c449220f9272722ac9fd55e34d4 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:03:43 +0700 Subject: [PATCH 40/64] test(nfts): check account balance & test total supply --- pallets/nfts/src/tests.rs | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4002c48e..f75c25d8 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,6 +164,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -173,6 +174,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); + assert_eq!(AccountBalance::::get((1, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } @@ -204,6 +206,7 @@ fn lifecycle_should_work() { account(10), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(10))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 6); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), @@ -212,8 +215,10 @@ fn lifecycle_should_work() { account(20), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(20))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 7); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); @@ -221,6 +226,8 @@ fn lifecycle_should_work() { assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); + assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -238,6 +245,7 @@ fn lifecycle_should_work() { Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), Error::::CollectionNotEmpty ); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(account(1)), @@ -248,7 +256,9 @@ fn lifecycle_should_work() { bvec![0], )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); + assert_eq!(AccountBalance::::get((0, account(10))), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); + assert_eq!(AccountBalance::::get((0, account(10))), 0); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -256,6 +266,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -305,6 +316,7 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -323,6 +335,7 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); + assert_eq!(AccountBalance::::get((0, account(1))), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -337,6 +350,7 @@ fn mint_should_work() { default_collection_config() )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(AccountBalance::::get((0, account(1))), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -402,6 +416,7 @@ fn mint_should_work() { account(2), Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); + assert_eq!(AccountBalance::::get((0, account(2))), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -440,6 +455,7 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); + assert_eq!(AccountBalance::::get((1, account(2))), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -478,6 +494,8 @@ fn transfer_should_work() { )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_eq!(AccountBalance::::get((0, account(2))), 0); + assert_eq!(AccountBalance::::get((0, account(3))), 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -492,7 +510,9 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - + assert_eq!(AccountBalance::::get((0, account(2))), 0); + assert_eq!(AccountBalance::::get((0, account(3))), 0); + assert_eq!(AccountBalance::::get((0, account(4))), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1746,15 +1766,17 @@ fn burn_works() { account(5), default_item_config() )); + assert_eq!(AccountBalance::::get((0, account(5))), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), Error::::NoPermission ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); + assert_eq!(AccountBalance::::get((0, account(5))), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); + assert_eq!(AccountBalance::::get((0, account(5))), 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2209,6 +2231,36 @@ fn clear_all_transfer_approvals_works() { }); } +#[test] +fn total_supply_should_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = account(1); + let total_items = 10; + + // no collection. + assert_eq!(Nfts::collection_items(collection_id), None); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + + // mint items and validate the total supply. + (0..total_items).into_iter().for_each(|i| { + assert_ok!(Nfts::force_mint( + RuntimeOrigin::root(), + collection_id, + i, + user_id.clone(), + ItemConfig::default() + )); + }); + assert_eq!(Nfts::collection_items(collection_id), Some(total_items)); + }); +} + #[test] fn max_supply_should_work() { new_test_ext().execute_with(|| { @@ -2545,6 +2597,7 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -2912,6 +2965,8 @@ fn claim_swap_should_work() { default_item_config(), )); + assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3002,6 +3057,8 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); + assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); + assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); From 684d87058226928029cbf37441f22626414a5022 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:39:53 +0700 Subject: [PATCH 41/64] test(nfts): allowance works --- pallets/api/src/nonfungibles/mod.rs | 2 +- pallets/nfts/src/features/approvals.rs | 8 +++- pallets/nfts/src/lib.rs | 2 +- pallets/nfts/src/tests.rs | 57 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index bc728ac8..4b6558e9 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -247,7 +247,7 @@ pub mod pallet { Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( - NftsOf::::allowance(&collection, &item, &owner, &operator).is_ok(), + NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 979035fa..89b8fc6a 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -231,7 +231,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub fn allowance( + pub fn check_allowance( collection: &T::CollectionId, item: &Option, owner: &T::AccountId, @@ -239,6 +239,9 @@ impl, I: 'static> Pallet { ) -> Result<(), DispatchError> { // Check if a `delegate` has a permission to spend the collection. if Allowances::::get((&collection, &owner, &delegate)) { + if let Some(item) = item { + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + }; return Ok(()); } // Check if a `delegate` has a permission to spend the collection item. @@ -251,7 +254,8 @@ impl, I: 'static> Pallet { let block_number = frame_system::Pallet::::block_number(); ensure!(block_number <= *d, Error::::ApprovalExpired); } + return Ok(()); }; - Ok(()) + Err(Error::::NoPermission.into()) } } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 14689293..c7d826b5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1060,7 +1060,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::allowance(&collection, &Some(item), &details.owner, &origin)?; + Self::check_allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index f75c25d8..5ad13e6e 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1850,6 +1850,63 @@ fn approval_lifecycle_works() { }); } +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(2), + None + )); + + // collection transfer approved. + assert_noop!( + Nfts::check_allowance(&0, &Some(43), &account(1), &account(2)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(1), &account(3)), + Error::::NoPermission + ); + assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(2))); + assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(1), &account(2))); + + // collection item transfer approved. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3), + None + )); + + assert_noop!( + Nfts::check_allowance(&0, &Some(43), &account(2), &account(3)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(2), &account(4)), + Error::::NoPermission + ); + assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(2), &account(3))); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { From 90ab45e90b809690072ea184644a941f68aa1c12 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:40:34 +0700 Subject: [PATCH 42/64] refactor(test): check_allowance_works --- pallets/nfts/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 5ad13e6e..9c3cce0d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1851,7 +1851,7 @@ fn approval_lifecycle_works() { } #[test] -fn allowance_works() { +fn check_allowance_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), From f862516ef68744c132dccab94fb265c27bb24c55 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:18:49 +0700 Subject: [PATCH 43/64] fix(nfts): cancel / approve collection transfer --- pallets/nfts/src/features/approvals.rs | 27 ++++------ pallets/nfts/src/tests.rs | 72 ++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 89b8fc6a..05696fee 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -180,27 +180,24 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let collection_owner = - Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - + if !Collection::::contains_key(collection) { + return Err(Error::::UnknownCollection.into()); + } let collection_config = Self::get_collection_config(&collection)?; ensure!( collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == collection_owner, Error::::NoPermission); - } - - Allowances::::mutate((&collection, &collection_owner, &delegate), |allowance| { + let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; + Allowances::::mutate((&collection, &origin, &delegate), |allowance| { *allowance = true; }); Self::deposit_event(Event::TransferApproved { collection, item: None, - owner: collection_owner, + owner: origin, delegate, deadline: None, }); @@ -212,18 +209,16 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let collection_owner = - Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == collection_owner, Error::::NoPermission); + if !Collection::::contains_key(collection) { + return Err(Error::::UnknownCollection.into()); } - Allowances::::remove((&collection, &collection_owner, &delegate)); + let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; + Allowances::::remove((&collection, &origin, &delegate)); Self::deposit_event(Event::ApprovalCancelled { collection, - owner: collection_owner, + owner: origin, item: None, delegate, }); diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 9c3cce0d..07f2a74d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1876,12 +1876,12 @@ fn check_allowance_works() { // collection transfer approved. assert_noop!( - Nfts::check_allowance(&0, &Some(43), &account(1), &account(2)), - Error::::UnknownItem + Nfts::check_allowance(&1, &None, &account(1), &account(2)), + Error::::NoPermission ); assert_noop!( - Nfts::check_allowance(&0, &Some(42), &account(1), &account(3)), - Error::::NoPermission + Nfts::check_allowance(&1, &Some(43), &account(1), &account(2)), + Error::::UnknownItem ); assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(2))); assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(1), &account(2))); @@ -1992,6 +1992,43 @@ fn cancel_approval_works() { }); } +#[test] +fn cancel_approval_collection_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + None, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), + Error::::NoPermission + ); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -2087,6 +2124,33 @@ fn approvals_limit_works() { }); } +#[test] +fn approval_collection_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(3), + None + )); + assert_eq!(Allowances::::get((0, account(1), account(3))), true); + }); +} + #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { From 7e55eb14fdbe30653590b1f2879ca53028f96a3f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:17:38 +0700 Subject: [PATCH 44/64] test(nfts): cancel approval collection --- pallets/nfts/src/tests.rs | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 07f2a74d..4fbec4de 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2021,6 +2021,13 @@ fn cancel_approval_collection_works() { ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: 0, + item: None, + owner: account(2), + delegate: account(3) + })); + assert_eq!(Allowances::::get((0, account(2), account(3))), false); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2127,6 +2134,11 @@ fn approvals_limit_works() { #[test] fn approval_collection_works() { new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2140,14 +2152,47 @@ fn approval_collection_works() { default_item_config() )); - assert_ok!(Nfts::approve_transfer( + // Error::ItemsNonTransferable. + assert_ok!(Nfts::lock_collection( RuntimeOrigin::signed(account(1)), + 1, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), + Error::::ItemsNonTransferable + ); + + // Error::MethodDisabled. + Features::set(&PalletFeatures::from_disabled(PalletFeature::Approvals.into())); + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), + Error::::MethodDisabled + ); + Features::set(&PalletFeatures::all_enabled()); + + // Error::UnknownCollection. + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), 0, None, account(3), None )); - assert_eq!(Allowances::::get((0, account(1), account(3))), true); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: account(2), + delegate: account(3), + deadline: None + })); + assert_eq!(Allowances::::get((0, account(2), account(3))), true); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } From af87aafd549885b21160cd52ecc5feea9df2c400 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:23:23 +0700 Subject: [PATCH 45/64] test(nfts): update approval test cases --- pallets/nfts/src/tests.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4fbec4de..10c95bd6 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1993,7 +1993,7 @@ fn cancel_approval_works() { } #[test] -fn cancel_approval_collection_works() { +fn cancel_approval_collection_works_with_admin() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2132,7 +2132,7 @@ fn approvals_limit_works() { } #[test] -fn approval_collection_works() { +fn approval_collection_works_with_admin() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2163,14 +2163,6 @@ fn approval_collection_works() { Error::::ItemsNonTransferable ); - // Error::MethodDisabled. - Features::set(&PalletFeatures::from_disabled(PalletFeature::Approvals.into())); - assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), - Error::::MethodDisabled - ); - Features::set(&PalletFeatures::all_enabled()); - // Error::UnknownCollection. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), From 06c0db92101888ca29f5df4bd069f6007f97bbcc Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:18:20 +0700 Subject: [PATCH 46/64] feat(nfts): get attribute read method --- pallets/api/src/nonfungibles/mod.rs | 105 ++++++++++++++++++-------- pallets/api/src/nonfungibles/types.rs | 6 +- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 4b6558e9..83d23585 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -14,10 +14,11 @@ mod types; pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; + use pallet_nfts::MintWitness; use sp_std::vec::Vec; use types::{ - AccountIdOf, CollectionDetailsFor, CollectionIdOf, ItemDetailsFor, ItemIdOf, NftsOf, - NftsWeightInfoOf, + AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, + ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -54,6 +55,14 @@ pub mod pallet { operator: AccountIdOf, item: Option>, }, + /// Returns the attribute of `item` for the given `key`. + #[codec(index = 6)] + GetAttribute { + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + }, } /// Results of state reads for the non-fungibles API. @@ -67,6 +76,7 @@ pub mod pallet { Collection(Option>), Item(Option>), Allowance(bool), + GetAttribute(Option>), } impl ReadResult { @@ -81,6 +91,7 @@ pub mod pallet { Collection(result) => result.encode(), Item(result) => result.encode(), Allowance(result) => result.encode(), + GetAttribute(result) => result.encode(), } } } @@ -103,46 +114,46 @@ pub mod pallet { Approval { /// The collection ID. collection: CollectionIdOf, + /// The item which is (dis)approved. `None` for all owner's items. + item: Option>, /// The owner providing the allowance. owner: AccountIdOf, /// The beneficiary of the allowance. operator: AccountIdOf, - /// The item which is (dis)approved. `None` for all owner's items. - item: Option>, /// Whether allowance is set or removed. approved: bool, }, - /// Event emitted when new item is minted to the account. - Mint { - /// The owner of the item. - to: AccountIdOf, - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - }, - /// Event emitted when item is burned. - Burn { - /// The collection ID. - collection: CollectionIdOf, - /// the item ID. - item: ItemIdOf, - }, - /// Event emitted when an item transfer occurs. + /// Event emitted when a token transfer occurs. + // Differing style: event name abides by the PSP22 standard. Transfer { /// The collection ID. collection: CollectionIdOf, - /// the item ID. + /// The collection item ID. item: ItemIdOf, - /// The source of the transfer. - from: AccountIdOf, - /// The recipient of the transfer. - to: AccountIdOf, + /// The source of the transfer. `None` when minting. + from: Option>, + /// The recipient of the transfer. `None` when burning. + to: Option>, + /// The amount minted. + value: Option>, }, } #[pallet::call] impl Pallet { + #[pallet::call_index(20)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn create(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + + // TODO: Fix weight + #[pallet::call_index(21)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn destroy(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -150,9 +161,24 @@ pub mod pallet { to: AccountIdOf, collection: CollectionIdOf, item: ItemIdOf, + mint_price: Option>, ) -> DispatchResult { - NftsOf::::mint(origin, collection, item, T::Lookup::unlookup(to.clone()), None)?; - Self::deposit_event(Event::Mint { to, collection, item }); + let account = ensure_signed(origin.clone())?; + let witness_data = MintWitness { mint_price, owned_item: Some(item) }; + NftsOf::::mint( + origin, + collection, + item, + T::Lookup::unlookup(to.clone()), + Some(witness_data), + )?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: None, + to: Some(account), + value: mint_price, + }); Ok(()) } @@ -163,8 +189,15 @@ pub mod pallet { collection: CollectionIdOf, item: ItemIdOf, ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; NftsOf::::burn(origin, collection, item)?; - Self::deposit_event(Event::Burn { collection, item }); + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(account), + to: None, + value: None, + }); Ok(()) } @@ -178,12 +211,18 @@ pub mod pallet { ) -> DispatchResult { let from = ensure_signed(origin.clone())?; NftsOf::::transfer(origin, collection, item, T::Lookup::unlookup(to.clone()))?; - Self::deposit_event(Event::Transfer { from, to, collection, item }); + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(from), + to: Some(to), + value: None, + }); Ok(()) } #[pallet::call_index(3)] - #[pallet::weight(NftsWeightInfoOf::::approve_transfer())] + #[pallet::weight(NftsWeightInfoOf::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( origin: OriginFor, collection: CollectionIdOf, @@ -252,6 +291,10 @@ pub mod pallet { BalanceOf { collection, owner } => ReadResult::BalanceOf( pallet_nfts::AccountBalance::::get((collection, owner)), ), + GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( + pallet_nfts::Attribute::::get((collection, item, namespace, key)) + .map(|attribute| attribute.0), + ), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index f81ea535..da949171 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,6 +1,6 @@ use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; +use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails}; use sp_runtime::BoundedBTreeMap; // Type aliases for pallet-nfts. @@ -15,14 +15,16 @@ pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -type ApprovalsOf = BoundedBTreeMap< +pub(super) type ApprovalsOf = BoundedBTreeMap< AccountIdOf, Option>, ::ApprovalsLimit, >; +pub(super) type ItemPriceOf = BalanceOf; // TODO: Multi-instances. pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; pub(super) type ItemDetailsFor = ItemDetails, ItemDepositOf, ApprovalsOf>; +pub(super) type AttributeNamespaceOf = AttributeNamespace>; From 9c5eb78718059e14c5bb167597f7d31f4bf293db Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:45:16 +0700 Subject: [PATCH 47/64] feat(nonfungibles + nfts): add new methods to manage attributes --- Cargo.lock | 8 +- pallets/api/src/nonfungibles/mod.rs | 198 ++++++++++++++---- pallets/api/src/nonfungibles/types.rs | 17 +- pallets/nfts/src/features/approvals.rs | 4 +- .../src/features/create_delete_collection.rs | 4 +- .../nfts/src/features/create_delete_item.rs | 4 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/lib.rs | 18 +- pallets/nfts/src/tests.rs | 66 +++--- 9 files changed, 228 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed534195..48f7b34c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "Inflector" @@ -822,7 +822,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.36.4", + "object 0.36.0", "rustc-demangle", ] @@ -7195,9 +7195,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 83d23585..efef2386 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -14,11 +14,14 @@ mod types; pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::*; - use pallet_nfts::MintWitness; + use pallet_nfts::{ + CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, + MintSettings, MintWitness, + }; use sp_std::vec::Vec; use types::{ AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, + CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -29,24 +32,12 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Returns the owner of an item. - #[codec(index = 0)] - OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Returns the owner of a collection. - #[codec(index = 1)] - CollectionOwner(CollectionIdOf), /// Number of items existing in a concrete collection. #[codec(index = 2)] TotalSupply(CollectionIdOf), /// Returns the total number of items in the collection owned by the account. #[codec(index = 3)] BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, - /// Returns the details of a collection. - #[codec(index = 4)] - Collection(CollectionIdOf), - /// Returns the details of an item. - #[codec(index = 5)] - Item { collection: CollectionIdOf, item: ItemIdOf }, /// Whether a spender is allowed to transfer an item or items from owner. #[codec(index = 6)] Allowance { @@ -55,6 +46,9 @@ pub mod pallet { operator: AccountIdOf, item: Option>, }, + /// Returns the owner of an item. + #[codec(index = 0)] + OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, /// Returns the attribute of `item` for the given `key`. #[codec(index = 6)] GetAttribute { @@ -63,20 +57,29 @@ pub mod pallet { namespace: AttributeNamespaceOf, key: BoundedVec, }, + /// Returns the owner of a collection. + #[codec(index = 1)] + CollectionOwner(CollectionIdOf), + /// Returns the details of a collection. + #[codec(index = 4)] + Collection(CollectionIdOf), + /// Returns the details of an item. + #[codec(index = 5)] + Item { collection: CollectionIdOf, item: ItemIdOf }, } /// Results of state reads for the non-fungibles API. #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { - OwnerOf(Option>), - CollectionOwner(Option>), TotalSupply(u128), BalanceOf(u32), - Collection(Option>), - Item(Option>), Allowance(bool), + OwnerOf(Option>), GetAttribute(Option>), + CollectionOwner(Option>), + Collection(Option>), + Item(Option>), } impl ReadResult { @@ -141,19 +144,6 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(20)] - #[pallet::weight(NftsWeightInfoOf::::create())] - pub fn create(_origin: OriginFor) -> DispatchResult { - Ok(()) - } - - // TODO: Fix weight - #[pallet::call_index(21)] - #[pallet::weight(NftsWeightInfoOf::::create())] - pub fn destroy(_origin: OriginFor) -> DispatchResult { - Ok(()) - } - #[pallet::call_index(0)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -250,6 +240,131 @@ pub mod pallet { Self::deposit_event(Event::Approval { collection, item, operator, owner, approved }); Ok(()) } + + #[pallet::call_index(4)] + #[pallet::weight(NftsWeightInfoOf::::create())] + pub fn create( + origin: OriginFor, + admin: AccountIdOf, + config: CreateCollectionConfigFor, + ) -> DispatchResult { + let collection_config = CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: config.max_supply, + mint_settings: MintSettings { + mint_type: config.mint_type, + start_block: config.start_block, + end_block: config.end_block, + ..MintSettings::default() + }, + }; + NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::weight(NftsWeightInfoOf::::destroy( + witness.item_metadatas, + witness.item_configs, + witness.attributes, + ))] + pub fn destroy( + origin: OriginFor, + collection: CollectionIdOf, + witness: DestroyWitness, + ) -> DispatchResultWithPostInfo { + NftsOf::::destroy(origin, collection, witness) + } + + #[pallet::call_index(6)] + #[pallet::weight(NftsWeightInfoOf::::set_attribute())] + pub fn set_attribute( + origin: OriginFor, + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + NftsOf::::set_attribute(origin, collection, item, namespace, key, value) + } + + #[pallet::call_index(7)] + #[pallet::weight(NftsWeightInfoOf::::clear_attribute())] + pub fn clear_attribute( + origin: OriginFor, + collection: CollectionIdOf, + item: Option>, + namespace: AttributeNamespaceOf, + key: BoundedVec, + ) -> DispatchResult { + NftsOf::::clear_attribute(origin, collection, item, namespace, key) + } + + #[pallet::call_index(8)] + #[pallet::weight(NftsWeightInfoOf::::set_metadata())] + pub fn set_metadata( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + data: BoundedVec, + ) -> DispatchResult { + NftsOf::::set_metadata(origin, collection, item, data) + } + + #[pallet::call_index(9)] + #[pallet::weight(NftsWeightInfoOf::::clear_metadata())] + pub fn clear_metadata( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + NftsOf::::clear_metadata(origin, collection, item) + } + + #[pallet::call_index(10)] + #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] + pub fn approve_item_attributes( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + delegate: AccountIdOf, + ) -> DispatchResult { + NftsOf::::approve_item_attributes( + origin, + collection, + item, + T::Lookup::unlookup(delegate.clone()), + ) + } + + #[pallet::call_index(11)] + #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] + pub fn cancel_item_attributes_approval( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + delegate: AccountIdOf, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + NftsOf::::cancel_item_attributes_approval( + origin, + collection, + item, + T::Lookup::unlookup(delegate.clone()), + witness, + ) + } + + #[pallet::call_index(12)] + #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] + pub fn set_max_supply( + origin: OriginFor, + collection: CollectionIdOf, + max_supply: u32, + ) -> DispatchResult { + NftsOf::::set_collection_max_supply(origin, collection, max_supply) + } } impl crate::Read for Pallet { @@ -274,27 +389,26 @@ pub mod pallet { fn read(value: Self::Read) -> Self::Result { use Read::*; match value { - OwnerOf { collection, item } => - ReadResult::OwnerOf(NftsOf::::owner(collection, item)), - CollectionOwner(collection) => - ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), TotalSupply(collection) => ReadResult::TotalSupply( NftsOf::::collection_items(collection).unwrap_or_default().into(), ), - Collection(collection) => - ReadResult::Collection(pallet_nfts::Collection::::get(collection)), - Item { collection, item } => - ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + BalanceOf { collection, owner } => + ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), - BalanceOf { collection, owner } => ReadResult::BalanceOf( - pallet_nfts::AccountBalance::::get((collection, owner)), - ), + OwnerOf { collection, item } => + ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( pallet_nfts::Attribute::::get((collection, item, namespace, key)) .map(|attribute| attribute.0), ), + CollectionOwner(collection) => + ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), + Collection(collection) => + ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + Item { collection, item } => + ReadResult::Item(pallet_nfts::Item::::get(collection, item)), } } } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index da949171..8c53ffd3 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,7 +1,9 @@ +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails}; -use sp_runtime::BoundedBTreeMap; +use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails, MintType}; +use scale_info::TypeInfo; +use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; @@ -28,3 +30,14 @@ pub(super) type CollectionDetailsFor = pub(super) type ItemDetailsFor = ItemDetails, ItemDepositOf, ApprovalsOf>; pub(super) type AttributeNamespaceOf = AttributeNamespace>; +pub(super) type CreateCollectionConfigFor = + CreateCollectionConfig, BlockNumberFor, CollectionIdOf>; + +#[derive(Clone, Copy, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct CreateCollectionConfig { + pub max_supply: Option, + pub mint_type: MintType, + pub price: Option, + pub start_block: Option, + pub end_block: Option, +} diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 05696fee..6d71c1a2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -171,7 +171,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(crate) fn do_approve_transfer_collection( + pub(crate) fn do_approve_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, @@ -204,7 +204,7 @@ impl, I: 'static> Pallet { Ok(()) } - pub(crate) fn do_cancel_approval_collection( + pub(crate) fn do_cancel_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 2ea5cd73..b7efd03a 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -137,8 +137,10 @@ impl, I: 'static> Pallet { } } + // TODO: Do we need another storage item to keep track of number of holders of a + // collection let _ = - AccountBalance::::clear_prefix((collection,), collection_details.items, None); + AccountBalance::::clear_prefix(collection, collection_details.items, None); let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 036a63b7..cc29f8da 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,7 +69,7 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); - AccountBalance::::mutate((collection, &mint_to), |balance| { + AccountBalance::::mutate(collection, &mint_to, |balance| { balance.saturating_inc(); }); @@ -266,7 +266,7 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); ItemAttributesApprovalsOf::::remove(&collection, &item); - AccountBalance::::mutate((collection, &owner), |balance| { + AccountBalance::::mutate(collection, &owner, |balance| { balance.saturating_dec(); }); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 04d9f4fe..3b25b014 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -88,10 +88,10 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balances. - AccountBalance::::mutate((collection, &details.owner), |balance| { + AccountBalance::::mutate(collection, &details.owner, |balance| { balance.saturating_dec(); }); - AccountBalance::::mutate((collection, &dest), |balance| { + AccountBalance::::mutate(collection, &dest, |balance| { balance.saturating_inc(); }); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index c7d826b5..bc8b67b6 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -404,14 +404,12 @@ pub mod pallet { /// Number of collection items that accounts own. #[pallet::storage] - pub type AccountBalance, I: 'static = ()> = StorageNMap< + pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< _, - ( - // Collection Id. - NMapKey, - // Collection Owner Id. - NMapKey, - ), + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, u32, ValueQuery, >; @@ -1333,8 +1331,7 @@ pub mod pallet { delegate, maybe_deadline, ), - None => - Self::do_approve_transfer_collection(maybe_check_origin, collection, delegate), + None => Self::do_approve_collection(maybe_check_origin, collection, delegate), } } @@ -1367,8 +1364,7 @@ pub mod pallet { match maybe_item { Some(item) => Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), - None => - Self::do_cancel_approval_collection(maybe_check_origin, collection, delegate), + None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), } } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 10c95bd6..397a715c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,7 +164,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -174,7 +174,7 @@ fn basic_minting_should_work() { )); assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); - assert_eq!(AccountBalance::::get((1, account(1))), 1); + assert_eq!(AccountBalance::::get(1, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } @@ -206,7 +206,7 @@ fn lifecycle_should_work() { account(10), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(10))), 1); + assert_eq!(AccountBalance::::get(0, account(10)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 6); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), @@ -215,10 +215,10 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(20))), 1); + assert_eq!(AccountBalance::::get(0, account(20)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 7); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); @@ -226,8 +226,8 @@ fn lifecycle_should_work() { assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); - assert_eq!(AccountBalance::::get((0, account(1))), 0); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 0); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -245,7 +245,7 @@ fn lifecycle_should_work() { Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), Error::::CollectionNotEmpty ); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(account(1)), @@ -256,9 +256,9 @@ fn lifecycle_should_work() { bvec![0], )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); - assert_eq!(AccountBalance::::get((0, account(10))), 0); + assert_eq!(AccountBalance::::get(0, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert_eq!(AccountBalance::::get((0, account(10))), 0); + assert_eq!(AccountBalance::::get(0, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -266,7 +266,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -316,7 +316,14 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + None, + account(3), + None + )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -335,7 +342,8 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - assert_eq!(AccountBalance::::get((0, account(1))), 0); + assert_eq!(AccountBalance::::iter_prefix(0).count(), 0); + assert_eq!(Allowances::::iter_prefix((0,)).count(), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -350,7 +358,7 @@ fn mint_should_work() { default_collection_config() )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - assert_eq!(AccountBalance::::get((0, account(1))), 1); + assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -416,7 +424,7 @@ fn mint_should_work() { account(2), Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); - assert_eq!(AccountBalance::::get((0, account(2))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -455,7 +463,7 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); - assert_eq!(AccountBalance::::get((1, account(2))), 1); + assert_eq!(AccountBalance::::get(1, account(2)), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -494,8 +502,8 @@ fn transfer_should_work() { )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); - assert_eq!(AccountBalance::::get((0, account(2))), 0); - assert_eq!(AccountBalance::::get((0, account(3))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(AccountBalance::::get(0, account(3)), 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -510,9 +518,9 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - assert_eq!(AccountBalance::::get((0, account(2))), 0); - assert_eq!(AccountBalance::::get((0, account(3))), 0); - assert_eq!(AccountBalance::::get((0, account(4))), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(AccountBalance::::get(0, account(3)), 0); + assert_eq!(AccountBalance::::get(0, account(4)), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1766,7 +1774,7 @@ fn burn_works() { account(5), default_item_config() )); - assert_eq!(AccountBalance::::get((0, account(5))), 2); + assert_eq!(AccountBalance::::get(0, account(5)), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1774,9 +1782,9 @@ fn burn_works() { Error::::NoPermission ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); - assert_eq!(AccountBalance::::get((0, account(5))), 1); + assert_eq!(AccountBalance::::get(0, account(5)), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); - assert_eq!(AccountBalance::::get((0, account(5))), 0); + assert_eq!(AccountBalance::::get(0, account(5)), 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2755,7 +2763,7 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 1); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -3123,8 +3131,8 @@ fn claim_swap_should_work() { default_item_config(), )); - assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); + assert_eq!(AccountBalance::::get(collection_id, user_1.clone()), 2); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 3); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3215,8 +3223,8 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); - assert_eq!(AccountBalance::::get((collection_id, user_1.clone())), 2); - assert_eq!(AccountBalance::::get((collection_id, user_2.clone())), 3); + assert_eq!(AccountBalance::::get(collection_id, user_1.clone()), 2); + assert_eq!(AccountBalance::::get(collection_id, user_2.clone()), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); From 9096b3f705ea996798e323c8ed85b69c2916757f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:04:01 +0700 Subject: [PATCH 48/64] refactor(nfts): toml lock file --- Cargo.lock | 20 ++++++++++---------- pallets/nfts/Cargo.toml | 3 +-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48f7b34c..71903ca0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -8240,39 +8240,39 @@ dependencies = [ [[package]] name = "pallet-nfts" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" +version = "0.1.0" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", - "sp-std", ] [[package]] name = "pallet-nfts" -version = "31.0.0" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-keystore", "sp-runtime", + "sp-std", ] [[package]] @@ -10857,7 +10857,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -11002,7 +11002,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 31.0.0", + "pallet-nfts 0.1.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 791db0a7..722e8ef8 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -6,8 +6,7 @@ homepage = "https://substrate.io" license.workspace = true name = "pallet-nfts" readme = "README.md" -repository.workspace = true -version = "31.0.0" +version = "0.1.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From 43349448c026c07626d8d7ea3f9745bb507251ff Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:06:00 +0700 Subject: [PATCH 49/64] fix(pallet-api): propagate try-runtime feature --- pallets/api/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/api/Cargo.toml b/pallets/api/Cargo.toml index 5d398724..31ccc076 100644 --- a/pallets/api/Cargo.toml +++ b/pallets/api/Cargo.toml @@ -60,5 +60,6 @@ std = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-nfts/try-runtime", "sp-runtime/try-runtime", ] From a38fc47df3478162068fa290a271d23095cd27a6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:36:29 +0700 Subject: [PATCH 50/64] fix(api/nonfungibles): unit tests --- pallets/api/src/nonfungibles/mod.rs | 4 +- pallets/api/src/nonfungibles/tests.rs | 407 ++++++++++++++------------ 2 files changed, 225 insertions(+), 186 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index efef2386..9655bbea 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -72,7 +72,7 @@ pub mod pallet { #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { - TotalSupply(u128), + TotalSupply(u32), BalanceOf(u32), Allowance(bool), OwnerOf(Option>), @@ -390,7 +390,7 @@ pub mod pallet { use Read::*; match value { TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default().into(), + NftsOf::::collection_items(collection).unwrap_or_default(), ), BalanceOf { collection, owner } => ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 54d85516..d757508a 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,184 +1,223 @@ -// TODO -// use codec::Encode; -// use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; -// use frame_system::pallet_prelude::BlockNumberFor; -// use pallet_nfts::{CollectionConfig, CollectionSettings, MintSettings}; - -// use super::types::*; -// use crate::{ -// mock::*, -// nonfungibles::{Event, Read::*}, -// }; - -// const ITEM: u32 = 1; - -// #[test] -// fn mint_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let collection = create_collection(owner.clone()); -// // Successfully mint a new collection item. -// assert_ok!(NonFungibles::mint(signed(owner.clone()), owner.clone(), collection, ITEM)); -// System::assert_last_event(Event::Mint { to: owner, collection, item: ITEM }.into()); -// }); -// } - -// #[test] -// fn burn_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully burn an existing new collection item. -// assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); -// System::assert_last_event(Event::Burn { collection, item }.into()); -// }); -// } - -// #[test] -// fn transfer() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let dest = account(BOB); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully burn an existing new collection item. -// assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); -// System::assert_last_event( -// Event::Transfer { collection, item, from: owner, to: dest }.into(), -// ); -// }); -// } - -// #[test] -// fn approve_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = create_collection_mint(owner.clone(), ITEM); -// // Successfully approve `spender` to transfer the collection item. -// assert_ok!(NonFungibles::approve(signed(owner.clone()), collection, item, spender.clone())); -// System::assert_last_event( -// Event::Approval { collection, item, owner, spender: spender.clone() }.into(), -// ); -// // Successfully transfer the item by the delegated account `spender`. -// assert_ok!(Nfts::transfer(signed(spender.clone()), collection, item, spender)); -// }); -// } - -// #[test] -// fn cancel_approval_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = -// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); -// // Successfully cancel the transfer approval of `spender` by `owner`. -// assert_ok!(NonFungibles::cancel_approval(signed(owner), collection, item, spender.clone())); -// // Failed to transfer the item by `spender` without permission. -// assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); -// }); -// } - -// #[test] -// fn owner_of_works() {} - -// #[test] -// fn collection_owner_works() { -// new_test_ext().execute_with(|| { -// let collection = create_collection(account(ALICE)); -// assert_eq!( -// NonFungibles::read_state(CollectionOwner(collection)), -// Nfts::collection_owner(collection).encode() -// ); -// }); -// } - -// #[test] -// fn total_supply_works() { -// new_test_ext().execute_with(|| { -// let (collection, _) = create_collection_mint(account(ALICE), ITEM); -// assert_eq!( -// NonFungibles::read_state(TotalSupply(collection)), -// (Nfts::items(&collection).count() as u8).encode() -// ); -// }); -// } - -// #[test] -// fn collection_works() { -// new_test_ext().execute_with(|| { -// let (collection, _) = create_collection_mint(account(ALICE), ITEM); -// assert_eq!( -// NonFungibles::read_state(Collection(collection)), -// pallet_nfts::Collection::::get(&collection).encode(), -// ); -// }); -// } - -// #[test] -// fn balance_of_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let (collection, _) = create_collection_mint(owner.clone(), ITEM); -// assert_eq!( -// NonFungibles::read_state(BalanceOf { collection, owner: owner.clone() }), -// (Nfts::owned_in_collection(&collection, &owner).count() as u8).encode() -// ); -// }); -// } - -// #[test] -// fn allowance_works() { -// new_test_ext().execute_with(|| { -// let owner = account(ALICE); -// let spender = account(BOB); -// let (collection, item) = -// create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); -// assert_eq!( -// NonFungibles::read_state(Allowance { spender: spender.clone(), collection, item }), -// super::Pallet::::allowance(collection, item, spender).encode() -// ); -// }); -// } - -// fn signed(account: AccountId) -> RuntimeOrigin { -// RuntimeOrigin::signed(account) -// } - -// fn create_collection_mint_and_approve( -// owner: AccountIdOf, -// item: ItemIdOf, -// spender: AccountIdOf, -// ) -> (u32, u32) { -// let (collection, item) = create_collection_mint(owner.clone(), item); -// assert_ok!(Nfts::approve_transfer(signed(owner), collection, item, spender, None)); -// (collection, item) -// } - -// fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { -// let collection = create_collection(owner.clone()); -// assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); -// (collection, item) -// } - -// fn create_collection(owner: AccountIdOf) -> u32 { -// let next_id = next_collection_id(); -// assert_ok!(Nfts::create( -// signed(owner.clone()), -// owner.clone(), -// collection_config_with_all_settings_enabled() -// )); -// next_id -// } - -// fn next_collection_id() -> u32 { -// pallet_nfts::NextCollectionId::::get().unwrap_or_default() -// } - -// fn collection_config_with_all_settings_enabled( -// ) -> CollectionConfig, CollectionIdOf> { -// CollectionConfig { -// settings: CollectionSettings::all_enabled(), -// max_supply: None, -// mint_settings: MintSettings::default(), -// } -// } +use codec::Encode; +use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; + +use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; +use crate::{ + mock::*, + nonfungibles::{Event, Read::*}, + Read, +}; + +const ITEM: u32 = 1; + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let collection = create_collection(owner.clone()); + // Successfully mint a new collection item. + assert_ok!(NonFungibles::mint( + signed(owner.clone()), + owner.clone(), + collection, + ITEM, + None + )); + System::assert_last_event( + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), value: None } + .into(), + ); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + System::assert_last_event( + Event::Transfer { collection, item, from: Some(owner), to: None, value: None }.into(), + ); + }); +} + +#[test] +fn transfer() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let dest = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully burn an existing new collection item. + assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + System::assert_last_event( + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), value: None } + .into(), + ); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let operator = account(BOB); + let (collection, item) = create_collection_mint(owner.clone(), ITEM); + // Successfully approve `spender` to transfer the collection item. + assert_ok!(NonFungibles::approve( + signed(owner.clone()), + collection, + Some(item), + operator.clone(), + true + )); + System::assert_last_event( + Event::Approval { + collection, + item: Some(item), + owner, + operator: operator.clone(), + approved: true, + } + .into(), + ); + // Successfully transfer the item by the delegated account `spender`. + assert_ok!(Nfts::transfer(signed(operator.clone()), collection, item, operator)); + }); +} + +#[test] +fn cancel_approval_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let spender = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); + // Successfully cancel the transfer approval of `spender` by `owner`. + assert_ok!(NonFungibles::approve( + signed(owner), + collection, + Some(item), + spender.clone(), + false + )); + // Failed to transfer the item by `spender` without permission. + assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + }); +} + +#[test] +fn owner_of_works() {} + +#[test] +fn collection_owner_works() { + new_test_ext().execute_with(|| { + let collection = create_collection(account(ALICE)); + assert_eq!( + NonFungibles::read(CollectionOwner(collection)).encode(), + Nfts::collection_owner(collection).encode() + ); + }); +} + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + Nfts::collection_items(collection).unwrap_or_default().encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = create_collection_mint(account(ALICE), ITEM); + assert_eq!( + NonFungibles::read(Collection(collection)).encode(), + pallet_nfts::Collection::::get(&collection).encode(), + ); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let (collection, _) = create_collection_mint(owner.clone(), ITEM); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: owner.clone() }).encode(), + AccountBalance::::get(collection, owner).encode() + ); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let owner = account(ALICE); + let operator = account(BOB); + let (collection, item) = + create_collection_mint_and_approve(owner.clone(), ITEM, operator.clone()); + assert_eq!( + NonFungibles::read(Allowance { + collection, + item: Some(item), + owner: owner.clone(), + operator: operator.clone(), + }) + .encode(), + Nfts::check_allowance(&collection, &Some(item), &owner, &operator) + .is_ok() + .encode() + ); + }); +} + +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) +} + +fn create_collection_mint_and_approve( + owner: AccountIdOf, + item: ItemIdOf, + spender: AccountIdOf, +) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner.clone(), item); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), spender, None)); + (collection, item) +} + +fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner.clone()); + assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); + (collection, item) +} + +fn create_collection(owner: AccountIdOf) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner.clone()), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + next_id +} + +fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() +} + +fn collection_config_with_all_settings_enabled( +) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} From a1f446816566bfba4574a9f754c9f110c8f8b8db Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:15:11 +0700 Subject: [PATCH 51/64] test(api/nonfungibles): encoding_read_result --- pallets/api/src/nonfungibles/mod.rs | 10 +-- pallets/api/src/nonfungibles/tests.rs | 109 ++++++++++++++++++++++++-- pallets/nfts/src/types.rs | 22 +++--- 3 files changed, 120 insertions(+), 21 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 9655bbea..eb88bfa6 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -137,8 +137,8 @@ pub mod pallet { from: Option>, /// The recipient of the transfer. `None` when burning. to: Option>, - /// The amount minted. - value: Option>, + /// The price of the collection item. + price: Option>, }, } @@ -167,7 +167,7 @@ pub mod pallet { item, from: None, to: Some(account), - value: mint_price, + price: mint_price, }); Ok(()) } @@ -186,7 +186,7 @@ pub mod pallet { item, from: Some(account), to: None, - value: None, + price: None, }); Ok(()) } @@ -206,7 +206,7 @@ pub mod pallet { item, from: Some(from), to: Some(to), - value: None, + price: None, }); Ok(()) } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index d757508a..063ceee3 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,23 +1,119 @@ use codec::Encode; -use frame_support::{assert_ok, traits::nonfungibles_v2::InspectEnumerable}; +use frame_support::assert_ok; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; use crate::{ mock::*, - nonfungibles::{Event, Read::*}, + nonfungibles::{Event, Read::*, ReadResult}, Read, }; const ITEM: u32 = 1; +mod encoding_read_result { + use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; + use sp_runtime::{BoundedBTreeMap, BoundedVec}; + + use super::*; + + #[test] + fn total_supply() { + let total_supply: u32 = 1_000_000; + assert_eq!(ReadResult::TotalSupply::(total_supply).encode(), total_supply.encode()); + } + + #[test] + fn balance_of() { + let balance: u32 = 100; + assert_eq!(ReadResult::BalanceOf::(balance).encode(), balance.encode()); + } + + #[test] + fn allowance() { + let allowance = false; + assert_eq!(ReadResult::Allowance::(allowance).encode(), allowance.encode()); + } + + #[test] + fn owner_of() { + let mut owner = Some(account(ALICE)); + assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); + owner = None; + assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); + } + + #[test] + fn get_attribute() { + let mut attribute = Some(BoundedVec::truncate_from("some attribute".as_bytes().to_vec())); + assert_eq!( + ReadResult::GetAttribute::(attribute.clone()).encode(), + attribute.encode() + ); + attribute = None; + assert_eq!( + ReadResult::GetAttribute::(attribute.clone()).encode(), + attribute.encode() + ); + } + + #[test] + fn collection_owner() { + let mut collection_owner = Some(account(ALICE)); + assert_eq!( + ReadResult::CollectionOwner::(collection_owner.clone()).encode(), + collection_owner.encode() + ); + collection_owner = None; + assert_eq!( + ReadResult::CollectionOwner::(collection_owner.clone()).encode(), + collection_owner.encode() + ); + } + + #[test] + fn collection() { + let mut collection_details = Some(CollectionDetails { + owner: account(ALICE), + owner_deposit: 0, + items: 0, + item_metadatas: 0, + item_configs: 0, + attributes: 0, + }); + assert_eq!( + ReadResult::Collection::(collection_details.clone()).encode(), + collection_details.encode() + ); + collection_details = None; + assert_eq!( + ReadResult::Collection::(collection_details.clone()).encode(), + collection_details.encode() + ); + } + + #[test] + fn item() { + let mut item_details = Some(ItemDetails { + owner: account(ALICE), + approvals: BoundedBTreeMap::default(), + deposit: ItemDeposit { amount: 0, account: account(BOB) }, + }); + assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); + item_details = None; + assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); + } +} + #[test] fn mint_works() { new_test_ext().execute_with(|| { let owner = account(ALICE); let collection = create_collection(owner.clone()); // Successfully mint a new collection item. + let balance_before_mint = AccountBalance::::get(collection.clone(), owner.clone()); + // assert_ok!(NonFungibles::mint( signed(owner.clone()), owner.clone(), @@ -25,8 +121,11 @@ fn mint_works() { ITEM, None )); + let balance_after_mint = AccountBalance::::get(collection.clone(), owner.clone()); + assert_eq!(balance_after_mint, 1); + assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), value: None } + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } .into(), ); }); @@ -40,7 +139,7 @@ fn burn_works() { // Successfully burn an existing new collection item. assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: None, value: None }.into(), + Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); }); } @@ -54,7 +153,7 @@ fn transfer() { // Successfully burn an existing new collection item. assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: Some(dest), value: None } + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } .into(), ); }); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index f08f1d09..061352c0 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,18 +94,18 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Collection's owner. - pub(super) owner: AccountId, + pub owner: AccountId, /// The total balance deposited by the owner for all the storage data associated with this /// collection. Used by `destroy`. - pub(super) owner_deposit: DepositBalance, + pub owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub(super) items: u32, + pub items: u32, /// The total number of outstanding item metadata of this collection. - pub(super) item_metadatas: u32, + pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. - pub(super) item_configs: u32, + pub item_configs: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + pub attributes: u32, } /// Witness data for the destroy transactions. @@ -145,21 +145,21 @@ pub struct MintWitness { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountId, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approvals: Approvals, + pub approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: Deposit, + pub deposit: Deposit, } /// Information about the reserved item deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub(super) account: AccountId, + pub account: AccountId, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + pub amount: DepositBalance, } /// Information about the collection's metadata. From 80b378e2fe5b0e12ae27b1f9ebb34ebc62987574 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:51:50 +0700 Subject: [PATCH 52/64] refactor(api/nonfungibles): pallet tests --- pallets/api/src/nonfungibles/tests.rs | 243 +++++++++++++++----------- 1 file changed, 143 insertions(+), 100 deletions(-) diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 063ceee3..05c82f60 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,7 +1,11 @@ use codec::Encode; -use frame_support::assert_ok; +use frame_support::{assert_noop, assert_ok}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AccountBalance, CollectionConfig, CollectionSettings, MintSettings}; +use pallet_nfts::{ + AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, + ItemDetails, MintSettings, +}; +use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; use crate::{ @@ -12,10 +16,9 @@ use crate::{ const ITEM: u32 = 1; -mod encoding_read_result { - use pallet_nfts::{CollectionDetails, ItemDeposit, ItemDetails}; - use sp_runtime::{BoundedBTreeMap, BoundedVec}; +type NftsError = pallet_nfts::Error; +mod encoding_read_result { use super::*; #[test] @@ -107,53 +110,72 @@ mod encoding_read_result { } #[test] -fn mint_works() { +fn transfer() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let collection = create_collection(owner.clone()); - // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection.clone(), owner.clone()); - // - assert_ok!(NonFungibles::mint( - signed(owner.clone()), - owner.clone(), - collection, - ITEM, - None - )); - let balance_after_mint = AccountBalance::::get(collection.clone(), owner.clone()); - assert_eq!(balance_after_mint, 1); - assert_eq!(balance_after_mint - balance_before_mint, 1); + let owner = ALICE; + let dest = BOB; + + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + for origin in vec![root(), none()] { + assert_noop!( + NonFungibles::transfer(origin, collection, item, account(dest)), + BadOrigin + ); + } + // Successfully burn an existing new collection item. + let balance_before_transfer = AccountBalance::::get(collection, &account(dest)); + assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, account(dest))); + let balance_after_transfer = AccountBalance::::get(collection, &account(dest)); + assert_eq!(AccountBalance::::get(collection, &account(owner)), 0); + assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( - Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } - .into(), + Event::Transfer { + collection, + item, + from: Some(account(owner)), + to: Some(account(dest)), + price: None, + } + .into(), ); }); } #[test] -fn burn_works() { +fn mint_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::burn(signed(owner.clone()), collection, ITEM)); + let owner = ALICE; + let collection = nfts::create_collection(owner); + + // Successfully mint a new collection item. + let balance_before_mint = AccountBalance::::get(collection, account(owner)); + assert_ok!(NonFungibles::mint(signed(owner), account(owner), collection, ITEM, None)); + let balance_after_mint = AccountBalance::::get(collection, account(owner)); + assert_eq!(balance_after_mint, 1); + assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), + Event::Transfer { + collection, + item: ITEM, + from: None, + to: Some(account(owner)), + price: None, + } + .into(), ); }); } #[test] -fn transfer() { +fn burn_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let dest = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); + let owner = ALICE; + // Successfully burn an existing new collection item. - assert_ok!(NonFungibles::transfer(signed(owner.clone()), collection, ITEM, dest.clone())); + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } + Event::Transfer { collection, item, from: Some(account(owner)), to: None, price: None } .into(), ); }); @@ -162,59 +184,63 @@ fn transfer() { #[test] fn approve_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let operator = account(BOB); - let (collection, item) = create_collection_mint(owner.clone(), ITEM); - // Successfully approve `spender` to transfer the collection item. + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully approve `oeprator` to transfer the collection item. assert_ok!(NonFungibles::approve( - signed(owner.clone()), + signed(owner), collection, Some(item), - operator.clone(), + account(operator), true )); System::assert_last_event( Event::Approval { collection, item: Some(item), - owner, - operator: operator.clone(), + owner: account(owner), + operator: account(operator), approved: true, } .into(), ); - // Successfully transfer the item by the delegated account `spender`. - assert_ok!(Nfts::transfer(signed(operator.clone()), collection, item, operator)); + // Successfully transfer the item by the delegated account `operator`. + assert_ok!(Nfts::transfer(signed(operator), collection, item, account(operator))); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let spender = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, spender.clone()); - // Successfully cancel the transfer approval of `spender` by `owner`. + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); + // Successfully cancel the transfer approval of `operator` by `owner`. assert_ok!(NonFungibles::approve( signed(owner), collection, Some(item), - spender.clone(), + account(operator), false )); - // Failed to transfer the item by `spender` without permission. - assert!(Nfts::transfer(signed(spender.clone()), collection, item, spender).is_err()); + // Failed to transfer the item by `operator` without permission. + assert_noop!( + Nfts::transfer(signed(operator), collection, item, account(operator)), + NftsError::NoPermission + ); }); } #[test] -fn owner_of_works() {} +fn owner_of_works() { + unimplemented!() +} #[test] fn collection_owner_works() { new_test_ext().execute_with(|| { - let collection = create_collection(account(ALICE)); + let collection = nfts::create_collection(ALICE); assert_eq!( NonFungibles::read(CollectionOwner(collection)).encode(), Nfts::collection_owner(collection).encode() @@ -225,7 +251,7 @@ fn collection_owner_works() { #[test] fn total_supply_works() { new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(TotalSupply(collection)).encode(), Nfts::collection_items(collection).unwrap_or_default().encode() @@ -236,7 +262,7 @@ fn total_supply_works() { #[test] fn collection_works() { new_test_ext().execute_with(|| { - let (collection, _) = create_collection_mint(account(ALICE), ITEM); + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(Collection(collection)).encode(), pallet_nfts::Collection::::get(&collection).encode(), @@ -247,11 +273,11 @@ fn collection_works() { #[test] fn balance_of_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let (collection, _) = create_collection_mint(owner.clone(), ITEM); + let owner = ALICE; + let (collection, _) = nfts::create_collection_mint(owner, ITEM); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: owner.clone() }).encode(), - AccountBalance::::get(collection, owner).encode() + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + AccountBalance::::get(collection, account(owner)).encode() ); }); } @@ -259,64 +285,81 @@ fn balance_of_works() { #[test] fn allowance_works() { new_test_ext().execute_with(|| { - let owner = account(ALICE); - let operator = account(BOB); - let (collection, item) = - create_collection_mint_and_approve(owner.clone(), ITEM, operator.clone()); + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( NonFungibles::read(Allowance { collection, item: Some(item), - owner: owner.clone(), - operator: operator.clone(), + owner: account(owner), + operator: account(operator), }) .encode(), - Nfts::check_allowance(&collection, &Some(item), &owner, &operator) + Nfts::check_allowance(&collection, &Some(item), &account(owner), &account(operator)) .is_ok() .encode() ); }); } -fn signed(account: AccountId) -> RuntimeOrigin { - RuntimeOrigin::signed(account) +fn signed(account_id: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(account(account_id)) } -fn create_collection_mint_and_approve( - owner: AccountIdOf, - item: ItemIdOf, - spender: AccountIdOf, -) -> (u32, u32) { - let (collection, item) = create_collection_mint(owner.clone(), item); - assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), spender, None)); - (collection, item) +fn root() -> RuntimeOrigin { + RuntimeOrigin::root() } -fn create_collection_mint(owner: AccountIdOf, item: ItemIdOf) -> (u32, u32) { - let collection = create_collection(owner.clone()); - assert_ok!(Nfts::mint(signed(owner.clone()), collection, item, owner, None)); - (collection, item) +fn none() -> RuntimeOrigin { + RuntimeOrigin::none() } -fn create_collection(owner: AccountIdOf) -> u32 { - let next_id = next_collection_id(); - assert_ok!(Nfts::create( - signed(owner.clone()), - owner.clone(), - collection_config_with_all_settings_enabled() - )); - next_id -} +mod nfts { + use super::*; -fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() -} + pub(super) fn create_collection_mint_and_approve( + owner: u8, + item: ItemIdOf, + operator: u8, + ) -> (u32, u32) { + let (collection, item) = create_collection_mint(owner, item); + assert_ok!(Nfts::approve_transfer( + signed(owner), + collection, + Some(item), + account(operator), + None + )); + (collection, item) + } + + pub(super) fn create_collection_mint(owner: u8, item: ItemIdOf) -> (u32, u32) { + let collection = create_collection(owner); + assert_ok!(Nfts::mint(signed(owner), collection, item, account(owner), None)); + (collection, item) + } + + pub(super) fn create_collection(owner: u8) -> u32 { + let next_id = next_collection_id(); + assert_ok!(Nfts::create( + signed(owner), + account(owner), + collection_config_with_all_settings_enabled() + )); + next_id + } + + pub(super) fn next_collection_id() -> u32 { + pallet_nfts::NextCollectionId::::get().unwrap_or_default() + } -fn collection_config_with_all_settings_enabled( -) -> CollectionConfig, CollectionIdOf> { - CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: None, - mint_settings: MintSettings::default(), + pub(super) fn collection_config_with_all_settings_enabled( + ) -> CollectionConfig, CollectionIdOf> { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } } } From f3e7e4a414aed1ec7406ae6f8cf82048eb514a03 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:30:10 +0700 Subject: [PATCH 53/64] test(nonfungibles): add tests and remove collection owner read --- pallets/api/src/nonfungibles/mod.rs | 70 ++++--- pallets/api/src/nonfungibles/tests.rs | 267 +++++++++++++++++++++++--- pallets/api/src/nonfungibles/types.rs | 2 + 3 files changed, 286 insertions(+), 53 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index eb88bfa6..7377048f 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -12,7 +12,7 @@ mod types; #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::Incrementable}; use frame_system::pallet_prelude::*; use pallet_nfts::{ CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, @@ -21,7 +21,8 @@ pub mod pallet { use sp_std::vec::Vec; use types::{ AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NftsOf, NftsWeightInfoOf, + CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NextCollectionIdOf, + NftsOf, NftsWeightInfoOf, }; use super::*; @@ -32,54 +33,62 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Number of items existing in a concrete collection. - #[codec(index = 2)] + /// Total item supply of a collection. + #[codec(index = 0)] TotalSupply(CollectionIdOf), - /// Returns the total number of items in the collection owned by the account. - #[codec(index = 3)] + /// Account balance for a specified collection. + #[codec(index = 1)] BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, - /// Whether a spender is allowed to transfer an item or items from owner. - #[codec(index = 6)] + /// Allowance for an operator approved by an owner, for a specified collection or item. + #[codec(index = 2)] Allowance { collection: CollectionIdOf, owner: AccountIdOf, operator: AccountIdOf, item: Option>, }, - /// Returns the owner of an item. - #[codec(index = 0)] + /// Owner of a specified collection item. + #[codec(index = 3)] OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Returns the attribute of `item` for the given `key`. - #[codec(index = 6)] + /// Attribute value of a collection item. + #[codec(index = 4)] GetAttribute { collection: CollectionIdOf, item: Option>, namespace: AttributeNamespaceOf, key: BoundedVec, }, - /// Returns the owner of a collection. - #[codec(index = 1)] - CollectionOwner(CollectionIdOf), - /// Returns the details of a collection. - #[codec(index = 4)] + /// Details of a collection. + #[codec(index = 6)] Collection(CollectionIdOf), - /// Returns the details of an item. - #[codec(index = 5)] + /// Details of a collection item. + #[codec(index = 7)] Item { collection: CollectionIdOf, item: ItemIdOf }, + /// Next collection ID. + #[codec(index = 8)] + NextCollectionId, } /// Results of state reads for the non-fungibles API. #[derive(Debug)] #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { + /// Total item supply of a collection. TotalSupply(u32), + /// Account balance for a specified collection. BalanceOf(u32), + /// Allowance for an operator approved by an owner, for a specified collection or item. Allowance(bool), + /// Owner of a specified collection owner. OwnerOf(Option>), + /// Attribute value of a collection item. GetAttribute(Option>), - CollectionOwner(Option>), + /// Details of a collection. Collection(Option>), + /// Details of a collection item. Item(Option>), + /// Next collection ID. + NextCollectionId(Option>), } impl ReadResult { @@ -88,13 +97,13 @@ pub mod pallet { use ReadResult::*; match self { OwnerOf(result) => result.encode(), - CollectionOwner(result) => result.encode(), TotalSupply(result) => result.encode(), BalanceOf(result) => result.encode(), Collection(result) => result.encode(), Item(result) => result.encode(), Allowance(result) => result.encode(), GetAttribute(result) => result.encode(), + NextCollectionId(result) => result.encode(), } } } @@ -140,6 +149,15 @@ pub mod pallet { /// The price of the collection item. price: Option>, }, + /// Event emitted when a collection is created. + Created { + /// The collection identifier. + id: CollectionIdOf, + /// The creator of the collection. + creator: AccountIdOf, + /// The administrator of the collection. + admin: AccountIdOf, + }, } #[pallet::call] @@ -248,6 +266,10 @@ pub mod pallet { admin: AccountIdOf, config: CreateCollectionConfigFor, ) -> DispatchResult { + let id = NextCollectionIdOf::::get() + .or(T::CollectionId::initial_value()) + .ok_or(pallet_nfts::Error::::UnknownCollection)?; + let creator = ensure_signed(origin.clone())?; let collection_config = CollectionConfig { settings: CollectionSettings::all_enabled(), max_supply: config.max_supply, @@ -259,6 +281,7 @@ pub mod pallet { }, }; NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } @@ -403,12 +426,13 @@ pub mod pallet { pallet_nfts::Attribute::::get((collection, item, namespace, key)) .map(|attribute| attribute.0), ), - CollectionOwner(collection) => - ReadResult::CollectionOwner(NftsOf::::collection_owner(collection)), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), Item { collection, item } => ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + NextCollectionId => ReadResult::NextCollectionId( + NextCollectionIdOf::::get().or(T::CollectionId::initial_value()), + ), } } } diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 05c82f60..e89ba0bd 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,5 +1,5 @@ use codec::Encode; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, traits::Incrementable}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{ AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, @@ -7,7 +7,7 @@ use pallet_nfts::{ }; use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; -use super::types::{AccountIdOf, CollectionIdOf, ItemIdOf}; +use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ mock::*, nonfungibles::{Event, Read::*, ReadResult}, @@ -61,20 +61,6 @@ mod encoding_read_result { ); } - #[test] - fn collection_owner() { - let mut collection_owner = Some(account(ALICE)); - assert_eq!( - ReadResult::CollectionOwner::(collection_owner.clone()).encode(), - collection_owner.encode() - ); - collection_owner = None; - assert_eq!( - ReadResult::CollectionOwner::(collection_owner.clone()).encode(), - collection_owner.encode() - ); - } - #[test] fn collection() { let mut collection_details = Some(CollectionDetails { @@ -107,6 +93,20 @@ mod encoding_read_result { item_details = None; assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); } + + #[test] + fn next_collection_id_works() { + let mut next_collection_id = Some(0); + assert_eq!( + ReadResult::NextCollectionId::(next_collection_id).encode(), + next_collection_id.encode() + ); + next_collection_id = None; + assert_eq!( + ReadResult::NextCollectionId::(next_collection_id).encode(), + next_collection_id.encode() + ); + } } #[test] @@ -232,33 +232,212 @@ fn cancel_approval_works() { }); } +#[test] +fn set_max_supply_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + assert_ok!(NonFungibles::set_max_supply(signed(owner), collection, 10)); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + }); + assert_noop!( + Nfts::mint(signed(owner), collection, 42, account(owner), None), + NftsError::MaxSupplyReached + ); + }); +} + #[test] fn owner_of_works() { - unimplemented!() + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(OwnerOf { collection, item }).encode(), + Nfts::owner(collection, item).encode() + ); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // No attribute set. + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute.clone() + }) + .encode(), + result.encode() + ); + // Successfully get an existing attribute. + result = Some(value.clone()); + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + value, + )); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute + }) + .encode(), + result.encode() + ); + }); } #[test] -fn collection_owner_works() { +fn clear_attribute_works() { new_test_ext().execute_with(|| { - let collection = nfts::create_collection(ALICE); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + BoundedVec::truncate_from("some value".as_bytes().to_vec()) + )); + // Successfully clear an attribute. + assert_ok!(Nfts::clear_attribute( + signed(ALICE), + collection, + Some(item), + pallet_nfts::AttributeNamespace::CollectionOwner, + attribute.clone(), + )); assert_eq!( - NonFungibles::read(CollectionOwner(collection)).encode(), - Nfts::collection_owner(collection).encode() + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: attribute + }) + .encode(), + result.encode() ); }); } #[test] -fn total_supply_works() { +fn approve_item_attribute_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // Successfully approve delegate to set attributes. + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + )); + result = Some(value); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item: Some(item), + namespace: pallet_nfts::AttributeNamespace::Account(account(BOB)), + key: attribute + }) + .encode(), + result.encode() + ); + }); +} + +#[test] +fn cancel_item_attribute_approval_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); + let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); + let mut result: Option::ValueLimit>> = None; + // Successfully approve delegate to set attributes. + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + )); + assert_ok!(Nfts::cancel_item_attributes_approval( + signed(ALICE), + collection, + item, + account(BOB), + pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } + )); + assert_noop!( + Nfts::set_attribute( + signed(BOB), + collection, + Some(item), + pallet_nfts::AttributeNamespace::Account(account(BOB)), + attribute.clone(), + value.clone() + ), + NftsError::NoPermission + ); + }); +} + +#[test] +fn next_collection_id_works() { + new_test_ext().execute_with(|| { + let _ = nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - Nfts::collection_items(collection).unwrap_or_default().encode() + NonFungibles::read(NextCollectionId).encode(), + pallet_nfts::NextCollectionId::::get() + .or(CollectionIdOf::::initial_value()) + .encode(), ); }); } +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_eq!(NonFungibles::read(TotalSupply(collection)).encode(), (i + 1).encode()); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + Nfts::collection_items(collection).unwrap_or_default().encode() + ); + }); + }); +} + #[test] fn collection_works() { new_test_ext().execute_with(|| { @@ -271,23 +450,51 @@ fn collection_works() { } #[test] -fn balance_of_works() { +fn item_works() { new_test_ext().execute_with(|| { - let owner = ALICE; - let (collection, _) = nfts::create_collection_mint(owner, ITEM); + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), - AccountBalance::::get(collection, account(owner)).encode() + NonFungibles::read(Item { collection, item }).encode(), + pallet_nfts::Item::::get(&collection, &item).encode(), ); }); } +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let collection = nfts::create_collection(owner); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + (i + 1).encode() + ); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + AccountBalance::::get(collection, account(owner)).encode() + ); + }); + }); +} + #[test] fn allowance_works() { new_test_ext().execute_with(|| { let owner = ALICE; let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); + assert_eq!( + NonFungibles::read(Allowance { + collection, + item: Some(item), + owner: account(owner), + operator: account(operator), + }) + .encode(), + true.encode() + ); assert_eq!( NonFungibles::read(Allowance { collection, diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index 8c53ffd3..f57ee697 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -7,12 +7,14 @@ use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; +pub(super) type NftsErrorOf = pallet_nfts::Error; pub(super) type NftsWeightInfoOf = ::WeightInfo; // Type aliases for pallet-nfts storage items. pub(super) type AccountIdOf = ::AccountId; pub(super) type BalanceOf = <>::Currency as Currency< ::AccountId, >>::Balance; +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId; pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = From e0c896cbe26bd351ce2e07ee1d83e42835b6410c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 12 Nov 2024 01:17:21 +0700 Subject: [PATCH 54/64] chore: update pallet & runtime --- pallets/api/src/fungibles/tests.rs | 286 ++++------- pallets/api/src/mock.rs | 61 ++- pallets/api/src/nonfungibles/mod.rs | 184 ++++--- pallets/api/src/nonfungibles/tests.rs | 285 +++++----- pallets/api/src/nonfungibles/types.rs | 30 +- pallets/nfts/src/benchmarking.rs | 12 +- pallets/nfts/src/common_functions.rs | 8 + pallets/nfts/src/features/approvals.rs | 31 +- pallets/nfts/src/tests.rs | 18 +- pallets/nfts/src/types.rs | 10 +- pallets/nfts/src/weights.rs | 685 +++++++++++++------------ runtime/devnet/src/config/api/mod.rs | 189 ++++++- runtime/devnet/src/config/assets.rs | 13 +- runtime/devnet/src/lib.rs | 5 +- 14 files changed, 963 insertions(+), 854 deletions(-) diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index 6e181a6f..f5c560bb 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -83,21 +83,17 @@ fn transfer_works() { let to = BOB; for origin in vec![root(), none()] { - assert_noop!(Fungibles::transfer(origin, token, account(to), value), BadOrigin); + assert_noop!(Fungibles::transfer(origin, token, to, value), BadOrigin); } // Check error works for `Assets::transfer_keep_alive()`. - assert_noop!( - Fungibles::transfer(signed(from), token, account(to), value), - AssetsError::Unknown - ); + assert_noop!(Fungibles::transfer(signed(from), token, to, value), AssetsError::Unknown); assets::create_and_mint_to(from, token, from, value * 2); - let balance_before_transfer = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::transfer(signed(from), token, account(to), value)); - let balance_after_transfer = Assets::balance(token, &account(to)); + let balance_before_transfer = Assets::balance(token, &to); + assert_ok!(Fungibles::transfer(signed(from), token, to, value)); + let balance_after_transfer = Assets::balance(token, &to); assert_eq!(balance_after_transfer, balance_before_transfer + value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } - .into(), + Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), ); }); } @@ -112,36 +108,26 @@ fn transfer_from_works() { let spender = CHARLIE; for origin in vec![root(), none()] { - assert_noop!( - Fungibles::transfer_from(origin, token, account(from), account(to), value), - BadOrigin - ); + assert_noop!(Fungibles::transfer_from(origin, token, from, to, value), BadOrigin); } // Check error works for `Assets::transfer_approved()`. assert_noop!( - Fungibles::transfer_from(signed(spender), token, account(from), account(to), value), + Fungibles::transfer_from(signed(spender), token, from, to, value), AssetsError::Unknown ); // Approve `spender` to transfer up to `value`. assets::create_mint_and_approve(spender, token, from, value * 2, spender, value); // Successfully call transfer from. - let from_balance_before_transfer = Assets::balance(token, &account(from)); - let to_balance_before_transfer = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::transfer_from( - signed(spender), - token, - account(from), - account(to), - value - )); - let from_balance_after_transfer = Assets::balance(token, &account(from)); - let to_balance_after_transfer = Assets::balance(token, &account(to)); + let from_balance_before_transfer = Assets::balance(token, &from); + let to_balance_before_transfer = Assets::balance(token, &to); + assert_ok!(Fungibles::transfer_from(signed(spender), token, from, to, value)); + let from_balance_after_transfer = Assets::balance(token, &from); + let to_balance_after_transfer = Assets::balance(token, &to); // Check that `to` has received the `value` tokens from `from`. assert_eq!(to_balance_after_transfer, to_balance_before_transfer + value); assert_eq!(from_balance_after_transfer, from_balance_before_transfer - value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: Some(account(to)), value } - .into(), + Event::Transfer { token, from: Some(from), to: Some(to), value }.into(), ); }); } @@ -158,7 +144,7 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, account(spender), value), + Fungibles::approve(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } @@ -175,20 +161,20 @@ mod approve { for origin in vec![root(), none()] { assert_noop!( - Fungibles::approve(origin, token, account(spender), value), + Fungibles::approve(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()` in `Greater` match arm. assert_noop!( - Fungibles::approve(signed(owner), token, account(spender), value), + Fungibles::approve(signed(owner), token, spender, value), AssetsError::Unknown.with_weight(WeightInfo::approve(1, 0)) ); assets::create_mint_and_approve(owner, token, owner, value, spender, value); // Check error works for `Assets::cancel_approval()` in `Less` match arm. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); @@ -207,61 +193,38 @@ mod approve { // Approves a value to spend that is higher than the current allowance. assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); + assert_eq!(Assets::allowance(token, &owner, &spender), 0); assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value), + Fungibles::approve(signed(owner), token, spender, value), Ok(Some(WeightInfo::approve(1, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); - System::assert_last_event( - Event::Approval { token, owner: account(owner), spender: account(spender), value } - .into(), - ); + assert_eq!(Assets::allowance(token, &owner, &spender), value); + System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); // Approves a value to spend that is lower than the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); // Approves a value to spend that is equal to the current allowance. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), value / 2), + Fungibles::approve(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); // Sets allowance to zero. assert_eq!( - Fungibles::approve(signed(owner), token, account(spender), 0), + Fungibles::approve(signed(owner), token, spender, 0), Ok(Some(WeightInfo::approve(0, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), 0); - System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: 0, - } - .into(), - ); + assert_eq!(Assets::allowance(token, &owner, &spender), 0); + System::assert_last_event(Event::Approval { token, owner, spender, value: 0 }.into()); }); } } @@ -276,34 +239,25 @@ fn increase_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::increase_allowance(origin, token, account(spender), value), + Fungibles::increase_allowance(origin, token, spender, value), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } // Check error works for `Assets::approve_transfer()`. assert_noop!( - Fungibles::increase_allowance(signed(owner), token, account(spender), value), + Fungibles::increase_allowance(signed(owner), token, spender, value), AssetsError::Unknown.with_weight(AssetsWeightInfo::approve_transfer()) ); assets::create_and_mint_to(owner, token, owner, value); - assert_eq!(0, Assets::allowance(token, &account(owner), &account(spender))); - assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); - System::assert_last_event( - Event::Approval { token, owner: account(owner), spender: account(spender), value } - .into(), - ); + assert_eq!(0, Assets::allowance(token, &owner, &spender)); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); + assert_eq!(Assets::allowance(token, &owner, &spender), value); + System::assert_last_event(Event::Approval { token, owner, spender, value }.into()); // Additive. - assert_ok!(Fungibles::increase_allowance(signed(owner), token, account(spender), value)); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value * 2); + assert_ok!(Fungibles::increase_allowance(signed(owner), token, spender, value)); + assert_eq!(Assets::allowance(token, &owner, &spender), value * 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value * 2, - } - .into(), + Event::Approval { token, owner, spender, value: value * 2 }.into(), ); }); } @@ -318,46 +272,40 @@ fn decrease_allowance_works() { for origin in vec![root(), none()] { assert_noop!( - Fungibles::decrease_allowance(origin, token, account(spender), 0), + Fungibles::decrease_allowance(origin, token, spender, 0), BadOrigin.with_weight(WeightInfo::approve(0, 0)) ); } assets::create_mint_and_approve(owner, token, owner, value, spender, value); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + assert_eq!(Assets::allowance(token, &owner, &spender), value); // Check error works for `Assets::cancel_approval()`. No error test for `approve_transfer` // because it is not possible. assert_ok!(Assets::freeze_asset(signed(owner), token)); assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), AssetsError::AssetNotLive.with_weight(WeightInfo::approve(0, 1)) ); assert_ok!(Assets::thaw_asset(signed(owner), token)); // Owner balance is not changed if decreased by zero. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), 0), + Fungibles::decrease_allowance(signed(owner), token, spender, 0), Ok(Some(WeightInfo::approve(0, 0)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value); + assert_eq!(Assets::allowance(token, &owner, &spender), value); // "Unapproved" error is returned if the current allowance is less than amount to decrease // with. assert_noop!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value * 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value * 2), AssetsError::Unapproved ); // Decrease allowance successfully. assert_eq!( - Fungibles::decrease_allowance(signed(owner), token, account(spender), value / 2), + Fungibles::decrease_allowance(signed(owner), token, spender, value / 2), Ok(Some(WeightInfo::approve(1, 1)).into()) ); - assert_eq!(Assets::allowance(token, &account(owner), &account(spender)), value / 2); + assert_eq!(Assets::allowance(token, &owner, &spender), value / 2); System::assert_last_event( - Event::Approval { - token, - owner: account(owner), - spender: account(spender), - value: value / 2, - } - .into(), + Event::Approval { token, owner, spender, value: value / 2 }.into(), ); }); } @@ -370,19 +318,14 @@ fn create_works() { let admin = ALICE; for origin in vec![root(), none()] { - assert_noop!(Fungibles::create(origin, id, account(admin), 100), BadOrigin); + assert_noop!(Fungibles::create(origin, id, admin, 100), BadOrigin); } assert!(!Assets::asset_exists(id)); - assert_ok!(Fungibles::create(signed(creator), id, account(admin), 100)); + assert_ok!(Fungibles::create(signed(creator), id, admin, 100)); assert!(Assets::asset_exists(id)); - System::assert_last_event( - Event::Created { id, creator: account(creator), admin: account(admin) }.into(), - ); + System::assert_last_event(Event::Created { id, creator, admin }.into()); // Check error works for `Assets::create()`. - assert_noop!( - Fungibles::create(signed(creator), id, account(admin), 100), - AssetsError::InUse - ); + assert_noop!(Fungibles::create(signed(creator), id, admin, 100), AssetsError::InUse); }); } @@ -393,11 +336,11 @@ fn start_destroy_works() { // Check error works for `Assets::start_destroy()`. assert_noop!(Fungibles::start_destroy(signed(ALICE), token), AssetsError::Unknown); - assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); assert_ok!(Fungibles::start_destroy(signed(ALICE), token)); // Check that the token is not live after starting the destroy process. assert_noop!( - Assets::mint(signed(ALICE), token, account(ALICE), 10 * UNIT), + Assets::mint(signed(ALICE), token, ALICE, 10 * UNIT), AssetsError::AssetNotLive ); }); @@ -416,7 +359,7 @@ fn set_metadata_works() { Fungibles::set_metadata(signed(ALICE), token, name.clone(), symbol.clone(), decimals), AssetsError::Unknown ); - assert_ok!(Assets::create(signed(ALICE), token, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), token, ALICE, 1)); assert_ok!(Fungibles::set_metadata( signed(ALICE), token, @@ -455,16 +398,16 @@ fn mint_works() { // Check error works for `Assets::mint()`. assert_noop!( - Fungibles::mint(signed(from), token, account(to), value), + Fungibles::mint(signed(from), token, to, value), sp_runtime::TokenError::UnknownAsset ); - assert_ok!(Assets::create(signed(from), token, account(from), 1)); - let balance_before_mint = Assets::balance(token, &account(to)); - assert_ok!(Fungibles::mint(signed(from), token, account(to), value)); - let balance_after_mint = Assets::balance(token, &account(to)); + assert_ok!(Assets::create(signed(from), token, from, 1)); + let balance_before_mint = Assets::balance(token, &to); + assert_ok!(Fungibles::mint(signed(from), token, to, value)); + let balance_after_mint = Assets::balance(token, &to); assert_eq!(balance_after_mint, balance_before_mint + value); System::assert_last_event( - Event::Transfer { token, from: None, to: Some(account(to)), value }.into(), + Event::Transfer { token, from: None, to: Some(to), value }.into(), ); }); } @@ -480,30 +423,27 @@ fn burn_works() { // "BalanceLow" error is returned if token is not created. assert_noop!( - Fungibles::burn(signed(owner), token, account(from), value), + Fungibles::burn(signed(owner), token, from, value), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); assets::create_and_mint_to(owner, token, from, total_supply); assert_eq!(Assets::total_supply(TOKEN), total_supply); // Check error works for `Assets::burn()`. assert_ok!(Assets::freeze_asset(signed(owner), token)); - assert_noop!( - Fungibles::burn(signed(owner), token, account(from), value), - AssetsError::AssetNotLive - ); + assert_noop!(Fungibles::burn(signed(owner), token, from, value), AssetsError::AssetNotLive); assert_ok!(Assets::thaw_asset(signed(owner), token)); // "BalanceLow" error is returned if the balance is less than amount to burn. assert_noop!( - Fungibles::burn(signed(owner), token, account(from), total_supply * 2), + Fungibles::burn(signed(owner), token, from, total_supply * 2), AssetsError::BalanceLow.with_weight(WeightInfo::balance_of()) ); - let balance_before_burn = Assets::balance(token, &account(from)); - assert_ok!(Fungibles::burn(signed(owner), token, account(from), value)); + let balance_before_burn = Assets::balance(token, &from); + assert_ok!(Fungibles::burn(signed(owner), token, from, value)); assert_eq!(Assets::total_supply(TOKEN), total_supply - value); - let balance_after_burn = Assets::balance(token, &account(from)); + let balance_after_burn = Assets::balance(token, &from); assert_eq!(balance_after_burn, balance_before_burn - value); System::assert_last_event( - Event::Transfer { token, from: Some(account(from)), to: None, value }.into(), + Event::Transfer { token, from: Some(from), to: None, value }.into(), ); }); } @@ -530,17 +470,17 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), ReadResult::BalanceOf(Default::default()) ); assets::create_and_mint_to(ALICE, TOKEN, ALICE, value); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }), ReadResult::BalanceOf(value) ); assert_eq!( - Fungibles::read(BalanceOf { token: TOKEN, owner: account(ALICE) }).encode(), - Assets::balance(TOKEN, account(ALICE)).encode(), + Fungibles::read(BalanceOf { token: TOKEN, owner: ALICE }).encode(), + Assets::balance(TOKEN, ALICE).encode(), ); }); } @@ -550,30 +490,17 @@ fn allowance_works() { new_test_ext().execute_with(|| { let value = 1_000 * UNIT; assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), ReadResult::Allowance(Default::default()) ); assets::create_mint_and_approve(ALICE, TOKEN, ALICE, value * 2, BOB, value); assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }), ReadResult::Allowance(value) ); assert_eq!( - Fungibles::read(Allowance { - token: TOKEN, - owner: account(ALICE), - spender: account(BOB) - }) - .encode(), - Assets::allowance(TOKEN, &account(ALICE), &account(BOB)).encode(), + Fungibles::read(Allowance { token: TOKEN, owner: ALICE, spender: BOB }).encode(), + Assets::allowance(TOKEN, &ALICE, &BOB).encode(), ); }); } @@ -607,7 +534,7 @@ fn token_metadata_works() { fn token_exists_works() { new_test_ext().execute_with(|| { assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(false)); - assert_ok!(Assets::create(signed(ALICE), TOKEN, account(ALICE), 1)); + assert_ok!(Assets::create(signed(ALICE), TOKEN, ALICE, 1)); assert_eq!(Fungibles::read(TokenExists(TOKEN)), ReadResult::TokenExists(true)); assert_eq!( Fungibles::read(TokenExists(TOKEN)).encode(), @@ -616,8 +543,8 @@ fn token_exists_works() { }); } -fn signed(account_id: u8) -> RuntimeOrigin { - RuntimeOrigin::signed(account(account_id)) +fn signed(account: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account) } fn root() -> RuntimeOrigin { @@ -632,31 +559,36 @@ fn none() -> RuntimeOrigin { mod assets { use super::*; - pub(super) fn create_and_mint_to(owner: u8, token: TokenId, to: u8, value: Balance) { - assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); - assert_ok!(Assets::mint(signed(owner), token, account(to), value)); + pub(super) fn create_and_mint_to( + owner: AccountId, + token: TokenId, + to: AccountId, + value: Balance, + ) { + assert_ok!(Assets::create(signed(owner), token, owner, 1)); + assert_ok!(Assets::mint(signed(owner), token, to, value)); } pub(super) fn create_mint_and_approve( - owner: u8, + owner: AccountId, token: TokenId, - to: u8, + to: AccountId, mint: Balance, - spender: u8, + spender: AccountId, approve: Balance, ) { create_and_mint_to(owner, token, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), token, account(spender), approve,)); + assert_ok!(Assets::approve_transfer(signed(to), token, spender, approve,)); } pub(super) fn create_and_set_metadata( - owner: u8, + owner: AccountId, token: TokenId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), token, account(owner), 1)); + assert_ok!(Assets::create(signed(owner), token, owner, 1)); assert_ok!(Assets::set_metadata(signed(owner), token, name, symbol, decimals)); } } @@ -681,11 +613,11 @@ mod read_weights { fn new() -> Self { Self { total_supply: Fungibles::weight(&TotalSupply(TOKEN)), - balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: account(ALICE) }), + balance_of: Fungibles::weight(&BalanceOf { token: TOKEN, owner: ALICE }), allowance: Fungibles::weight(&Allowance { token: TOKEN, - owner: account(ALICE), - spender: account(BOB), + owner: ALICE, + spender: BOB, }), token_name: Fungibles::weight(&TokenName(TOKEN)), token_symbol: Fungibles::weight(&TokenSymbol(TOKEN)), @@ -767,15 +699,15 @@ mod ensure_codec_indexes { [ (TotalSupply::(Default::default()), 0u8, "TotalSupply"), ( - BalanceOf:: { token: Default::default(), owner: account(Default::default()) }, + BalanceOf:: { token: Default::default(), owner: Default::default() }, 1, "BalanceOf", ), ( Allowance:: { token: Default::default(), - owner: account(Default::default()), - spender: account(Default::default()), + owner: Default::default(), + spender: Default::default(), }, 2, "Allowance", @@ -799,7 +731,7 @@ mod ensure_codec_indexes { ( transfer { token: Default::default(), - to: account(Default::default()), + to: Default::default(), value: Default::default(), }, 3u8, @@ -808,8 +740,8 @@ mod ensure_codec_indexes { ( transfer_from { token: Default::default(), - from: account(Default::default()), - to: account(Default::default()), + from: Default::default(), + to: Default::default(), value: Default::default(), }, 4, @@ -818,7 +750,7 @@ mod ensure_codec_indexes { ( approve { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 5, @@ -827,7 +759,7 @@ mod ensure_codec_indexes { ( increase_allowance { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 6, @@ -836,7 +768,7 @@ mod ensure_codec_indexes { ( decrease_allowance { token: Default::default(), - spender: account(Default::default()), + spender: Default::default(), value: Default::default(), }, 7, @@ -845,7 +777,7 @@ mod ensure_codec_indexes { ( create { id: Default::default(), - admin: account(Default::default()), + admin: Default::default(), min_balance: Default::default(), }, 11, @@ -866,7 +798,7 @@ mod ensure_codec_indexes { ( mint { token: Default::default(), - account: account(Default::default()), + account: Default::default(), value: Default::default(), }, 19, @@ -875,7 +807,7 @@ mod ensure_codec_indexes { ( burn { token: Default::default(), - account: account(Default::default()), + account: Default::default(), value: Default::default(), }, 20, diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 920d590f..8a4ad27d 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -1,28 +1,28 @@ +use codec::{Decode, Encode}; use frame_support::{ derive_impl, parameter_types, traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; use pallet_nfts::PalletFeatures; +use scale_info::TypeInfo; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - BuildStorage, MultiSignature, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Lazy, Verify}, + BuildStorage, }; -pub(crate) const ALICE: u8 = 1; -pub(crate) const BOB: u8 = 2; -pub(crate) const CHARLIE: u8 = 3; +pub(crate) const ALICE: AccountId = 1; +pub(crate) const BOB: AccountId = 2; +pub(crate) const CHARLIE: AccountId = 3; pub(crate) const INIT_AMOUNT: Balance = 100_000_000 * UNIT; pub(crate) const UNIT: Balance = 10_000_000_000; type Block = frame_system::mocking::MockBlock; -pub(crate) type AccountId = ::AccountId; +pub(crate) type AccountId = u64; pub(crate) type Balance = u128; // For terminology in tests. pub(crate) type TokenId = u32; -type Signature = MultiSignature; -type AccountPublic = ::Signer; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -99,7 +99,7 @@ impl pallet_assets::Config for Test { type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type Extra = (); - type ForceOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; @@ -119,12 +119,35 @@ parameter_types! { pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); } +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] +pub struct Noop; + +impl IdentifyAccount for Noop { + type AccountId = AccountId; + + fn into_account(self) -> Self::AccountId { + 0 + } +} + +impl Verify for Noop { + type Signer = Noop; + + fn verify>( + &self, + _msg: L, + _signer: &::AccountId, + ) -> bool { + false + } +} + impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; type CollectionDeposit = ConstU128<2>; type CollectionId = u32; - type CreateOrigin = AsEnsureOriginWithArg>; + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; type DepositPerByte = ConstU128<1>; type Features = Features; @@ -140,11 +163,8 @@ impl pallet_nfts::Config for Test { type MaxDeadlineDuration = ConstU64<10000>; type MaxTips = ConstU32<10>; type MetadataDepositBase = ConstU128<1>; - /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. - type OffchainPublic = AccountPublic; - /// Off-chain = signature On-chain - therefore no conversion needed. - /// It needs to be From for benchmarking. - type OffchainSignature = Signature; + type OffchainPublic = Noop; + type OffchainSignature = Noop; type RuntimeEvent = RuntimeEvent; type StringLimit = ConstU32<50>; type ValueLimit = ConstU32<50>; @@ -155,22 +175,13 @@ impl crate::nonfungibles::Config for Test { type RuntimeEvent = RuntimeEvent; } -/// Initialize a new account ID. -pub(crate) fn account(id: u8) -> AccountId { - [id; 32].into() -} - pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default() .build_storage() .expect("Frame system builds valid default genesis config"); pallet_balances::GenesisConfig:: { - balances: vec![ - (account(ALICE), INIT_AMOUNT), - (account(BOB), INIT_AMOUNT), - (account(CHARLIE), INIT_AMOUNT), - ], + balances: vec![(ALICE, INIT_AMOUNT), (BOB, INIT_AMOUNT), (CHARLIE, INIT_AMOUNT)], } .assimilate_storage(&mut t) .expect("Pallet balances storage can be assimilated"); diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 7377048f..1a5b07b8 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -5,24 +5,22 @@ pub use pallet::*; use pallet_nfts::WeightInfo; use sp_runtime::traits::StaticLookup; +pub use types::*; #[cfg(test)] mod tests; -mod types; +pub mod types; #[frame_support::pallet] pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::Incrementable}; use frame_system::pallet_prelude::*; - use pallet_nfts::{ - CancelAttributesApprovalWitness, CollectionConfig, CollectionSettings, DestroyWitness, - MintSettings, MintWitness, - }; + use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness}; + use sp_runtime::BoundedVec; use sp_std::vec::Vec; use types::{ - AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionDetailsFor, CollectionIdOf, - CreateCollectionConfigFor, ItemDetailsFor, ItemIdOf, ItemPriceOf, NextCollectionIdOf, - NftsOf, NftsWeightInfoOf, + AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionConfigFor, CollectionDetailsFor, + CollectionIdOf, ItemIdOf, ItemPriceOf, NextCollectionIdOf, NftsOf, NftsWeightInfoOf, }; use super::*; @@ -48,25 +46,24 @@ pub mod pallet { item: Option>, }, /// Owner of a specified collection item. - #[codec(index = 3)] + #[codec(index = 5)] OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Attribute value of a collection item. - #[codec(index = 4)] + /// Attribute value of a collection item. (Error: bounded collection is not partial) + #[codec(index = 6)] GetAttribute { collection: CollectionIdOf, - item: Option>, + item: ItemIdOf, namespace: AttributeNamespaceOf, key: BoundedVec, }, /// Details of a collection. - #[codec(index = 6)] + #[codec(index = 9)] Collection(CollectionIdOf), - /// Details of a collection item. - #[codec(index = 7)] - Item { collection: CollectionIdOf, item: ItemIdOf }, /// Next collection ID. - #[codec(index = 8)] + #[codec(index = 10)] NextCollectionId, + #[codec(index = 11)] + ItemMetadata { collection: CollectionIdOf, item: ItemIdOf }, } /// Results of state reads for the non-fungibles API. @@ -74,7 +71,7 @@ pub mod pallet { #[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum ReadResult { /// Total item supply of a collection. - TotalSupply(u32), + TotalSupply(u128), /// Account balance for a specified collection. BalanceOf(u32), /// Allowance for an operator approved by an owner, for a specified collection or item. @@ -82,13 +79,13 @@ pub mod pallet { /// Owner of a specified collection owner. OwnerOf(Option>), /// Attribute value of a collection item. - GetAttribute(Option>), + GetAttribute(Option>), /// Details of a collection. Collection(Option>), - /// Details of a collection item. - Item(Option>), /// Next collection ID. NextCollectionId(Option>), + /// Collection item metadata. + ItemMetadata(Option>), } impl ReadResult { @@ -100,10 +97,10 @@ pub mod pallet { TotalSupply(result) => result.encode(), BalanceOf(result) => result.encode(), Collection(result) => result.encode(), - Item(result) => result.encode(), Allowance(result) => result.encode(), GetAttribute(result) => result.encode(), NextCollectionId(result) => result.encode(), + ItemMetadata(result) => result.encode(), } } } @@ -162,54 +159,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(NftsWeightInfoOf::::mint())] - pub fn mint( - origin: OriginFor, - to: AccountIdOf, - collection: CollectionIdOf, - item: ItemIdOf, - mint_price: Option>, - ) -> DispatchResult { - let account = ensure_signed(origin.clone())?; - let witness_data = MintWitness { mint_price, owned_item: Some(item) }; - NftsOf::::mint( - origin, - collection, - item, - T::Lookup::unlookup(to.clone()), - Some(witness_data), - )?; - Self::deposit_event(Event::Transfer { - collection, - item, - from: None, - to: Some(account), - price: mint_price, - }); - Ok(()) - } - - #[pallet::call_index(1)] - #[pallet::weight(NftsWeightInfoOf::::burn())] - pub fn burn( - origin: OriginFor, - collection: CollectionIdOf, - item: ItemIdOf, - ) -> DispatchResult { - let account = ensure_signed(origin.clone())?; - NftsOf::::burn(origin, collection, item)?; - Self::deposit_event(Event::Transfer { - collection, - item, - from: Some(account), - to: None, - price: None, - }); - Ok(()) - } - - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( origin: OriginFor, @@ -229,7 +179,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight(NftsWeightInfoOf::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( origin: OriginFor, @@ -259,33 +209,25 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(4)] + #[pallet::call_index(7)] #[pallet::weight(NftsWeightInfoOf::::create())] pub fn create( origin: OriginFor, admin: AccountIdOf, - config: CreateCollectionConfigFor, + config: CollectionConfigFor, ) -> DispatchResult { + // 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::::get() .or(T::CollectionId::initial_value()) .ok_or(pallet_nfts::Error::::UnknownCollection)?; let creator = ensure_signed(origin.clone())?; - let collection_config = CollectionConfig { - settings: CollectionSettings::all_enabled(), - max_supply: config.max_supply, - mint_settings: MintSettings { - mint_type: config.mint_type, - start_block: config.start_block, - end_block: config.end_block, - ..MintSettings::default() - }, - }; - NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), collection_config)?; + NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), config)?; Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } - #[pallet::call_index(5)] + #[pallet::call_index(8)] #[pallet::weight(NftsWeightInfoOf::::destroy( witness.item_metadatas, witness.item_configs, @@ -299,7 +241,7 @@ pub mod pallet { NftsOf::::destroy(origin, collection, witness) } - #[pallet::call_index(6)] + #[pallet::call_index(12)] #[pallet::weight(NftsWeightInfoOf::::set_attribute())] pub fn set_attribute( origin: OriginFor, @@ -312,7 +254,7 @@ pub mod pallet { NftsOf::::set_attribute(origin, collection, item, namespace, key, value) } - #[pallet::call_index(7)] + #[pallet::call_index(13)] #[pallet::weight(NftsWeightInfoOf::::clear_attribute())] pub fn clear_attribute( origin: OriginFor, @@ -324,7 +266,7 @@ pub mod pallet { NftsOf::::clear_attribute(origin, collection, item, namespace, key) } - #[pallet::call_index(8)] + #[pallet::call_index(14)] #[pallet::weight(NftsWeightInfoOf::::set_metadata())] pub fn set_metadata( origin: OriginFor, @@ -335,7 +277,7 @@ pub mod pallet { NftsOf::::set_metadata(origin, collection, item, data) } - #[pallet::call_index(9)] + #[pallet::call_index(15)] #[pallet::weight(NftsWeightInfoOf::::clear_metadata())] pub fn clear_metadata( origin: OriginFor, @@ -345,7 +287,7 @@ pub mod pallet { NftsOf::::clear_metadata(origin, collection, item) } - #[pallet::call_index(10)] + #[pallet::call_index(16)] #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] pub fn approve_item_attributes( origin: OriginFor, @@ -361,7 +303,7 @@ pub mod pallet { ) } - #[pallet::call_index(11)] + #[pallet::call_index(17)] #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] pub fn cancel_item_attributes_approval( origin: OriginFor, @@ -379,7 +321,7 @@ pub mod pallet { ) } - #[pallet::call_index(12)] + #[pallet::call_index(18)] #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] pub fn set_max_supply( origin: OriginFor, @@ -388,6 +330,53 @@ pub mod pallet { ) -> DispatchResult { NftsOf::::set_collection_max_supply(origin, collection, max_supply) } + + #[pallet::call_index(19)] + #[pallet::weight(NftsWeightInfoOf::::mint())] + pub fn mint( + origin: OriginFor, + to: AccountIdOf, + collection: CollectionIdOf, + item: ItemIdOf, + witness: MintWitness, ItemPriceOf>, + ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; + let mint_price = witness.mint_price; + NftsOf::::mint( + origin, + collection, + item, + T::Lookup::unlookup(to.clone()), + Some(witness), + )?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: None, + to: Some(account), + price: mint_price, + }); + Ok(()) + } + + #[pallet::call_index(20)] + #[pallet::weight(NftsWeightInfoOf::::burn())] + pub fn burn( + origin: OriginFor, + collection: CollectionIdOf, + item: ItemIdOf, + ) -> DispatchResult { + let account = ensure_signed(origin.clone())?; + NftsOf::::burn(origin, collection, item)?; + Self::deposit_event(Event::Transfer { + collection, + item, + from: Some(account), + to: None, + price: None, + }); + Ok(()) + } } impl crate::Read for Pallet { @@ -413,7 +402,7 @@ pub mod pallet { use Read::*; match value { TotalSupply(collection) => ReadResult::TotalSupply( - NftsOf::::collection_items(collection).unwrap_or_default(), + NftsOf::::collection_items(collection).unwrap_or_default() as u128, ), BalanceOf { collection, owner } => ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), @@ -423,13 +412,14 @@ pub mod pallet { OwnerOf { collection, item } => ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( - pallet_nfts::Attribute::::get((collection, item, namespace, key)) - .map(|attribute| attribute.0), + pallet_nfts::Attribute::::get((collection, Some(item), namespace, key)) + .map(|attribute| attribute.0.into()), ), Collection(collection) => ReadResult::Collection(pallet_nfts::Collection::::get(collection)), - Item { collection, item } => - ReadResult::Item(pallet_nfts::Item::::get(collection, item)), + ItemMetadata { collection, item } => ReadResult::ItemMetadata( + NftsOf::::item_metadata(collection, item).map(|metadata| metadata.into()), + ), NextCollectionId => ReadResult::NextCollectionId( NextCollectionIdOf::::get().or(T::CollectionId::initial_value()), ), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index e89ba0bd..79d484a2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -2,10 +2,10 @@ use codec::Encode; use frame_support::{assert_noop, assert_ok, traits::Incrementable}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_nfts::{ - AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, ItemDeposit, - ItemDetails, MintSettings, + AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, DestroyWitness, + MintSettings, MintWitness, }; -use sp_runtime::{BoundedBTreeMap, BoundedVec, DispatchError::BadOrigin}; +use sp_runtime::{BoundedVec, DispatchError::BadOrigin}; use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ @@ -23,7 +23,7 @@ mod encoding_read_result { #[test] fn total_supply() { - let total_supply: u32 = 1_000_000; + let total_supply: u128 = 1_000_000; assert_eq!(ReadResult::TotalSupply::(total_supply).encode(), total_supply.encode()); } @@ -41,7 +41,7 @@ mod encoding_read_result { #[test] fn owner_of() { - let mut owner = Some(account(ALICE)); + let mut owner = Some(ALICE); assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); owner = None; assert_eq!(ReadResult::OwnerOf::(owner.clone()).encode(), owner.encode()); @@ -49,7 +49,7 @@ mod encoding_read_result { #[test] fn get_attribute() { - let mut attribute = Some(BoundedVec::truncate_from("some attribute".as_bytes().to_vec())); + let mut attribute = Some("some attribute".as_bytes().to_vec()); assert_eq!( ReadResult::GetAttribute::(attribute.clone()).encode(), attribute.encode() @@ -64,7 +64,7 @@ mod encoding_read_result { #[test] fn collection() { let mut collection_details = Some(CollectionDetails { - owner: account(ALICE), + owner: ALICE, owner_deposit: 0, items: 0, item_metadatas: 0, @@ -82,18 +82,6 @@ mod encoding_read_result { ); } - #[test] - fn item() { - let mut item_details = Some(ItemDetails { - owner: account(ALICE), - approvals: BoundedBTreeMap::default(), - deposit: ItemDeposit { amount: 0, account: account(BOB) }, - }); - assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); - item_details = None; - assert_eq!(ReadResult::Item::(item_details.clone()).encode(), item_details.encode()); - } - #[test] fn next_collection_id_works() { let mut next_collection_id = Some(0); @@ -107,6 +95,14 @@ mod encoding_read_result { next_collection_id.encode() ); } + + #[test] + fn item_metadata_works() { + let mut data = Some("some metadata".as_bytes().to_vec()); + assert_eq!(ReadResult::ItemMetadata::(data.clone()).encode(), data.encode()); + data = None; + assert_eq!(ReadResult::ItemMetadata::(data.clone()).encode(), data.encode()); + } } #[test] @@ -117,26 +113,17 @@ fn transfer() { let (collection, item) = nfts::create_collection_mint(owner, ITEM); for origin in vec![root(), none()] { - assert_noop!( - NonFungibles::transfer(origin, collection, item, account(dest)), - BadOrigin - ); + assert_noop!(NonFungibles::transfer(origin, collection, item, dest), BadOrigin); } // Successfully burn an existing new collection item. - let balance_before_transfer = AccountBalance::::get(collection, &account(dest)); - assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, account(dest))); - let balance_after_transfer = AccountBalance::::get(collection, &account(dest)); - assert_eq!(AccountBalance::::get(collection, &account(owner)), 0); + let balance_before_transfer = AccountBalance::::get(collection, &dest); + assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, dest)); + let balance_after_transfer = AccountBalance::::get(collection, &dest); + assert_eq!(AccountBalance::::get(collection, &owner), 0); assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( - Event::Transfer { - collection, - item, - from: Some(account(owner)), - to: Some(account(dest)), - price: None, - } - .into(), + Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } + .into(), ); }); } @@ -148,20 +135,20 @@ fn mint_works() { let collection = nfts::create_collection(owner); // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection, account(owner)); - assert_ok!(NonFungibles::mint(signed(owner), account(owner), collection, ITEM, None)); - let balance_after_mint = AccountBalance::::get(collection, account(owner)); + let balance_before_mint = AccountBalance::::get(collection, owner); + assert_ok!(NonFungibles::mint( + signed(owner), + owner, + collection, + ITEM, + MintWitness { mint_price: None, owned_item: None } + )); + let balance_after_mint = AccountBalance::::get(collection, owner); assert_eq!(balance_after_mint, 1); assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( - Event::Transfer { - collection, - item: ITEM, - from: None, - to: Some(account(owner)), - price: None, - } - .into(), + Event::Transfer { collection, item: ITEM, from: None, to: Some(owner), price: None } + .into(), ); }); } @@ -175,8 +162,7 @@ fn burn_works() { let (collection, item) = nfts::create_collection_mint(owner, ITEM); assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); System::assert_last_event( - Event::Transfer { collection, item, from: Some(account(owner)), to: None, price: None } - .into(), + Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); }); } @@ -188,25 +174,13 @@ fn approve_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint(owner, ITEM); // Successfully approve `oeprator` to transfer the collection item. - assert_ok!(NonFungibles::approve( - signed(owner), - collection, - Some(item), - account(operator), - true - )); + assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, true)); System::assert_last_event( - Event::Approval { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - approved: true, - } - .into(), + Event::Approval { collection, item: Some(item), owner, operator, approved: true } + .into(), ); // Successfully transfer the item by the delegated account `operator`. - assert_ok!(Nfts::transfer(signed(operator), collection, item, account(operator))); + assert_ok!(Nfts::transfer(signed(operator), collection, item, operator)); }); } @@ -217,16 +191,10 @@ fn cancel_approval_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); // Successfully cancel the transfer approval of `operator` by `owner`. - assert_ok!(NonFungibles::approve( - signed(owner), - collection, - Some(item), - account(operator), - false - )); + assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, false)); // Failed to transfer the item by `operator` without permission. assert_noop!( - Nfts::transfer(signed(operator), collection, item, account(operator)), + Nfts::transfer(signed(operator), collection, item, operator), NftsError::NoPermission ); }); @@ -239,10 +207,10 @@ fn set_max_supply_works() { let collection = nfts::create_collection(owner); assert_ok!(NonFungibles::set_max_supply(signed(owner), collection, 10)); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); }); assert_noop!( - Nfts::mint(signed(owner), collection, 42, account(owner), None), + Nfts::mint(signed(owner), collection, 42, owner, None), NftsError::MaxSupplyReached ); }); @@ -263,15 +231,14 @@ fn owner_of_works() { fn get_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); let mut result: Option::ValueLimit>> = None; // No attribute set. assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute.clone() }) @@ -291,7 +258,7 @@ fn get_attribute_works() { assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute }) @@ -301,13 +268,44 @@ fn get_attribute_works() { }); } +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let value = BoundedVec::truncate_from("some metadata".as_bytes().to_vec()); + assert_ok!(NonFungibles::set_metadata(signed(ALICE), collection, item, value.clone())); + assert_eq!( + NonFungibles::read(ItemMetadata { collection, item }).encode(), + Some(value).encode() + ); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + assert_ok!(NonFungibles::set_metadata( + signed(ALICE), + collection, + item, + BoundedVec::truncate_from("some metadata".as_bytes().to_vec()) + )); + assert_ok!(NonFungibles::clear_metadata(signed(ALICE), collection, item)); + assert_eq!( + NonFungibles::read(ItemMetadata { collection, item }).encode(), + ReadResult::::ItemMetadata(None).encode() + ); + }); +} + #[test] fn clear_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let result: Option::ValueLimit>> = None; assert_ok!(Nfts::set_attribute( signed(ALICE), collection, @@ -327,7 +325,7 @@ fn clear_attribute_works() { assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), + item, namespace: pallet_nfts::AttributeNamespace::CollectionOwner, key: attribute }) @@ -342,25 +340,24 @@ fn approve_item_attribute_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; // Successfully approve delegate to set attributes. - assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, BOB)); assert_ok!(Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); - result = Some(value); + let result: Option::ValueLimit>> = Some(value); assert_eq!( NonFungibles::read(GetAttribute { collection, - item: Some(item), - namespace: pallet_nfts::AttributeNamespace::Account(account(BOB)), + item, + namespace: pallet_nfts::AttributeNamespace::Account(BOB), key: attribute }) .encode(), @@ -374,16 +371,15 @@ fn cancel_item_attribute_approval_works() { new_test_ext().execute_with(|| { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - let mut attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; // Successfully approve delegate to set attributes. - assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, account(BOB))); + assert_ok!(Nfts::approve_item_attributes(signed(ALICE), collection, item, BOB)); assert_ok!(Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -391,7 +387,7 @@ fn cancel_item_attribute_approval_works() { signed(ALICE), collection, item, - account(BOB), + BOB, pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } )); assert_noop!( @@ -399,7 +395,7 @@ fn cancel_item_attribute_approval_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(account(BOB)), + pallet_nfts::AttributeNamespace::Account(BOB), attribute.clone(), value.clone() ), @@ -428,34 +424,57 @@ fn total_supply_works() { let owner = ALICE; let collection = nfts::create_collection(owner); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); - assert_eq!(NonFungibles::read(TotalSupply(collection)).encode(), (i + 1).encode()); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + ((i + 1) as u128).encode() + ); assert_eq!( NonFungibles::read(TotalSupply(collection)).encode(), - Nfts::collection_items(collection).unwrap_or_default().encode() + (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() ); }); }); } #[test] -fn collection_works() { +fn create_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(Collection(collection)).encode(), - pallet_nfts::Collection::::get(&collection).encode(), - ); + let owner = ALICE; + let next_collection_id = pallet_nfts::NextCollectionId::::get().unwrap_or_default(); + assert_ok!(NonFungibles::create( + signed(owner), + owner, + CollectionConfig { + max_supply: None, + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled() + }, + )); + assert_eq!(Nfts::collection_owner(next_collection_id), Some(owner)); }); } #[test] -fn item_works() { +fn destroy_works() { new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let collection = nfts::create_collection(ALICE); + assert_ok!(NonFungibles::destroy( + signed(ALICE), + collection, + DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } + )); + assert_eq!(Nfts::collection_owner(collection), None); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( - NonFungibles::read(Item { collection, item }).encode(), - pallet_nfts::Item::::get(&collection, &item).encode(), + NonFungibles::read(Collection(collection)).encode(), + pallet_nfts::Collection::::get(&collection).encode(), ); }); } @@ -466,14 +485,14 @@ fn balance_of_works() { let owner = ALICE; let collection = nfts::create_collection(owner); (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), + NonFungibles::read(BalanceOf { collection, owner }).encode(), (i + 1).encode() ); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner: account(owner) }).encode(), - AccountBalance::::get(collection, account(owner)).encode() + NonFungibles::read(BalanceOf { collection, owner }).encode(), + AccountBalance::::get(collection, owner).encode() ); }); }); @@ -486,32 +505,22 @@ fn allowance_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( - NonFungibles::read(Allowance { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - }) - .encode(), + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) + .encode(), true.encode() ); assert_eq!( - NonFungibles::read(Allowance { - collection, - item: Some(item), - owner: account(owner), - operator: account(operator), - }) - .encode(), - Nfts::check_allowance(&collection, &Some(item), &account(owner), &account(operator)) + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) + .encode(), + Nfts::check_allowance(&collection, &Some(item), &owner, &operator) .is_ok() .encode() ); }); } -fn signed(account_id: u8) -> RuntimeOrigin { - RuntimeOrigin::signed(account(account_id)) +fn signed(account_id: AccountId) -> RuntimeOrigin { + RuntimeOrigin::signed(account_id) } fn root() -> RuntimeOrigin { @@ -526,32 +535,26 @@ mod nfts { use super::*; pub(super) fn create_collection_mint_and_approve( - owner: u8, + owner: AccountId, item: ItemIdOf, - operator: u8, + operator: AccountId, ) -> (u32, u32) { let (collection, item) = create_collection_mint(owner, item); - assert_ok!(Nfts::approve_transfer( - signed(owner), - collection, - Some(item), - account(operator), - None - )); + assert_ok!(Nfts::approve_transfer(signed(owner), collection, Some(item), operator, None)); (collection, item) } - pub(super) fn create_collection_mint(owner: u8, item: ItemIdOf) -> (u32, u32) { + pub(super) fn create_collection_mint(owner: AccountId, item: ItemIdOf) -> (u32, u32) { let collection = create_collection(owner); - assert_ok!(Nfts::mint(signed(owner), collection, item, account(owner), None)); + assert_ok!(Nfts::mint(signed(owner), collection, item, owner, None)); (collection, item) } - pub(super) fn create_collection(owner: u8) -> u32 { + pub(super) fn create_collection(owner: AccountId) -> u32 { let next_id = next_collection_id(); assert_ok!(Nfts::create( signed(owner), - account(owner), + owner, collection_config_with_all_settings_enabled() )); next_id diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs index f57ee697..6e686389 100644 --- a/pallets/api/src/nonfungibles/types.rs +++ b/pallets/api/src/nonfungibles/types.rs @@ -1,13 +1,12 @@ -use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{AttributeNamespace, CollectionDetails, ItemDeposit, ItemDetails, MintType}; -use scale_info::TypeInfo; -use sp_runtime::{BoundedBTreeMap, RuntimeDebug}; +pub use pallet_nfts::{ + AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, + DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, +}; // Type aliases for pallet-nfts. pub(super) type NftsOf = pallet_nfts::Pallet; -pub(super) type NftsErrorOf = pallet_nfts::Error; pub(super) type NftsWeightInfoOf = ::WeightInfo; // Type aliases for pallet-nfts storage items. pub(super) type AccountIdOf = ::AccountId; @@ -19,27 +18,10 @@ pub(super) type CollectionIdOf = as Inspect<::AccountId>>::CollectionId; pub(super) type ItemIdOf = as Inspect<::AccountId>>::ItemId; -pub(super) type ApprovalsOf = BoundedBTreeMap< - AccountIdOf, - Option>, - ::ApprovalsLimit, ->; pub(super) type ItemPriceOf = BalanceOf; // TODO: Multi-instances. -pub(super) type ItemDepositOf = ItemDeposit, AccountIdOf>; pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; -pub(super) type ItemDetailsFor = - ItemDetails, ItemDepositOf, ApprovalsOf>; pub(super) type AttributeNamespaceOf = AttributeNamespace>; -pub(super) type CreateCollectionConfigFor = - CreateCollectionConfig, BlockNumberFor, CollectionIdOf>; - -#[derive(Clone, Copy, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub struct CreateCollectionConfig { - pub max_supply: Option, - pub mint_type: MintType, - pub price: Option, - pub start_block: Option, - pub end_block: Option, -} +pub(super) type CollectionConfigFor = + CollectionConfig, BlockNumberFor, CollectionIdOf>; diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..ab66da26 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -578,9 +578,9 @@ benchmarks_instance_pallet! { let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let deadline = BlockNumberFor::::max_value(); - }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) + }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(deadline) }.into()); + assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); } cancel_approval { @@ -590,10 +590,10 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) + Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -603,7 +603,7 @@ benchmarks_instance_pallet! { let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 6fe483f1..89de1f05 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,6 +39,14 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.items) } + /// Get the metadata of the collection item. + pub fn item_metadata( + collection: T::CollectionId, + item: T::ItemId, + ) -> Option> { + ItemMetadataOf::::get(collection, item).map(|metadata| metadata.data) + } + /// Validates the signature of the given data with the provided signer's account ID. /// /// # Errors diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 6d71c1a2..e1e79ef4 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -180,24 +180,26 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - if !Collection::::contains_key(collection) { - return Err(Error::::UnknownCollection.into()); - } + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + let collection_config = Self::get_collection_config(&collection)?; ensure!( collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; - Allowances::::mutate((&collection, &origin, &delegate), |allowance| { + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + Allowances::::mutate((&collection, &owner, &delegate), |allowance| { *allowance = true; }); Self::deposit_event(Event::TransferApproved { collection, item: None, - owner: origin, + owner, delegate, deadline: None, }); @@ -209,19 +211,14 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - if !Collection::::contains_key(collection) { - return Err(Error::::UnknownCollection.into()); - } + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - let origin = maybe_check_origin.ok_or(Error::::WrongOrigin)?; - Allowances::::remove((&collection, &origin, &delegate)); + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + Allowances::::remove((&collection, &owner, &delegate)); - Self::deposit_event(Event::ApprovalCancelled { - collection, - owner: origin, - item: None, - delegate, - }); + Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); Ok(()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 397a715c..4d0f08c9 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -318,7 +318,7 @@ fn destroy_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), @@ -2017,22 +2017,22 @@ fn cancel_approval_collection_works_with_admin() { )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), Error::::UnknownCollection ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, item: None, - owner: account(2), + owner: account(1), delegate: account(3) })); assert_eq!(Allowances::::get((0, account(2), account(3))), false); @@ -2156,7 +2156,7 @@ fn approval_collection_works_with_admin() { RuntimeOrigin::signed(account(1)), 0, 42, - account(2), + account(1), default_item_config() )); @@ -2178,7 +2178,7 @@ fn approval_collection_works_with_admin() { ); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(3), @@ -2187,11 +2187,11 @@ fn approval_collection_works_with_admin() { assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, - owner: account(2), + owner: account(1), delegate: account(3), deadline: None })); - assert_eq!(Allowances::::get((0, account(2), account(3))), true); + assert_eq!(Allowances::::get((0, account(1), account(3))), true); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 061352c0..941da6ca 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -145,21 +145,21 @@ pub struct MintWitness { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub owner: AccountId, + pub(super) owner: AccountId, /// The approved transferrer of this item, if one is set. - pub approvals: Approvals, + pub(super) approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub deposit: Deposit, + pub(super) deposit: Deposit, } /// Information about the reserved item deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub account: AccountId, + pub(super) account: AccountId, /// An amount that gets reserved. - pub amount: DepositBalance, + pub(super) amount: DepositBalance, } /// Information about the collection's metadata. diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index c5fb60a2..c374d6db 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -1,30 +1,14 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. //! Autogenerated weights for `pallet_nfts` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 +//! DATE: 2024-10-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `R0GUE`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// ./target/release/pop-node // benchmark // pallet // --chain=dev @@ -34,12 +18,11 @@ // --no-storage-info // --no-median-slopes // --no-min-squares -// --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nfts/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./pallets/nfts/src/weights.rs +// --template=./scripts/pallet-weights-template.hbs +// --extrinsic= #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -107,10 +90,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `216` + // Measured: `105` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(27_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -126,10 +109,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -141,6 +124,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -152,15 +137,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` + // Measured: `32216 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1004_u64)) + // Minimum execution time: 982_000_000 picoseconds. + Weight::from_parts(937_587_516, 2523990) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1005_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -174,18 +163,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(42_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -195,18 +186,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -218,22 +211,24 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `564` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(59_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -245,6 +240,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -253,12 +250,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `593` - // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `605` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(83_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -269,12 +266,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `763 + i * (108 ±0)` + // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 20_022 + .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -286,10 +283,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -299,10 +296,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -312,10 +309,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -329,10 +326,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -342,10 +339,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `369` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -355,10 +352,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `238` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -368,10 +365,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `203` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -381,10 +378,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -400,10 +397,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -413,10 +410,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(19_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -430,30 +427,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Measured: `308` + // Estimated: `4466` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4466) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -461,12 +458,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Measured: `686 + n * (398 ±0)` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 4466) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -485,10 +482,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -502,10 +499,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -519,10 +516,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `398` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -536,10 +533,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` + // Measured: `643` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(29_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -549,10 +546,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `410` + // Measured: `337` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -560,10 +557,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -571,10 +568,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -582,10 +579,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -595,10 +592,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,10 +605,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `323` + // Measured: `250` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -625,10 +622,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `518` + // Measured: `478` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -644,28 +641,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `717` + // Estimated: `6068` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(45_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(390_532, 0) + // Standard Error: 84_277 + .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -673,10 +672,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `494` + // Measured: `421` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -686,10 +685,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `513` + // Measured: `440` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -705,18 +704,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:4) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `834` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(10_u64)) + // Minimum execution time: 75_000_000 picoseconds. + Weight::from_parts(77_000_000, 7662) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -726,6 +727,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -739,22 +742,22 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `629` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(107_476_765, 6078) + // Standard Error: 61_259 + .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) @@ -766,12 +769,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Measured: `514` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(57_358_180, 4466) + // Standard Error: 54_968 + .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -794,10 +797,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `216` + // Measured: `105` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(27_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -813,10 +816,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -828,6 +831,8 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -839,15 +844,19 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` + // Measured: `32216 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1004_u64)) + // Minimum execution time: 982_000_000 picoseconds. + Weight::from_parts(937_587_516, 2523990) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) + // Standard Error: 12_288 + .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1005_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -861,18 +870,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(42_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -882,18 +893,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `455` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -905,22 +918,24 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `564` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(59_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -932,6 +947,8 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -940,12 +957,12 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `593` - // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `605` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(83_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) @@ -956,12 +973,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `763 + i * (108 ±0)` + // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 20_022 + .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -973,10 +990,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -986,10 +1003,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -999,10 +1016,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1016,10 +1033,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1029,10 +1046,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `369` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1042,10 +1059,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `238` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1055,10 +1072,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `203` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1068,10 +1085,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `435` + // Measured: `395` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1087,10 +1104,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1100,10 +1117,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(19_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1117,30 +1134,30 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Measured: `308` + // Estimated: `4466` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4466) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1001 w:1000) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1148,12 +1165,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Measured: `686 + n * (398 ±0)` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(19_000_000, 4466) + // Standard Error: 6_379 + .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1172,10 +1189,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1189,10 +1206,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1206,10 +1223,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `398` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(30_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1223,10 +1240,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` + // Measured: `643` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(29_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1236,10 +1253,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `410` + // Measured: `337` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1247,10 +1264,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1258,10 +1275,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `418` + // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1269,10 +1286,10 @@ impl WeightInfo for () { /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `76` + // Measured: `3` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1282,10 +1299,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `340` + // Measured: `267` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1295,10 +1312,10 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `323` + // Measured: `250` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1312,10 +1329,10 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `518` + // Measured: `478` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,28 +1348,30 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:2) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `705` - // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `717` + // Estimated: `6068` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(45_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(390_532, 0) + // Standard Error: 84_277 + .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1360,10 +1379,10 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `494` + // Measured: `421` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1373,10 +1392,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `513` + // Measured: `440` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1392,18 +1411,20 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:2 w:2) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:4) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `834` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(10_u64)) + // Minimum execution time: 75_000_000 picoseconds. + Weight::from_parts(77_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1413,6 +1434,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountBalance` (r:1 w:1) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1426,22 +1449,22 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `629` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(107_476_765, 6078) + // Standard Error: 61_259 + .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(1001), added: 3476, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) @@ -1453,16 +1476,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Measured: `514` + // Estimated: `4466 + n * (2954 ±0)` + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(57_358_180, 4466) + // Standard Error: 54_968 + .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } -} +} \ No newline at end of file diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 035a6014..93f4853f 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use codec::Decode; use cumulus_primitives_core::Weight; -use frame_support::traits::Contains; +use frame_support::traits::{ConstU32, Contains}; pub(crate) use pallet_api::Extension; use pallet_api::{extension::*, Read}; use sp_core::ConstU8; @@ -11,7 +11,9 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::TrustBackedAssetsInstance, fungibles, Runtime, RuntimeCall, RuntimeEvent, + config::{assets::TrustBackedAssetsInstance, xcm::LocalOriginToLocation}, + fungibles, nonfungibles, Balances, Ismp, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, TransactionByteFee, }; mod versioning; @@ -32,6 +34,9 @@ pub enum RuntimeRead { /// Fungible token queries. #[codec(index = 150)] Fungibles(fungibles::Read), + /// Non-fungible token queries. + #[codec(index = 151)] + NonFungibles(nonfungibles::Read), } impl Readable for RuntimeRead { @@ -43,6 +48,7 @@ impl Readable for RuntimeRead { fn weight(&self) -> Weight { match self { RuntimeRead::Fungibles(key) => fungibles::Pallet::weight(key), + RuntimeRead::NonFungibles(key) => nonfungibles::Pallet::weight(key), } } @@ -50,16 +56,20 @@ impl Readable for RuntimeRead { fn read(self) -> Self::Result { match self { RuntimeRead::Fungibles(key) => RuntimeResult::Fungibles(fungibles::Pallet::read(key)), + RuntimeRead::NonFungibles(key) => + RuntimeResult::NonFungibles(nonfungibles::Pallet::read(key)), } } } /// The result of a runtime state read. #[derive(Debug)] -#[cfg_attr(test, derive(PartialEq, Clone))] +#[cfg_attr(feature = "std", derive(PartialEq, Clone))] pub enum RuntimeResult { /// Fungible token read results. Fungibles(fungibles::ReadResult), + /// Non-fungible token read results. + NonFungibles(nonfungibles::ReadResult), } impl RuntimeResult { @@ -67,6 +77,7 @@ impl RuntimeResult { fn encode(&self) -> Vec { match self { RuntimeResult::Fungibles(result) => result.encode(), + RuntimeResult::NonFungibles(result) => result.encode(), } } } @@ -77,6 +88,10 @@ impl fungibles::Config for Runtime { type WeightInfo = fungibles::weights::SubstrateWeight; } +impl nonfungibles::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + #[derive(Default)] pub struct Config; impl pallet_api::extension::Config for Config { @@ -130,8 +145,8 @@ pub struct Filter(PhantomData); impl> Contains for Filter { fn contains(c: &RuntimeCall) -> bool { - use fungibles::Call::*; - T::BaseCallFilter::contains(c) && + let contain_fungibles: bool = { + use fungibles::Call::*; matches!( c, RuntimeCall::Fungibles( @@ -142,26 +157,63 @@ impl> Contains f create { .. } | set_metadata { .. } | start_destroy { .. } | clear_metadata { .. } | - mint { .. } | burn { .. } + mint { .. } | burn { .. }, + ) + ) + }; + + let contain_nonfungibles: bool = { + use nonfungibles::Call::*; + matches!( + c, + RuntimeCall::NonFungibles( + transfer { .. } | + approve { .. } | create { .. } | + destroy { .. } | set_metadata { .. } | + clear_metadata { .. } | + set_attribute { .. } | + clear_attribute { .. } | + approve_item_attributes { .. } | + cancel_item_attributes_approval { .. } | + mint { .. } | burn { .. } | + set_max_supply { .. }, ) ) + }; + + T::BaseCallFilter::contains(c) && contain_fungibles | contain_nonfungibles } } impl Contains for Filter { fn contains(r: &RuntimeRead) -> bool { - use fungibles::Read::*; - matches!( - r, - RuntimeRead::Fungibles( - TotalSupply(..) | - BalanceOf { .. } | - Allowance { .. } | - TokenName(..) | TokenSymbol(..) | - TokenDecimals(..) | - TokenExists(..) + let contain_fungibles: bool = { + use fungibles::Read::*; + matches!( + r, + RuntimeRead::Fungibles( + TotalSupply(..) | + BalanceOf { .. } | Allowance { .. } | + TokenName(..) | TokenSymbol(..) | + TokenDecimals(..) | TokenExists(..), + ) + ) + }; + let contain_nonfungibles: bool = { + use nonfungibles::Read::*; + matches!( + r, + RuntimeRead::NonFungibles( + TotalSupply(..) | + BalanceOf { .. } | Allowance { .. } | + OwnerOf { .. } | GetAttribute { .. } | + Collection { .. } | NextCollectionId | + ItemMetadata { .. }, + ) ) - ) + }; + + contain_fungibles | contain_nonfungibles } } @@ -169,8 +221,9 @@ impl Contains for Filter { mod tests { use codec::Encode; use pallet_api::fungibles::Call::*; - use sp_core::crypto::AccountId32; - use RuntimeCall::{Balances, Fungibles}; + use pallet_nfts::MintWitness; + use sp_core::{bounded_vec, crypto::AccountId32}; + use RuntimeCall::{Balances, Fungibles, NonFungibles}; use super::*; @@ -181,6 +234,10 @@ mod tests { let value = 1_000; let result = fungibles::ReadResult::::TotalSupply(value); assert_eq!(RuntimeResult::Fungibles(result).encode(), value.encode()); + + let value = 1_000; + let result = nonfungibles::ReadResult::::TotalSupply(value); + assert_eq!(RuntimeResult::NonFungibles(result).encode(), value.encode()); } #[test] @@ -228,6 +285,71 @@ mod tests { } } + #[test] + fn filter_allows_nonfungibles_calls() { + use pallet_api::nonfungibles::{ + types::{CollectionConfig, CollectionSettings, MintSettings}, + Call::*, + }; + use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness}; + + for call in vec![ + NonFungibles(transfer { collection: 0, item: 0, to: ACCOUNT }), + NonFungibles(approve { + collection: 0, + item: Some(0), + operator: ACCOUNT, + approved: false, + }), + NonFungibles(create { + admin: ACCOUNT, + config: CollectionConfig { + max_supply: Some(0), + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled(), + }, + }), + NonFungibles(destroy { + collection: 0, + witness: DestroyWitness { attributes: 0, item_configs: 0, item_metadatas: 0 }, + }), + NonFungibles(set_attribute { + collection: 0, + item: Some(0), + namespace: pallet_nfts::AttributeNamespace::Pallet, + key: bounded_vec![], + value: bounded_vec![], + }), + NonFungibles(clear_attribute { + collection: 0, + item: Some(0), + namespace: pallet_nfts::AttributeNamespace::Pallet, + key: bounded_vec![], + }), + NonFungibles(set_metadata { collection: 0, item: 0, data: bounded_vec![] }), + NonFungibles(clear_metadata { collection: 0, item: 0 }), + NonFungibles(approve_item_attributes { collection: 0, item: 0, delegate: ACCOUNT }), + NonFungibles(cancel_item_attributes_approval { + collection: 0, + item: 0, + delegate: ACCOUNT, + witness: CancelAttributesApprovalWitness { account_attributes: 0 }, + }), + NonFungibles(set_max_supply { collection: 0, max_supply: 0 }), + NonFungibles(mint { + to: ACCOUNT, + collection: 0, + item: 0, + witness: MintWitness { mint_price: None, owned_item: None }, + }), + NonFungibles(burn { collection: 0, item: 0 }), + ] + .iter() + { + assert!(Filter::::contains(call)) + } + } + #[test] fn filter_allows_fungibles_reads() { use super::{fungibles::Read::*, RuntimeRead::*}; @@ -245,4 +367,33 @@ mod tests { assert!(Filter::::contains(&read)) } } + + #[test] + fn filter_allows_nonfungibles_reads() { + use super::{nonfungibles::Read::*, RuntimeRead::*}; + + for read in vec![ + NonFungibles(TotalSupply(1)), + NonFungibles(BalanceOf { collection: 1, owner: ACCOUNT }), + NonFungibles(Allowance { + collection: 1, + item: None, + owner: ACCOUNT, + operator: ACCOUNT, + }), + NonFungibles(OwnerOf { collection: 1, item: 1 }), + NonFungibles(GetAttribute { + collection: 0, + item: 0, + namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + key: bounded_vec![], + }), + NonFungibles(Collection(1)), + NonFungibles(NextCollectionId), + ] + .iter() + { + assert!(Filter::::contains(read)) + } + } } diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 326b7e59..28a51d52 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -6,7 +6,7 @@ use frame_support::{ use frame_system::{EnsureRoot, EnsureSigned}; use pallet_nfts::PalletFeatures; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId, Signature}; -use sp_runtime::traits::Verify; +use sp_runtime::traits::{Get, Verify}; use crate::{ deposit, AccountId, Assets, Balance, Balances, BlockNumber, Nfts, Runtime, RuntimeEvent, @@ -37,6 +37,15 @@ parameter_types! { pub const NftsMaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(PartialEq, Clone))] +pub struct KeyLimit; +impl Get for KeyLimit { + fn get() -> u32 { + N + } +} + impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; @@ -56,7 +65,7 @@ impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ItemId = ItemId; // TODO: source from primitives - type KeyLimit = ConstU32<64>; + type KeyLimit = KeyLimit<64>; type Locker = (); type MaxAttributesPerCall = ConstU32<10>; type MaxDeadlineDuration = NftsMaxDeadlineDuration; diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index f539cbde..1d860f62 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -39,7 +39,7 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use pallet_api::fungibles; +use pallet_api::{fungibles, nonfungibles}; use pallet_balances::Call as BalancesCall; use pallet_ismp::mmr::{Leaf, Proof, ProofKeys}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; @@ -637,6 +637,8 @@ mod runtime { // Pop API #[runtime::pallet_index(150)] pub type Fungibles = fungibles::Pallet; + #[runtime::pallet_index(151)] + pub type NonFungibles = nonfungibles::Pallet; } #[cfg(feature = "runtime-benchmarks")] @@ -648,6 +650,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] [pallet_message_queue, MessageQueue] + [pallet_nfts, Nfts] [pallet_sudo, Sudo] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] From f67dab1ae98fe0f04c278ab7f2de363859d6ae36 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:42:12 +0700 Subject: [PATCH 55/64] fix: becnhmark helper --- pallets/api/src/mock.rs | 19 +++++++++++++++++++ runtime/devnet/src/config/api/mod.rs | 7 +++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 8a4ad27d..1e6216f5 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -142,6 +142,25 @@ impl Verify for Noop { } } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_nfts::pallet::BenchmarkHelper for () { + fn collection(i: u16) -> u32 { + i.into() + } + + fn item(i: u16) -> u32 { + i.into() + } + + fn signer() -> (Noop, u64) { + unimplemented!() + } + + fn sign(signer: &Noop, message: &[u8]) -> Noop { + unimplemented!() + } +} + impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 93f4853f..b7c33279 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use codec::Decode; use cumulus_primitives_core::Weight; -use frame_support::traits::{ConstU32, Contains}; +use frame_support::traits::Contains; pub(crate) use pallet_api::Extension; use pallet_api::{extension::*, Read}; use sp_core::ConstU8; @@ -11,9 +11,8 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::{assets::TrustBackedAssetsInstance, xcm::LocalOriginToLocation}, - fungibles, nonfungibles, Balances, Ismp, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, - RuntimeHoldReason, TransactionByteFee, + config::assets::TrustBackedAssetsInstance, fungibles, nonfungibles, Runtime, RuntimeCall, + RuntimeEvent, }; mod versioning; From a4e16e8822f4ce16fe909d5ee918c22c99df37ea Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:39:46 +0700 Subject: [PATCH 56/64] feat: multi instances & function comments --- pallets/api/src/mock.rs | 7 +- pallets/api/src/nonfungibles/mod.rs | 172 ++++++++++++++++++++++---- pallets/api/src/nonfungibles/tests.rs | 52 ++++---- pallets/api/src/nonfungibles/types.rs | 27 ---- 4 files changed, 186 insertions(+), 72 deletions(-) delete mode 100644 pallets/api/src/nonfungibles/types.rs diff --git a/pallets/api/src/mock.rs b/pallets/api/src/mock.rs index 1e6216f5..d11a8c98 100644 --- a/pallets/api/src/mock.rs +++ b/pallets/api/src/mock.rs @@ -32,7 +32,7 @@ frame_support::construct_runtime!( Assets: pallet_assets::, Balances: pallet_balances, Fungibles: crate::fungibles, - Nfts: pallet_nfts, + Nfts: pallet_nfts::, NonFungibles: crate::nonfungibles } ); @@ -161,7 +161,8 @@ impl pallet_nfts::pallet::BenchmarkHelper for () { } } -impl pallet_nfts::Config for Test { +type NftsInstance = pallet_nfts::Instance1; +impl pallet_nfts::Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU128<1>; type CollectionDeposit = ConstU128<2>; @@ -191,7 +192,9 @@ impl pallet_nfts::Config for Test { } impl crate::nonfungibles::Config for Test { + type NftsInstance = NftsInstance; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 1a5b07b8..b3370a84 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -2,14 +2,40 @@ //! assets. The goal is to provide a simplified, consistent API that adheres to standards in the //! smart contract space. +use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; +use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; use pallet_nfts::WeightInfo; +pub use pallet_nfts::{ + AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, + DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, +}; use sp_runtime::traits::StaticLookup; -pub use types::*; #[cfg(test)] mod tests; -pub mod types; + +type AccountIdOf = ::AccountId; +type NftsOf = pallet_nfts::Pallet>; +type NftsErrorOf = pallet_nfts::Error>; +type NftsWeightInfoOf = >>::WeightInfo; +type NftsInstanceOf = ::NftsInstance; +type BalanceOf = <>>::Currency as Currency< + ::AccountId, +>>::Balance; +type CollectionIdOf = + as Inspect<::AccountId>>::CollectionId; +type ItemIdOf = as Inspect<::AccountId>>::ItemId; +type ItemPriceOf = BalanceOf; +type CollectionDetailsFor = CollectionDetails, BalanceOf>; +type AttributeNamespaceOf = AttributeNamespace>; +type CollectionConfigFor = + CollectionConfig, BlockNumberFor, CollectionIdOf>; +// Type aliases for storage items. +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; +pub(super) type AttributeOf = pallet_nfts::Attribute>; +pub(super) type CollectionOf = pallet_nfts::Collection>; #[frame_support::pallet] pub mod pallet { @@ -18,10 +44,6 @@ pub mod pallet { use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness}; use sp_runtime::BoundedVec; use sp_std::vec::Vec; - use types::{ - AccountIdOf, AttributeNamespaceOf, BalanceOf, CollectionConfigFor, CollectionDetailsFor, - CollectionIdOf, ItemIdOf, ItemPriceOf, NextCollectionIdOf, NftsOf, NftsWeightInfoOf, - }; use super::*; @@ -31,39 +53,64 @@ pub mod pallet { #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Total item supply of a collection. + /// Total item supply of a specified collection. #[codec(index = 0)] TotalSupply(CollectionIdOf), /// Account balance for a specified collection. #[codec(index = 1)] - BalanceOf { collection: CollectionIdOf, owner: AccountIdOf }, + BalanceOf { + // The collection. + collection: CollectionIdOf, + // The owner of the collection . + owner: AccountIdOf, + }, /// Allowance for an operator approved by an owner, for a specified collection or item. #[codec(index = 2)] Allowance { + // The collection. collection: CollectionIdOf, + // The collection item. + item: Option>, + // The owner of the collection item. owner: AccountIdOf, + // The delegated operator of collection item. operator: AccountIdOf, - item: Option>, }, /// Owner of a specified collection item. #[codec(index = 5)] - OwnerOf { collection: CollectionIdOf, item: ItemIdOf }, - /// Attribute value of a collection item. (Error: bounded collection is not partial) + OwnerOf { + // The collection. + collection: CollectionIdOf, + // The collection item. + item: ItemIdOf, + }, + /// Attribute value of a specified collection item. (Error: bounded collection is not + /// partial) #[codec(index = 6)] GetAttribute { + // The collection. collection: CollectionIdOf, + // The collection item. item: ItemIdOf, + // The namespace of the attribute. namespace: AttributeNamespaceOf, + // The key of the attribute. key: BoundedVec, }, - /// Details of a collection. + /// Details of a specified collection. #[codec(index = 9)] Collection(CollectionIdOf), /// Next collection ID. #[codec(index = 10)] NextCollectionId, + /// Metadata of a specified collection item. #[codec(index = 11)] - ItemMetadata { collection: CollectionIdOf, item: ItemIdOf }, + ItemMetadata { + // The collection. + collection: CollectionIdOf, + // The collection item. + item: ItemIdOf, + }, } /// Results of state reads for the non-fungibles API. @@ -78,13 +125,13 @@ pub mod pallet { Allowance(bool), /// Owner of a specified collection owner. OwnerOf(Option>), - /// Attribute value of a collection item. + /// Attribute value of a specified collection item. GetAttribute(Option>), - /// Details of a collection. + /// Details of a specified collection. Collection(Option>), /// Next collection ID. NextCollectionId(Option>), - /// Collection item metadata. + /// Metadata of a specified collection item. ItemMetadata(Option>), } @@ -107,9 +154,13 @@ pub mod pallet { /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] - pub trait Config: frame_system::Config + pallet_nfts::Config { + pub trait Config: frame_system::Config + pallet_nfts::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The instance of pallet-nfts. + type NftsInstance; + /// Weight information for dispatchables in this pallet. + type WeightInfo: WeightInfo; } #[pallet::pallet] @@ -159,6 +210,12 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// 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. + /// - `to` - The recipient account. #[pallet::call_index(3)] #[pallet::weight(NftsWeightInfoOf::::transfer())] pub fn transfer( @@ -179,6 +236,13 @@ pub mod pallet { 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. + /// - `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::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] pub fn approve( @@ -209,6 +273,12 @@ pub mod pallet { Ok(()) } + /// 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::::create())] pub fn create( @@ -220,13 +290,19 @@ pub mod pallet { // issues for setting it to xcm's `Location`. This can easily be done differently. let id = NextCollectionIdOf::::get() .or(T::CollectionId::initial_value()) - .ok_or(pallet_nfts::Error::::UnknownCollection)?; + .ok_or(NftsErrorOf::::UnknownCollection)?; let creator = ensure_signed(origin.clone())?; NftsOf::::create(origin, T::Lookup::unlookup(admin.clone()), config)?; Self::deposit_event(Event::Created { id, admin, creator }); Ok(()) } + /// Destroy a collection of fungible items. + /// + /// # Parameters + /// - `collection` - The identifier of the collection to be destroyed. + /// - `witness` - Information on the items minted in the collection. This must be + /// correct. #[pallet::call_index(8)] #[pallet::weight(NftsWeightInfoOf::::destroy( witness.item_metadatas, @@ -241,6 +317,14 @@ pub mod pallet { NftsOf::::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::::set_attribute())] pub fn set_attribute( @@ -254,6 +338,13 @@ pub mod pallet { NftsOf::::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::::clear_attribute())] pub fn clear_attribute( @@ -266,6 +357,12 @@ pub mod pallet { NftsOf::::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::::set_metadata())] pub fn set_metadata( @@ -287,6 +384,12 @@ pub mod pallet { NftsOf::::clear_metadata(origin, collection, item) } + /// Approve item's attributes to be changed by a delegated third-party account. + /// + /// # Parameters + /// - `collection` - The collection of the item. + /// - `item` - The item that holds attributes. + /// - `delegate` - The account to delegate permission to change attributes of the item. #[pallet::call_index(16)] #[pallet::weight(NftsWeightInfoOf::::approve_item_attributes())] pub fn approve_item_attributes( @@ -303,6 +406,14 @@ pub mod pallet { ) } + /// Cancel the previously provided approval to change item's attributes. + /// All the previously set attributes by the `delegate` will be removed. + /// + /// # Parameters + /// - `collection` - 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. #[pallet::call_index(17)] #[pallet::weight(NftsWeightInfoOf::::cancel_item_attributes_approval(witness.account_attributes))] pub fn cancel_item_attributes_approval( @@ -321,6 +432,11 @@ pub mod pallet { ) } + /// Set the maximum number of items a collection could have. + /// + /// # Parameters + /// - `collection` - The identifier of the collection to change. + /// - `max_supply` - The maximum number of items a collection could have. #[pallet::call_index(18)] #[pallet::weight(NftsWeightInfoOf::::set_collection_max_supply())] pub fn set_max_supply( @@ -331,6 +447,15 @@ pub mod pallet { NftsOf::::set_collection_max_supply(origin, collection, max_supply) } + /// Mint an item of a particular collection. + /// + /// # Parameters + /// - `collection` - The collection of the item to be minted. + /// - `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`. #[pallet::call_index(19)] #[pallet::weight(NftsWeightInfoOf::::mint())] pub fn mint( @@ -359,6 +484,11 @@ pub mod pallet { Ok(()) } + /// Destroy a single collection item. + /// + /// # Parameters + /// - `collection` - The collection of the item to be burned. + /// - `item` - The item to be burned. #[pallet::call_index(20)] #[pallet::weight(NftsWeightInfoOf::::burn())] pub fn burn( @@ -405,18 +535,18 @@ pub mod pallet { NftsOf::::collection_items(collection).unwrap_or_default() as u128, ), BalanceOf { collection, owner } => - ReadResult::BalanceOf(pallet_nfts::AccountBalance::::get(collection, owner)), + ReadResult::BalanceOf(AccountBalanceOf::::get(collection, owner)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), OwnerOf { collection, item } => ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( - pallet_nfts::Attribute::::get((collection, Some(item), namespace, key)) + AttributeOf::::get((collection, Some(item), namespace, key)) .map(|attribute| attribute.0.into()), ), Collection(collection) => - ReadResult::Collection(pallet_nfts::Collection::::get(collection)), + ReadResult::Collection(CollectionOf::::get(collection)), ItemMetadata { collection, item } => ReadResult::ItemMetadata( NftsOf::::item_metadata(collection, item).map(|metadata| metadata.into()), ), diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 79d484a2..290f49f2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -1,22 +1,24 @@ use codec::Encode; -use frame_support::{assert_noop, assert_ok, traits::Incrementable}; -use frame_system::pallet_prelude::BlockNumberFor; -use pallet_nfts::{ - AccountBalance, CollectionConfig, CollectionDetails, CollectionSettings, DestroyWitness, - MintSettings, MintWitness, +use frame_support::{ + assert_noop, assert_ok, + sp_runtime::{BoundedVec, DispatchError::BadOrigin}, + traits::Incrementable, }; -use sp_runtime::{BoundedVec, DispatchError::BadOrigin}; -use super::types::{CollectionIdOf, ItemIdOf}; use crate::{ mock::*, - nonfungibles::{Event, Read::*, ReadResult}, + nonfungibles::{ + AccountBalanceOf, BlockNumberFor, CollectionConfig, CollectionDetails, CollectionIdOf, + CollectionOf, CollectionSettings, DestroyWitness, ItemIdOf, MintSettings, MintWitness, + NextCollectionIdOf, NftsInstanceOf, Read::*, ReadResult, + }, Read, }; const ITEM: u32 = 1; -type NftsError = pallet_nfts::Error; +type NftsError = pallet_nfts::Error>; +type Event = crate::nonfungibles::Event; mod encoding_read_result { use super::*; @@ -116,10 +118,10 @@ fn transfer() { assert_noop!(NonFungibles::transfer(origin, collection, item, dest), BadOrigin); } // Successfully burn an existing new collection item. - let balance_before_transfer = AccountBalance::::get(collection, &dest); + let balance_before_transfer = AccountBalanceOf::::get(collection, &dest); assert_ok!(NonFungibles::transfer(signed(owner), collection, ITEM, dest)); - let balance_after_transfer = AccountBalance::::get(collection, &dest); - assert_eq!(AccountBalance::::get(collection, &owner), 0); + let balance_after_transfer = AccountBalanceOf::::get(collection, &dest); + assert_eq!(AccountBalanceOf::::get(collection, &owner), 0); assert_eq!(balance_after_transfer - balance_before_transfer, 1); System::assert_last_event( Event::Transfer { collection, item, from: Some(owner), to: Some(dest), price: None } @@ -135,7 +137,7 @@ fn mint_works() { let collection = nfts::create_collection(owner); // Successfully mint a new collection item. - let balance_before_mint = AccountBalance::::get(collection, owner); + let balance_before_mint = AccountBalanceOf::::get(collection, owner); assert_ok!(NonFungibles::mint( signed(owner), owner, @@ -143,7 +145,7 @@ fn mint_works() { ITEM, MintWitness { mint_price: None, owned_item: None } )); - let balance_after_mint = AccountBalance::::get(collection, owner); + let balance_after_mint = AccountBalanceOf::::get(collection, owner); assert_eq!(balance_after_mint, 1); assert_eq!(balance_after_mint - balance_before_mint, 1); System::assert_last_event( @@ -233,7 +235,9 @@ fn get_attribute_works() { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option::ValueLimit>> = None; + let mut result: Option< + BoundedVec>>::ValueLimit>, + > = None; // No attribute set. assert_eq!( NonFungibles::read(GetAttribute { @@ -305,7 +309,9 @@ fn clear_attribute_works() { let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let result: Option::ValueLimit>> = None; + let result: Option< + BoundedVec>>::ValueLimit>, + > = None; assert_ok!(Nfts::set_attribute( signed(ALICE), collection, @@ -352,7 +358,9 @@ fn approve_item_attribute_works() { attribute.clone(), value.clone() )); - let result: Option::ValueLimit>> = Some(value); + let result: Option< + BoundedVec>>::ValueLimit>, + > = Some(value); assert_eq!( NonFungibles::read(GetAttribute { collection, @@ -411,7 +419,7 @@ fn next_collection_id_works() { assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); assert_eq!( NonFungibles::read(NextCollectionId).encode(), - pallet_nfts::NextCollectionId::::get() + NextCollectionIdOf::::get() .or(CollectionIdOf::::initial_value()) .encode(), ); @@ -441,7 +449,7 @@ fn total_supply_works() { fn create_works() { new_test_ext().execute_with(|| { let owner = ALICE; - let next_collection_id = pallet_nfts::NextCollectionId::::get().unwrap_or_default(); + let next_collection_id = NextCollectionIdOf::::get().unwrap_or_default(); assert_ok!(NonFungibles::create( signed(owner), owner, @@ -474,7 +482,7 @@ fn collection_works() { let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); assert_eq!( NonFungibles::read(Collection(collection)).encode(), - pallet_nfts::Collection::::get(&collection).encode(), + CollectionOf::::get(&collection).encode(), ); }); } @@ -492,7 +500,7 @@ fn balance_of_works() { ); assert_eq!( NonFungibles::read(BalanceOf { collection, owner }).encode(), - AccountBalance::::get(collection, owner).encode() + AccountBalanceOf::::get(collection, owner).encode() ); }); }); @@ -561,7 +569,7 @@ mod nfts { } pub(super) fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() + NextCollectionIdOf::::get().unwrap_or_default() } pub(super) fn collection_config_with_all_settings_enabled( diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs deleted file mode 100644 index 6e686389..00000000 --- a/pallets/api/src/nonfungibles/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -use frame_support::traits::{nonfungibles_v2::Inspect, Currency}; -use frame_system::pallet_prelude::BlockNumberFor; -pub use pallet_nfts::{ - AttributeNamespace, CollectionConfig, CollectionDetails, CollectionSetting, CollectionSettings, - DestroyWitness, ItemDeposit, ItemDetails, ItemSetting, MintSettings, MintType, MintWitness, -}; - -// Type aliases for pallet-nfts. -pub(super) type NftsOf = pallet_nfts::Pallet; -pub(super) type NftsWeightInfoOf = ::WeightInfo; -// Type aliases for pallet-nfts storage items. -pub(super) type AccountIdOf = ::AccountId; -pub(super) type BalanceOf = <>::Currency as Currency< - ::AccountId, ->>::Balance; -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId; -pub(super) type CollectionIdOf = - as Inspect<::AccountId>>::CollectionId; -pub(super) type ItemIdOf = - as Inspect<::AccountId>>::ItemId; -pub(super) type ItemPriceOf = BalanceOf; -// TODO: Multi-instances. -pub(super) type CollectionDetailsFor = - CollectionDetails, BalanceOf>; -pub(super) type AttributeNamespaceOf = AttributeNamespace>; -pub(super) type CollectionConfigFor = - CollectionConfig, BlockNumberFor, CollectionIdOf>; From 73e1df5a48751531b28f5715232c4a43a98472cb Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:31:33 +0700 Subject: [PATCH 57/64] feat(devnet): pallet nfts instance configuration --- runtime/devnet/src/config/api/mod.rs | 9 ++++--- runtime/devnet/src/config/assets.rs | 8 +++--- runtime/devnet/src/config/proxy.rs | 38 ++++++++++++++-------------- runtime/devnet/src/lib.rs | 2 +- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index b7c33279..5ea1d923 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -11,8 +11,8 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::TrustBackedAssetsInstance, fungibles, nonfungibles, Runtime, RuntimeCall, - RuntimeEvent, + config::assets::{NftsInstance, TrustBackedAssetsInstance}, + fungibles, nonfungibles, Runtime, RuntimeCall, RuntimeEvent, }; mod versioning; @@ -88,7 +88,9 @@ impl fungibles::Config for Runtime { } impl nonfungibles::Config for Runtime { + type NftsInstance = NftsInstance; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } #[derive(Default)] @@ -287,8 +289,7 @@ mod tests { #[test] fn filter_allows_nonfungibles_calls() { use pallet_api::nonfungibles::{ - types::{CollectionConfig, CollectionSettings, MintSettings}, - Call::*, + Call::*, CollectionConfig, CollectionSettings, MintSettings, }; use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness}; diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 28a51d52..97c2a9e7 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -46,7 +46,9 @@ impl Get for KeyLimit { } } -impl pallet_nfts::Config for Runtime { +pub(crate) type NftsInstance = pallet_nfts::Instance1; +pub type NftsCall = pallet_nfts::Call; +impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; @@ -95,8 +97,8 @@ impl pallet_nft_fractionalization::Config for Runtime { type Deposit = AssetDeposit; type NewAssetName = NewAssetName; type NewAssetSymbol = NewAssetSymbol; - type NftCollectionId = ::CollectionId; - type NftId = ::ItemId; + type NftCollectionId = >::CollectionId; + type NftId = >::ItemId; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index ff70240e..161178dc 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -5,7 +5,7 @@ use pop_runtime_common::proxy::{ }; use sp_runtime::traits::BlakeTwo256; -use super::assets::TrustBackedAssetsCall; +use super::assets::{NftsCall, TrustBackedAssetsCall}; use crate::{Balances, Runtime, RuntimeCall, RuntimeEvent}; impl InstanceFilter for ProxyType { @@ -45,13 +45,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::create { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::destroy { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::redeposit { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::transfer_ownership { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_team { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_collection { .. }) | + RuntimeCall::Nfts(NftsCall::create { .. }) | + RuntimeCall::Nfts(NftsCall::destroy { .. }) | + RuntimeCall::Nfts(NftsCall::redeposit { .. }) | + RuntimeCall::Nfts(NftsCall::transfer_ownership { .. }) | + RuntimeCall::Nfts(NftsCall::set_team { .. }) | + RuntimeCall::Nfts(NftsCall::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(NftsCall::lock_collection { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -66,17 +66,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::force_mint { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::update_mint_settings { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::mint_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::lock_item_properties { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::set_collection_metadata { .. }) | - RuntimeCall::Nfts(pallet_nfts::Call::clear_collection_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::force_mint { .. }) | + RuntimeCall::Nfts(NftsCall::update_mint_settings { .. }) | + RuntimeCall::Nfts(NftsCall::mint_pre_signed { .. }) | + RuntimeCall::Nfts(NftsCall::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(NftsCall::lock_item_transfer { .. }) | + RuntimeCall::Nfts(NftsCall::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(NftsCall::lock_item_properties { .. }) | + RuntimeCall::Nfts(NftsCall::set_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::clear_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::set_collection_metadata { .. }) | + RuntimeCall::Nfts(NftsCall::clear_collection_metadata { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 1d860f62..839f819d 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -628,7 +628,7 @@ mod runtime { // Assets #[runtime::pallet_index(50)] - pub type Nfts = pallet_nfts::Pallet; + pub type Nfts = pallet_nfts::Pallet; #[runtime::pallet_index(51)] pub type NftFractionalization = pallet_nft_fractionalization::Pallet; #[runtime::pallet_index(52)] From bbb9bb4f4a1c61d5d0cb335e31667789cef243b6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:46:04 +0700 Subject: [PATCH 58/64] chore: resolve feedback --- Cargo.lock | 22 +++++++++++----------- pallets/nfts/Cargo.toml | 3 ++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71903ca0..3414de0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -7366,7 +7366,7 @@ dependencies = [ "log", "pallet-assets", "pallet-balances", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "parity-scale-codec", "pop-chain-extension", "scale-info", @@ -8240,39 +8240,39 @@ dependencies = [ [[package]] name = "pallet-nfts" -version = "0.1.0" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-keystore", "sp-runtime", + "sp-std", ] [[package]] name = "pallet-nfts" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1cd476809de3840e19091a083d5a79178af1f108ad489706e1f9e04c8836a4" +version = "31.0.0" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", - "sp-std", ] [[package]] @@ -10857,7 +10857,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -11002,7 +11002,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts 0.1.0", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 722e8ef8..791db0a7 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -6,7 +6,8 @@ homepage = "https://substrate.io" license.workspace = true name = "pallet-nfts" readme = "README.md" -version = "0.1.0" +repository.workspace = true +version = "31.0.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From e07565dc8c292a64ba9df1267bb0b731d47f4c72 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Sat, 16 Nov 2024 17:53:09 +0700 Subject: [PATCH 59/64] feat(api/nonfungibles): destroy collection witness data & weights (#383) chore: rename nfts instance feat(api/nonfungibles): destroy collection witness data & weights (#383) chore: rename nfts instance fix(api/nonfungibles): pallet weight testing --- pallets/api/src/nonfungibles/benchmarking.rs | 110 +++ pallets/api/src/nonfungibles/mod.rs | 114 +-- pallets/api/src/nonfungibles/tests.rs | 674 ++++++++++++++---- pallets/api/src/nonfungibles/weights.rs | 217 ++++++ pallets/nfts/src/benchmarking.rs | 62 +- pallets/nfts/src/common_functions.rs | 5 + pallets/nfts/src/features/approvals.rs | 18 + .../src/features/create_delete_collection.rs | 11 +- .../nfts/src/features/create_delete_item.rs | 16 +- pallets/nfts/src/features/transfer.rs | 23 +- pallets/nfts/src/lib.rs | 9 +- pallets/nfts/src/migration.rs | 120 ---- pallets/nfts/src/tests.rs | 50 +- pallets/nfts/src/types.rs | 12 + pallets/nfts/src/weights.rs | 570 ++++++++------- runtime/devnet/src/config/api/mod.rs | 12 +- runtime/devnet/src/config/assets.rs | 10 +- runtime/devnet/src/config/proxy.rs | 38 +- runtime/devnet/src/lib.rs | 1 + 19 files changed, 1461 insertions(+), 611 deletions(-) create mode 100644 pallets/api/src/nonfungibles/benchmarking.rs create mode 100644 pallets/api/src/nonfungibles/weights.rs delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/api/src/nonfungibles/benchmarking.rs b/pallets/api/src/nonfungibles/benchmarking.rs new file mode 100644 index 00000000..45d9d5bd --- /dev/null +++ b/pallets/api/src/nonfungibles/benchmarking.rs @@ -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 + > as Inspect<::AccountId>>::ItemId: Zero, + > as Inspect<::AccountId>>::CollectionId: Zero, +)] +mod benchmarks { + use super::*; + + #[benchmark] + // Storage: `Collection` + fn total_supply() { + #[block] + { + Pallet::::read(Read::TotalSupply(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `AccountBalance` + fn balance_of() { + #[block] + { + Pallet::::read(Read::BalanceOf { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + }); + } + } + + #[benchmark] + // Storage: `Allowances`, `Item` + fn allowance() { + #[block] + { + Pallet::::read(Read::Allowance { + collection: CollectionIdOf::::zero(), + owner: account("Alice", 0, SEED), + operator: account("Bob", 0, SEED), + item: Some(ItemIdOf::::zero()), + }); + } + } + + #[benchmark] + // Storage: `Item` + fn owner_of() { + #[block] + { + Pallet::::read(Read::OwnerOf { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } + + #[benchmark] + // Storage: `Attribute` + fn get_attribute() { + #[block] + { + Pallet::::read(Read::GetAttribute { + key: BoundedVec::default(), + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + namespace: AttributeNamespace::CollectionOwner, + }); + } + } + + #[benchmark] + // Storage: `Collection` + fn collection() { + #[block] + { + Pallet::::read(Read::Collection(CollectionIdOf::::zero())); + } + } + + #[benchmark] + // Storage: `NextCollectionId` + fn next_collection_id() { + #[block] + { + Pallet::::read(Read::NextCollectionId); + } + } + + #[benchmark] + // Storage: `ItemMetadata` + fn item_metadata() { + #[block] + { + Pallet::::read(Read::ItemMetadata { + collection: CollectionIdOf::::zero(), + item: ItemIdOf::::zero(), + }); + } + } +} diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index b3370a84..6da7de5f 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -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 = ::AccountId; type NftsOf = pallet_nfts::Pallet>; @@ -31,15 +36,19 @@ type CollectionDetailsFor = CollectionDetails, BalanceOf>; type AttributeNamespaceOf = AttributeNamespace>; type CollectionConfigFor = CollectionConfig, BlockNumberFor, CollectionIdOf>; -// Type aliases for storage items. -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +// Type aliases for pallet-nfts storage items. pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; pub(super) type AttributeOf = pallet_nfts::Attribute>; +pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; pub(super) type CollectionOf = pallet_nfts::Collection>; #[frame_support::pallet] 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; @@ -59,42 +68,42 @@ pub mod pallet { /// Account balance for a specified collection. #[codec(index = 1)] BalanceOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The owner of the collection . + /// The owner of the collection . owner: AccountIdOf, }, /// Allowance for an operator approved by an owner, for a specified collection or item. #[codec(index = 2)] Allowance { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: Option>, - // The owner of the collection item. + /// The owner of the collection item. owner: AccountIdOf, - // The delegated operator of collection item. + /// The delegated operator of collection item. operator: AccountIdOf, }, /// Owner of a specified collection item. #[codec(index = 5)] OwnerOf { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, /// Attribute value of a specified collection item. (Error: bounded collection is not /// partial) #[codec(index = 6)] GetAttribute { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, - // The namespace of the attribute. + /// The namespace of the attribute. namespace: AttributeNamespaceOf, - // The key of the attribute. + /// The key of the attribute. key: BoundedVec, }, /// Details of a specified collection. @@ -106,9 +115,9 @@ pub mod pallet { /// Metadata of a specified collection item. #[codec(index = 11)] ItemMetadata { - // The collection. + /// The collection. collection: CollectionIdOf, - // The collection item. + /// The collection item. item: ItemIdOf, }, } @@ -213,8 +222,8 @@ pub mod pallet { /// 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::::transfer())] @@ -239,38 +248,49 @@ pub mod pallet { /// 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::::approve_transfer() + NftsWeightInfoOf::::cancel_approval())] + #[pallet::weight( + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) + + NftsWeightInfoOf::::cancel_approval(item.is_some() as u32) + )] pub fn approve( origin: OriginFor, collection: CollectionIdOf, item: Option>, operator: AccountIdOf, approved: bool, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let owner = ensure_signed(origin.clone())?; - if approved { + let weight = if approved { NftsOf::::approve_transfer( origin, collection, item, T::Lookup::unlookup(operator.clone()), None, - )?; + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::approve_transfer(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::approve_transfer(item.is_some() as u32) } else { NftsOf::::cancel_approval( origin, collection, item, T::Lookup::unlookup(operator.clone()), - )?; - } + ) + .map_err(|e| { + e.with_weight(NftsWeightInfoOf::::cancel_approval(item.is_some() as u32)) + })?; + NftsWeightInfoOf::::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. @@ -286,21 +306,21 @@ pub mod pallet { admin: AccountIdOf, config: CollectionConfigFor, ) -> 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::::get() .or(T::CollectionId::initial_value()) .ok_or(NftsErrorOf::::UnknownCollection)?; - let creator = ensure_signed(origin.clone())?; NftsOf::::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)] @@ -308,6 +328,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -410,7 +432,7 @@ pub mod pallet { /// 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. @@ -450,9 +472,9 @@ pub mod pallet { /// 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`. @@ -487,8 +509,8 @@ pub mod pallet { /// 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::::burn())] pub fn burn( @@ -520,8 +542,18 @@ pub mod pallet { /// /// # Parameters /// - `request` - The read request. - fn weight(_request: &Self::Read) -> Weight { - Default::default() + fn weight(request: &Self::Read) -> Weight { + use Read::*; + match request { + TotalSupply(_) => ::WeightInfo::total_supply(), + BalanceOf { .. } => ::WeightInfo::balance_of(), + Allowance { .. } => ::WeightInfo::allowance(), + OwnerOf { .. } => ::WeightInfo::owner_of(), + GetAttribute { .. } => ::WeightInfo::get_attribute(), + Collection(_) => ::WeightInfo::collection(), + ItemMetadata { .. } => ::WeightInfo::item_metadata(), + NextCollectionId => ::WeightInfo::next_collection_id(), + } } /// Performs the requested read and returns the result. diff --git a/pallets/api/src/nonfungibles/tests.rs b/pallets/api/src/nonfungibles/tests.rs index 290f49f2..68260ab2 100644 --- a/pallets/api/src/nonfungibles/tests.rs +++ b/pallets/api/src/nonfungibles/tests.rs @@ -2,19 +2,21 @@ use codec::Encode; use frame_support::{ assert_noop, assert_ok, sp_runtime::{BoundedVec, DispatchError::BadOrigin}, - traits::Incrementable, }; +use pallet_nfts::WeightInfo as NftsWeightInfoTrait; use crate::{ mock::*, nonfungibles::{ - AccountBalanceOf, BlockNumberFor, CollectionConfig, CollectionDetails, CollectionIdOf, + AccountBalanceOf, AttributeNamespace, AttributeOf, BlockNumberFor, + CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails, CollectionIdOf, CollectionOf, CollectionSettings, DestroyWitness, ItemIdOf, MintSettings, MintWitness, - NextCollectionIdOf, NftsInstanceOf, Read::*, ReadResult, + NextCollectionIdOf, NftsInstanceOf, NftsWeightInfoOf, Read::*, ReadResult, }, Read, }; +const COLLECTION: u32 = 0; const ITEM: u32 = 1; type NftsError = pallet_nfts::Error>; @@ -71,7 +73,9 @@ mod encoding_read_result { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }); assert_eq!( ReadResult::Collection::(collection_details.clone()).encode(), @@ -160,9 +164,14 @@ fn burn_works() { new_test_ext().execute_with(|| { let owner = ALICE; + // "UnknownItem" error is returned if collection item is not created. + assert_noop!(NonFungibles::burn(signed(owner), COLLECTION, ITEM), NftsError::UnknownItem); // Successfully burn an existing new collection item. let (collection, item) = nfts::create_collection_mint(owner, ITEM); + let balance_before_burn = AccountBalanceOf::::get(collection, owner); assert_ok!(NonFungibles::burn(signed(owner), collection, ITEM)); + let balance_after_burn = AccountBalanceOf::::get(collection, owner); + assert_eq!(balance_after_burn, balance_before_burn - 1); System::assert_last_event( Event::Transfer { collection, item, from: Some(owner), to: None, price: None }.into(), ); @@ -175,8 +184,12 @@ fn approve_works() { let owner = ALICE; let operator = BOB; let (collection, item) = nfts::create_collection_mint(owner, ITEM); - // Successfully approve `oeprator` to transfer the collection item. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, true)); + // Successfully approve `operator` to transfer the collection item. + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer(1)).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &Some(item), &owner, &operator)); System::assert_last_event( Event::Approval { collection, item: Some(item), owner, operator, approved: true } .into(), @@ -186,6 +199,26 @@ fn approve_works() { }); } +#[test] +fn approve_collection_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully approve `operator` to transfer all items within the collection. + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, true), + Ok(Some(NftsWeightInfoOf::::approve_transfer(0)).into()) + ); + assert_ok!(Nfts::check_allowance(&collection, &None, &owner, &operator)); + System::assert_last_event( + Event::Approval { collection, item: None, owner, operator, approved: true }.into(), + ); + // Successfully transfer the item by the delegated account `operator`. + assert_ok!(Nfts::transfer(signed(operator), collection, item, operator)); + }); +} + #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { @@ -193,7 +226,38 @@ fn cancel_approval_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); // Successfully cancel the transfer approval of `operator` by `owner`. - assert_ok!(NonFungibles::approve(signed(owner), collection, Some(item), operator, false)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, Some(item), operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval(1)).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &Some(item), &owner, &operator), + Err(NftsError::NoPermission.into()) + ); + // Failed to transfer the item by `operator` without permission. + assert_noop!( + Nfts::transfer(signed(operator), collection, item, operator), + NftsError::NoPermission + ); + }); +} + +#[test] +fn cancel_collection_approval_works() { + new_test_ext().execute_with(|| { + let owner = ALICE; + let operator = BOB; + let (collection, item) = nfts::create_collection_mint(owner, ITEM); + // Successfully cancel the transfer collection approval of `operator` by `owner`. + assert_ok!(Nfts::approve_transfer(signed(owner), collection, None, operator, None)); + assert_eq!( + NonFungibles::approve(signed(owner), collection, None, operator, false), + Ok(Some(NftsWeightInfoOf::::cancel_approval(0)).into()) + ); + assert_eq!( + Nfts::check_allowance(&collection, &None, &owner, &operator), + Err(NftsError::NoPermission.into()) + ); // Failed to transfer the item by `operator` without permission. assert_noop!( Nfts::transfer(signed(operator), collection, item, operator), @@ -218,60 +282,6 @@ fn set_max_supply_works() { }); } -#[test] -fn owner_of_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(OwnerOf { collection, item }).encode(), - Nfts::owner(collection, item).encode() - ); - }); -} - -#[test] -fn get_attribute_works() { - new_test_ext().execute_with(|| { - let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); - let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); - let value = BoundedVec::truncate_from("some value".as_bytes().to_vec()); - let mut result: Option< - BoundedVec>>::ValueLimit>, - > = None; - // No attribute set. - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute.clone() - }) - .encode(), - result.encode() - ); - // Successfully get an existing attribute. - result = Some(value.clone()); - assert_ok!(Nfts::set_attribute( - signed(ALICE), - collection, - Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, - attribute.clone(), - value, - )); - assert_eq!( - NonFungibles::read(GetAttribute { - collection, - item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, - key: attribute - }) - .encode(), - result.encode() - ); - }); -} - #[test] fn set_metadata_works() { new_test_ext().execute_with(|| { @@ -316,7 +326,7 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), BoundedVec::truncate_from("some value".as_bytes().to_vec()) )); @@ -325,14 +335,14 @@ fn clear_attribute_works() { signed(ALICE), collection, Some(item), - pallet_nfts::AttributeNamespace::CollectionOwner, + AttributeNamespace::CollectionOwner, attribute.clone(), )); assert_eq!( NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::CollectionOwner, + namespace: AttributeNamespace::CollectionOwner, key: attribute }) .encode(), @@ -354,7 +364,7 @@ fn approve_item_attribute_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -365,7 +375,7 @@ fn approve_item_attribute_works() { NonFungibles::read(GetAttribute { collection, item, - namespace: pallet_nfts::AttributeNamespace::Account(BOB), + namespace: AttributeNamespace::Account(BOB), key: attribute }) .encode(), @@ -387,7 +397,7 @@ fn cancel_item_attribute_approval_works() { signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() )); @@ -396,14 +406,14 @@ fn cancel_item_attribute_approval_works() { collection, item, BOB, - pallet_nfts::CancelAttributesApprovalWitness { account_attributes: 1 } + CancelAttributesApprovalWitness { account_attributes: 1 } )); assert_noop!( Nfts::set_attribute( signed(BOB), collection, Some(item), - pallet_nfts::AttributeNamespace::Account(BOB), + AttributeNamespace::Account(BOB), attribute.clone(), value.clone() ), @@ -412,78 +422,79 @@ fn cancel_item_attribute_approval_works() { }); } -#[test] -fn next_collection_id_works() { - new_test_ext().execute_with(|| { - let _ = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!(NonFungibles::read(NextCollectionId).encode(), Some(1).encode()); - assert_eq!( - NonFungibles::read(NextCollectionId).encode(), - NextCollectionIdOf::::get() - .or(CollectionIdOf::::initial_value()) - .encode(), - ); - }); -} - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let owner = ALICE; - let collection = nfts::create_collection(owner); - (0..10).into_iter().for_each(|i| { - assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - ((i + 1) as u128).encode() - ); - assert_eq!( - NonFungibles::read(TotalSupply(collection)).encode(), - (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() - ); - }); - }); -} - #[test] fn create_works() { new_test_ext().execute_with(|| { - let owner = ALICE; + let creator = ALICE; + let admin = ALICE; let next_collection_id = NextCollectionIdOf::::get().unwrap_or_default(); + for origin in vec![root(), none()] { + assert_noop!( + NonFungibles::create( + origin, + admin, + CollectionConfig { + max_supply: None, + mint_settings: MintSettings::default(), + settings: CollectionSettings::all_enabled() + }, + ), + BadOrigin + ); + } assert_ok!(NonFungibles::create( - signed(owner), - owner, + signed(creator), + admin, CollectionConfig { max_supply: None, mint_settings: MintSettings::default(), settings: CollectionSettings::all_enabled() }, )); - assert_eq!(Nfts::collection_owner(next_collection_id), Some(owner)); + assert_eq!(Nfts::collection_owner(next_collection_id), Some(creator)); + System::assert_last_event(Event::Created { id: next_collection_id, creator, admin }.into()); }); } #[test] fn destroy_works() { new_test_ext().execute_with(|| { - let collection = nfts::create_collection(ALICE); - assert_ok!(NonFungibles::destroy( - signed(ALICE), - collection, - DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } - )); + let collection = COLLECTION; + let witness = DestroyWitness { + item_metadatas: 0, + item_configs: 0, + item_holders: 0, + attributes: 0, + allowances: 0, + }; + // Check error works for `Nfts::destroy()`. + assert_noop!( + NonFungibles::destroy(signed(ALICE), collection, witness), + NftsError::UnknownCollection + ); + nfts::create_collection(ALICE); + assert_ok!(NonFungibles::destroy(signed(ALICE), collection, witness)); assert_eq!(Nfts::collection_owner(collection), None); }); } #[test] -fn collection_works() { +fn total_supply_works() { new_test_ext().execute_with(|| { - let (collection, _) = nfts::create_collection_mint(ALICE, ITEM); - assert_eq!( - NonFungibles::read(Collection(collection)).encode(), - CollectionOf::::get(&collection).encode(), - ); + let owner = ALICE; + let collection = nfts::create_collection(owner); + assert_eq!(NonFungibles::read(TotalSupply(collection)), ReadResult::TotalSupply(0)); + (0..10).into_iter().for_each(|i| { + assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); + assert_eq!( + NonFungibles::read(TotalSupply(collection)), + ReadResult::TotalSupply((i + 1).into()) + ); + assert_eq!( + NonFungibles::read(TotalSupply(collection)).encode(), + (Nfts::collection_items(collection).unwrap_or_default() as u128).encode() + ); + }); }); } @@ -492,11 +503,15 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let owner = ALICE; let collection = nfts::create_collection(owner); + assert_eq!( + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(Default::default()) + ); (0..10).into_iter().for_each(|i| { assert_ok!(Nfts::mint(signed(owner), collection, i, owner, None)); assert_eq!( - NonFungibles::read(BalanceOf { collection, owner }).encode(), - (i + 1).encode() + NonFungibles::read(BalanceOf { collection, owner }), + ReadResult::BalanceOf(i + 1) ); assert_eq!( NonFungibles::read(BalanceOf { collection, owner }).encode(), @@ -513,9 +528,8 @@ fn allowance_works() { let operator = BOB; let (collection, item) = nfts::create_collection_mint_and_approve(owner, ITEM, operator); assert_eq!( - NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) - .encode(), - true.encode() + NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }), + ReadResult::Allowance(true) ); assert_eq!( NonFungibles::read(Allowance { collection, item: Some(item), owner, operator }) @@ -527,6 +541,131 @@ fn allowance_works() { }); } +#[test] +fn owner_of_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }), + ReadResult::OwnerOf(Some(ALICE)) + ); + assert_eq!( + NonFungibles::read(OwnerOf { collection: COLLECTION, item: ITEM }).encode(), + Nfts::owner(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn get_attribute_works() { + new_test_ext().execute_with(|| { + let (collection, item) = nfts::create_collection_mint(ALICE, ITEM); + let attribute = BoundedVec::truncate_from("some attribute".as_bytes().to_vec()); + let raw_value = "some value".as_bytes().to_vec(); + let value = BoundedVec::truncate_from(raw_value.clone()); + let namespace = AttributeNamespace::CollectionOwner; + // No attribute set. + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(None) + ); + // Successfully get an existing attribute. + assert_ok!(Nfts::set_attribute( + signed(ALICE), + collection, + Some(item), + namespace.clone(), + attribute.clone(), + value, + )); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }), + ReadResult::GetAttribute(Some(raw_value)) + ); + assert_eq!( + NonFungibles::read(GetAttribute { + collection, + item, + namespace: namespace.clone(), + key: attribute.clone() + }) + .encode(), + AttributeOf::::get((collection, Some(item), namespace, attribute)) + .map(|result| result.0) + .encode() + ); + }); +} + +#[test] +fn collection_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(Collection(COLLECTION)), ReadResult::Collection(None),); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)), + ReadResult::Collection(CollectionOf::::get(COLLECTION)), + ); + assert_eq!( + NonFungibles::read(Collection(COLLECTION)).encode(), + CollectionOf::::get(COLLECTION).encode(), + ); + }); +} + +#[test] +fn item_metadata_works() { + new_test_ext().execute_with(|| { + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(None) + ); + nfts::create_collection_mint(ALICE, ITEM); + let value = "some metadata".as_bytes().to_vec(); + assert_ok!(NonFungibles::set_metadata( + signed(ALICE), + COLLECTION, + ITEM, + BoundedVec::truncate_from(value.clone()) + )); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }), + ReadResult::ItemMetadata(Some(value)) + ); + assert_eq!( + NonFungibles::read(ItemMetadata { collection: COLLECTION, item: ITEM }).encode(), + Nfts::item_metadata(COLLECTION, ITEM).encode() + ); + }); +} + +#[test] +fn next_collection_id_works() { + new_test_ext().execute_with(|| { + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(0))); + nfts::create_collection_mint(ALICE, ITEM); + assert_eq!(NonFungibles::read(NextCollectionId), ReadResult::NextCollectionId(Some(1))); + assert_eq!( + NonFungibles::read(NextCollectionId).encode(), + Some(NextCollectionIdOf::::get().unwrap_or_default()).encode(), + ); + }); +} + fn signed(account_id: AccountId) -> RuntimeOrigin { RuntimeOrigin::signed(account_id) } @@ -539,6 +678,7 @@ fn none() -> RuntimeOrigin { RuntimeOrigin::none() } +// Helper functions for interacting with pallet-nfts. mod nfts { use super::*; @@ -559,7 +699,7 @@ mod nfts { } pub(super) fn create_collection(owner: AccountId) -> u32 { - let next_id = next_collection_id(); + let next_id = NextCollectionIdOf::::get().unwrap_or_default(); assert_ok!(Nfts::create( signed(owner), owner, @@ -568,10 +708,6 @@ mod nfts { next_id } - pub(super) fn next_collection_id() -> u32 { - NextCollectionIdOf::::get().unwrap_or_default() - } - pub(super) fn collection_config_with_all_settings_enabled( ) -> CollectionConfig, CollectionIdOf> { CollectionConfig { @@ -581,3 +717,287 @@ mod nfts { } } } + +mod read_weights { + use frame_support::weights::Weight; + + use super::*; + use crate::nonfungibles::{weights::WeightInfo, Config}; + + struct ReadWeightInfo { + total_supply: Weight, + balance_of: Weight, + allowance: Weight, + owner_of: Weight, + get_attribute: Weight, + collection: Weight, + next_collection_id: Weight, + item_metadata: Weight, + } + + impl ReadWeightInfo { + fn new() -> Self { + Self { + total_supply: NonFungibles::weight(&TotalSupply(COLLECTION)), + balance_of: NonFungibles::weight(&BalanceOf { + collection: COLLECTION, + owner: ALICE, + }), + allowance: NonFungibles::weight(&Allowance { + collection: COLLECTION, + item: Some(ITEM), + owner: ALICE, + operator: BOB, + }), + owner_of: NonFungibles::weight(&OwnerOf { collection: COLLECTION, item: ITEM }), + get_attribute: NonFungibles::weight(&GetAttribute { + collection: COLLECTION, + item: ITEM, + namespace: AttributeNamespace::CollectionOwner, + key: BoundedVec::default(), + }), + collection: NonFungibles::weight(&Collection(COLLECTION)), + next_collection_id: NonFungibles::weight(&NextCollectionId), + item_metadata: NonFungibles::weight(&ItemMetadata { + collection: COLLECTION, + item: ITEM, + }), + } + } + } + + #[test] + fn ensure_read_matches_benchmarks() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + assert_eq!(total_supply, ::WeightInfo::total_supply()); + assert_eq!(balance_of, ::WeightInfo::balance_of()); + assert_eq!(allowance, ::WeightInfo::allowance()); + assert_eq!(owner_of, ::WeightInfo::owner_of()); + assert_eq!(get_attribute, ::WeightInfo::get_attribute()); + assert_eq!(collection, ::WeightInfo::collection()); + assert_eq!(next_collection_id, ::WeightInfo::next_collection_id()); + assert_eq!(item_metadata, ::WeightInfo::item_metadata()); + } + + // These types read from the `Collection` storage. + #[test] + fn ensure_collection_variants_match() { + let ReadWeightInfo { total_supply, collection, .. } = ReadWeightInfo::new(); + + assert_eq!(total_supply, collection); + } + + // Proof size is based on `MaxEncodedLen`, not hardware. + // This test ensures that the data structure sizes do not change with upgrades. + #[test] + fn ensure_expected_proof_size_does_not_change() { + let ReadWeightInfo { + allowance, + balance_of, + collection, + get_attribute, + item_metadata, + next_collection_id, + owner_of, + total_supply, + } = ReadWeightInfo::new(); + + // These values come from `weights.rs`. + assert_eq!(total_supply.proof_size(), 3557); + assert_eq!(balance_of.proof_size(), 3529); + assert_eq!(allowance.proof_size(), 4326); + assert_eq!(owner_of.proof_size(), 4326); + assert_eq!(get_attribute.proof_size(), 3944); + assert_eq!(collection.proof_size(), 3557); + assert_eq!(next_collection_id.proof_size(), 1489); + assert_eq!(item_metadata.proof_size(), 3812); + } +} + +mod ensure_codec_indexes { + use super::{Encode, *}; + use crate::{mock::RuntimeCall::NonFungibles, nonfungibles}; + + #[test] + fn ensure_read_variant_indexes() { + [ + (TotalSupply::(Default::default()), 0u8, "TotalSupply"), + ( + BalanceOf:: { collection: Default::default(), owner: Default::default() }, + 1, + "BalanceOf", + ), + ( + Allowance:: { + collection: Default::default(), + item: Default::default(), + owner: Default::default(), + operator: Default::default(), + }, + 2, + "Allowance", + ), + ( + OwnerOf:: { collection: Default::default(), item: Default::default() }, + 5, + "OwnerOf", + ), + ( + GetAttribute:: { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 6, + "GetAttribute", + ), + (Collection::(Default::default()), 9, "Collection"), + (NextCollectionId, 10, "NextCollectionId"), + ( + ItemMetadata { collection: Default::default(), item: Default::default() }, + 11, + "ItemMetadata", + ), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!(variant.encode()[0], *expected_index, "{name} variant index changed"); + }) + } + + #[test] + fn ensure_dispatchable_indexes() { + use nonfungibles::Call::*; + + [ + ( + transfer { + collection: Default::default(), + item: Default::default(), + to: Default::default(), + }, + 3u8, + "transfer", + ), + ( + approve { + collection: Default::default(), + item: Default::default(), + operator: Default::default(), + approved: Default::default(), + }, + 4, + "approve", + ), + (create { admin: Default::default(), config: Default::default() }, 7, "create"), + ( + destroy { + collection: Default::default(), + witness: DestroyWitness { + item_metadatas: Default::default(), + item_configs: Default::default(), + item_holders: Default::default(), + attributes: Default::default(), + allowances: Default::default(), + }, + }, + 8, + "destroy", + ), + ( + set_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + value: Default::default(), + }, + 12, + "set_attribute", + ), + ( + clear_attribute { + collection: Default::default(), + item: Default::default(), + namespace: AttributeNamespace::CollectionOwner, + key: Default::default(), + }, + 13, + "clear_attribute", + ), + ( + set_metadata { + collection: Default::default(), + item: Default::default(), + data: Default::default(), + }, + 14, + "set_metadata", + ), + ( + clear_metadata { collection: Default::default(), item: Default::default() }, + 15, + "clear_metadata", + ), + ( + approve_item_attributes { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + }, + 16, + "approve_item_attributes", + ), + ( + cancel_item_attributes_approval { + collection: Default::default(), + item: Default::default(), + delegate: Default::default(), + witness: CancelAttributesApprovalWitness { + account_attributes: Default::default(), + }, + }, + 17, + "cancel_item_attributes_approval", + ), + ( + set_max_supply { collection: Default::default(), max_supply: Default::default() }, + 18, + "set_max_supply", + ), + ( + mint { + to: Default::default(), + collection: Default::default(), + item: Default::default(), + witness: MintWitness { + owned_item: Default::default(), + mint_price: Default::default(), + }, + }, + 19, + "mint", + ), + (burn { collection: Default::default(), item: Default::default() }, 20, "burn"), + ] + .iter() + .for_each(|(variant, expected_index, name)| { + assert_eq!( + NonFungibles(variant.to_owned()).encode()[1], + *expected_index, + "{name} dispatchable index changed" + ); + }) + } +} diff --git a/pallets/api/src/nonfungibles/weights.rs b/pallets/api/src/nonfungibles/weights.rs new file mode 100644 index 00000000..f0b8fa83 --- /dev/null +++ b/pallets/api/src/nonfungibles/weights.rs @@ -0,0 +1,217 @@ + +//! Autogenerated weights for `nonfungibles` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `R0GUE`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/pop-node +// benchmark +// pallet +// --chain=dev +// --wasm-execution=compiled +// --pallet=nonfungibles +// --steps=50 +// --repeat=20 +// --json +// --template +// ./scripts/pallet-weights-template.hbs +// --output=./pallets/api/src/nonfungibles/weights.rs +// --extrinsic= + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `nonfungibles`. +pub trait WeightInfo { + fn total_supply() -> Weight; + fn balance_of() -> Weight; + fn allowance() -> Weight; + fn owner_of() -> Weight; + fn get_attribute() -> Weight; + fn collection() -> Weight; + fn next_collection_id() -> Weight; + fn item_metadata() -> Weight; +} + +/// Weights for `nonfungibles` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn total_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + fn balance_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3529` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3529) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn allowance() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + fn owner_of() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `4326` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + fn get_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3944` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(5_000_000, 3944) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + fn collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3557` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3557) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::NextCollectionId` (r:1 w:0) + /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn next_collection_id() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `1489` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + fn item_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3812` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(3_000_000, 3812) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } +} + diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index ab66da26..58209b8b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -64,6 +64,27 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account (caller, caller_lookup) } +fn approve_collection, I: 'static>( + index: u32, +) -> (T::AccountId, AccountIdLookupOf) { + let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; + if caller != whitelisted_caller() { + whitelist_account!(caller); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let delegate: T::AccountId = account("delegate", 0, SEED + index); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + assert_ok!(Nfts::::approve_transfer( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + None, + delegate_lookup.clone(), + Some(deadline), + )); + (caller, caller_lookup) +} + fn mint_item, I: 'static>( index: u16, ) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { @@ -77,7 +98,7 @@ fn mint_item, I: 'static>( let item_exists = Item::::contains_key(&collection, &item); let item_config = ItemConfigOf::::get(&collection, &item); if item_exists { - return (item, caller, caller_lookup) + return (item, caller, caller_lookup); } else if let Some(item_config) = item_config { assert_ok!(Nfts::::force_mint( SystemOrigin::Signed(caller.clone()).into(), @@ -250,6 +271,8 @@ benchmarks_instance_pallet! { let m in 0 .. 1_000; let c in 0 .. 1_000; let a in 0 .. 1_000; + let h in 0 .. 1_000; + let l in 0 .. 1_000; let (collection, caller, _) = create_collection::(); add_collection_metadata::(); @@ -267,6 +290,13 @@ benchmarks_instance_pallet! { for i in 0..a { add_collection_attribute::(i as u16); } + for i in 0..h { + mint_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..l { + approve_collection::(i as u32); + } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { @@ -573,27 +603,45 @@ benchmarks_instance_pallet! { } approve_transfer { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup, Some(deadline)) + let maybe_deadline = if i == 0 { + None + } else { + Some(BlockNumberFor::::max_value()) + }; + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, maybe_deadline) verify { - assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); + assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); } cancel_approval { + let i in 0..1; + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, Some(item), delegate_lookup) + let maybe_item = if i == 0 { + None + } else { + Some(item) + }; + Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 89de1f05..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,6 +39,11 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.items) } + /// Get the allowances to spend items within the collection. + pub fn collection_allowances(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.allowances) + } + /// Get the metadata of the collection item. pub fn item_metadata( collection: T::CollectionId, diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index e1e79ef4..2647492c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -195,6 +195,15 @@ impl, I: 'static> Pallet { Allowances::::mutate((&collection, &owner, &delegate), |allowance| { *allowance = true; }); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_inc(); + Ok(()) + }, + )?; Self::deposit_event(Event::TransferApproved { collection, @@ -217,6 +226,15 @@ impl, I: 'static> Pallet { ensure!(check_origin == owner, Error::::NoPermission); } Allowances::::remove((&collection, &owner, &delegate)); + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result<(), DispatchError> { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + collection_details.allowances.saturating_dec(); + Ok(()) + }, + )?; Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index b7efd03a..1d08cd1b 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,7 +54,9 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, + item_holders: 0, attributes: 0, + allowances: 0, }, ); CollectionRoleOf::::insert( @@ -119,6 +121,11 @@ impl, I: 'static> Pallet { collection_details.item_configs == witness.item_configs, Error::::BadWitness ); + ensure!( + collection_details.item_holders == witness.item_holders, + Error::::BadWitness + ); + ensure!(collection_details.allowances == witness.allowances, Error::::BadWitness); for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { if let Some(depositor) = metadata.deposit.account { @@ -137,8 +144,6 @@ impl, I: 'static> Pallet { } } - // TODO: Do we need another storage item to keep track of number of holders of a - // collection let _ = AccountBalance::::clear_prefix(collection, collection_details.items, None); let _ = Allowances::::clear_prefix((collection,), collection_details.items, None); @@ -152,7 +157,9 @@ impl, I: 'static> Pallet { Ok(DestroyWitness { item_metadatas: collection_details.item_metadatas, item_configs: collection_details.item_configs, + item_holders: collection_details.item_holders, attributes: collection_details.attributes, + allowances: collection_details.allowances, }) }) } diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index cc29f8da..a7b7ddf3 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -69,9 +69,15 @@ impl, I: 'static> Pallet { } collection_details.items.saturating_inc(); - AccountBalance::::mutate(collection, &mint_to, |balance| { - balance.saturating_inc(); - }); + + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + balance.clone() + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config @@ -257,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 3b25b014..dbe6f3b0 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -54,7 +54,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult, ) -> DispatchResult { // Retrieve collection details. - let collection_details = + let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,13 +87,23 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balances. - AccountBalance::::mutate(collection, &details.owner, |balance| { - balance.saturating_dec(); - }); - AccountBalance::::mutate(collection, &dest, |balance| { + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + balance.clone() + }); + if owner_balance == 0 { + collection_details.item_holders.saturating_dec(); + } + // Update account balance of the destination account. + let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { balance.saturating_inc(); + balance.clone() }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); @@ -108,6 +118,7 @@ impl, I: 'static> Pallet { // Update item details. Item::::insert(&collection, &item, &details); + Collection::::insert(&collection, &collection_details); ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index bc8b67b6..37e8b29c 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,7 +30,6 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -832,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -847,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1311,7 +1314,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer())] + #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, @@ -1350,7 +1353,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::cancel_approval())] + #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs deleted file mode 100644 index af611bf1..00000000 --- a/pallets/nfts/src/migration.rs +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use frame_support::traits::OnRuntimeUpgrade; -use log; -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; - -use super::*; - -pub mod v1 { - use frame_support::{pallet_prelude::*, weights::Weight}; - - use super::*; - - #[derive(Decode)] - pub struct OldCollectionDetails { - pub owner: AccountId, - pub owner_deposit: DepositBalance, - pub items: u32, - pub item_metadatas: u32, - pub attributes: u32, - } - - impl OldCollectionDetails { - /// Migrates the old collection details to the new v1 format. - fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { - CollectionDetails { - owner: self.owner, - owner_deposit: self.owner_deposit, - items: self.items, - item_metadatas: self.item_metadatas, - item_configs, - attributes: self.attributes, - } - } - } - - /// A migration utility to update the storage version from v0 to v1 for the pallet. - pub struct MigrateToV1(core::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { - fn on_runtime_upgrade() -> Weight { - let in_code_version = Pallet::::in_code_storage_version(); - let on_chain_version = Pallet::::on_chain_storage_version(); - - log::info!( - target: LOG_TARGET, - "Running migration with in-code storage version {:?} / onchain {:?}", - in_code_version, - on_chain_version - ); - - if on_chain_version == 0 && in_code_version == 1 { - let mut translated = 0u64; - let mut configs_iterated = 0u64; - Collection::::translate::< - OldCollectionDetails>, - _, - >(|key, old_value| { - let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; - configs_iterated += item_configs as u64; - translated.saturating_inc(); - Some(old_value.migrate_to_v1(item_configs)) - }); - - in_code_version.put::>(); - - log::info!( - target: LOG_TARGET, - "Upgraded {} records, storage to version {:?}", - translated, - in_code_version - ); - T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) - } else { - log::info!( - target: LOG_TARGET, - "Migration did not execute. This probably should be removed" - ); - T::DbWeight::get().reads(1) - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let prev_count = Collection::::iter().count(); - Ok((prev_count as u32).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(prev_count: Vec) -> Result<(), TryRuntimeError> { - let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( - "the state parameter should be something that was generated by pre_upgrade", - ); - let post_count = Collection::::iter().count() as u32; - ensure!( - prev_count == post_count, - "the records count before and after the migration should be the same" - ); - - ensure!(Pallet::::on_chain_storage_version() >= 1, "wrong storage version"); - - Ok(()) - } - } -} diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4d0f08c9..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -165,6 +165,7 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42)]); assert_ok!(Nfts::force_create( @@ -175,10 +176,37 @@ fn basic_minting_should_work() { assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); assert_eq!(AccountBalance::::get(1, account(1)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } +#[test] +fn collection_item_holders_should_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + let total = 5; + for i in 0..total { + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, i, account(1), None)); + } + assert_eq!(AccountBalance::::get(0, account(1)), total); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, total, account(2), None)); + assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, total)); + assert_eq!(AccountBalance::::get(0, account(2)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); + }); +} + #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { @@ -223,6 +251,7 @@ fn lifecycle_should_work() { assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); assert_eq!(Collection::::get(0).unwrap().item_configs, 3); + assert_eq!(Collection::::get(0).unwrap().item_holders, 3); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); @@ -317,6 +346,7 @@ fn destroy_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), 0, @@ -360,6 +390,7 @@ fn mint_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(AccountBalance::::get(0, account(1)), 1); assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -425,6 +456,7 @@ fn mint_should_work() { Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 2); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -464,6 +496,7 @@ fn mint_should_work() { Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); assert_eq!(AccountBalance::::get(1, account(2)), 1); + assert_eq!(Collection::::get(1).unwrap().item_holders, 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -500,10 +533,11 @@ fn transfer_should_work() { account(2), default_item_config() )); - + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -521,6 +555,7 @@ fn transfer_should_work() { assert_eq!(AccountBalance::::get(0, account(2)), 0); assert_eq!(AccountBalance::::get(0, account(3)), 0); assert_eq!(AccountBalance::::get(0, account(4)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1775,6 +1810,7 @@ fn burn_works() { default_item_config() )); assert_eq!(AccountBalance::::get(0, account(5)), 2); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1783,8 +1819,10 @@ fn burn_works() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); assert_eq!(AccountBalance::::get(0, account(5)), 1); + assert_eq!(Collection::::get(0).unwrap().item_holders, 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); assert_eq!(AccountBalance::::get(0, account(5)), 0); + assert_eq!(Collection::::get(0).unwrap().item_holders, 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2036,6 +2074,7 @@ fn cancel_approval_collection_works_with_admin() { delegate: account(3) })); assert_eq!(Allowances::::get((0, account(2), account(3))), false); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 0); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2192,6 +2231,7 @@ fn approval_collection_works_with_admin() { deadline: None })); assert_eq!(Allowances::::get((0, account(1), account(3))), true); + assert_eq!(Nfts::collection_allowances(0).unwrap(), 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -4114,7 +4154,13 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0 } + DestroyWitness { + item_configs: 0, + item_metadatas: 0, + attributes: 0, + allowances: 0, + item_holders: 0 + } )); assert_eq!(Collection::::get(0), None); assert_eq!(Balances::reserved_balance(&account(1)), 10); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 941da6ca..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -104,8 +104,12 @@ pub struct CollectionDetails { pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. pub attributes: u32, + /// The total number of allowances to spend all items within collections. + pub allowances: u32, } /// Witness data for the destroy transactions. @@ -117,9 +121,15 @@ pub struct DestroyWitness { /// The total number of outstanding item configs of this collection. #[codec(compact)] pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + #[codec(compact)] + pub item_holders: u32, /// The total number of attributes for this collection. #[codec(compact)] pub attributes: u32, + /// The total number of allowances to spend all items within collections. + #[codec(compact)] + pub allowances: u32, } impl CollectionDetails { @@ -127,7 +137,9 @@ impl CollectionDetails { DestroyWitness { item_metadatas: self.item_metadatas, item_configs: self.item_configs, + item_holders: self.item_holders, attributes: self.attributes, + allowances: self.allowances, } } } diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index c374d6db..b3307503 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 -//! DATE: 2024-10-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `R0GUE`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -36,7 +36,7 @@ use core::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(m: u32, c: u32, a: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, h: u32, l: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -59,8 +59,8 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer() -> Weight; - fn cancel_approval() -> Weight; + fn approve_transfer(i: u32, ) -> Weight; + fn cancel_approval(i: u32, ) -> Weight; fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -91,16 +91,16 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -110,14 +110,14 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -126,6 +126,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -137,19 +139,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1006_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -160,7 +160,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -171,10 +171,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,7 +183,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -194,10 +194,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -206,7 +206,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -223,15 +223,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -250,15 +250,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -266,12 +266,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -285,7 +285,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -298,35 +298,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -334,12 +334,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -347,28 +347,28 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,7 +386,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -397,20 +397,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -424,13 +424,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -462,8 +462,8 @@ impl WeightInfo for SubstrateWeight { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -473,7 +473,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -482,7 +482,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -494,15 +494,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,32 +511,32 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,25 +544,37 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -582,20 +594,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,7 +620,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -624,8 +636,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -633,8 +645,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -649,12 +661,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -662,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -674,8 +686,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -687,7 +699,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -696,8 +708,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -712,12 +724,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -726,7 +738,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -742,12 +754,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -761,7 +773,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -769,12 +781,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -788,7 +800,7 @@ impl WeightInfo for () { /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -798,16 +810,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(27_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::NextCollectionId` (r:1 w:1) /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) @@ -817,14 +829,14 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3549) + // Estimated: `3557` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) @@ -833,6 +845,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:0) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:0) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) @@ -844,19 +858,17 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, c: u32, a: u32, ) -> Weight { + /// The range of component `h` is `[0, 1000]`. + /// The range of component `l` is `[0, 1000]`. + fn destroy(_m: u32, _c: u32, a: u32, _h: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32216 + a * (366 ±0)` + // Measured: `32875 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` // Minimum execution time: 982_000_000 picoseconds. - Weight::from_parts(937_587_516, 2523990) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(34_348, 0).saturating_mul(m.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(23_800, 0).saturating_mul(c.into())) - // Standard Error: 12_288 - .saturating_add(Weight::from_parts(5_095_505, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1005_u64)) + Weight::from_parts(4_613_129_128, 2523990) + // Standard Error: 125_087 + .saturating_add(Weight::from_parts(5_072_767, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1006_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) @@ -867,7 +879,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -878,10 +890,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(41_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -890,7 +902,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) @@ -901,10 +913,10 @@ impl WeightInfo for () { /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `390` // Estimated: `4326` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + Weight::from_parts(39_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -913,7 +925,7 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) @@ -930,15 +942,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `576` + // Measured: `584` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -957,15 +969,15 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `613` // Estimated: `6068` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(83_000_000, 6068) + Weight::from_parts(38_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:5000 w:5000) @@ -973,12 +985,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `690 + i * (108 ±0)` - // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 20_022 - .saturating_add(Weight::from_parts(16_005_327, 0).saturating_mul(i.into())) + // Measured: `698 + i * (108 ±0)` + // Estimated: `3557 + i * (3336 ±0)` + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3557) + // Standard Error: 30_743 + .saturating_add(Weight::from_parts(15_569_470, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -992,7 +1004,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1005,35 +1017,35 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) + Weight::from_parts(11_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `425` // Estimated: `3593` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) @@ -1041,12 +1053,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `296` + // Measured: `304` // Estimated: `6078` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 6078) @@ -1054,28 +1066,28 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionAccount` (r:0 w:2) /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3549` + // Measured: `246` + // Estimated: `3557` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + Weight::from_parts(12_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `203` - // Estimated: `3549` + // Estimated: `3557` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1093,7 +1105,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1104,20 +1116,20 @@ impl WeightInfo for () { /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3944` - // Minimum execution time: 37_000_000 picoseconds. - Weight::from_parts(38_000_000, 3944) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `271` + // Measured: `279` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3944) @@ -1131,13 +1143,13 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `943` + // Measured: `951` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + Weight::from_parts(37_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1169,8 +1181,8 @@ impl WeightInfo for () { // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(19_000_000, 4466) - // Standard Error: 6_379 - .saturating_add(Weight::from_parts(5_018_740, 0).saturating_mul(n.into())) + // Standard Error: 10_431 + .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1180,7 +1192,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1189,7 +1201,7 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `499` + // Measured: `507` // Estimated: `3812` // Minimum execution time: 30_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) @@ -1201,15 +1213,15 @@ impl WeightInfo for () { /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `809` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3812) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1218,32 +1230,32 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `333` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `643` + // Measured: `651` // Estimated: `3759` // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1251,25 +1263,37 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - fn approve_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn approve_transfer(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `308 + i * (29 ±0)` + // Estimated: `3574 + i * (2163 ±0)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(16_969_387, 3574) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn cancel_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `4326` + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:0 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + fn cancel_approval(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312 + i * (33 ±0)` + // Estimated: `3557 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1289,20 +1313,20 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + Weight::from_parts(9_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `267` - // Estimated: `3549` + // Measured: `275` + // Estimated: `3557` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1315,7 +1339,7 @@ impl WeightInfo for () { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + Weight::from_parts(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,8 +1355,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1340,8 +1364,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1356,12 +1380,12 @@ impl WeightInfo for () { /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `717` + // Measured: `725` // Estimated: `6068` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(45_000_000, 6068) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -1369,9 +1393,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(390_532, 0) - // Standard Error: 84_277 - .saturating_add(Weight::from_parts(3_087_492, 0).saturating_mul(n.into())) + Weight::from_parts(2_101_372, 0) + // Standard Error: 5_552 + .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1381,8 +1405,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 7662) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1394,7 +1418,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1403,8 +1427,8 @@ impl WeightInfo for () { /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) @@ -1419,12 +1443,12 @@ impl WeightInfo for () { /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `907` + // Measured: `915` // Estimated: `7662` - // Minimum execution time: 75_000_000 picoseconds. - Weight::from_parts(77_000_000, 7662) + // Minimum execution time: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1433,7 +1457,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountBalance` (r:1 w:1) /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) @@ -1449,12 +1473,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `493` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(107_476_765, 6078) - // Standard Error: 61_259 - .saturating_add(Weight::from_parts(27_610_007, 0).saturating_mul(n.into())) + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(102_689_064, 6078) + // Standard Error: 25_175 + .saturating_add(Weight::from_parts(27_553_304, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -1468,7 +1492,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1476,16 +1500,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `522` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(57_358_180, 4466) - // Standard Error: 54_968 - .saturating_add(Weight::from_parts(27_429_606, 0).saturating_mul(n.into())) + // Minimum execution time: 50_000_000 picoseconds. + Weight::from_parts(55_735_551, 4466) + // Standard Error: 34_490 + .saturating_add(Weight::from_parts(26_799_214, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } -} \ No newline at end of file +} diff --git a/runtime/devnet/src/config/api/mod.rs b/runtime/devnet/src/config/api/mod.rs index 5ea1d923..d96fd85b 100644 --- a/runtime/devnet/src/config/api/mod.rs +++ b/runtime/devnet/src/config/api/mod.rs @@ -11,7 +11,7 @@ use sp_std::vec::Vec; use versioning::*; use crate::{ - config::assets::{NftsInstance, TrustBackedAssetsInstance}, + config::assets::{TrustBackedAssetsInstance, TrustBackedNftsInstance}, fungibles, nonfungibles, Runtime, RuntimeCall, RuntimeEvent, }; @@ -88,7 +88,7 @@ impl fungibles::Config for Runtime { } impl nonfungibles::Config for Runtime { - type NftsInstance = NftsInstance; + type NftsInstance = TrustBackedNftsInstance; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -311,7 +311,13 @@ mod tests { }), NonFungibles(destroy { collection: 0, - witness: DestroyWitness { attributes: 0, item_configs: 0, item_metadatas: 0 }, + witness: DestroyWitness { + attributes: 0, + item_configs: 0, + item_metadatas: 0, + item_holders: 0, + allowances: 0, + }, }), NonFungibles(set_attribute { collection: 0, diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 97c2a9e7..65405ea4 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -46,9 +46,9 @@ impl Get for KeyLimit { } } -pub(crate) type NftsInstance = pallet_nfts::Instance1; -pub type NftsCall = pallet_nfts::Call; -impl pallet_nfts::Config for Runtime { +pub(crate) type TrustBackedNftsInstance = pallet_nfts::Instance1; +pub type TrustBackedNftsCall = pallet_nfts::Call; +impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; @@ -97,8 +97,8 @@ impl pallet_nft_fractionalization::Config for Runtime { type Deposit = AssetDeposit; type NewAssetName = NewAssetName; type NewAssetSymbol = NewAssetSymbol; - type NftCollectionId = >::CollectionId; - type NftId = >::ItemId; + type NftCollectionId = >::CollectionId; + type NftId = >::ItemId; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/devnet/src/config/proxy.rs b/runtime/devnet/src/config/proxy.rs index 161178dc..48653027 100644 --- a/runtime/devnet/src/config/proxy.rs +++ b/runtime/devnet/src/config/proxy.rs @@ -5,7 +5,7 @@ use pop_runtime_common::proxy::{ }; use sp_runtime::traits::BlakeTwo256; -use super::assets::{NftsCall, TrustBackedAssetsCall}; +use super::assets::{TrustBackedAssetsCall, TrustBackedNftsCall}; use crate::{Balances, Runtime, RuntimeCall, RuntimeEvent}; impl InstanceFilter for ProxyType { @@ -45,13 +45,13 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::set_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::clear_metadata { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::set_min_balance { .. }) | - RuntimeCall::Nfts(NftsCall::create { .. }) | - RuntimeCall::Nfts(NftsCall::destroy { .. }) | - RuntimeCall::Nfts(NftsCall::redeposit { .. }) | - RuntimeCall::Nfts(NftsCall::transfer_ownership { .. }) | - RuntimeCall::Nfts(NftsCall::set_team { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_max_supply { .. }) | - RuntimeCall::Nfts(NftsCall::lock_collection { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::create { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::destroy { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::redeposit { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::transfer_ownership { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_team { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_max_supply { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_collection { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -66,17 +66,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::Assets(TrustBackedAssetsCall::thaw_asset { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::touch_other { .. }) | RuntimeCall::Assets(TrustBackedAssetsCall::refund_other { .. }) | - RuntimeCall::Nfts(NftsCall::force_mint { .. }) | - RuntimeCall::Nfts(NftsCall::update_mint_settings { .. }) | - RuntimeCall::Nfts(NftsCall::mint_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::set_attributes_pre_signed { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::unlock_item_transfer { .. }) | - RuntimeCall::Nfts(NftsCall::lock_item_properties { .. }) | - RuntimeCall::Nfts(NftsCall::set_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::set_collection_metadata { .. }) | - RuntimeCall::Nfts(NftsCall::clear_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::force_mint { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::update_mint_settings { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::mint_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_attributes_pre_signed { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::unlock_item_transfer { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::lock_item_properties { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::set_collection_metadata { .. }) | + RuntimeCall::Nfts(TrustBackedNftsCall::clear_collection_metadata { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 839f819d..736f0be7 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -646,6 +646,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [fungibles, Fungibles] + [nonfungibles, NonFungibles] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] From 9dd80cc0734236f8c052ae0353acf17677d4e26b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:14:46 +0700 Subject: [PATCH 60/64] chore: clippy --- pallets/nfts/src/benchmarking.rs | 2 +- pallets/nfts/src/features/create_delete_item.rs | 2 +- pallets/nfts/src/features/transfer.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 58209b8b..d8876d52 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -295,7 +295,7 @@ benchmarks_instance_pallet! { burn_item::(i as u16); } for i in 0..l { - approve_collection::(i as u32); + approve_collection::(i); } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index a7b7ddf3..08cf5f95 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -73,7 +73,7 @@ impl, I: 'static> Pallet { let account_balance = AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { balance.saturating_inc(); - balance.clone() + *balance }); if account_balance == 1 { collection_details.item_holders.saturating_inc(); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index dbe6f3b0..3f2dae3b 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -91,7 +91,7 @@ impl, I: 'static> Pallet { let owner_balance = AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { balance.saturating_dec(); - balance.clone() + *balance }); if owner_balance == 0 { collection_details.item_holders.saturating_dec(); @@ -99,7 +99,7 @@ impl, I: 'static> Pallet { // Update account balance of the destination account. let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { balance.saturating_inc(); - balance.clone() + *balance }); if dest_balance == 1 { collection_details.item_holders.saturating_inc(); From 73f49946f2dc5ef5c3785eaa4236dcf11bfe4393 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:59:35 +0700 Subject: [PATCH 61/64] chore: taplo fmt --- pallets/nfts/Cargo.toml | 8 ++++---- pallets/nfts/runtime-api/Cargo.toml | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 791db0a7..bef584b8 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Parity Technologies ", "R0GUE "] +authors = [ "Parity Technologies ", "R0GUE " ] description = "Fork of FRAME NFTs pallet" edition.workspace = true homepage = "https://substrate.io" @@ -10,13 +10,13 @@ repository.workspace = true version = "31.0.0" [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] +targets = [ "x86_64-unknown-linux-gnu" ] [dependencies] codec = { workspace = true } enumflags2 = { workspace = true } log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +scale-info = { features = [ "derive" ], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -31,7 +31,7 @@ pallet-balances.workspace = true sp-keystore.workspace = true [features] -default = ["std"] +default = [ "std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml index d9a748d6..503642ef 100644 --- a/pallets/nfts/runtime-api/Cargo.toml +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Parity Technologies ", "R0GUE "] +authors = [ "Parity Technologies ", "R0GUE " ] description = "Runtime API for the FRAME NFTs pallet." edition.workspace = true homepage = "https://substrate.io" @@ -13,13 +13,13 @@ version = "23.0.0" workspace = true [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] +targets = [ "x86_64-unknown-linux-gnu" ] [dependencies] -codec = { features = ["derive"], workspace = true } +codec = { features = [ "derive" ], workspace = true } pallet-nfts.workspace = true sp-api.workspace = true [features] -default = ["std"] -std = ["codec/std", "pallet-nfts/std", "sp-api/std"] +default = [ "std" ] +std = [ "codec/std", "pallet-nfts/std", "sp-api/std" ] From e303439a758cac88cefdc2d516ddce751abee648 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:51:59 +0700 Subject: [PATCH 62/64] fix: rebase & update integration tests --- pallets/api/src/nonfungibles/mod.rs | 38 +- pallets/api/src/nonfungibles/types.rs | 31 ++ pop-api/integration-tests/Cargo.toml | 2 + .../contracts/nonfungibles/lib.rs | 4 +- .../integration-tests/src/nonfungibles/mod.rs | 327 +++++++++++++----- .../src/nonfungibles/utils.rs | 56 ++- pop-api/src/v0/nonfungibles/mod.rs | 6 +- pop-api/src/v0/nonfungibles/types.rs | 10 + 8 files changed, 335 insertions(+), 139 deletions(-) create mode 100644 pallets/api/src/nonfungibles/types.rs diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index 6da7de5f..4bdd99ce 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -11,37 +11,17 @@ pub use pallet_nfts::{ CollectionSetting, CollectionSettings, DestroyWitness, ItemDeposit, ItemDetails, ItemMetadata, ItemSetting, MintSettings, MintType, MintWitness, }; -use sp_runtime::traits::StaticLookup; +use sp_runtime::{traits::StaticLookup, BoundedVec}; +use types::*; use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; #[cfg(test)] mod tests; +pub mod types; pub mod weights; -type AccountIdOf = ::AccountId; -type NftsOf = pallet_nfts::Pallet>; -type NftsErrorOf = pallet_nfts::Error>; -type NftsWeightInfoOf = >>::WeightInfo; -type NftsInstanceOf = ::NftsInstance; -type BalanceOf = <>>::Currency as Currency< - ::AccountId, ->>::Balance; -type CollectionIdOf = - as Inspect<::AccountId>>::CollectionId; -type ItemIdOf = as Inspect<::AccountId>>::ItemId; -type ItemPriceOf = BalanceOf; -type CollectionDetailsFor = CollectionDetails, BalanceOf>; -type AttributeNamespaceOf = AttributeNamespace>; -type CollectionConfigFor = - CollectionConfig, BlockNumberFor, CollectionIdOf>; -// Type aliases for pallet-nfts storage items. -pub(super) type AccountBalanceOf = pallet_nfts::AccountBalance>; -pub(super) type AttributeOf = pallet_nfts::Attribute>; -pub(super) type NextCollectionIdOf = pallet_nfts::NextCollectionId>; -pub(super) type CollectionOf = pallet_nfts::Collection>; - #[frame_support::pallet] pub mod pallet { use frame_support::{ @@ -50,8 +30,6 @@ pub mod pallet { traits::Incrementable, }; use frame_system::pallet_prelude::*; - use pallet_nfts::{CancelAttributesApprovalWitness, DestroyWitness, MintWitness}; - use sp_runtime::BoundedVec; use sp_std::vec::Vec; use super::*; @@ -104,7 +82,7 @@ pub mod pallet { /// The namespace of the attribute. namespace: AttributeNamespaceOf, /// The key of the attribute. - key: BoundedVec, + key: AttributeKey, }, /// Details of a specified collection. #[codec(index = 9)] @@ -354,8 +332,8 @@ pub mod pallet { collection: CollectionIdOf, item: Option>, namespace: AttributeNamespaceOf, - key: BoundedVec, - value: BoundedVec, + key: AttributeKey, + value: AttributeValue, ) -> DispatchResult { NftsOf::::set_attribute(origin, collection, item, namespace, key, value) } @@ -374,7 +352,7 @@ pub mod pallet { collection: CollectionIdOf, item: Option>, namespace: AttributeNamespaceOf, - key: BoundedVec, + key: AttributeKey, ) -> DispatchResult { NftsOf::::clear_attribute(origin, collection, item, namespace, key) } @@ -391,7 +369,7 @@ pub mod pallet { origin: OriginFor, collection: CollectionIdOf, item: ItemIdOf, - data: BoundedVec, + data: MetadataData, ) -> DispatchResult { NftsOf::::set_metadata(origin, collection, item, data) } diff --git a/pallets/api/src/nonfungibles/types.rs b/pallets/api/src/nonfungibles/types.rs new file mode 100644 index 00000000..e15d430b --- /dev/null +++ b/pallets/api/src/nonfungibles/types.rs @@ -0,0 +1,31 @@ +use super::*; + +pub(super) type AccountIdOf = ::AccountId; +pub(super) type NftsOf = pallet_nfts::Pallet>; +pub(super) type NftsErrorOf = pallet_nfts::Error>; +pub(super) type NftsWeightInfoOf = >>::WeightInfo; +pub(super) type NftsInstanceOf = ::NftsInstance; +pub(super) type BalanceOf = + <>>::Currency as Currency< + ::AccountId, + >>::Balance; +pub(super) type CollectionIdOf = + as Inspect<::AccountId>>::CollectionId; +pub(super) type ItemIdOf = + as Inspect<::AccountId>>::ItemId; +pub(super) type ItemPriceOf = BalanceOf; +pub(super) type CollectionDetailsFor = CollectionDetails, BalanceOf>; +pub(super) type AttributeNamespaceOf = AttributeNamespace>; +pub(super) type CollectionConfigFor = + CollectionConfig, BlockNumberFor, CollectionIdOf>; +// Public due to pop-api integration tests crate. +pub type AccountBalanceOf = pallet_nfts::AccountBalance>; +pub type AttributeOf = pallet_nfts::Attribute>; +pub type AttributeKey = BoundedVec>>::KeyLimit>; +pub type AttributeValue = + BoundedVec>>::ValueLimit>; +pub type CollectionOf = pallet_nfts::Collection>; +pub type CollectionConfigOf = pallet_nfts::CollectionConfigOf>; +pub type NextCollectionIdOf = pallet_nfts::NextCollectionId>; +pub type MetadataData = + BoundedVec>>::StringLimit>; diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index f87cdddb..edc7017f 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -13,6 +13,7 @@ frame-support = { version = "36.0.0", default-features = false } frame-support-procedural = { version = "=30.0.1", default-features = false } frame-system = { version = "36.1.0", default-features = false } log = "0.4.22" +pallet-api = { path = "../../pallets/api", default-features = false } pallet-assets = { version = "37.0.0", default-features = false } pallet-balances = { version = "37.0.0", default-features = false } pallet-contracts = { version = "35.0.0", default-features = false } @@ -38,6 +39,7 @@ devnet = [ ] std = [ "frame-support/std", "frame-system/std", + "pallet-api/std", "pallet-assets/std", "pallet-balances/std", "pallet-contracts/std", diff --git a/pop-api/integration-tests/contracts/nonfungibles/lib.rs b/pop-api/integration-tests/contracts/nonfungibles/lib.rs index 13446791..717498a1 100644 --- a/pop-api/integration-tests/contracts/nonfungibles/lib.rs +++ b/pop-api/integration-tests/contracts/nonfungibles/lib.rs @@ -54,11 +54,11 @@ mod nonfungibles { pub fn allowance( &self, collection: CollectionId, + item: Option, owner: AccountId, operator: AccountId, - item: Option, ) -> Result { - api::allowance(collection, owner, operator, item) + api::allowance(collection, item, owner, operator) } #[ink(message)] diff --git a/pop-api/integration-tests/src/nonfungibles/mod.rs b/pop-api/integration-tests/src/nonfungibles/mod.rs index c92652c0..5c236f9f 100644 --- a/pop-api/integration-tests/src/nonfungibles/mod.rs +++ b/pop-api/integration-tests/src/nonfungibles/mod.rs @@ -1,8 +1,10 @@ use frame_support::BoundedVec; +use pallet_api::nonfungibles::types::*; use pop_api::{ nonfungibles::{ events::{Approval, AttributeSet, Transfer}, - types::*, + AttributeNamespace, CancelAttributesApprovalWitness, CollectionConfig, CollectionDetails, + CollectionId, CollectionSettings, DestroyWitness, ItemId, MintSettings, MintWitness, }, primitives::BlockNumber, }; @@ -13,8 +15,8 @@ use super::*; mod utils; -const COLLECTION_ID: CollectionId = 0; -const ITEM_ID: ItemId = 1; +const COLLECTION: CollectionId = 0; +const ITEM: ItemId = 0; const CONTRACT: &str = "contracts/nonfungibles/target/ink/nonfungibles.wasm"; #[test] @@ -22,20 +24,20 @@ fn total_supply_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - // No tokens in circulation. + // No collection item is created. assert_eq!( - total_supply(&addr, COLLECTION_ID), - Ok(Nfts::collection_items(COLLECTION_ID).unwrap_or_default() as u128) + total_supply(&addr, COLLECTION), + Ok(Nfts::collection_items(COLLECTION).unwrap_or_default() as u128) ); - assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(0)); + assert_eq!(total_supply(&addr, COLLECTION), Ok(0)); - // Tokens in circulation. - nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); + // Collection item is created. + nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM); assert_eq!( - total_supply(&addr, COLLECTION_ID), - Ok(Nfts::collection_items(COLLECTION_ID).unwrap_or_default() as u128) + total_supply(&addr, COLLECTION), + Ok(Nfts::collection_items(COLLECTION).unwrap_or_default() as u128) ); - assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(1)); + assert_eq!(total_supply(&addr, COLLECTION), Ok(1)); }); } @@ -44,20 +46,14 @@ fn balance_of_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - // No tokens in circulation. - assert_eq!( - balance_of(&addr, COLLECTION_ID, ALICE), - Ok(nfts::balance_of(COLLECTION_ID, ALICE)), - ); - assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(0)); + // No collection item is created. + assert_eq!(balance_of(&addr, COLLECTION, ALICE), Ok(nfts::balance_of(COLLECTION, ALICE)),); + assert_eq!(total_supply(&addr, COLLECTION), Ok(0)); - // Tokens in circulation. - nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); - assert_eq!( - balance_of(&addr, COLLECTION_ID, ALICE), - Ok(nfts::balance_of(COLLECTION_ID, ALICE)), - ); - assert_eq!(total_supply(&addr, COLLECTION_ID), Ok(1)); + // Collection item is created. + nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM); + assert_eq!(balance_of(&addr, COLLECTION, ALICE), Ok(nfts::balance_of(COLLECTION, ALICE)),); + assert_eq!(total_supply(&addr, COLLECTION), Ok(1)); }); } @@ -65,23 +61,20 @@ fn balance_of_works() { fn allowance_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - // No tokens in circulation. + // No collection item is created. assert_eq!( - allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, None), - Ok(!Nfts::check_allowance(&COLLECTION_ID, &None, &addr, &ALICE).is_err()), + allowance(&addr.clone(), COLLECTION, None, addr.clone(), ALICE), + Ok(!Nfts::check_allowance(&COLLECTION, &None, &addr, &ALICE).is_err()), ); - assert_eq!(allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, None), Ok(false)); + assert_eq!(allowance(&addr.clone(), COLLECTION, None, addr.clone(), ALICE), Ok(false)); - let (_, item) = - nfts::create_collection_mint_and_approve(&addr, &addr, ITEM_ID, &addr, &ALICE); + // Collection item is created. + let (_, item) = nfts::create_collection_mint_and_approve(&addr, &addr, ITEM, &addr, &ALICE); assert_eq!( - allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, Some(item)), - Ok(Nfts::check_allowance(&COLLECTION_ID, &Some(item), &addr.clone(), &ALICE).is_ok()), - ); - assert_eq!( - allowance(&addr.clone(), COLLECTION_ID, addr.clone(), ALICE, Some(item)), - Ok(true) + allowance(&addr.clone(), COLLECTION, Some(item), addr.clone(), ALICE), + Ok(Nfts::check_allowance(&COLLECTION, &Some(item), &addr.clone(), &ALICE).is_ok()), ); + assert_eq!(allowance(&addr.clone(), COLLECTION, Some(item), addr.clone(), ALICE), Ok(true)); }); } @@ -90,24 +83,86 @@ fn transfer_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); - let before_transfer_balance = nfts::balance_of(COLLECTION_ID, ALICE); + // Collection item does not exist. + assert_eq!( + transfer(&addr, COLLECTION, ITEM, ALICE), + Err(Module { index: 50, error: [1, 0] }) + ); + // Create a collection and mint to a contract address. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); + // Privilege to transfer a collection item is locked. + nfts::lock_item_transfer(&addr, COLLECTION, ITEM); + assert_eq!( + transfer(&addr, COLLECTION, ITEM, ALICE), + Err(Module { index: 50, error: [12, 0] }) + ); + nfts::unlock_item_transfer(&addr, COLLECTION, ITEM); + // Successful transfer. + let before_transfer_balance = nfts::balance_of(COLLECTION, ALICE); assert_ok!(transfer(&addr, collection, item, ALICE)); - let after_transfer_balance = nfts::balance_of(COLLECTION_ID, ALICE); + let after_transfer_balance = nfts::balance_of(COLLECTION, ALICE); assert_eq!(after_transfer_balance - before_transfer_balance, 1); + // Successfully emit event. + let from = account_id_from_slice(addr.as_ref()); + let to = account_id_from_slice(ALICE.as_ref()); + let expected = Transfer { from: Some(from), to: Some(to), item: ITEM }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); + // Collection item does not exist, i.e. burnt. + nfts::burn(COLLECTION, ITEM, &ALICE); + assert_eq!( + transfer(&addr, COLLECTION, ITEM, ALICE), + Err(Module { index: 50, error: [20, 0] }) + ); }); } #[test] -fn approve_works() { +fn approve_item_transfer_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + // Collection item does not exist. + assert_eq!( + approve(&addr, COLLECTION, Some(ITEM), ALICE, true), + Err(Module { index: 50, error: [20, 0] }) + ); + // Successful approvals. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(approve(&addr, collection, Some(item), ALICE, true)); - assert!(Nfts::check_allowance(&collection, &Some(item), &addr.clone(), &ALICE).is_ok(),); + assert!(Nfts::check_allowance(&collection, &Some(item), &addr.clone(), &ALICE).is_ok()); + // Successfully emit event. + let owner = account_id_from_slice(addr.as_ref()); + let operator = account_id_from_slice(ALICE.as_ref()); + let expected = Approval { owner, operator, item: Some(item), approved: true }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); + // New value overrides old value. + assert_ok!(approve(&addr, collection, Some(item), ALICE, false)); + assert!(Nfts::check_allowance(&collection, &Some(item), &addr.clone(), &ALICE).is_err()); + }); +} - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(ALICE), collection, item, BOB.into())); +#[test] +fn approve_collection_transfer_works() { + new_test_ext().execute_with(|| { + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // Collection does not exist. + assert_eq!( + approve(&addr, COLLECTION, None, ALICE, true), + Err(Module { index: 50, error: [1, 0] }) + ); + // Successful approvals. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); + assert_ok!(approve(&addr, collection, None, ALICE, true)); + assert!(Nfts::check_allowance(&collection, &None, &addr.clone(), &ALICE).is_ok()); + // Successfully emit event. + let owner = account_id_from_slice(addr.as_ref()); + let operator = account_id_from_slice(ALICE.as_ref()); + let expected = Approval { owner, operator, item: None, approved: true }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); + // New value overrides old value. + assert_ok!(approve(&addr, collection, None, ALICE, false)); + assert!(Nfts::check_allowance(&collection, &None, &addr.clone(), &ALICE).is_err()); }); } @@ -115,7 +170,7 @@ fn approve_works() { fn owner_of_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &ALICE, ITEM); assert_eq!(owner_of(&addr, collection, item), Ok(ALICE)); }); } @@ -125,7 +180,7 @@ fn get_attribute_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(addr.clone()), @@ -153,7 +208,7 @@ fn set_attribute_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(set_attribute( &addr.clone(), @@ -165,14 +220,14 @@ fn set_attribute_works() { )); assert_eq!( - pallet_nfts::Attribute::::get(( + AttributeOf::::get(( collection, Some(item), pallet_nfts::AttributeNamespace::CollectionOwner, - AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + AttributeKey::::truncate_from("some attribute".as_bytes().to_vec()), )) .map(|attribute| attribute.0), - Some(AttributeValue::truncate_from("some value".as_bytes().to_vec())) + Some(AttributeValue::::truncate_from("some value".as_bytes().to_vec())) ); }); } @@ -182,7 +237,7 @@ fn clear_attribute_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(addr.clone()), collection, @@ -199,11 +254,11 @@ fn clear_attribute_works() { "some attribute".as_bytes().to_vec() )); assert_eq!( - pallet_nfts::Attribute::::get(( + AttributeOf::::get(( collection, Some(item), pallet_nfts::AttributeNamespace::CollectionOwner, - AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + AttributeKey::::truncate_from("some attribute".as_bytes().to_vec()), )) .map(|attribute| attribute.0), None @@ -216,7 +271,7 @@ fn approve_item_attributes_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(approve_item_attributes(&addr.clone(), collection, item, ALICE)); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(ALICE), @@ -227,14 +282,14 @@ fn approve_item_attributes_works() { BoundedVec::truncate_from("some value".as_bytes().to_vec()), )); assert_eq!( - pallet_nfts::Attribute::::get(( + AttributeOf::::get(( collection, Some(item), pallet_nfts::AttributeNamespace::Account(ALICE), - AttributeKey::truncate_from("some attribute".as_bytes().to_vec()), + AttributeKey::::truncate_from("some attribute".as_bytes().to_vec()), )) .map(|attribute| attribute.0), - Some(AttributeValue::truncate_from("some value".as_bytes().to_vec())) + Some(AttributeValue::::truncate_from("some value".as_bytes().to_vec())) ); }); } @@ -244,7 +299,7 @@ fn cancel_item_attributes_approval_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(Nfts::approve_item_attributes( RuntimeOrigin::signed(addr.clone()), collection, @@ -283,9 +338,21 @@ fn set_metadata_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + // Collection does not exist. + assert_eq!( + set_metadata(&addr.clone(), COLLECTION, ITEM, vec![]), + Err(Module { index: 50, error: [0, 0] }) + ); + // No Permission. + let (collection, item) = nfts::create_collection_and_mint_to(&ALICE, &ALICE, &ALICE, ITEM); + assert_eq!( + set_metadata(&addr.clone(), collection, item, vec![]), + Err(Module { index: 50, error: [0, 0] }), + ); + // Successful set metadata. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(set_metadata(&addr.clone(), collection, item, vec![])); - assert_eq!(Nfts::item_metadata(collection, item), Some(MetadataData::default())); + assert_eq!(Nfts::item_metadata(collection, item), Some(MetadataData::::default())); }); } @@ -294,12 +361,18 @@ fn clear_metadata_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); + // Collection does not exist. + assert_eq!( + clear_metadata(&addr.clone(), COLLECTION, ITEM), + Err(Module { index: 50, error: [0, 0] }) + ); + // Successful clear metadata. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); assert_ok!(Nfts::set_metadata( RuntimeOrigin::signed(addr.clone()), collection, item, - MetadataData::default() + MetadataData::::default() )); assert_ok!(clear_metadata(&addr.clone(), collection, item)); assert_eq!(Nfts::item_metadata(collection, item), None); @@ -322,7 +395,7 @@ fn create_works() { } )); assert_eq!( - pallet_nfts::Collection::::get(collection), + CollectionOf::::get(collection), Some(pallet_nfts::CollectionDetails { owner: addr.clone(), owner_deposit: 100000000000, @@ -330,6 +403,8 @@ fn create_works() { item_metadatas: 0, item_configs: 0, attributes: 0, + item_holders: 0, + allowances: 0 }) ); }); @@ -340,13 +415,51 @@ fn destroy_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + // Collection does not exist. + assert_eq!( + destroy( + &addr.clone(), + COLLECTION, + DestroyWitness { + item_metadatas: 0, + item_configs: 0, + attributes: 0, + item_holders: 0, + allowances: 0 + } + ), + Err(Module { index: 50, error: [1, 0] }) + ); + // Destroying can only be done by the collection owner. + let collection = nfts::create_collection(&ALICE, &ALICE); + assert_eq!( + destroy( + &addr.clone(), + collection, + DestroyWitness { + item_metadatas: 0, + item_configs: 0, + attributes: 0, + item_holders: 0, + allowances: 0 + } + ), + Err(Module { index: 50, error: [0, 0] }) + ); + // Successful destroy. let collection = nfts::create_collection(&addr, &addr); assert_ok!(destroy( &addr.clone(), collection, - DestroyWitness { item_metadatas: 0, item_configs: 0, attributes: 0 } + DestroyWitness { + item_metadatas: 0, + item_configs: 0, + attributes: 0, + item_holders: 0, + allowances: 0 + } )); - assert_eq!(pallet_nfts::Collection::::get(collection), None); + assert_eq!(CollectionOf::::get(collection), None); }); } @@ -356,26 +469,18 @@ fn set_max_supply_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let value = 10; + // Collection does not exist. + assert_eq!( + set_max_supply(&addr.clone(), COLLECTION, value), + Err(Module { index: 50, error: [32, 0] }) + ); + // Sucessfully set max supply. let collection = nfts::create_collection(&addr, &addr); assert_ok!(set_max_supply(&addr.clone(), collection, value)); - - (0..value).into_iter().for_each(|i| { - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(addr.clone()), - collection, - i, - ALICE.into(), - None - )); - }); - assert!(Nfts::mint( - RuntimeOrigin::signed(addr.clone()), - collection, - value + 1, - ALICE.into(), - None - ) - .is_err()); + assert_eq!(nfts::max_supply(collection), Some(value)); + // Non-additive, sets new value. + assert_ok!(set_max_supply(&addr.clone(), collection, value + 1)); + assert_eq!(nfts::max_supply(collection), Some(value + 1)); }); } @@ -385,15 +490,50 @@ fn mint_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let value = 10; + // Collection does not exist. + assert_eq!( + mint( + &addr.clone(), + ALICE, + COLLECTION, + ITEM, + MintWitness { mint_price: None, owned_item: None } + ), + Err(Module { index: 50, error: [32, 0] }) + ); + // Mitning can only be done by the collection owner. + let collection = nfts::create_collection(&ALICE, &ALICE); + assert_eq!( + mint( + &addr.clone(), + ALICE, + collection, + ITEM, + MintWitness { mint_price: None, owned_item: None } + ), + Err(Module { index: 50, error: [0, 0] }) + ); + // Successful mint. let collection = nfts::create_collection(&addr, &addr); assert_ok!(mint( &addr.clone(), ALICE, collection, - ITEM_ID, - MintWitness { mint_price: None, owned_item: None } + ITEM, + MintWitness { owned_item: None, mint_price: None } )); - assert_eq!(nfts::balance_of(COLLECTION_ID, ALICE), 1); + assert_eq!(nfts::balance_of(collection, ALICE), 1); + // Minting an existing item ID. + assert_eq!( + mint( + &addr.clone(), + ALICE, + collection, + ITEM, + MintWitness { owned_item: None, mint_price: None } + ), + Err(Module { index: 50, error: [2, 0] }) + ); }); } @@ -402,8 +542,17 @@ fn burn_works() { new_test_ext().execute_with(|| { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM_ID); - assert_ok!(burn(&addr.clone(), collection, ITEM_ID,)); - assert_eq!(nfts::balance_of(COLLECTION_ID, addr), 0); + // Collection item does not exist. + assert_eq!( + burn(&addr.clone(), COLLECTION, ITEM), + Err(Module { index: 50, error: [20, 0] }) + ); + // Burning can only be done by the collection item owner. + let (collection, item) = nfts::create_collection_and_mint_to(&ALICE, &ALICE, &BOB, ITEM); + assert_eq!(burn(&addr.clone(), collection, item), Err(Module { index: 50, error: [0, 0] })); + // Successful burn. + let (collection, item) = nfts::create_collection_and_mint_to(&addr, &addr, &addr, ITEM); + assert_ok!(burn(&addr.clone(), collection, item)); + assert_eq!(nfts::balance_of(COLLECTION, addr.clone()), 0); }); } diff --git a/pop-api/integration-tests/src/nonfungibles/utils.rs b/pop-api/integration-tests/src/nonfungibles/utils.rs index 0c1c3c19..48d4dbaa 100644 --- a/pop-api/integration-tests/src/nonfungibles/utils.rs +++ b/pop-api/integration-tests/src/nonfungibles/utils.rs @@ -1,9 +1,5 @@ use super::*; -pub(super) type AttributeKey = BoundedVec::KeyLimit>; -pub(super) type AttributeValue = BoundedVec::ValueLimit>; -pub(super) type MetadataData = BoundedVec::StringLimit>; - pub(super) fn total_supply(addr: &AccountId32, collection: CollectionId) -> Result { let result = do_bare_call("total_supply", addr, collection.encode()); decoded::>(result.clone()) @@ -24,11 +20,11 @@ pub(super) fn balance_of( pub(super) fn allowance( addr: &AccountId32, collection: CollectionId, + item: Option, owner: AccountId32, operator: AccountId32, - item: Option, ) -> Result { - let params = [collection.encode(), owner.encode(), operator.encode(), item.encode()].concat(); + let params = [collection.encode(), item.encode(), owner.encode(), operator.encode()].concat(); let result = do_bare_call("allowance", &addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -82,11 +78,11 @@ pub(super) fn get_attribute( collection.encode(), item.encode(), namespace.encode(), - AttributeKey::truncate_from(key).encode(), + AttributeKey::::truncate_from(key).encode(), ] .concat(); let result = do_bare_call("get_attribute", &addr, params); - decoded::, Error>>(result.clone()) + decoded::>, Error>>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) .map(|value| value.map(|v| v.to_vec())) } @@ -134,8 +130,8 @@ pub(super) fn set_attribute( collection.encode(), item.encode(), namespace.encode(), - AttributeKey::truncate_from(key).encode(), - AttributeValue::truncate_from(value).encode(), + AttributeKey::::truncate_from(key).encode(), + AttributeValue::::truncate_from(value).encode(), ] .concat(); let result = do_bare_call("set_attribute", &addr, params); @@ -293,10 +289,6 @@ pub(super) mod nfts { next_id } - pub(crate) fn next_collection_id() -> u32 { - pallet_nfts::NextCollectionId::::get().unwrap_or_default() - } - pub(crate) fn mint( collection: CollectionId, item: ItemId, @@ -313,8 +305,38 @@ pub(super) mod nfts { item } + pub(crate) fn burn(collection: CollectionId, item: ItemId, owner: &AccountId32) { + assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection, item)); + } + + pub(crate) fn lock_item_transfer(owner: &AccountId32, collection: CollectionId, item: ItemId) { + assert_ok!(Nfts::lock_item_transfer( + RuntimeOrigin::signed(owner.clone()), + collection, + item + )); + } + + pub(crate) fn unlock_item_transfer( + owner: &AccountId32, + collection: CollectionId, + item: ItemId, + ) { + assert_ok!(Nfts::unlock_item_transfer( + RuntimeOrigin::signed(owner.clone()), + collection, + item + )); + } + pub(crate) fn balance_of(collection: CollectionId, owner: AccountId32) -> u32 { - pallet_nfts::AccountBalance::::get(collection, owner) + AccountBalanceOf::::get(collection, owner) + } + + pub(crate) fn max_supply(collection: CollectionId) -> Option { + CollectionConfigOf::::get(collection) + .map(|config| config.max_supply) + .unwrap_or_default() } pub(super) fn collection_config_with_all_settings_enabled( @@ -325,4 +347,8 @@ pub(super) mod nfts { mint_settings: pallet_nfts::MintSettings::default(), } } + + pub(crate) fn next_collection_id() -> u32 { + NextCollectionIdOf::::get().unwrap_or_default() + } } diff --git a/pop-api/src/v0/nonfungibles/mod.rs b/pop-api/src/v0/nonfungibles/mod.rs index 7b2bd187..438b7fa5 100644 --- a/pop-api/src/v0/nonfungibles/mod.rs +++ b/pop-api/src/v0/nonfungibles/mod.rs @@ -44,15 +44,15 @@ pub fn balance_of(collection: CollectionId, owner: AccountId) -> Result { #[inline] pub fn allowance( collection: CollectionId, + item: Option, owner: AccountId, operator: AccountId, - item: Option, ) -> Result { build_read_state(ALLOWANCE) - .input::<(CollectionId, AccountId, AccountId, Option)>() + .input::<(CollectionId, Option, AccountId, AccountId)>() .output::, true>() .handle_error_code::() - .call(&(collection, owner, operator, item)) + .call(&(collection, item, owner, operator)) } #[inline] diff --git a/pop-api/src/v0/nonfungibles/types.rs b/pop-api/src/v0/nonfungibles/types.rs index c630f04b..5cd725ae 100644 --- a/pop-api/src/v0/nonfungibles/types.rs +++ b/pop-api/src/v0/nonfungibles/types.rs @@ -22,8 +22,12 @@ pub struct CollectionDetails { pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. pub attributes: u32, + /// The total number of allowances to spend all items within collections. + pub allowances: u32, } /// Attribute namespaces for non-fungible tokens. @@ -69,9 +73,15 @@ pub struct DestroyWitness { /// The total number of outstanding item configs of this collection. #[codec(compact)] pub item_configs: u32, + /// The total number of accounts that hold items of the collection. + #[codec(compact)] + pub item_holders: u32, /// The total number of attributes for this collection. #[codec(compact)] pub attributes: u32, + /// The total number of allowances to spend all items within collections. + #[codec(compact)] + pub allowances: u32, } /// Witness data for items mint transactions. From 515176ca84786ed172fc45aa3ab98ef81422aa61 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 17:54:30 +0700 Subject: [PATCH 63/64] chore: reformatting --- pallets/api/src/nonfungibles/mod.rs | 15 ++++++--------- pallets/nfts/Cargo.toml | 8 ++++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/pallets/api/src/nonfungibles/mod.rs b/pallets/api/src/nonfungibles/mod.rs index e60a9c15..4bdd99ce 100644 --- a/pallets/api/src/nonfungibles/mod.rs +++ b/pallets/api/src/nonfungibles/mod.rs @@ -544,22 +544,19 @@ pub mod pallet { TotalSupply(collection) => ReadResult::TotalSupply( NftsOf::::collection_items(collection).unwrap_or_default() as u128, ), - BalanceOf { collection, owner } => { - ReadResult::BalanceOf(AccountBalanceOf::::get(collection, owner)) - }, + BalanceOf { collection, owner } => + ReadResult::BalanceOf(AccountBalanceOf::::get(collection, owner)), Allowance { collection, owner, operator, item } => ReadResult::Allowance( NftsOf::::check_allowance(&collection, &item, &owner, &operator).is_ok(), ), - OwnerOf { collection, item } => { - ReadResult::OwnerOf(NftsOf::::owner(collection, item)) - }, + OwnerOf { collection, item } => + ReadResult::OwnerOf(NftsOf::::owner(collection, item)), GetAttribute { collection, item, namespace, key } => ReadResult::GetAttribute( AttributeOf::::get((collection, Some(item), namespace, key)) .map(|attribute| attribute.0.into()), ), - Collection(collection) => { - ReadResult::Collection(CollectionOf::::get(collection)) - }, + Collection(collection) => + ReadResult::Collection(CollectionOf::::get(collection)), ItemMetadata { collection, item } => ReadResult::ItemMetadata( NftsOf::::item_metadata(collection, item).map(|metadata| metadata.into()), ), diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index 791db0a7..bef584b8 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Parity Technologies ", "R0GUE "] +authors = [ "Parity Technologies ", "R0GUE " ] description = "Fork of FRAME NFTs pallet" edition.workspace = true homepage = "https://substrate.io" @@ -10,13 +10,13 @@ repository.workspace = true version = "31.0.0" [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] +targets = [ "x86_64-unknown-linux-gnu" ] [dependencies] codec = { workspace = true } enumflags2 = { workspace = true } log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +scale-info = { features = [ "derive" ], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -31,7 +31,7 @@ pallet-balances.workspace = true sp-keystore.workspace = true [features] -default = ["std"] +default = [ "std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", From e836ccb88f9c58fcf7d789650893b0f0fc9470a2 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 19 Nov 2024 09:22:18 +0700 Subject: [PATCH 64/64] chore: feature gating integration tests --- pop-api/integration-tests/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index 4738d010..a396c3a5 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -16,7 +16,9 @@ use scale::{Decode, Encode}; use sp_runtime::{AccountId32, BuildStorage, DispatchError}; use utils::*; +#[cfg(any(feature = "devnet", feature = "testnet"))] mod fungibles; +#[cfg(any(feature = "devnet"))] mod nonfungibles; mod utils;