From c503f863f92ced0b830c9a3b7ed7c7c8683aeac0 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 01/99] chore: fork pallet nfts --- Cargo.lock | 28 +- Cargo.toml | 2 +- pallets/nfts/Cargo.toml | 58 + pallets/nfts/README.md | 108 + pallets/nfts/runtime-api/Cargo.toml | 25 + pallets/nfts/runtime-api/README.md | 3 + pallets/nfts/runtime-api/src/lib.rs | 59 + pallets/nfts/src/benchmarking.rs | 882 ++++ pallets/nfts/src/common_functions.rs | 83 + pallets/nfts/src/features/approvals.rs | 176 + pallets/nfts/src/features/atomic_swap.rs | 236 + pallets/nfts/src/features/attributes.rs | 526 +++ pallets/nfts/src/features/buy_sell.rs | 173 + .../src/features/create_delete_collection.rs | 154 + .../nfts/src/features/create_delete_item.rs | 274 ++ pallets/nfts/src/features/lock.rs | 167 + pallets/nfts/src/features/metadata.rs | 284 ++ pallets/nfts/src/features/mod.rs | 28 + pallets/nfts/src/features/roles.rs | 154 + pallets/nfts/src/features/settings.rs | 179 + pallets/nfts/src/features/transfer.rs | 236 + pallets/nfts/src/impl_nonfungibles.rs | 509 +++ pallets/nfts/src/lib.rs | 1937 ++++++++ pallets/nfts/src/macros.rs | 66 + pallets/nfts/src/migration.rs | 120 + pallets/nfts/src/mock.rs | 104 + pallets/nfts/src/tests.rs | 3878 +++++++++++++++++ pallets/nfts/src/types.rs | 568 +++ pallets/nfts/src/weights.rs | 1468 +++++++ 29 files changed, 12479 insertions(+), 6 deletions(-) create mode 100644 pallets/nfts/Cargo.toml create mode 100644 pallets/nfts/README.md create mode 100644 pallets/nfts/runtime-api/Cargo.toml create mode 100644 pallets/nfts/runtime-api/README.md create mode 100644 pallets/nfts/runtime-api/src/lib.rs create mode 100644 pallets/nfts/src/benchmarking.rs create mode 100644 pallets/nfts/src/common_functions.rs create mode 100644 pallets/nfts/src/features/approvals.rs create mode 100644 pallets/nfts/src/features/atomic_swap.rs create mode 100644 pallets/nfts/src/features/attributes.rs create mode 100644 pallets/nfts/src/features/buy_sell.rs create mode 100644 pallets/nfts/src/features/create_delete_collection.rs create mode 100644 pallets/nfts/src/features/create_delete_item.rs create mode 100644 pallets/nfts/src/features/lock.rs create mode 100644 pallets/nfts/src/features/metadata.rs create mode 100644 pallets/nfts/src/features/mod.rs create mode 100644 pallets/nfts/src/features/roles.rs create mode 100644 pallets/nfts/src/features/settings.rs create mode 100644 pallets/nfts/src/features/transfer.rs create mode 100644 pallets/nfts/src/impl_nonfungibles.rs create mode 100644 pallets/nfts/src/lib.rs create mode 100644 pallets/nfts/src/macros.rs create mode 100644 pallets/nfts/src/migration.rs create mode 100644 pallets/nfts/src/mock.rs create mode 100644 pallets/nfts/src/tests.rs create mode 100644 pallets/nfts/src/types.rs create mode 100644 pallets/nfts/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index fa10958c..d2bf2ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -497,7 +497,7 @@ dependencies = [ "pallet-collator-selection", "pallet-message-queue", "pallet-multisig", - "pallet-nfts", + "pallet-nfts 30.0.0", "pallet-nfts-runtime-api", "pallet-proxy", "pallet-session", @@ -8230,7 +8230,7 @@ dependencies = [ "frame-system", "log", "pallet-assets", - "pallet-nfts", + "pallet-nfts 30.0.0", "parity-scale-codec", "scale-info", "sp-runtime", @@ -8256,13 +8256,31 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nfts" +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", +] + [[package]] name = "pallet-nfts-runtime-api" version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0ca7a0446d2d3c27f726a016c6366218df2e0bfef9ed35886b252cfa9757f6c" dependencies = [ - "pallet-nfts", + "pallet-nfts 30.0.0", "parity-scale-codec", "sp-api", "sp-std", @@ -10838,7 +10856,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", @@ -10983,7 +11001,7 @@ dependencies = [ "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", - "pallet-nfts", + "pallet-nfts 31.0.0", "pallet-nfts-runtime-api", "pallet-preimage", "pallet-proxy", diff --git a/Cargo.toml b/Cargo.toml index c8ab144a..0c73e23f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ substrate-wasm-builder = "23.0.0" # Local pallet-api = { path = "pallets/api", default-features = false } +pallet-nfts = { path = "pallets/nfts", default-features = false } pop-chain-extension = { path = "./extension", default-features = false } pop-primitives = { path = "./primitives", default-features = false } pop-runtime-common = { path = "runtime/common", default-features = false } @@ -90,7 +91,6 @@ pallet-contracts = { version = "35.0.0", default-features = false } pallet-message-queue = { version = "39.0.0", default-features = false } pallet-multisig = { version = "36.0.0", default-features = false } pallet-nft-fractionalization = { version = "18.0.0", default-features = false } -pallet-nfts = { version = "30.0.0", default-features = false } pallet-nfts-runtime-api = { version = "22.0.0", default-features = false } pallet-preimage = { version = "36.0.0", default-features = false } pallet-proxy = { version = "36.0.0", default-features = false } diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml new file mode 100644 index 00000000..f23b50f0 --- /dev/null +++ b/pallets/nfts/Cargo.toml @@ -0,0 +1,58 @@ +[package] +authors.workspace = true +description = "Fork of FRAME NFTs pallet (polkadot v1.15.0)" +edition.workspace = true +homepage = "https://substrate.io" +license.workspace = true +name = "pallet-nfts" +readme = "README.md" +repository.workspace = true +version = "31.0.0" + + +[package.metadata.docs.rs] +targets = [ "x86_64-unknown-linux-gnu" ] + +[dependencies] +codec = { workspace = true } +enumflags2 = { workspace = true } +log = { workspace = true } +scale-info = { features = [ "derive" ], workspace = true } + +# Substrate +frame-benchmarking = { optional = true, workspace = true } +frame-support.workspace = true +frame-system.workspace = true +sp-core.workspace = true +sp-io.workspace = true +sp-runtime.workspace = true + +[dev-dependencies] +pallet-balances = { default-features = true, workspace = true } +sp-keystore = { default-features = true, workspace = true } + +[features] +default = [ "std" ] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +std = [ + "codec/std", + "enumflags2/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md new file mode 100644 index 00000000..93ccf294 --- /dev/null +++ b/pallets/nfts/README.md @@ -0,0 +1,108 @@ +# NFTs pallet + +A pallet for dealing with non-fungible assets. + +## Overview + +The NFTs pallet provides functionality for non-fungible tokens' management, including: + +* Collection Creation +* NFT Minting +* NFT Transfers and Atomic Swaps +* NFT Trading methods +* Attributes Management +* NFT Burning + +To use it in your runtime, you need to implement +[`nfts::Config`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/trait.Config.html). + +The supported dispatchable functions are documented in the +[`nfts::Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum. + +### Terminology + +* **Collection creation:** The creation of a new collection. +* **NFT minting:** The action of creating a new item within a collection. +* **NFT transfer:** The action of sending an item from one account to another. +* **Atomic swap:** The action of exchanging items between accounts without needing a 3rd party service. +* **NFT burning:** The destruction of an item. +* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly one instance of + such an item in existence and there is exactly one owning account (though that owning account could be a proxy account + or multi-sig account). +* **Soul Bound NFT:** An item that is non-transferable from the account which it is minted into. + +### Goals + +The NFTs pallet in Substrate is designed to make the following possible: + +* Allow accounts to permissionlessly create nft collections. +* Allow a named (permissioned) account to mint and burn unique items within a collection. +* Move items between accounts permissionlessly. +* Allow a named (permissioned) account to freeze and unfreeze items within a collection or the entire collection. +* Allow the owner of an item to delegate the ability to transfer the item to some named third-party. +* Allow third-parties to store information in an NFT _without_ owning it (Eg. save game state). + +## Interface + +### Permissionless dispatchables + +* `create`: Create a new collection by placing a deposit. +* `mint`: Mint a new item within a collection (when the minting is public). +* `transfer`: Send an item to a new owner. +* `redeposit`: Update the deposit amount of an item, potentially freeing funds. +* `approve_transfer`: Name a delegate who may authorize a transfer. +* `cancel_approval`: Revert the effects of a previous `approve_transfer`. +* `approve_item_attributes`: Name a delegate who may change item's attributes within a namespace. +* `cancel_item_attributes_approval`: Revert the effects of a previous `approve_item_attributes`. +* `set_price`: Set the price for an item. +* `buy_item`: Buy an item. +* `pay_tips`: Pay tips, could be used for paying the creator royalties. +* `create_swap`: Create an offer to swap an NFT for another NFT and optionally some fungibles. +* `cancel_swap`: Cancel previously created swap offer. +* `claim_swap`: Swap items in an atomic way. + + +### Permissioned dispatchables + +* `destroy`: Destroy a collection. This destroys all the items inside the collection and refunds the deposit. +* `force_mint`: Mint a new item within a collection. +* `burn`: Destroy an item within a collection. +* `lock_item_transfer`: Prevent an individual item from being transferred. +* `unlock_item_transfer`: Revert the effects of a previous `lock_item_transfer`. +* `clear_all_transfer_approvals`: Clears all transfer approvals set by calling the `approve_transfer`. +* `lock_collection`: Prevent all items within a collection from being transferred (making them all `soul bound`). +* `lock_item_properties`: Lock item's metadata or attributes. +* `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items + will not be affected.) +* `set_team`: Alter the permissioned accounts of a collection. +* `set_collection_max_supply`: Change the max supply of a collection. +* `update_mint_settings`: Update the minting settings for collection. + + +### Metadata (permissioned) dispatchables + +* `set_attribute`: Set a metadata attribute of an item or collection. +* `clear_attribute`: Remove a metadata attribute of an item or collection. +* `set_metadata`: Set general metadata of an item (E.g. an IPFS address of an image url). +* `clear_metadata`: Remove general metadata of an item. +* `set_collection_metadata`: Set general metadata of a collection. +* `clear_collection_metadata`: Remove general metadata of a collection. + + +### Force (i.e. governance) dispatchables + +* `force_create`: Create a new collection (the collection id can not be chosen). +* `force_collection_owner`: Change collection's owner. +* `force_collection_config`: Change collection's config. +* `force_set_attribute`: Set an attribute. + +Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and +its associated variants for documentation on each function. + +## Related Modules + +* [`System`](https://docs.rs/frame-system/latest/frame_system/) +* [`Support`](https://docs.rs/frame-support/latest/frame_support/) +* [`Assets`](https://docs.rs/pallet-assets/latest/pallet_assets/) + +License: Apache-2.0 diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml new file mode 100644 index 00000000..17fd68f2 --- /dev/null +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -0,0 +1,25 @@ +[package] +authors.workspace = true +description = "Runtime API for the FRAME NFTs pallet. (polkadot v1.15.0)" +edition.workspace = true +homepage = "https://substrate.io" +license = "Apache-2.0" +name = "pallet-nfts-runtime-api" +readme = "README.md" +repository.workspace = true +version = "23.0.0" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = [ "x86_64-unknown-linux-gnu" ] + +[dependencies] +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" ] diff --git a/pallets/nfts/runtime-api/README.md b/pallets/nfts/runtime-api/README.md new file mode 100644 index 00000000..289036d2 --- /dev/null +++ b/pallets/nfts/runtime-api/README.md @@ -0,0 +1,3 @@ +RPC runtime API for the FRAME NFTs pallet. + +License: Apache-2.0 diff --git a/pallets/nfts/runtime-api/src/lib.rs b/pallets/nfts/runtime-api/src/lib.rs new file mode 100644 index 00000000..87faa790 --- /dev/null +++ b/pallets/nfts/runtime-api/src/lib.rs @@ -0,0 +1,59 @@ +// 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. + +//! Runtime API definition for the FRAME NFTs pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; +use codec::{Decode, Encode}; + +sp_api::decl_runtime_apis! { + pub trait NftsApi + where + AccountId: Encode + Decode, + CollectionId: Encode, + ItemId: Encode, + { + fn owner(collection: CollectionId, item: ItemId) -> Option; + + fn collection_owner(collection: CollectionId) -> Option; + + fn attribute( + collection: CollectionId, + item: ItemId, + key: Vec, + ) -> Option>; + + fn custom_attribute( + account: AccountId, + collection: CollectionId, + item: ItemId, + key: Vec, + ) -> Option>; + + fn system_attribute( + collection: CollectionId, + item: Option, + key: Vec, + ) -> Option>; + + fn collection_attribute(collection: CollectionId, key: Vec) -> Option>; + } +} diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs new file mode 100644 index 00000000..8fa87557 --- /dev/null +++ b/pallets/nfts/src/benchmarking.rs @@ -0,0 +1,882 @@ +// 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. + +//! Nfts pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use enumflags2::{BitFlag, BitFlags}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, +}; +use frame_support::{ + assert_ok, + traits::{EnsureOrigin, Get, UnfilteredDispatchable}, + BoundedVec, +}; +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; + +fn create_collection, I: 'static>( +) -> (T::CollectionId, T::AccountId, AccountIdLookupOf) { + let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let collection = T::Helper::collection(0); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + assert_ok!(Nfts::::force_create( + SystemOrigin::Root.into(), + caller_lookup.clone(), + default_collection_config::() + )); + (collection, caller, caller_lookup) +} + +fn add_collection_metadata, I: 'static>() -> (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()); + assert_ok!(Nfts::::set_collection_metadata( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + vec![0; T::StringLimit::get() as usize].try_into().unwrap(), + )); + (caller, caller_lookup) +} + +fn mint_item, I: 'static>( + index: u16, +) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { + let item = T::Helper::item(index); + let collection = T::Helper::collection(0); + let caller = Collection::::get(collection).unwrap().owner; + if caller != whitelisted_caller() { + whitelist_account!(caller); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let item_exists = Item::::contains_key(&collection, &item); + let item_config = ItemConfigOf::::get(&collection, &item); + if item_exists { + return (item, caller, caller_lookup) + } else if let Some(item_config) = item_config { + assert_ok!(Nfts::::force_mint( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + caller_lookup.clone(), + item_config, + )); + } else { + assert_ok!(Nfts::::mint( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + caller_lookup.clone(), + None, + )); + } + (item, caller, caller_lookup) +} + +fn lock_item, I: 'static>( + index: u16, +) -> (T::ItemId, 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 item = T::Helper::item(index); + assert_ok!(Nfts::::lock_item_transfer( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + )); + (item, caller, caller_lookup) +} + +fn burn_item, I: 'static>( + index: u16, +) -> (T::ItemId, 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 item = T::Helper::item(index); + assert_ok!(Nfts::::burn( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + )); + (item, caller, caller_lookup) +} + +fn add_item_metadata, I: 'static>( + item: T::ItemId, +) -> (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()); + assert_ok!(Nfts::::set_metadata( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + vec![0; T::StringLimit::get() as usize].try_into().unwrap(), + )); + (caller, caller_lookup) +} + +fn add_item_attribute, I: 'static>( + item: T::ItemId, +) -> (BoundedVec, 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 key: BoundedVec<_, _> = vec![0; T::KeyLimit::get() as usize].try_into().unwrap(); + assert_ok!(Nfts::::set_attribute( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + Some(item), + AttributeNamespace::CollectionOwner, + key.clone(), + vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), + )); + (key, caller, caller_lookup) +} + +fn add_collection_attribute, I: 'static>( + i: u16, +) -> (BoundedVec, 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 key: BoundedVec<_, _> = make_filled_vec(i, T::KeyLimit::get() as usize).try_into().unwrap(); + assert_ok!(Nfts::::set_attribute( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + None, + AttributeNamespace::CollectionOwner, + key.clone(), + vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), + )); + (key, caller, caller_lookup) +} + +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +fn make_collection_config, I: 'static>( + disable_settings: BitFlags, +) -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::from_disabled(disable_settings), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn default_collection_config, I: 'static>() -> CollectionConfigFor { + make_collection_config::(CollectionSetting::empty()) +} + +fn default_item_config() -> ItemConfig { + ItemConfig { settings: ItemSettings::all_enabled() } +} + +fn make_filled_vec(value: u16, length: usize) -> Vec { + let mut vec = vec![0u8; length]; + let mut s = Vec::from(value.to_be_bytes()); + vec.truncate(length - s.len()); + vec.append(&mut s); + vec +} + +benchmarks_instance_pallet! { + create { + let collection = T::Helper::collection(0); + let origin = T::CreateOrigin::try_successful_origin(&collection) + .map_err(|_| BenchmarkError::Weightless)?; + let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); + whitelist_account!(caller); + let admin = T::Lookup::unlookup(caller.clone()); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let call = Call::::create { admin, config: default_collection_config::() }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::NextCollectionIdIncremented { next_id: Some(T::Helper::collection(1)) }.into()); + } + + force_create { + let caller: T::AccountId = whitelisted_caller(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + }: _(SystemOrigin::Root, caller_lookup, default_collection_config::()) + verify { + assert_last_event::(Event::NextCollectionIdIncremented { next_id: Some(T::Helper::collection(1)) }.into()); + } + + destroy { + let m in 0 .. 1_000; + let c in 0 .. 1_000; + let a in 0 .. 1_000; + + let (collection, caller, _) = create_collection::(); + add_collection_metadata::(); + for i in 0..m { + mint_item::(i as u16); + add_item_metadata::(T::Helper::item(i as u16)); + lock_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..c { + mint_item::(i as u16); + lock_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..a { + add_collection_attribute::(i as u16); + } + let witness = Collection::::get(collection).unwrap().destroy_witness(); + }: _(SystemOrigin::Signed(caller), collection, witness) + verify { + assert_last_event::(Event::Destroyed { collection }.into()); + } + + mint { + let (collection, caller, caller_lookup) = create_collection::(); + let item = T::Helper::item(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, None) + verify { + assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); + } + + force_mint { + let (collection, caller, caller_lookup) = create_collection::(); + let item = T::Helper::item(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, default_item_config()) + verify { + assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); + } + + burn { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::Burned { collection, item, owner: caller }.into()); + } + + transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, target_lookup) + verify { + assert_last_event::(Event::Transferred { collection, item, from: caller, to: target }.into()); + } + + redeposit { + let i in 0 .. 5_000; + let (collection, caller, _) = create_collection::(); + let items = (0..i).map(|x| mint_item::(x as u16).0).collect::>(); + Nfts::::force_collection_config( + SystemOrigin::Root.into(), + collection, + make_collection_config::(CollectionSetting::DepositRequired.into()), + )?; + }: _(SystemOrigin::Signed(caller.clone()), collection, items.clone()) + verify { + assert_last_event::(Event::Redeposited { collection, successful_items: items }.into()); + } + + lock_item_transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller.clone()), T::Helper::collection(0), T::Helper::item(0)) + verify { + assert_last_event::(Event::ItemTransferLocked { collection: T::Helper::collection(0), item: T::Helper::item(0) }.into()); + } + + unlock_item_transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + Nfts::::lock_item_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + )?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::ItemTransferUnlocked { collection, item }.into()); + } + + lock_collection { + let (collection, caller, _) = create_collection::(); + let lock_settings = CollectionSettings::from_disabled( + CollectionSetting::TransferableItems | + CollectionSetting::UnlockedMetadata | + CollectionSetting::UnlockedAttributes | + CollectionSetting::UnlockedMaxSupply, + ); + }: _(SystemOrigin::Signed(caller.clone()), collection, lock_settings) + verify { + assert_last_event::(Event::CollectionLocked { collection }.into()); + } + + transfer_ownership { + let (collection, caller, _) = create_collection::(); + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + let origin = SystemOrigin::Signed(target.clone()).into(); + Nfts::::set_accept_ownership(origin, Some(collection))?; + }: _(SystemOrigin::Signed(caller), collection, target_lookup) + verify { + assert_last_event::(Event::OwnerChanged { collection, new_owner: target }.into()); + } + + set_team { + let (collection, caller, _) = create_collection::(); + let target0 = Some(T::Lookup::unlookup(account("target", 0, SEED))); + let target1 = Some(T::Lookup::unlookup(account("target", 1, SEED))); + let target2 = Some(T::Lookup::unlookup(account("target", 2, SEED))); + }: _(SystemOrigin::Signed(caller), collection, target0, target1, target2) + verify { + assert_last_event::(Event::TeamChanged{ + collection, + issuer: Some(account("target", 0, SEED)), + admin: Some(account("target", 1, SEED)), + freezer: Some(account("target", 2, SEED)), + }.into()); + } + + force_collection_owner { + let (collection, _, _) = create_collection::(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + let call = Call::::force_collection_owner { + collection, + owner: target_lookup, + }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::OwnerChanged { collection, new_owner: target }.into()); + } + + force_collection_config { + let (collection, caller, _) = create_collection::(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let call = Call::::force_collection_config { + collection, + config: make_collection_config::(CollectionSetting::DepositRequired.into()), + }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::CollectionConfigChanged { collection }.into()); + } + + lock_item_properties { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let lock_metadata = true; + let lock_attributes = true; + }: _(SystemOrigin::Signed(caller), collection, item, lock_metadata, lock_attributes) + verify { + assert_last_event::(Event::ItemPropertiesLocked { collection, item, lock_metadata, lock_attributes }.into()); + } + + set_attribute { + let key: BoundedVec<_, _> = vec![0u8; T::KeyLimit::get() as usize].try_into().unwrap(); + let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller), collection, Some(item), AttributeNamespace::CollectionOwner, key.clone(), value.clone()) + verify { + assert_last_event::( + Event::AttributeSet { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + value, + } + .into(), + ); + } + + force_set_attribute { + let key: BoundedVec<_, _> = vec![0u8; T::KeyLimit::get() as usize].try_into().unwrap(); + let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Root, Some(caller), collection, Some(item), AttributeNamespace::CollectionOwner, key.clone(), value.clone()) + verify { + assert_last_event::( + Event::AttributeSet { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + value, + } + .into(), + ); + } + + clear_attribute { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + let (key, ..) = add_item_attribute::(item); + }: _(SystemOrigin::Signed(caller), collection, Some(item), AttributeNamespace::CollectionOwner, key.clone()) + verify { + assert_last_event::( + Event::AttributeCleared { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + }.into(), + ); + } + + approve_item_attributes { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + }: _(SystemOrigin::Signed(caller), collection, item, target_lookup) + verify { + assert_last_event::( + Event::ItemAttributesApprovalAdded { + collection, + item, + delegate: target, + } + .into(), + ); + } + + cancel_item_attributes_approval { + let n in 0 .. 1_000; + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + Nfts::::approve_item_attributes( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + target_lookup.clone(), + )?; + T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); + let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); + for i in 0..n { + let key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); + Nfts::::set_attribute( + SystemOrigin::Signed(target.clone()).into(), + T::Helper::collection(0), + Some(item), + AttributeNamespace::Account(target.clone()), + key.try_into().unwrap(), + value.clone(), + )?; + } + let witness = CancelAttributesApprovalWitness { account_attributes: n }; + }: _(SystemOrigin::Signed(caller), collection, item, target_lookup, witness) + verify { + assert_last_event::( + Event::ItemAttributesApprovalRemoved { + collection, + item, + delegate: target, + } + .into(), + ); + } + + set_metadata { + let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller), collection, item, data.clone()) + verify { + assert_last_event::(Event::ItemMetadataSet { collection, item, data }.into()); + } + + clear_metadata { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + }: _(SystemOrigin::Signed(caller), collection, item) + verify { + assert_last_event::(Event::ItemMetadataCleared { collection, item }.into()); + } + + set_collection_metadata { + let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + }: _(SystemOrigin::Signed(caller), collection, data.clone()) + verify { + assert_last_event::(Event::CollectionMetadataSet { collection, data }.into()); + } + + clear_collection_metadata { + let (collection, caller, _) = create_collection::(); + add_collection_metadata::(); + }: _(SystemOrigin::Signed(caller), collection) + verify { + assert_last_event::(Event::CollectionMetadataCleared { collection }.into()); + } + + approve_transfer { + 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, item, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + + cancel_approval { + 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, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); + } + + clear_all_transfer_approvals { + 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, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); + } + + set_accept_ownership { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let collection = T::Helper::collection(0); + }: _(SystemOrigin::Signed(caller.clone()), Some(collection)) + verify { + assert_last_event::(Event::OwnershipAcceptanceChanged { + who: caller, + maybe_collection: Some(collection), + }.into()); + } + + set_collection_max_supply { + let (collection, caller, _) = create_collection::(); + }: _(SystemOrigin::Signed(caller.clone()), collection, u32::MAX) + verify { + assert_last_event::(Event::CollectionMaxSupplySet { + collection, + max_supply: u32::MAX, + }.into()); + } + + update_mint_settings { + let (collection, caller, _) = create_collection::(); + let mint_settings = MintSettings { + mint_type: MintType::HolderOf(T::Helper::collection(0)), + start_block: Some(One::one()), + end_block: Some(One::one()), + price: Some(ItemPrice::::from(1u32)), + default_item_settings: ItemSettings::all_enabled(), + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, mint_settings) + verify { + assert_last_event::(Event::CollectionMintSettingsUpdated { collection }.into()); + } + + set_price { + 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 price = ItemPrice::::from(100u32); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, Some(price), Some(delegate_lookup)) + verify { + assert_last_event::(Event::ItemPriceSet { + collection, + item, + price, + whitelisted_buyer: Some(delegate), + }.into()); + } + + buy_item { + let (collection, seller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let buyer: T::AccountId = account("buyer", 0, SEED); + let buyer_lookup = T::Lookup::unlookup(buyer.clone()); + let price = ItemPrice::::from(0u32); + let origin = SystemOrigin::Signed(seller.clone()).into(); + Nfts::::set_price(origin, collection, item, Some(price), Some(buyer_lookup))?; + T::Currency::make_free_balance_be(&buyer, DepositBalanceOf::::max_value()); + }: _(SystemOrigin::Signed(buyer.clone()), collection, item, price) + verify { + assert_last_event::(Event::ItemBought { + collection, + item, + price, + seller, + buyer, + }.into()); + } + + pay_tips { + let n in 0 .. T::MaxTips::get() as u32; + let amount = BalanceOf::::from(100u32); + let caller: T::AccountId = whitelisted_caller(); + let collection = T::Helper::collection(0); + let item = T::Helper::item(0); + let tips: BoundedVec<_, _> = vec![ + ItemTip + { collection, item, receiver: caller.clone(), amount }; n as usize + ].try_into().unwrap(); + }: _(SystemOrigin::Signed(caller.clone()), tips) + verify { + if !n.is_zero() { + assert_last_event::(Event::TipSent { + collection, + item, + sender: caller.clone(), + receiver: caller.clone(), + amount, + }.into()); + } + } + + create_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(100u32); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = T::MaxDeadlineDuration::get(); + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(caller.clone()), collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration) + verify { + let current_block = frame_system::Pallet::::block_number(); + assert_last_event::(Event::SwapCreated { + offered_collection: collection, + offered_item: item1, + desired_collection: collection, + desired_item: Some(item2), + price: Some(price_with_direction), + deadline: current_block.saturating_add(duration), + }.into()); + } + + cancel_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(100u32); + let origin = SystemOrigin::Signed(caller.clone()).into(); + let duration = T::MaxDeadlineDuration::get(); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + frame_system::Pallet::::set_block_number(One::one()); + Nfts::::create_swap(origin, collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration)?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item1) + verify { + assert_last_event::(Event::SwapCancelled { + offered_collection: collection, + offered_item: item1, + desired_collection: collection, + desired_item: Some(item2), + price: Some(price_with_direction), + deadline: duration.saturating_add(One::one()), + }.into()); + } + + claim_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(0u32); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = T::MaxDeadlineDuration::get(); + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + let origin = SystemOrigin::Signed(caller.clone()); + frame_system::Pallet::::set_block_number(One::one()); + Nfts::::transfer(origin.clone().into(), collection, item2, target_lookup)?; + Nfts::::create_swap( + origin.clone().into(), + collection, + item1, + collection, + Some(item2), + Some(price_with_direction.clone()), + duration, + )?; + }: _(SystemOrigin::Signed(target.clone()), collection, item2, collection, item1, Some(price_with_direction.clone())) + verify { + let current_block = frame_system::Pallet::::block_number(); + assert_last_event::(Event::SwapClaimed { + sent_collection: collection, + sent_item: item2, + sent_item_owner: target, + received_collection: collection, + received_item: item1, + received_item_owner: caller, + price: Some(price_with_direction), + deadline: duration.saturating_add(One::one()), + }.into()); + } + + mint_pre_signed { + let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let (caller_public, caller) = T::Helper::signer(); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + + let collection = T::Helper::collection(0); + let item = T::Helper::item(0); + assert_ok!(Nfts::::force_create( + SystemOrigin::Root.into(), + caller_lookup.clone(), + default_collection_config::() + )); + + let metadata = vec![0u8; T::StringLimit::get() as usize]; + let mut attributes = vec![]; + let attribute_value = vec![0u8; T::ValueLimit::get() as usize]; + for i in 0..n { + let attribute_key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); + attributes.push((attribute_key, attribute_value.clone())); + } + let mint_data = PreSignedMint { + collection, + item, + attributes, + metadata: metadata.clone(), + only_account: None, + deadline: One::one(), + mint_price: Some(DepositBalanceOf::::min_value()), + }; + let message = Encode::encode(&mint_data); + let signature = T::Helper::sign(&caller_public, &message); + + let target: T::AccountId = account("target", 0, SEED); + T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature.into(), caller) + verify { + let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); + assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); + } + + set_attributes_pre_signed { + let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let (collection, _, _) = create_collection::(); + + let item_owner: T::AccountId = account("item_owner", 0, SEED); + let item_owner_lookup = T::Lookup::unlookup(item_owner.clone()); + + let (signer_public, signer) = T::Helper::signer(); + + T::Currency::make_free_balance_be(&item_owner, DepositBalanceOf::::max_value()); + + let item = T::Helper::item(0); + assert_ok!(Nfts::::force_mint( + SystemOrigin::Root.into(), + collection, + item, + item_owner_lookup.clone(), + default_item_config(), + )); + + let mut attributes = vec![]; + let attribute_value = vec![0u8; T::ValueLimit::get() as usize]; + for i in 0..n { + let attribute_key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); + attributes.push((attribute_key, attribute_value.clone())); + } + let pre_signed_data = PreSignedAttributes { + collection, + item, + attributes, + namespace: AttributeNamespace::Account(signer.clone()), + deadline: One::one(), + }; + let message = Encode::encode(&pre_signed_data); + let signature = T::Helper::sign(&signer_public, &message); + + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature.into(), signer.clone()) + verify { + assert_last_event::( + Event::PreSignedAttributesSet { + collection, + item, + namespace: AttributeNamespace::Account(signer.clone()), + } + .into(), + ); + } + + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs new file mode 100644 index 00000000..f51de192 --- /dev/null +++ b/pallets/nfts/src/common_functions.rs @@ -0,0 +1,83 @@ +// 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. + +//! Various pieces of common functionality. + +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 { + Item::::get(collection, item).map(|i| i.owner) + } + + /// Get the owner of the collection, if the collection exists. + pub fn collection_owner(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.owner) + } + + /// Validates the signature of the given data with the provided signer's account ID. + /// + /// # Errors + /// + /// This function returns a [`WrongSignature`](crate::Error::WrongSignature) error if the + /// signature is invalid or the verification process fails. + pub fn validate_signature( + data: &Vec, + signature: &T::OffchainSignature, + signer: &T::AccountId, + ) -> DispatchResult { + if signature.verify(&**data, &signer) { + return Ok(()) + } + + // NOTE: for security reasons modern UIs implicitly wrap the data requested to sign into + // , that's why we support both wrapped and raw versions. + let prefix = b""; + let suffix = b""; + let mut wrapped: Vec = Vec::with_capacity(data.len() + prefix.len() + suffix.len()); + wrapped.extend(prefix); + wrapped.extend(data); + wrapped.extend(suffix); + + ensure!(signature.verify(&*wrapped, &signer), Error::::WrongSignature); + + Ok(()) + } + + pub(crate) fn set_next_collection_id(collection: T::CollectionId) { + let next_id = collection.increment(); + NextCollectionId::::set(next_id); + Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); + } + + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub fn set_next_id(id: T::CollectionId) { + NextCollectionId::::set(Some(id)); + } + + #[cfg(test)] + pub fn get_next_id() -> T::CollectionId { + NextCollectionId::::get() + .or(T::CollectionId::initial_value()) + .expect("Failed to get next collection ID") + } +} diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs new file mode 100644 index 00000000..ad5d93c2 --- /dev/null +++ b/pallets/nfts/src/features/approvals.rs @@ -0,0 +1,176 @@ +// 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. + +//! This module contains helper functions for the approval logic implemented in the NFTs pallet. +//! 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::*; + +impl, I: 'static> Pallet { + /// Approves the transfer of an item to a delegate. + /// + /// This function is used to approve the transfer of the specified `item` in the `collection` to + /// a `delegate`. If `maybe_check_origin` is specified, the function ensures that the + /// `check_origin` account is the owner of the item, granting them permission to approve the + /// transfer. The `delegate` is the account that will be allowed to take control of the item. + /// Optionally, a `deadline` can be specified to set a time limit for the approval. The + /// `deadline` is expressed in block numbers and is added to the current block number to + /// determine the absolute deadline for the approval. After approving the transfer, the function + /// emits the `TransferApproved` event. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, + /// granting permission to approve the transfer. If `None`, no permission check is performed. + /// - `collection`: The identifier of the collection containing the item to be transferred. + /// - `item`: The identifier of the item to be transferred. + /// - `delegate`: The account that will be allowed to take control of the item. + /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for + /// the approval. + pub(crate) fn do_approve_transfer( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + maybe_deadline: Option>, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + 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 == details.owner, Error::::NoPermission); + } + + let now = frame_system::Pallet::::block_number(); + let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + + details + .approvals + .try_insert(delegate.clone(), deadline) + .map_err(|_| Error::::ReachedApprovalLimit)?; + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::TransferApproved { + collection, + item, + owner: details.owner, + delegate, + deadline, + }); + + Ok(()) + } + + /// Cancels the approval for the transfer of an item to a delegate. + /// + /// This function is used to cancel the approval for the transfer of the specified `item` in the + /// `collection` to a `delegate`. If `maybe_check_origin` is specified, the function ensures + /// that the `check_origin` account is the owner of the item or that the approval is past its + /// deadline, granting permission to cancel the approval. After canceling the approval, the + /// function emits the `ApprovalCancelled` event. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the item or + /// that the approval is past its deadline, granting permission to cancel the approval. If + /// `None`, no permission check is performed. + /// - `collection`: The identifier of the collection containing the item. + /// - `item`: The identifier of the item. + /// - `delegate`: The account that was previously allowed to take control of the item. + pub(crate) fn do_cancel_approval( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + ) -> DispatchResult { + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; + + let is_past_deadline = if let Some(deadline) = maybe_deadline { + let now = frame_system::Pallet::::block_number(); + now > *deadline + } else { + false + }; + + if !is_past_deadline { + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == details.owner, Error::::NoPermission); + } + } + + details.approvals.remove(&delegate); + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::ApprovalCancelled { + collection, + item, + owner: details.owner, + delegate, + }); + + Ok(()) + } + + /// Clears all transfer approvals for an item. + /// + /// This function is used to clear all transfer approvals for the specified `item` in the + /// `collection`. If `maybe_check_origin` is specified, the function ensures that the + /// `check_origin` account is the owner of the item, granting permission to clear all transfer + /// approvals. After clearing all approvals, the function emits the `AllApprovalsCancelled` + /// event. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, + /// granting permission to clear all transfer approvals. If `None`, no permission check is + /// performed. + /// - `collection`: The collection ID containing the item. + /// - `item`: The item ID for which transfer approvals will be cleared. + pub(crate) fn do_clear_all_transfer_approvals( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == details.owner, Error::::NoPermission); + } + + details.approvals.clear(); + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::AllApprovalsCancelled { + collection, + item, + owner: details.owner, + }); + + Ok(()) + } +} diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs new file mode 100644 index 00000000..31c93fba --- /dev/null +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -0,0 +1,236 @@ +// 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. + +//! This module contains helper functions for performing atomic swaps implemented in the NFTs +//! pallet. +//! The bitflag [`PalletFeature::Swaps`] needs to be set in [`Config::Features`] for NFTs +//! to have the functionality defined in this module. + +use frame_support::{ + pallet_prelude::*, + traits::{Currency, ExistenceRequirement::KeepAlive}, +}; + +use crate::*; + +impl, I: 'static> Pallet { + /// Creates a new swap offer for the specified item. + /// + /// This function is used to create a new swap offer for the specified item. The `caller` + /// account must be the owner of the item. The swap offer specifies the `offered_collection`, + /// `offered_item`, `desired_collection`, `maybe_desired_item`, `maybe_price`, and `duration`. + /// The `duration` specifies the deadline by which the swap must be claimed. If + /// `maybe_desired_item` is `Some`, the specified item is expected in return for the swap. If + /// `maybe_desired_item` is `None`, it indicates that any item from the `desired_collection` can + /// be offered in return. The `maybe_price` specifies an optional price for the swap. If + /// specified, the other party must offer the specified `price` or higher for the swap. After + /// creating the swap, the function emits the `SwapCreated` event. + /// + /// - `caller`: The account creating the swap offer, which must be the owner of the item. + /// - `offered_collection_id`: The collection ID containing the offered item. + /// - `offered_item_id`: The item ID offered for the swap. + /// - `desired_collection_id`: The collection ID containing the desired item (if any). + /// - `maybe_desired_item_id`: The ID of the desired item (if any). + /// - `maybe_price`: The optional price for the swap. + /// - `duration`: The duration (in block numbers) specifying the deadline for the swap claim. + pub(crate) fn do_create_swap( + caller: T::AccountId, + offered_collection_id: T::CollectionId, + offered_item_id: T::ItemId, + desired_collection_id: T::CollectionId, + maybe_desired_item_id: Option, + maybe_price: Option>>, + duration: frame_system::pallet_prelude::BlockNumberFor, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Swaps), + Error::::MethodDisabled + ); + ensure!(duration <= T::MaxDeadlineDuration::get(), Error::::WrongDuration); + + let item = Item::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownItem)?; + ensure!(item.owner == caller, Error::::NoPermission); + + match maybe_desired_item_id { + Some(desired_item_id) => ensure!( + Item::::contains_key(&desired_collection_id, &desired_item_id), + Error::::UnknownItem + ), + None => ensure!( + Collection::::contains_key(&desired_collection_id), + Error::::UnknownCollection + ), + }; + + let now = frame_system::Pallet::::block_number(); + let deadline = duration.saturating_add(now); + + PendingSwapOf::::insert( + &offered_collection_id, + &offered_item_id, + PendingSwap { + desired_collection: desired_collection_id, + desired_item: maybe_desired_item_id, + price: maybe_price.clone(), + deadline, + }, + ); + + Self::deposit_event(Event::SwapCreated { + offered_collection: offered_collection_id, + offered_item: offered_item_id, + desired_collection: desired_collection_id, + desired_item: maybe_desired_item_id, + price: maybe_price, + deadline, + }); + + Ok(()) + } + + /// Cancels the specified swap offer. + /// + /// This function is used to cancel the specified swap offer created by the `caller` account. If + /// the swap offer's deadline has not yet passed, the `caller` must be the owner of the offered + /// item; otherwise, anyone can cancel an expired offer. + /// After canceling the swap offer, the function emits the `SwapCancelled` event. + /// + /// - `caller`: The account canceling the swap offer. + /// - `offered_collection_id`: The collection ID containing the offered item. + /// - `offered_item_id`: The item ID offered for the swap. + pub(crate) fn do_cancel_swap( + caller: T::AccountId, + offered_collection_id: T::CollectionId, + offered_item_id: T::ItemId, + ) -> DispatchResult { + let swap = PendingSwapOf::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownSwap)?; + + let now = frame_system::Pallet::::block_number(); + if swap.deadline > now { + let item = Item::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownItem)?; + ensure!(item.owner == caller, Error::::NoPermission); + } + + PendingSwapOf::::remove(&offered_collection_id, &offered_item_id); + + Self::deposit_event(Event::SwapCancelled { + offered_collection: offered_collection_id, + offered_item: offered_item_id, + desired_collection: swap.desired_collection, + desired_item: swap.desired_item, + price: swap.price, + deadline: swap.deadline, + }); + + Ok(()) + } + + /// Claims the specified swap offer. + /// + /// This function is used to claim a swap offer specified by the `send_collection_id`, + /// `send_item_id`, `receive_collection_id`, and `receive_item_id`. The `caller` account must be + /// the owner of the item specified by `send_collection_id` and `send_item_id`. If the claimed + /// swap has an associated `price`, it will be transferred between the owners of the two items + /// based on the `price.direction`. After the swap is completed, the function emits the + /// `SwapClaimed` event. + /// + /// - `caller`: The account claiming the swap offer, which must be the owner of the sent item. + /// - `send_collection_id`: The identifier of the collection containing the item being sent. + /// - `send_item_id`: The identifier of the item being sent for the swap. + /// - `receive_collection_id`: The identifier of the collection containing the item being + /// received. + /// - `receive_item_id`: The identifier of the item being received in the swap. + /// - `witness_price`: The optional witness price for the swap (price that was offered in the + /// swap). + pub(crate) fn do_claim_swap( + caller: T::AccountId, + send_collection_id: T::CollectionId, + send_item_id: T::ItemId, + receive_collection_id: T::CollectionId, + receive_item_id: T::ItemId, + witness_price: Option>>, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Swaps), + Error::::MethodDisabled + ); + + let send_item = Item::::get(&send_collection_id, &send_item_id) + .ok_or(Error::::UnknownItem)?; + let receive_item = Item::::get(&receive_collection_id, &receive_item_id) + .ok_or(Error::::UnknownItem)?; + let swap = PendingSwapOf::::get(&receive_collection_id, &receive_item_id) + .ok_or(Error::::UnknownSwap)?; + + ensure!(send_item.owner == caller, Error::::NoPermission); + ensure!( + swap.desired_collection == send_collection_id && swap.price == witness_price, + Error::::UnknownSwap + ); + + if let Some(desired_item) = swap.desired_item { + ensure!(desired_item == send_item_id, Error::::UnknownSwap); + } + + let now = frame_system::Pallet::::block_number(); + ensure!(now <= swap.deadline, Error::::DeadlineExpired); + + if let Some(ref price) = swap.price { + match price.direction { + PriceDirection::Send => T::Currency::transfer( + &receive_item.owner, + &send_item.owner, + price.amount, + KeepAlive, + )?, + PriceDirection::Receive => T::Currency::transfer( + &send_item.owner, + &receive_item.owner, + price.amount, + KeepAlive, + )?, + }; + } + + // This also removes the swap. + Self::do_transfer(send_collection_id, send_item_id, receive_item.owner.clone(), |_, _| { + Ok(()) + })?; + Self::do_transfer( + receive_collection_id, + receive_item_id, + send_item.owner.clone(), + |_, _| Ok(()), + )?; + + Self::deposit_event(Event::SwapClaimed { + sent_collection: send_collection_id, + sent_item: send_item_id, + sent_item_owner: send_item.owner, + received_collection: receive_collection_id, + received_item: receive_item_id, + received_item_owner: receive_item.owner, + price: swap.price, + deadline: swap.deadline, + }); + + Ok(()) + } +} diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs new file mode 100644 index 00000000..ab0cdc68 --- /dev/null +++ b/pallets/nfts/src/features/attributes.rs @@ -0,0 +1,526 @@ +// 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. + +//! This module contains helper methods to configure attributes for items and collections in the +//! NFTs pallet. +//! 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::*; + +impl, I: 'static> Pallet { + /// Sets the attribute of an item or a collection. + /// + /// This function is used to set an attribute for an item or a collection. It checks the + /// provided `namespace` and verifies the permission of the caller to perform the action. The + /// `collection` and `maybe_item` parameters specify the target for the attribute. + /// + /// - `origin`: The account attempting to set the attribute. + /// - `collection`: The identifier of the collection to which the item belongs, or the + /// collection itself if setting a collection attribute. + /// - `maybe_item`: The identifier of the item to which the attribute belongs, or `None` if + /// setting a collection attribute. + /// - `namespace`: The namespace in which the attribute is being set. It can be either + /// `CollectionOwner`, `ItemOwner`, or `Account` (pre-approved external address). + /// - `key`: The key of the attribute. It should be a vector of bytes within the limits defined + /// by `T::KeyLimit`. + /// - `value`: The value of the attribute. It should be a vector of bytes within the limits + /// defined by `T::ValueLimit`. + /// - `depositor`: The account that is paying the deposit for the attribute. + /// + /// Note: For the `CollectionOwner` namespace, the collection/item must have the + /// `UnlockedAttributes` setting enabled. + /// The deposit for setting an attribute is based on the `T::DepositPerByte` and + /// `T::AttributeDepositBase` configuration. + pub(crate) fn do_set_attribute( + origin: T::AccountId, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + depositor: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + ensure!( + Self::is_valid_namespace(&origin, &namespace, &collection, &maybe_item)?, + Error::::NoPermission + ); + + let collection_config = Self::get_collection_config(&collection)?; + // for the `CollectionOwner` namespace we need to check if the collection/item is not locked + match namespace { + AttributeNamespace::CollectionOwner => match maybe_item { + None => { + ensure!( + collection_config.is_setting_enabled(CollectionSetting::UnlockedAttributes), + Error::::LockedCollectionAttributes + ) + }, + Some(item) => { + let maybe_is_locked = Self::get_item_config(&collection, &item) + .map(|c| c.has_disabled_setting(ItemSetting::UnlockedAttributes))?; + ensure!(!maybe_is_locked, Error::::LockedItemAttributes); + }, + }, + _ => (), + } + + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); + let attribute_exists = attribute.is_some(); + if !attribute_exists { + collection_details.attributes.saturating_inc(); + } + + let old_deposit = + attribute.map_or(AttributeDeposit { account: None, amount: Zero::zero() }, |m| m.1); + + let mut deposit = Zero::zero(); + // disabled DepositRequired setting only affects the CollectionOwner namespace + if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) || + namespace != AttributeNamespace::CollectionOwner + { + deposit = T::DepositPerByte::get() + .saturating_mul(((key.len() + value.len()) as u32).into()) + .saturating_add(T::AttributeDepositBase::get()); + } + + let is_collection_owner_namespace = namespace == AttributeNamespace::CollectionOwner; + let is_depositor_collection_owner = + is_collection_owner_namespace && collection_details.owner == depositor; + + // NOTE: in the CollectionOwner namespace if the depositor is `None` that means the deposit + // was paid by the collection's owner. + let old_depositor = + if is_collection_owner_namespace && old_deposit.account.is_none() && attribute_exists { + Some(collection_details.owner.clone()) + } else { + old_deposit.account + }; + let depositor_has_changed = old_depositor != Some(depositor.clone()); + + // NOTE: when we transfer an item, we don't move attributes in the ItemOwner namespace. + // When the new owner updates the same attribute, we will update the depositor record + // and return the deposit to the previous owner. + if depositor_has_changed { + if let Some(old_depositor) = old_depositor { + T::Currency::unreserve(&old_depositor, old_deposit.amount); + } + T::Currency::reserve(&depositor, deposit)?; + } else if deposit > old_deposit.amount { + T::Currency::reserve(&depositor, deposit - old_deposit.amount)?; + } else if deposit < old_deposit.amount { + T::Currency::unreserve(&depositor, old_deposit.amount - deposit); + } + + if is_depositor_collection_owner { + if !depositor_has_changed { + collection_details.owner_deposit.saturating_reduce(old_deposit.amount); + } + collection_details.owner_deposit.saturating_accrue(deposit); + } + + let new_deposit_owner = match is_depositor_collection_owner { + true => None, + false => Some(depositor), + }; + Attribute::::insert( + (&collection, maybe_item, &namespace, &key), + (&value, AttributeDeposit { account: new_deposit_owner, amount: deposit }), + ); + + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace }); + Ok(()) + } + + /// Sets the attribute of an item or a collection without performing deposit checks. + /// + /// This function is used to force-set an attribute for an item or a collection without + /// performing the deposit checks. It bypasses the deposit requirement and should only be used + /// in specific situations where deposit checks are not necessary or handled separately. + /// + /// - `set_as`: The account that would normally pay for the deposit. + /// - `collection`: The identifier of the collection to which the item belongs, or the + /// collection itself if setting a collection attribute. + /// - `maybe_item`: The identifier of the item to which the attribute belongs, or `None` if + /// setting a collection attribute. + /// - `namespace`: The namespace in which the attribute is being set. It can be either + /// `CollectionOwner`, `ItemOwner`, or `Account` (pre-approved external address). + /// - `key`: The key of the attribute. It should be a vector of bytes within the limits defined + /// by `T::KeyLimit`. + /// - `value`: The value of the attribute. It should be a vector of bytes within the limits + /// defined by `T::ValueLimit`. + pub(crate) fn do_force_set_attribute( + set_as: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); + if let Some((_, deposit)) = attribute { + if deposit.account != set_as && deposit.amount != Zero::zero() { + if let Some(deposit_account) = deposit.account { + T::Currency::unreserve(&deposit_account, deposit.amount); + } + } + } else { + collection_details.attributes.saturating_inc(); + } + + Attribute::::insert( + (&collection, maybe_item, &namespace, &key), + (&value, AttributeDeposit { account: set_as, amount: Zero::zero() }), + ); + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace }); + Ok(()) + } + + /// Sets multiple attributes for an item or a collection. + /// + /// This function checks the pre-signed data is valid and updates the attributes of an item or + /// collection. It is limited by [`Config::MaxAttributesPerCall`] to prevent excessive storage + /// consumption in a single transaction. + /// + /// - `origin`: The account initiating the transaction. + /// - `data`: The data containing the details of the pre-signed attributes to be set. + /// - `signer`: The account of the pre-signed attributes signer. + pub(crate) fn do_set_attributes_pre_signed( + origin: T::AccountId, + data: PreSignedAttributesOf, + signer: T::AccountId, + ) -> DispatchResult { + let PreSignedAttributes { collection, item, attributes, namespace, deadline } = data; + + ensure!( + attributes.len() <= T::MaxAttributesPerCall::get() as usize, + Error::::MaxAttributesLimitReached + ); + + let now = frame_system::Pallet::::block_number(); + ensure!(deadline >= now, Error::::DeadlineExpired); + + let item_details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(item_details.owner == origin, Error::::NoPermission); + + // Only the CollectionOwner and Account() namespaces could be updated in this way. + // For the Account() namespace we check and set the approval if it wasn't set before. + match &namespace { + AttributeNamespace::CollectionOwner => {}, + AttributeNamespace::Account(account) => { + ensure!(account == &signer, Error::::NoPermission); + let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); + if !approvals.contains(account) { + Self::do_approve_item_attributes( + origin.clone(), + collection, + item, + account.clone(), + )?; + } + }, + _ => return Err(Error::::WrongNamespace.into()), + } + + for (key, value) in attributes { + Self::do_set_attribute( + signer.clone(), + collection, + Some(item), + namespace.clone(), + Self::construct_attribute_key(key)?, + Self::construct_attribute_value(value)?, + origin.clone(), + )?; + } + Self::deposit_event(Event::PreSignedAttributesSet { collection, item, namespace }); + Ok(()) + } + + /// Clears an attribute of an item or a collection. + /// + /// This function allows clearing an attribute from an item or a collection. It verifies the + /// permission of the caller to perform the action based on the provided `namespace` and + /// `depositor` account. The deposit associated with the attribute, if any, will be unreserved. + /// + /// - `maybe_check_origin`: An optional account that acts as an additional security check when + /// clearing the attribute. This can be `None` if no additional check is required. + /// - `collection`: The identifier of the collection to which the item belongs, or the + /// collection itself if clearing a collection attribute. + /// - `maybe_item`: The identifier of the item to which the attribute belongs, or `None` if + /// clearing a collection attribute. + /// - `namespace`: The namespace in which the attribute is being cleared. It can be either + /// `CollectionOwner`, `ItemOwner`, or `Account`. + /// - `key`: The key of the attribute to be cleared. It should be a vector of bytes within the + /// limits defined by `T::KeyLimit`. + pub(crate) fn do_clear_attribute( + maybe_check_origin: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + ) -> DispatchResult { + let (_, deposit) = Attribute::::take((collection, maybe_item, &namespace, &key)) + .ok_or(Error::::AttributeNotFound)?; + + if let Some(check_origin) = &maybe_check_origin { + // validate the provided namespace when it's not a root call and the caller is not + // the same as the `deposit.account` (e.g. the deposit was paid by different account) + if deposit.account != maybe_check_origin { + ensure!( + Self::is_valid_namespace(&check_origin, &namespace, &collection, &maybe_item)?, + Error::::NoPermission + ); + } + + // can't clear `CollectionOwner` type attributes if the collection/item is locked + match namespace { + AttributeNamespace::CollectionOwner => match maybe_item { + None => { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config + .is_setting_enabled(CollectionSetting::UnlockedAttributes), + Error::::LockedCollectionAttributes + ) + }, + Some(item) => { + // NOTE: if the item was previously burned, the ItemConfigOf record + // might not exist. In that case, we allow to clear the attribute. + let maybe_is_locked = Self::get_item_config(&collection, &item) + .map_or(None, |c| { + Some(c.has_disabled_setting(ItemSetting::UnlockedAttributes)) + }); + if let Some(is_locked) = maybe_is_locked { + ensure!(!is_locked, Error::::LockedItemAttributes); + // Only the collection's admin can clear attributes in that namespace. + // e.g. in off-chain mints, the attribute's depositor will be the item's + // owner, that's why we need to do this extra check. + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + }, + }, + _ => (), + }; + } + + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + collection_details.attributes.saturating_dec(); + + match deposit.account { + Some(deposit_account) => { + T::Currency::unreserve(&deposit_account, deposit.amount); + }, + None if namespace == AttributeNamespace::CollectionOwner => { + collection_details.owner_deposit.saturating_reduce(deposit.amount); + T::Currency::unreserve(&collection_details.owner, deposit.amount); + }, + _ => (), + } + + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key, namespace }); + + Ok(()) + } + + /// Approves a delegate to set attributes on behalf of the item's owner. + /// + /// This function allows the owner of an item to approve a delegate to set attributes in the + /// `Account(delegate)` namespace. The maximum number of approvals is determined by + /// the configuration `T::MaxAttributesApprovals`. + /// + /// - `check_origin`: The account of the item's owner attempting to approve the delegate. + /// - `collection`: The identifier of the collection to which the item belongs. + /// - `item`: The identifier of the item for which the delegate is being approved. + /// - `delegate`: The account that is being approved to set attributes on behalf of the item's + /// owner. + pub(crate) fn do_approve_item_attributes( + check_origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(check_origin == details.owner, Error::::NoPermission); + + ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { + approvals + .try_insert(delegate.clone()) + .map_err(|_| Error::::ReachedApprovalLimit)?; + + Self::deposit_event(Event::ItemAttributesApprovalAdded { collection, item, delegate }); + Ok(()) + }) + } + + /// Cancels the approval of an item's attributes by a delegate. + /// + /// This function allows the owner of an item to cancel the approval of a delegate to set + /// attributes in the `Account(delegate)` namespace. The delegate's approval is removed, in + /// addition to attributes the `delegate` previously created, and any unreserved deposit + /// is returned. The number of attributes that the delegate has set for the item must + /// not exceed the `account_attributes` provided in the `witness`. + /// This function is used to prevent unintended or malicious cancellations. + /// + /// - `check_origin`: The account of the item's owner attempting to cancel the delegate's + /// approval. + /// - `collection`: The identifier of the collection to which the item belongs. + /// - `item`: The identifier of the item for which the delegate's approval is being canceled. + /// - `delegate`: The account whose approval is being canceled. + /// - `witness`: The witness containing the number of attributes set by the delegate for the + /// item. + pub(crate) fn do_cancel_item_attributes_approval( + check_origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(check_origin == details.owner, Error::::NoPermission); + + ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { + approvals.remove(&delegate); + + let mut attributes: u32 = 0; + let mut deposited: DepositBalanceOf = Zero::zero(); + for (_, (_, deposit)) in Attribute::::drain_prefix(( + &collection, + Some(item), + AttributeNamespace::Account(delegate.clone()), + )) { + attributes.saturating_inc(); + deposited = deposited.saturating_add(deposit.amount); + } + ensure!(attributes <= witness.account_attributes, Error::::BadWitness); + + if !deposited.is_zero() { + T::Currency::unreserve(&delegate, deposited); + } + + Self::deposit_event(Event::ItemAttributesApprovalRemoved { + collection, + item, + delegate, + }); + Ok(()) + }) + } + + /// A helper method to check whether an attribute namespace is valid. + fn is_valid_namespace( + origin: &T::AccountId, + namespace: &AttributeNamespace, + collection: &T::CollectionId, + maybe_item: &Option, + ) -> Result { + let mut result = false; + match namespace { + AttributeNamespace::CollectionOwner => + result = Self::has_role(&collection, &origin, CollectionRole::Admin), + AttributeNamespace::ItemOwner => + if let Some(item) = maybe_item { + let item_details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + result = origin == &item_details.owner + }, + AttributeNamespace::Account(account_id) => + if let Some(item) = maybe_item { + let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); + result = account_id == origin && approvals.contains(&origin) + }, + _ => (), + }; + Ok(result) + } + + /// A helper method to construct an attribute's key. + /// + /// # Errors + /// + /// This function returns an [`IncorrectData`](crate::Error::IncorrectData) error if the + /// provided attribute `key` is too long. + pub fn construct_attribute_key( + key: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(key).map_err(|_| Error::::IncorrectData)?) + } + + /// A helper method to construct an attribute's value. + /// + /// # Errors + /// + /// This function returns an [`IncorrectData`](crate::Error::IncorrectData) error if the + /// provided `value` is too long. + pub fn construct_attribute_value( + value: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(value).map_err(|_| Error::::IncorrectData)?) + } + + /// A helper method to check whether a system attribute is set for a given item. + /// + /// # Errors + /// + /// This function returns an [`IncorrectData`](crate::Error::IncorrectData) error if the + /// provided pallet attribute is too long. + pub fn has_system_attribute( + collection: &T::CollectionId, + item: &T::ItemId, + attribute_key: PalletAttributes, + ) -> Result { + let attribute = ( + &collection, + Some(item), + AttributeNamespace::Pallet, + &Self::construct_attribute_key(attribute_key.encode())?, + ); + Ok(Attribute::::contains_key(attribute)) + } +} diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs new file mode 100644 index 00000000..8cf86f79 --- /dev/null +++ b/pallets/nfts/src/features/buy_sell.rs @@ -0,0 +1,173 @@ +// 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. + +//! This module contains helper functions to perform the buy and sell functionalities of the NFTs +//! pallet. +//! The bitflag [`PalletFeature::Trading`] needs to be set in the [`Config::Features`] for NFTs +//! to have the functionality defined in this module. + +use frame_support::{ + pallet_prelude::*, + traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, +}; + +use crate::*; + +impl, I: 'static> Pallet { + /// Pays the specified tips to the corresponding receivers. + /// + /// This function is used to pay tips from the `sender` account to multiple receivers. The tips + /// are specified as a `BoundedVec` of `ItemTipOf` with a maximum length of `T::MaxTips`. For + /// each tip, the function transfers the `amount` to the `receiver` account. The sender is + /// responsible for ensuring the validity of the provided tips. + /// + /// - `sender`: The account that pays the tips. + /// - `tips`: A `BoundedVec` containing the tips to be paid, where each tip contains the + /// `collection`, `item`, `receiver`, and `amount`. + pub(crate) fn do_pay_tips( + sender: T::AccountId, + tips: BoundedVec, T::MaxTips>, + ) -> DispatchResult { + for tip in tips { + let ItemTip { collection, item, receiver, amount } = tip; + T::Currency::transfer(&sender, &receiver, amount, KeepAlive)?; + Self::deposit_event(Event::TipSent { + collection, + item, + sender: sender.clone(), + receiver, + amount, + }); + } + Ok(()) + } + + /// Sets the price and whitelists a buyer for an item in the specified collection. + /// + /// This function is used to set the price and whitelist a buyer for an item in the + /// specified `collection`. The `sender` account must be the owner of the item. The item's price + /// and the whitelisted buyer can be set to allow trading the item. If `price` is `None`, the + /// item will be marked as not for sale. + /// + /// - `collection`: The identifier of the collection containing the item. + /// - `item`: The identifier of the item for which the price and whitelist information will be + /// set. + /// - `sender`: The account that sets the price and whitelist information for the item. + /// - `price`: The optional price for the item. + /// - `whitelisted_buyer`: The optional account that is whitelisted to buy the item at the set + /// price. + pub(crate) fn do_set_price( + collection: T::CollectionId, + item: T::ItemId, + sender: T::AccountId, + price: Option>, + whitelisted_buyer: Option, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Trading), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(details.owner == sender, Error::::NoPermission); + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + item_config.is_setting_enabled(ItemSetting::Transferable), + Error::::ItemLocked + ); + + if let Some(ref price) = price { + ItemPriceOf::::insert(&collection, &item, (price, whitelisted_buyer.clone())); + Self::deposit_event(Event::ItemPriceSet { + collection, + item, + price: *price, + whitelisted_buyer, + }); + } else { + ItemPriceOf::::remove(&collection, &item); + Self::deposit_event(Event::ItemPriceRemoved { collection, item }); + } + + Ok(()) + } + + /// Buys the specified item from the collection. + /// + /// This function is used to buy an item from the specified `collection`. The `buyer` account + /// will attempt to buy the item with the provided `bid_price`. The item's current owner will + /// receive the bid price if it is equal to or higher than the item's set price. If + /// `whitelisted_buyer` is specified in the item's price information, only that account is + /// allowed to buy the item. If the item is not for sale, or the bid price is too low, the + /// function will return an error. + /// + /// - `collection`: The identifier of the collection containing the item to be bought. + /// - `item`: The identifier of the item to be bought. + /// - `buyer`: The account that attempts to buy the item. + /// - `bid_price`: The bid price offered by the buyer for the item. + pub(crate) fn do_buy_item( + collection: T::CollectionId, + item: T::ItemId, + buyer: T::AccountId, + bid_price: ItemPrice, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Trading), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(details.owner != buyer, Error::::NoPermission); + + let price_info = + ItemPriceOf::::get(&collection, &item).ok_or(Error::::NotForSale)?; + + ensure!(bid_price >= price_info.0, Error::::BidTooLow); + + if let Some(only_buyer) = price_info.1 { + ensure!(only_buyer == buyer, Error::::NoPermission); + } + + T::Currency::transfer( + &buyer, + &details.owner, + price_info.0, + ExistenceRequirement::KeepAlive, + )?; + + let old_owner = details.owner.clone(); + + Self::do_transfer(collection, item, buyer.clone(), |_, _| Ok(()))?; + + Self::deposit_event(Event::ItemBought { + collection, + item, + price: price_info.0, + seller: old_owner, + buyer, + }); + + Ok(()) + } +} diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs new file mode 100644 index 00000000..348ec6b9 --- /dev/null +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -0,0 +1,154 @@ +// 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. + +//! 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::*; + +impl, I: 'static> Pallet { + /// Create a new collection with the given `collection`, `owner`, `admin`, `config`, `deposit`, + /// and `event`. + /// + /// This function creates a new collection with the provided parameters. It reserves the + /// required deposit from the owner's account, sets the collection details, assigns admin roles, + /// and inserts the provided configuration. Finally, it emits the specified event upon success. + /// + /// # Errors + /// + /// This function returns a [`CollectionIdInUse`](crate::Error::CollectionIdInUse) error if the + /// collection ID is already in use. + pub fn do_create_collection( + collection: T::CollectionId, + owner: T::AccountId, + admin: T::AccountId, + config: CollectionConfigFor, + deposit: DepositBalanceOf, + event: Event, + ) -> DispatchResult { + ensure!(!Collection::::contains_key(collection), Error::::CollectionIdInUse); + + T::Currency::reserve(&owner, deposit)?; + + Collection::::insert( + collection, + CollectionDetails { + owner: owner.clone(), + owner_deposit: deposit, + items: 0, + item_metadatas: 0, + item_configs: 0, + attributes: 0, + }, + ); + CollectionRoleOf::::insert( + collection, + admin, + CollectionRoles( + CollectionRole::Admin | CollectionRole::Freezer | CollectionRole::Issuer, + ), + ); + + CollectionConfigOf::::insert(&collection, config); + CollectionAccount::::insert(&owner, &collection, ()); + + Self::deposit_event(event); + + if let Some(max_supply) = config.max_supply { + Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); + } + + Ok(()) + } + + /// Destroy the specified collection with the given `collection`, `witness`, and + /// `maybe_check_owner`. + /// + /// This function destroys the specified collection if it exists and meets the necessary + /// conditions. It checks the provided `witness` against the actual collection details and + /// removes the collection along with its associated metadata, attributes, and configurations. + /// The necessary deposits are returned to the corresponding accounts, and the roles and + /// configurations for the collection are cleared. Finally, it emits the `Destroyed` event upon + /// successful destruction. + /// + /// # Errors + /// + /// This function returns a dispatch error in the following cases: + /// - If the collection ID is not found + /// ([`UnknownCollection`](crate::Error::UnknownCollection)). + /// - If the provided `maybe_check_owner` does not match the actual owner + /// ([`NoPermission`](crate::Error::NoPermission)). + /// - If the collection is not empty (contains items) + /// ([`CollectionNotEmpty`](crate::Error::CollectionNotEmpty)). + /// - If the `witness` does not match the actual collection details + /// ([`BadWitness`](crate::Error::BadWitness)). + pub fn do_destroy_collection( + collection: T::CollectionId, + witness: DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Collection::::try_mutate_exists(collection, |maybe_details| { + let collection_details = + maybe_details.take().ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = maybe_check_owner { + ensure!(collection_details.owner == check_owner, Error::::NoPermission); + } + ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); + ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); + ensure!( + collection_details.item_metadatas == witness.item_metadatas, + Error::::BadWitness + ); + ensure!( + collection_details.item_configs == witness.item_configs, + Error::::BadWitness + ); + + for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { + if let Some(depositor) = metadata.deposit.account { + T::Currency::unreserve(&depositor, metadata.deposit.amount); + } + } + + CollectionMetadataOf::::remove(&collection); + Self::clear_roles(&collection)?; + + for (_, (_, deposit)) in Attribute::::drain_prefix((&collection,)) { + if !deposit.amount.is_zero() { + if let Some(account) = deposit.account { + T::Currency::unreserve(&account, deposit.amount); + } + } + } + + CollectionAccount::::remove(&collection_details.owner, &collection); + T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); + CollectionConfigOf::::remove(&collection); + let _ = ItemConfigOf::::clear_prefix(&collection, witness.item_configs, None); + + Self::deposit_event(Event::Destroyed { collection }); + + Ok(DestroyWitness { + item_metadatas: collection_details.item_metadatas, + item_configs: collection_details.item_configs, + attributes: collection_details.attributes, + }) + }) + } +} diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs new file mode 100644 index 00000000..e9843b2e --- /dev/null +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -0,0 +1,274 @@ +// 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. + +//! 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::*; + +impl, I: 'static> Pallet { + /// Mint a new unique item with the given `collection`, `item`, and other minting configuration + /// details. + /// + /// This function performs the minting of a new unique item. It checks if the item does not + /// already exist in the given collection, and if the max supply limit (if configured) is not + /// reached. It also reserves the required deposit for the item and sets the item details + /// accordingly. + /// + /// # Errors + /// + /// This function returns a dispatch error in the following cases: + /// - If the collection ID is invalid ([`UnknownCollection`](crate::Error::UnknownCollection)). + /// - If the item already exists in the collection + /// ([`AlreadyExists`](crate::Error::AlreadyExists)). + /// - If the item configuration already exists + /// ([`InconsistentItemConfig`](crate::Error::InconsistentItemConfig)). + /// - If the max supply limit (if configured) for the collection is reached + /// ([`MaxSupplyReached`](crate::Error::MaxSupplyReached)). + /// - If any error occurs in the `with_details_and_config` closure. + pub fn do_mint( + collection: T::CollectionId, + item: T::ItemId, + maybe_depositor: Option, + mint_to: T::AccountId, + item_config: ItemConfig, + with_details_and_config: impl FnOnce( + &CollectionDetailsFor, + &CollectionConfigFor, + ) -> DispatchResult, + ) -> DispatchResult { + ensure!(!Item::::contains_key(collection, item), Error::::AlreadyExists); + + Collection::::try_mutate( + &collection, + |maybe_collection_details| -> DispatchResult { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + + let collection_config = Self::get_collection_config(&collection)?; + with_details_and_config(collection_details, &collection_config)?; + + if let Some(max_supply) = collection_config.max_supply { + ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); + } + + collection_details.items.saturating_inc(); + + let collection_config = Self::get_collection_config(&collection)?; + let deposit_amount = match collection_config + .is_setting_enabled(CollectionSetting::DepositRequired) + { + true => T::ItemDeposit::get(), + false => Zero::zero(), + }; + let deposit_account = match maybe_depositor { + None => collection_details.owner.clone(), + Some(depositor) => depositor, + }; + + let item_owner = mint_to.clone(); + Account::::insert((&item_owner, &collection, &item), ()); + + if let Ok(existing_config) = ItemConfigOf::::try_get(&collection, &item) { + ensure!(existing_config == item_config, Error::::InconsistentItemConfig); + } else { + ItemConfigOf::::insert(&collection, &item, item_config); + collection_details.item_configs.saturating_inc(); + } + + T::Currency::reserve(&deposit_account, deposit_amount)?; + + let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; + let details = ItemDetails { + owner: item_owner, + approvals: ApprovalsOf::::default(), + deposit, + }; + Item::::insert(&collection, &item, details); + Ok(()) + }, + )?; + + Self::deposit_event(Event::Issued { collection, item, owner: mint_to }); + Ok(()) + } + + /// Mints a new item using a pre-signed message. + /// + /// This function allows minting a new item using a pre-signed message. The minting process is + /// similar to the regular minting process, but it is performed by a pre-authorized account. The + /// `mint_to` account receives the newly minted item. The minting process is configurable + /// through the provided `mint_data`. The attributes, metadata, and price of the item are set + /// according to the provided `mint_data`. The `with_details_and_config` closure is called to + /// validate the provided `collection_details` and `collection_config` before minting the item. + /// + /// - `mint_to`: The account that receives the newly minted item. + /// - `mint_data`: The pre-signed minting data containing the `collection`, `item`, + /// `attributes`, `metadata`, `deadline`, `only_account`, and `mint_price`. + /// - `signer`: The account that is authorized to mint the item using the pre-signed message. + pub(crate) fn do_mint_pre_signed( + mint_to: T::AccountId, + mint_data: PreSignedMintOf, + signer: T::AccountId, + ) -> DispatchResult { + let PreSignedMint { + collection, + item, + attributes, + metadata, + deadline, + only_account, + mint_price, + } = mint_data; + let metadata = Self::construct_metadata(metadata)?; + + ensure!( + attributes.len() <= T::MaxAttributesPerCall::get() as usize, + Error::::MaxAttributesLimitReached + ); + if let Some(account) = only_account { + ensure!(account == mint_to, Error::::WrongOrigin); + } + + let now = frame_system::Pallet::::block_number(); + ensure!(deadline >= now, Error::::DeadlineExpired); + + ensure!( + Self::has_role(&collection, &signer, CollectionRole::Issuer), + Error::::NoPermission + ); + + let item_config = ItemConfig { settings: Self::get_default_item_settings(&collection)? }; + Self::do_mint( + collection, + item, + Some(mint_to.clone()), + mint_to.clone(), + item_config, + |collection_details, _| { + if let Some(price) = mint_price { + T::Currency::transfer( + &mint_to, + &collection_details.owner, + price, + ExistenceRequirement::KeepAlive, + )?; + } + Ok(()) + }, + )?; + let admin_account = Self::find_account_by_role(&collection, CollectionRole::Admin); + if let Some(admin_account) = admin_account { + for (key, value) in attributes { + Self::do_set_attribute( + admin_account.clone(), + collection, + Some(item), + AttributeNamespace::CollectionOwner, + Self::construct_attribute_key(key)?, + Self::construct_attribute_value(value)?, + mint_to.clone(), + )?; + } + if !metadata.len().is_zero() { + Self::do_set_item_metadata( + Some(admin_account.clone()), + collection, + item, + metadata, + Some(mint_to.clone()), + )?; + } + } + Ok(()) + } + + /// Burns the specified item with the given `collection`, `item`, and `with_details`. + /// + /// # Errors + /// + /// This function returns a dispatch error in the following cases: + /// - If the collection ID is invalid ([`UnknownCollection`](crate::Error::UnknownCollection)). + /// - If the item is locked ([`ItemLocked`](crate::Error::ItemLocked)). + pub fn do_burn( + collection: T::CollectionId, + item: T::ItemId, + with_details: impl FnOnce(&ItemDetailsFor) -> DispatchResult, + ) -> DispatchResult { + ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); + ensure!( + !Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?, + Error::::ItemLocked + ); + let item_config = Self::get_item_config(&collection, &item)?; + // NOTE: if item's settings are not empty (e.g. item's metadata is locked) + // then we keep the config record and don't remove it + let remove_config = !item_config.has_disabled_settings(); + let owner = Collection::::try_mutate( + &collection, + |maybe_collection_details| -> Result { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + let details = Item::::get(&collection, &item) + .ok_or(Error::::UnknownCollection)?; + with_details(&details)?; + + // Return the deposit. + T::Currency::unreserve(&details.deposit.account, details.deposit.amount); + collection_details.items.saturating_dec(); + + if remove_config { + collection_details.item_configs.saturating_dec(); + } + + // Clear the metadata if it's not locked. + if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) { + if let Some(metadata) = ItemMetadataOf::::take(&collection, &item) { + let depositor_account = + metadata.deposit.account.unwrap_or(collection_details.owner.clone()); + + T::Currency::unreserve(&depositor_account, metadata.deposit.amount); + collection_details.item_metadatas.saturating_dec(); + + if depositor_account == collection_details.owner { + collection_details + .owner_deposit + .saturating_reduce(metadata.deposit.amount); + } + } + } + + Ok(details.owner) + }, + )?; + + Item::::remove(&collection, &item); + Account::::remove((&owner, &collection, &item)); + ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); + ItemAttributesApprovalsOf::::remove(&collection, &item); + + if remove_config { + ItemConfigOf::::remove(&collection, &item); + } + + Self::deposit_event(Event::Burned { collection, item, owner }); + Ok(()) + } +} diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs new file mode 100644 index 00000000..4649f4a0 --- /dev/null +++ b/pallets/nfts/src/features/lock.rs @@ -0,0 +1,167 @@ +// 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. + +//! This module contains helper methods to configure locks on collections and items for the NFTs +//! pallet. + +use frame_support::pallet_prelude::*; + +use crate::*; + +impl, I: 'static> Pallet { + /// Locks a collection with specified settings. + /// + /// The origin must be the owner of the collection to lock it. This function disables certain + /// settings on the collection. The only setting that can't be disabled is `DepositRequired`. + /// + /// 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. + /// - `lock_settings`: The collection settings to be locked. + pub(crate) fn do_lock_collection( + origin: T::AccountId, + collection: T::CollectionId, + lock_settings: CollectionSettings, + ) -> DispatchResult { + ensure!(Self::collection_owner(collection) == Some(origin), Error::::NoPermission); + ensure!( + !lock_settings.is_disabled(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + + for setting in lock_settings.get_disabled() { + config.disable_setting(setting); + } + + Self::deposit_event(Event::::CollectionLocked { collection }); + Ok(()) + }) + } + + /// Locks the transfer of an item within a collection. + /// + /// The origin must have the `Freezer` role within the collection to lock the transfer of the + /// item. This function disables the `Transferable` setting on the item, preventing it from + /// being transferred to other accounts. + /// + /// - `origin`: The origin of the transaction, representing the account attempting to lock the + /// item transfer. + /// - `collection`: The identifier of the collection to which the item belongs. + /// - `item`: The identifier of the item to be locked for transfer. + pub(crate) fn do_lock_item_transfer( + origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + ensure!( + Self::has_role(&collection, &origin, CollectionRole::Freezer), + Error::::NoPermission + ); + + let mut config = Self::get_item_config(&collection, &item)?; + if !config.has_disabled_setting(ItemSetting::Transferable) { + config.disable_setting(ItemSetting::Transferable); + } + ItemConfigOf::::insert(&collection, &item, config); + + Self::deposit_event(Event::::ItemTransferLocked { collection, item }); + Ok(()) + } + + /// Unlocks the transfer of an item within a collection. + /// + /// The origin must have the `Freezer` role within the collection to unlock the transfer of the + /// item. This function enables the `Transferable` setting on the item, allowing it to be + /// transferred to other accounts. + /// + /// - `origin`: The origin of the transaction, representing the account attempting to unlock the + /// item transfer. + /// - `collection`: The identifier of the collection to which the item belongs. + /// - `item`: The identifier of the item to be unlocked for transfer. + pub(crate) fn do_unlock_item_transfer( + origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + ensure!( + Self::has_role(&collection, &origin, CollectionRole::Freezer), + Error::::NoPermission + ); + + let mut config = Self::get_item_config(&collection, &item)?; + if config.has_disabled_setting(ItemSetting::Transferable) { + config.enable_setting(ItemSetting::Transferable); + } + ItemConfigOf::::insert(&collection, &item, config); + + Self::deposit_event(Event::::ItemTransferUnlocked { collection, item }); + Ok(()) + } + + /// Locks the metadata and attributes of an item within a collection. + /// + /// The origin must have the `Admin` role within the collection to lock the metadata and + /// attributes of the item. This function disables the `UnlockedMetadata` and + /// `UnlockedAttributes` settings on the item, preventing modifications to its metadata and + /// attributes. + /// + /// - `maybe_check_origin`: An optional origin representing the account attempting to lock the + /// item properties. If provided, this account must have the `Admin` role within the + /// collection. If `None`, no permission check is performed, and the function can be called + /// from any origin. + /// - `collection`: The identifier of the collection to which the item belongs. + /// - `item`: The identifier of the item to be locked for properties. + /// - `lock_metadata`: A boolean indicating whether to lock the metadata of the item. + /// - `lock_attributes`: A boolean indicating whether to lock the attributes of the item. + pub(crate) fn do_lock_item_properties( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + ItemConfigOf::::try_mutate(collection, item, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::UnknownItem)?; + + if lock_metadata { + config.disable_setting(ItemSetting::UnlockedMetadata); + } + if lock_attributes { + config.disable_setting(ItemSetting::UnlockedAttributes); + } + + Self::deposit_event(Event::::ItemPropertiesLocked { + collection, + item, + lock_metadata, + lock_attributes, + }); + Ok(()) + }) + } +} diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs new file mode 100644 index 00000000..b3d16b12 --- /dev/null +++ b/pallets/nfts/src/features/metadata.rs @@ -0,0 +1,284 @@ +// 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. + +//! This module contains helper methods to configure the metadata of collections and items. + +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. + /// + /// - `maybe_check_origin`: An optional account ID that is allowed to set the metadata. If + /// `None`, it's considered the root account. + /// - `collection`: The ID of the collection to which the item belongs. + /// - `item`: The ID of the item to set the metadata for. + /// - `data`: The metadata to set for the item. + /// - `maybe_depositor`: An optional account ID that will provide the deposit for the metadata. + /// If `None`, the collection's owner provides the deposit. + /// + /// Emits `ItemMetadataSet` event upon successful setting of the metadata. + /// Returns `Ok(())` on success, or one of the following dispatch errors: + /// - `UnknownCollection`: The specified collection does not exist. + /// - `UnknownItem`: The specified item does not exist within the collection. + /// - `LockedItemMetadata`: The metadata for the item is locked and cannot be modified. + /// - `NoPermission`: The caller does not have the required permission to set the metadata. + /// - `DepositExceeded`: The deposit amount exceeds the maximum allowed value. + pub(crate) fn do_set_item_metadata( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + maybe_depositor: Option, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + is_root || item_config.is_setting_enabled(ItemSetting::UnlockedMetadata), + Error::::LockedItemMetadata + ); + + let collection_config = Self::get_collection_config(&collection)?; + + ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { + if metadata.is_none() { + collection_details.item_metadatas.saturating_inc(); + } + + let old_deposit = metadata + .take() + .map_or(ItemMetadataDeposit { account: None, amount: Zero::zero() }, |m| m.deposit); + + let mut deposit = Zero::zero(); + if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) && !is_root + { + deposit = T::DepositPerByte::get() + .saturating_mul(((data.len()) as u32).into()) + .saturating_add(T::MetadataDepositBase::get()); + } + + let depositor = maybe_depositor.clone().unwrap_or(collection_details.owner.clone()); + let old_depositor = old_deposit.account.unwrap_or(collection_details.owner.clone()); + + if depositor != old_depositor { + T::Currency::unreserve(&old_depositor, old_deposit.amount); + T::Currency::reserve(&depositor, deposit)?; + } else if deposit > old_deposit.amount { + T::Currency::reserve(&depositor, deposit - old_deposit.amount)?; + } else if deposit < old_deposit.amount { + T::Currency::unreserve(&depositor, old_deposit.amount - deposit); + } + + if maybe_depositor.is_none() { + collection_details.owner_deposit.saturating_accrue(deposit); + collection_details.owner_deposit.saturating_reduce(old_deposit.amount); + } + + *metadata = Some(ItemMetadata { + deposit: ItemMetadataDeposit { account: maybe_depositor, amount: deposit }, + data: data.clone(), + }); + + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::ItemMetadataSet { collection, item, data }); + Ok(()) + }) + } + + /// Clears the metadata for a specific item within a collection. + /// + /// - `maybe_check_origin`: An optional account ID that is allowed to clear the metadata. If + /// `None`, it's considered the root account. + /// - `collection`: The ID of the collection to which the item belongs. + /// - `item`: The ID of the item for which to clear the metadata. + /// + /// Emits `ItemMetadataCleared` event upon successful clearing of the metadata. + /// Returns `Ok(())` on success, or one of the following dispatch errors: + /// - `UnknownCollection`: The specified collection does not exist. + /// - `MetadataNotFound`: The metadata for the specified item was not found. + /// - `LockedItemMetadata`: The metadata for the item is locked and cannot be modified. + /// - `NoPermission`: The caller does not have the required permission to clear the metadata. + pub(crate) fn do_clear_item_metadata( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); + let metadata = ItemMetadataOf::::take(collection, item) + .ok_or(Error::::MetadataNotFound)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let depositor_account = + metadata.deposit.account.unwrap_or(collection_details.owner.clone()); + + // NOTE: if the item was previously burned, the ItemConfigOf record might not exist + let is_locked = Self::get_item_config(&collection, &item) + .map_or(false, |c| c.has_disabled_setting(ItemSetting::UnlockedMetadata)); + + ensure!(is_root || !is_locked, Error::::LockedItemMetadata); + + collection_details.item_metadatas.saturating_dec(); + T::Currency::unreserve(&depositor_account, metadata.deposit.amount); + + if depositor_account == collection_details.owner { + collection_details.owner_deposit.saturating_reduce(metadata.deposit.amount); + } + + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::ItemMetadataCleared { collection, item }); + + Ok(()) + } + + /// Sets the metadata for a specific collection. + /// + /// - `maybe_check_origin`: An optional account ID that is allowed to set the collection + /// metadata. If `None`, it's considered the root account. + /// - `collection`: The ID of the collection for which to set the metadata. + /// - `data`: The metadata to set for the collection. + /// + /// Emits `CollectionMetadataSet` event upon successful setting of the metadata. + /// Returns `Ok(())` on success, or one of the following dispatch errors: + /// - `UnknownCollection`: The specified collection does not exist. + /// - `LockedCollectionMetadata`: The metadata for the collection is locked and cannot be + /// modified. + /// - `NoPermission`: The caller does not have the required permission to set the metadata. + pub(crate) fn do_set_collection_metadata( + maybe_check_origin: Option, + collection: T::CollectionId, + data: BoundedVec, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + is_root || collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), + Error::::LockedCollectionMetadata + ); + + let mut details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { + let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); + details.owner_deposit.saturating_reduce(old_deposit); + let mut deposit = Zero::zero(); + if !is_root && collection_config.is_setting_enabled(CollectionSetting::DepositRequired) + { + deposit = T::DepositPerByte::get() + .saturating_mul(((data.len()) as u32).into()) + .saturating_add(T::MetadataDepositBase::get()); + } + if deposit > old_deposit { + T::Currency::reserve(&details.owner, deposit - old_deposit)?; + } else if deposit < old_deposit { + T::Currency::unreserve(&details.owner, old_deposit - deposit); + } + details.owner_deposit.saturating_accrue(deposit); + + Collection::::insert(&collection, details); + + *metadata = Some(CollectionMetadata { deposit, data: data.clone() }); + + Self::deposit_event(Event::CollectionMetadataSet { collection, data }); + Ok(()) + }) + } + + /// Clears the metadata for a specific collection. + /// + /// - `maybe_check_origin`: An optional account ID that is allowed to clear the collection + /// metadata. If `None`, it's considered the root account. + /// - `collection`: The ID of the collection for which to clear the metadata. + /// + /// Emits `CollectionMetadataCleared` event upon successful clearing of the metadata. + /// Returns `Ok(())` on success, or one of the following dispatch errors: + /// - `UnknownCollection`: The specified collection does not exist. + /// - `MetadataNotFound`: The metadata for the collection was not found. + /// - `LockedCollectionMetadata`: The metadata for the collection is locked and cannot be + /// modified. + /// - `NoPermission`: The caller does not have the required permission to clear the metadata. + pub(crate) fn do_clear_collection_metadata( + maybe_check_origin: Option, + collection: T::CollectionId, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let mut details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + let collection_config = Self::get_collection_config(&collection)?; + + ensure!( + maybe_check_origin.is_none() || + collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), + Error::::LockedCollectionMetadata + ); + + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { + let deposit = metadata.take().ok_or(Error::::UnknownCollection)?.deposit; + T::Currency::unreserve(&details.owner, deposit); + details.owner_deposit.saturating_reduce(deposit); + Collection::::insert(&collection, details); + Self::deposit_event(Event::CollectionMetadataCleared { collection }); + Ok(()) + }) + } + + /// A helper method to construct metadata. + /// + /// # Errors + /// + /// This function returns an [`IncorrectMetadata`](crate::Error::IncorrectMetadata) dispatch + /// error if the provided metadata is too long. + pub fn construct_metadata( + metadata: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(metadata).map_err(|_| Error::::IncorrectMetadata)?) + } +} diff --git a/pallets/nfts/src/features/mod.rs b/pallets/nfts/src/features/mod.rs new file mode 100644 index 00000000..752feaf5 --- /dev/null +++ b/pallets/nfts/src/features/mod.rs @@ -0,0 +1,28 @@ +// 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. + +pub mod approvals; +pub mod atomic_swap; +pub mod attributes; +pub mod buy_sell; +pub mod create_delete_collection; +pub mod create_delete_item; +pub mod lock; +pub mod metadata; +pub mod roles; +pub mod settings; +pub mod transfer; diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs new file mode 100644 index 00000000..053eaf0b --- /dev/null +++ b/pallets/nfts/src/features/roles.rs @@ -0,0 +1,154 @@ +// 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. + +//! This module contains helper methods to configure account roles for existing collections. + +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. + /// + /// - `maybe_check_owner`: An optional account ID used to check ownership permission. If `None`, + /// it is considered as the root. + /// - `collection`: The ID of the collection for which to set the team roles. + /// - `issuer`: An optional account ID representing the issuer role. + /// - `admin`: An optional account ID representing the admin role. + /// - `freezer`: An optional account ID representing the freezer role. + /// + /// This function allows the owner or the root (when `maybe_check_owner` is `None`) to set the + /// team roles for a specific collection. The root can change the role from `None` to + /// `Some(account)`, but other roles can only be updated by the root or an account with an + /// existing role in the collection. + pub(crate) fn do_set_team( + maybe_check_owner: Option, + collection: T::CollectionId, + issuer: Option, + admin: Option, + freezer: Option, + ) -> DispatchResult { + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + let is_root = maybe_check_owner.is_none(); + if let Some(check_origin) = maybe_check_owner { + ensure!(check_origin == details.owner, Error::::NoPermission); + } + + let roles_map = [ + (issuer.clone(), CollectionRole::Issuer), + (admin.clone(), CollectionRole::Admin), + (freezer.clone(), CollectionRole::Freezer), + ]; + + // only root can change the role from `None` to `Some(account)` + if !is_root { + for (account, role) in roles_map.iter() { + if account.is_some() { + ensure!( + Self::find_account_by_role(&collection, *role).is_some(), + Error::::NoPermission + ); + } + } + } + + let roles = roles_map + .into_iter() + .filter_map(|(account, role)| account.map(|account| (account, role))) + .collect(); + + let account_to_role = Self::group_roles_by_account(roles); + + // Delete the previous records. + Self::clear_roles(&collection)?; + + // Insert new records. + for (account, roles) in account_to_role { + CollectionRoleOf::::insert(&collection, &account, roles); + } + + Self::deposit_event(Event::TeamChanged { collection, issuer, admin, freezer }); + Ok(()) + }) + } + + /// Clears all the roles in a specified collection. + /// + /// - `collection_id`: A collection to clear the roles in. + /// + /// This function clears all the roles associated with the given `collection_id`. It throws an + /// error if some of the roles were left in storage, indicating that the maximum number of roles + /// may need to be adjusted. + pub(crate) fn clear_roles(collection_id: &T::CollectionId) -> Result<(), DispatchError> { + let res = CollectionRoleOf::::clear_prefix( + &collection_id, + CollectionRoles::max_roles() as u32, + None, + ); + ensure!(res.maybe_cursor.is_none(), Error::::RolesNotCleared); + Ok(()) + } + + /// Returns true if a specified account has a provided role within that collection. + /// + /// - `collection_id`: A collection to check the role in. + /// - `account_id`: An account to check the role for. + /// - `role`: A role to validate. + /// + /// Returns `true` if the account has the specified role, `false` otherwise. + pub(crate) fn has_role( + collection_id: &T::CollectionId, + account_id: &T::AccountId, + role: CollectionRole, + ) -> bool { + CollectionRoleOf::::get(&collection_id, &account_id) + .map_or(false, |roles| roles.has_role(role)) + } + + /// Finds the account by a provided role within a collection. + /// + /// - `collection_id`: A collection to check the role in. + /// - `role`: A role to find the account for. + /// + /// Returns `Some(T::AccountId)` if the record was found, `None` otherwise. + pub(crate) fn find_account_by_role( + collection_id: &T::CollectionId, + role: CollectionRole, + ) -> Option { + CollectionRoleOf::::iter_prefix(&collection_id).into_iter().find_map( + |(account, roles)| if roles.has_role(role) { Some(account.clone()) } else { None }, + ) + } + + /// Groups provided roles by account, given one account could have multiple roles. + /// + /// - `input`: A vector of (Account, Role) tuples. + /// + /// Returns a grouped vector of `(Account, Roles)` tuples. + pub fn group_roles_by_account( + input: Vec<(T::AccountId, CollectionRole)>, + ) -> Vec<(T::AccountId, CollectionRoles)> { + let mut result = BTreeMap::new(); + for (account, role) in input.into_iter() { + result.entry(account).or_insert(CollectionRoles::none()).add_role(role); + } + result.into_iter().collect() + } +} diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs new file mode 100644 index 00000000..9c7ac7ca --- /dev/null +++ b/pallets/nfts/src/features/settings.rs @@ -0,0 +1,179 @@ +// 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. + +//! This module provides helper methods to configure collection settings for the NFTs pallet. + +use frame_support::pallet_prelude::*; + +use crate::*; + +impl, I: 'static> Pallet { + /// Forcefully change the configuration of a collection. + /// + /// - `collection`: The ID of the collection for which to update the configuration. + /// - `config`: The new collection configuration to set. + /// + /// This function allows for changing the configuration of a collection without any checks. + /// It updates the collection configuration and emits a `CollectionConfigChanged` event. + pub(crate) fn do_force_collection_config( + collection: T::CollectionId, + config: CollectionConfigFor, + ) -> DispatchResult { + ensure!(Collection::::contains_key(&collection), Error::::UnknownCollection); + CollectionConfigOf::::insert(&collection, config); + Self::deposit_event(Event::CollectionConfigChanged { collection }); + Ok(()) + } + + /// Set the maximum supply for a collection. + /// + /// - `maybe_check_owner`: An optional account ID used to check permissions. + /// - `collection`: The ID of the collection for which to set the maximum supply. + /// - `max_supply`: The new maximum supply to set for the collection. + /// + /// This function checks if the setting `UnlockedMaxSupply` is enabled in the collection + /// configuration. If it is not enabled, it returns an `Error::MaxSupplyLocked`. If + /// `maybe_check_owner` is `Some(owner)`, it checks if the caller of the function is the + /// owner of the collection. If the caller is not the owner and the `maybe_check_owner` + /// parameter is provided, it returns an `Error::NoPermission`. + /// + /// It also checks if the new maximum supply is greater than the current number of items in + /// the collection, and if not, it returns an `Error::MaxSupplyTooSmall`. If all checks pass, + /// it updates the collection configuration with the new maximum supply and emits a + /// `CollectionMaxSupplySet` event. + pub(crate) fn do_set_collection_max_supply( + maybe_check_owner: Option, + collection: T::CollectionId, + max_supply: u32, + ) -> DispatchResult { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::UnlockedMaxSupply), + Error::::MaxSupplyLocked + ); + + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &details.owner, Error::::NoPermission); + } + + ensure!(details.items <= max_supply, Error::::MaxSupplyTooSmall); + + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + config.max_supply = Some(max_supply); + Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); + Ok(()) + }) + } + + /// Update the mint settings for a collection. + /// + /// - `maybe_check_origin`: An optional account ID used to check issuer permissions. + /// - `collection`: The ID of the collection for which to update the mint settings. + /// - `mint_settings`: The new mint settings to set for the collection. + /// + /// This function updates the mint settings for a collection. If `maybe_check_origin` is + /// `Some(origin)`, it checks if the caller of the function has the `CollectionRole::Issuer` + /// for the given collection. If the caller doesn't have the required permission and + /// `maybe_check_origin` is provided, it returns an `Error::NoPermission`. If all checks + /// pass, it updates the collection configuration with the new mint settings and emits a + /// `CollectionMintSettingsUpdated` event. + pub(crate) fn do_update_mint_settings( + maybe_check_origin: Option, + collection: T::CollectionId, + mint_settings: MintSettings< + BalanceOf, + frame_system::pallet_prelude::BlockNumberFor, + T::CollectionId, + >, + ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Issuer), + Error::::NoPermission + ); + } + + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + config.mint_settings = mint_settings; + Self::deposit_event(Event::CollectionMintSettingsUpdated { collection }); + Ok(()) + }) + } + + /// Get the configuration for a specific collection. + /// + /// - `collection_id`: The ID of the collection for which to retrieve the configuration. + /// + /// This function attempts to fetch the configuration (`CollectionConfigFor`) associated + /// with the given `collection_id`. If the configuration exists, it returns `Ok(config)`, + /// otherwise, it returns a `DispatchError` with `Error::NoConfig`. + pub(crate) fn get_collection_config( + collection_id: &T::CollectionId, + ) -> Result, DispatchError> { + let config = + CollectionConfigOf::::get(&collection_id).ok_or(Error::::NoConfig)?; + Ok(config) + } + + /// Get the configuration for a specific item within a collection. + /// + /// - `collection_id`: The ID of the collection to which the item belongs. + /// - `item_id`: The ID of the item for which to retrieve the configuration. + /// + /// This function attempts to fetch the configuration (`ItemConfig`) associated with the given + /// `collection_id` and `item_id`. If the configuration exists, it returns `Ok(config)`, + /// otherwise, it returns a `DispatchError` with `Error::UnknownItem`. + pub(crate) fn get_item_config( + collection_id: &T::CollectionId, + item_id: &T::ItemId, + ) -> Result { + let config = ItemConfigOf::::get(&collection_id, &item_id) + .ok_or(Error::::UnknownItem)?; + Ok(config) + } + + /// Get the default item settings for a specific collection. + /// + /// - `collection_id`: The ID of the collection for which to retrieve the default item settings. + /// + /// This function fetches the `default_item_settings` from the collection configuration + /// associated with the given `collection_id`. If the collection configuration exists, it + /// returns `Ok(default_item_settings)`, otherwise, it returns a `DispatchError` with + /// `Error::NoConfig`. + pub(crate) fn get_default_item_settings( + collection_id: &T::CollectionId, + ) -> Result { + let collection_config = Self::get_collection_config(collection_id)?; + Ok(collection_config.mint_settings.default_item_settings) + } + + /// Check if a specified pallet feature is enabled. + /// + /// - `feature`: The feature to check. + /// + /// This function checks if the given `feature` is enabled in the runtime using the + /// pallet's `T::Features::get()` function. It returns `true` if the feature is enabled, + /// otherwise it returns `false`. + pub(crate) fn is_pallet_feature_enabled(feature: PalletFeature) -> bool { + let features = T::Features::get(); + return features.is_enabled(feature) + } +} diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs new file mode 100644 index 00000000..b7223a7c --- /dev/null +++ b/pallets/nfts/src/features/transfer.rs @@ -0,0 +1,236 @@ +// 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. + +//! This module contains helper methods to perform the transfer functionalities +//! of the NFTs pallet. + +use frame_support::pallet_prelude::*; + +use crate::*; + +impl, I: 'static> Pallet { + /// Transfer an NFT to the specified destination account. + /// + /// - `collection`: The ID of the collection to which the NFT belongs. + /// - `item`: The ID of the NFT to transfer. + /// - `dest`: The destination account to which the NFT will be transferred. + /// - `with_details`: A closure that provides access to the collection and item details, + /// allowing customization of the transfer process. + /// + /// This function performs the actual transfer of an NFT to the destination account. + /// It checks various conditions like item lock status and transferability settings + /// for the collection and item before transferring the NFT. + /// + /// # Errors + /// + /// This function returns a dispatch error in the following cases: + /// - If the collection ID is invalid ([`UnknownCollection`](crate::Error::UnknownCollection)). + /// - If the item ID is invalid ([`UnknownItem`](crate::Error::UnknownItem)). + /// - If the item is locked or transferring it is disabled + /// ([`ItemLocked`](crate::Error::ItemLocked)). + /// - If the collection or item is non-transferable + /// ([`ItemsNonTransferable`](crate::Error::ItemsNonTransferable)). + pub fn do_transfer( + collection: T::CollectionId, + item: T::ItemId, + dest: T::AccountId, + with_details: impl FnOnce( + &CollectionDetailsFor, + &mut ItemDetailsFor, + ) -> DispatchResult, + ) -> DispatchResult { + // Retrieve collection details. + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + // Ensure the item is not locked. + ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); + + // Ensure the item is not transfer disabled on the system level attribute. + ensure!( + !Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?, + Error::::ItemLocked + ); + + // Retrieve collection config and check if items are transferable. + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + // Retrieve item config and check if the item is transferable. + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + item_config.is_setting_enabled(ItemSetting::Transferable), + Error::::ItemLocked + ); + + // Retrieve the item details. + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + // Perform the transfer with custom details using the provided closure. + with_details(&collection_details, &mut details)?; + + // Update account ownership information. + Account::::remove((&details.owner, &collection, &item)); + Account::::insert((&dest, &collection, &item), ()); + let origin = details.owner; + details.owner = dest; + + // The approved accounts have to be reset to `None`, because otherwise pre-approve attack + // would be possible, where the owner can approve their second account before making the + // transaction and then claiming the item back. + details.approvals.clear(); + + // Update item details. + Item::::insert(&collection, &item, &details); + ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); + + // Emit `Transferred` event. + Self::deposit_event(Event::Transferred { + collection, + item, + from: origin, + to: details.owner, + }); + Ok(()) + } + + /// Transfer ownership of a collection to another account. + /// + /// - `origin`: The account requesting the transfer. + /// - `collection`: The ID of the collection to transfer ownership. + /// - `owner`: The new account that will become the owner of the collection. + /// + /// This function transfers the ownership of a collection to the specified account. + /// It performs checks to ensure that the `origin` is the current owner and that the + /// new owner is an acceptable account based on the collection's acceptance settings. + pub(crate) fn do_transfer_ownership( + origin: T::AccountId, + collection: T::CollectionId, + new_owner: T::AccountId, + ) -> DispatchResult { + // Check if the new owner is acceptable based on the collection's acceptance settings. + let acceptable_collection = OwnershipAcceptance::::get(&new_owner); + ensure!(acceptable_collection.as_ref() == Some(&collection), Error::::Unaccepted); + + // Try to retrieve and mutate the collection details. + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + // Check if the `origin` is the current owner of the collection. + ensure!(origin == details.owner, Error::::NoPermission); + if details.owner == new_owner { + return Ok(()) + } + + // Move the deposit to the new owner. + T::Currency::repatriate_reserved( + &details.owner, + &new_owner, + details.owner_deposit, + Reserved, + )?; + + // Update account ownership information. + CollectionAccount::::remove(&details.owner, &collection); + CollectionAccount::::insert(&new_owner, &collection, ()); + + details.owner = new_owner.clone(); + OwnershipAcceptance::::remove(&new_owner); + frame_system::Pallet::::dec_consumers(&new_owner); + + // Emit `OwnerChanged` event. + Self::deposit_event(Event::OwnerChanged { collection, new_owner }); + 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. + /// - `maybe_collection`: An optional collection ID to set the ownership acceptance. + /// + /// If `maybe_collection` is `Some(collection)`, then the account `who` will accept + /// ownership transfers for the specified collection. If `maybe_collection` is `None`, + /// then the account `who` will unset the ownership acceptance, effectively refusing + /// ownership transfers for any collection. + pub(crate) fn do_set_accept_ownership( + who: T::AccountId, + maybe_collection: Option, + ) -> DispatchResult { + let exists = OwnershipAcceptance::::contains_key(&who); + match (exists, maybe_collection.is_some()) { + (false, true) => { + frame_system::Pallet::::inc_consumers(&who)?; + }, + (true, false) => { + frame_system::Pallet::::dec_consumers(&who); + }, + _ => {}, + } + if let Some(collection) = maybe_collection.as_ref() { + OwnershipAcceptance::::insert(&who, collection); + } else { + OwnershipAcceptance::::remove(&who); + } + + // Emit `OwnershipAcceptanceChanged` event. + Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_collection }); + Ok(()) + } + + /// Forcefully change the owner of a collection. + /// + /// - `collection`: The ID of the collection to change ownership. + /// - `owner`: The new account that will become the owner of the collection. + /// + /// This function allows for changing the ownership of a collection without any checks. + /// It moves the deposit to the new owner, updates the collection's owner, and emits + /// an `OwnerChanged` event. + pub(crate) fn do_force_collection_owner( + collection: T::CollectionId, + owner: T::AccountId, + ) -> DispatchResult { + // Try to retrieve and mutate the collection details. + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + if details.owner == owner { + return Ok(()) + } + + // Move the deposit to the new owner. + T::Currency::repatriate_reserved( + &details.owner, + &owner, + details.owner_deposit, + Reserved, + )?; + + // Update collection accounts and set the new owner. + CollectionAccount::::remove(&details.owner, &collection); + CollectionAccount::::insert(&owner, &collection, ()); + details.owner = owner.clone(); + + // Emit `OwnerChanged` event. + Self::deposit_event(Event::OwnerChanged { collection, new_owner: owner }); + Ok(()) + }) + } +} diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs new file mode 100644 index 00000000..362cccd9 --- /dev/null +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -0,0 +1,509 @@ +// 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. + +//! Implementations for `nonfungibles` traits. + +use frame_support::{ + ensure, + storage::KeyPrefixIterator, + traits::{tokens::nonfungibles_v2::*, Get}, + BoundedSlice, +}; +use sp_runtime::{DispatchError, DispatchResult}; + +use super::*; + +impl, I: 'static> Inspect<::AccountId> for Pallet { + type CollectionId = T::CollectionId; + type ItemId = T::ItemId; + + fn owner( + collection: &Self::CollectionId, + item: &Self::ItemId, + ) -> Option<::AccountId> { + Item::::get(collection, item).map(|a| a.owner) + } + + fn collection_owner(collection: &Self::CollectionId) -> Option<::AccountId> { + Collection::::get(collection).map(|a| a.owner) + } + + /// Returns the attribute value of `item` of `collection` corresponding to `key`. + /// + /// When `key` is empty, we return the item metadata value. + /// + /// By default this is `None`; no attributes are defined. + fn attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> Option> { + if key.is_empty() { + // We make the empty key map to the item metadata value. + ItemMetadataOf::::get(collection, item).map(|m| m.data.into()) + } else { + let namespace = AttributeNamespace::CollectionOwner; + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) + } + } + + /// Returns the custom attribute value of `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn custom_attribute( + account: &T::AccountId, + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> Option> { + let namespace = Account::::get((account, collection, item)) + .map(|_| AttributeNamespace::ItemOwner) + .unwrap_or_else(|| AttributeNamespace::Account(account.clone())); + + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) + } + + /// Returns the system attribute value of `item` of `collection` corresponding to `key` if + /// `item` is `Some`. Otherwise, returns the system attribute value of `collection` + /// corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn system_attribute( + collection: &Self::CollectionId, + item: Option<&Self::ItemId>, + key: &[u8], + ) -> Option> { + let namespace = AttributeNamespace::Pallet; + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get((collection, item, namespace, key)).map(|a| a.0.into()) + } + + /// Returns the attribute value of `item` of `collection` corresponding to `key`. + /// + /// When `key` is empty, we return the item metadata value. + /// + /// By default this is `None`; no attributes are defined. + fn collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> Option> { + if key.is_empty() { + // We make the empty key map to the item metadata value. + CollectionMetadataOf::::get(collection).map(|m| m.data.into()) + } else { + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get(( + collection, + Option::::None, + AttributeNamespace::CollectionOwner, + key, + )) + .map(|a| a.0.into()) + } + } + + /// Returns `true` if the `item` of `collection` may be transferred. + /// + /// Default implementation is that all items are transferable. + fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool { + use PalletAttributes::TransferDisabled; + match Self::has_system_attribute(&collection, &item, TransferDisabled) { + Ok(transfer_disabled) if transfer_disabled => return false, + _ => (), + } + match ( + CollectionConfigOf::::get(collection), + ItemConfigOf::::get(collection, item), + ) { + (Some(cc), Some(ic)) + if cc.is_setting_enabled(CollectionSetting::TransferableItems) && + ic.is_setting_enabled(ItemSetting::Transferable) => + true, + _ => false, + } + } +} + +impl, I: 'static> InspectRole<::AccountId> for Pallet { + 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) + } +} + +impl, I: 'static> Create<::AccountId, CollectionConfigFor> + for Pallet +{ + /// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`. + fn create_collection( + who: &T::AccountId, + admin: &T::AccountId, + config: &CollectionConfigFor, + ) -> Result { + // DepositRequired can be disabled by calling the force_create() only + ensure!( + !config.has_disabled_setting(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + + let collection = NextCollectionId::::get() + .or(T::CollectionId::initial_value()) + .ok_or(Error::::UnknownCollection)?; + + Self::do_create_collection( + collection, + who.clone(), + admin.clone(), + *config, + T::CollectionDeposit::get(), + Event::Created { collection, creator: who.clone(), owner: admin.clone() }, + )?; + + Self::set_next_collection_id(collection); + + Ok(collection) + } + + /// Create a collection of nonfungible items with `collection` Id to be owned by `who` and + /// managed by `admin`. Should be only used for applications that do not have an + /// incremental order for the collection IDs and is a replacement for the auto id creation. + /// + /// + /// SAFETY: This function can break the pallet if it is used in combination with the auto + /// increment functionality, as it can claim a value in the ID sequence. + fn create_collection_with_id( + collection: T::CollectionId, + who: &T::AccountId, + admin: &T::AccountId, + config: &CollectionConfigFor, + ) -> Result<(), DispatchError> { + // DepositRequired can be disabled by calling the force_create() only + ensure!( + !config.has_disabled_setting(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + + Self::do_create_collection( + collection, + who.clone(), + admin.clone(), + *config, + T::CollectionDeposit::get(), + Event::Created { collection, creator: who.clone(), owner: admin.clone() }, + ) + } +} + +impl, I: 'static> Destroy<::AccountId> for Pallet { + type DestroyWitness = DestroyWitness; + + fn get_destroy_witness(collection: &Self::CollectionId) -> Option { + Collection::::get(collection).map(|a| a.destroy_witness()) + } + + fn destroy( + collection: Self::CollectionId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Self::do_destroy_collection(collection, witness, maybe_check_owner) + } +} + +impl, I: 'static> Mutate<::AccountId, ItemConfig> for Pallet { + fn mint_into( + collection: &Self::CollectionId, + item: &Self::ItemId, + who: &T::AccountId, + item_config: &ItemConfig, + deposit_collection_owner: bool, + ) -> DispatchResult { + Self::do_mint( + *collection, + *item, + match deposit_collection_owner { + true => None, + false => Some(who.clone()), + }, + who.clone(), + *item_config, + |_, _| Ok(()), + ) + } + + fn burn( + collection: &Self::CollectionId, + item: &Self::ItemId, + maybe_check_owner: Option<&T::AccountId>, + ) -> DispatchResult { + Self::do_burn(*collection, *item, |d| { + if let Some(check_owner) = maybe_check_owner { + if &d.owner != check_owner { + return Err(Error::::NoPermission.into()) + } + } + Ok(()) + }) + } + + fn set_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + Self::do_force_set_attribute( + None, + *collection, + Some(*item), + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + Self::construct_attribute_value(value.to_vec())?, + ) + } + + fn set_typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| { + value.using_encoded(|v| { + >::set_attribute(collection, item, k, v) + }) + }) + } + + fn set_collection_attribute( + collection: &Self::CollectionId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + Self::do_force_set_attribute( + None, + *collection, + None, + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + Self::construct_attribute_value(value.to_vec())?, + ) + } + + fn set_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| { + value.using_encoded(|v| { + >::set_collection_attribute( + collection, k, v, + ) + }) + }) + } + + fn set_item_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + item: &Self::ItemId, + data: &[u8], + ) -> DispatchResult { + Self::do_set_item_metadata( + who.cloned(), + *collection, + *item, + Self::construct_metadata(data.to_vec())?, + None, + ) + } + + fn set_collection_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + data: &[u8], + ) -> DispatchResult { + Self::do_set_collection_metadata( + who.cloned(), + *collection, + Self::construct_metadata(data.to_vec())?, + ) + } + + fn clear_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> DispatchResult { + Self::do_clear_attribute( + None, + *collection, + Some(*item), + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + ) + } + + fn clear_typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| { + >::clear_attribute(collection, item, k) + }) + } + + fn clear_collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> DispatchResult { + Self::do_clear_attribute( + None, + *collection, + None, + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + ) + } + + fn clear_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| { + >::clear_collection_attribute(collection, k) + }) + } + + fn clear_item_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + item: &Self::ItemId, + ) -> DispatchResult { + Self::do_clear_item_metadata(who.cloned(), *collection, *item) + } + + fn clear_collection_metadata( + who: Option<&T::AccountId>, + collection: &Self::CollectionId, + ) -> DispatchResult { + Self::do_clear_collection_metadata(who.cloned(), *collection) + } +} + +impl, I: 'static> Transfer for Pallet { + fn transfer( + collection: &Self::CollectionId, + item: &Self::ItemId, + destination: &T::AccountId, + ) -> DispatchResult { + Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(())) + } + + fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { + let transfer_disabled = + Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?; + // Can't lock the item twice + if transfer_disabled { + return Err(Error::::ItemLocked.into()) + } + + >::set_attribute( + collection, + item, + &PalletAttributes::::TransferDisabled.encode(), + &[], + ) + } + + fn enable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { + >::clear_attribute( + collection, + item, + &PalletAttributes::::TransferDisabled.encode(), + ) + } +} + +impl, I: 'static> Trading> for Pallet { + fn buy_item( + collection: &Self::CollectionId, + item: &Self::ItemId, + buyer: &T::AccountId, + bid_price: &ItemPrice, + ) -> DispatchResult { + Self::do_buy_item(*collection, *item, buyer.clone(), *bid_price) + } + + fn set_price( + collection: &Self::CollectionId, + item: &Self::ItemId, + sender: &T::AccountId, + price: Option>, + whitelisted_buyer: Option, + ) -> DispatchResult { + Self::do_set_price(*collection, *item, sender.clone(), price, whitelisted_buyer) + } + + fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option> { + ItemPriceOf::::get(collection, item).map(|a| a.0) + } +} + +impl, I: 'static> InspectEnumerable for Pallet { + type CollectionsIterator = KeyPrefixIterator<>::CollectionId>; + type ItemsIterator = KeyPrefixIterator<>::ItemId>; + type OwnedInCollectionIterator = KeyPrefixIterator<>::ItemId>; + type OwnedIterator = + KeyPrefixIterator<(>::CollectionId, >::ItemId)>; + + /// Returns an iterator of the collections in existence. + /// + /// NOTE: iterating this list invokes a storage read per item. + fn collections() -> Self::CollectionsIterator { + Collection::::iter_keys() + } + + /// Returns an iterator of the items of a `collection` in existence. + /// + /// NOTE: iterating this list invokes a storage read per item. + fn items(collection: &Self::CollectionId) -> Self::ItemsIterator { + Item::::iter_key_prefix(collection) + } + + /// Returns an iterator of the items of all collections owned by `who`. + /// + /// NOTE: iterating this list invokes a storage read per item. + fn owned(who: &T::AccountId) -> Self::OwnedIterator { + Account::::iter_key_prefix((who,)) + } + + /// Returns an iterator of the items of `collection` owned by `who`. + /// + /// NOTE: iterating this list invokes a storage read per item. + fn owned_in_collection( + collection: &Self::CollectionId, + who: &T::AccountId, + ) -> Self::OwnedInCollectionIterator { + Account::::iter_key_prefix((who, collection)) + } +} diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs new file mode 100644 index 00000000..89bfb963 --- /dev/null +++ b/pallets/nfts/src/lib.rs @@ -0,0 +1,1937 @@ +// 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. + +//! # Nfts Module +//! +//! A simple, secure module for dealing with non-fungible items. +//! +//! ## Related Modules +//! +//! * [`System`](../frame_system/index.html) +//! * [`Support`](../frame_support/index.html) + +#![recursion_limit = "256"] +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod migration; +#[cfg(test)] +pub mod mock; +#[cfg(test)] +mod tests; + +mod common_functions; +/// A library providing the feature set of this pallet. It contains modules with helper methods that +/// perform storage updates and checks required by this pallet's dispatchables. To use pallet level +/// features, make sure to set appropriate bitflags for [`Config::Features`] in your runtime +/// configuration trait. +mod features; +mod impl_nonfungibles; +mod types; + +pub mod macros; +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 types::*; +pub use weights::WeightInfo; + +/// The log target of this pallet. +pub const LOG_TARGET: &'static str = "runtime::nfts"; + +/// A type alias for the account ID type used in the dispatchable functions of this pallet. +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + +#[frame_support::pallet] +pub mod pallet { + 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); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); + + #[cfg(feature = "runtime-benchmarks")] + pub trait BenchmarkHelper { + fn collection(i: u16) -> CollectionId; + fn item(i: u16) -> ItemId; + fn signer() -> (Public, AccountId); + fn sign(signer: &Public, message: &[u8]) -> Signature; + } + #[cfg(feature = "runtime-benchmarks")] + impl + BenchmarkHelper< + CollectionId, + ItemId, + sp_runtime::MultiSigner, + sp_runtime::AccountId32, + sp_runtime::MultiSignature, + > for () + where + CollectionId: From, + ItemId: From, + { + 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) + .unwrap(), + ) + } + } + + #[pallet::config] + /// The module configuration trait. + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// Identifier for the collection of item. + /// + /// SAFETY: The functions in the `Incrementable` trait are fallible. If the functions + /// of the implementation both return `None`, the automatic CollectionId generation + /// should not be used. So the `create` and `force_create` extrinsics and the + /// `create_collection` function will return an `UnknownCollection` Error. Instead use + /// the `create_collection_with_id` function. However, if the `Incrementable` trait + /// implementation has an incremental order, the `create_collection_with_id` function + /// should not be used as it can claim a value in the ID sequence. + type CollectionId: Member + Parameter + MaxEncodedLen + Copy + Incrementable; + + /// The type used to identify a unique item within a collection. + type ItemId: Member + Parameter + MaxEncodedLen + Copy; + + /// The currency mechanism, used for paying for reserves. + type Currency: ReservableCurrency; + + /// The origin which may forcibly create or destroy an item or otherwise alter privileged + /// attributes. + type ForceOrigin: EnsureOrigin; + + /// Standard collection creation is only allowed if the origin attempting it and the + /// collection are in this set. + type CreateOrigin: EnsureOriginWithArg< + Self::RuntimeOrigin, + Self::CollectionId, + Success = Self::AccountId, + >; + + /// Locker trait to enable Locking mechanism downstream. + type Locker: Locker; + + /// The basic amount of funds that must be reserved for collection. + #[pallet::constant] + type CollectionDeposit: Get>; + + /// The basic amount of funds that must be reserved for an item. + #[pallet::constant] + type ItemDeposit: Get>; + + /// The basic amount of funds that must be reserved when adding metadata to your item. + #[pallet::constant] + type MetadataDepositBase: Get>; + + /// The basic amount of funds that must be reserved when adding an attribute to an item. + #[pallet::constant] + type AttributeDepositBase: Get>; + + /// The additional funds that must be reserved for the number of bytes store in metadata, + /// either "normal" metadata or attribute metadata. + #[pallet::constant] + type DepositPerByte: Get>; + + /// The maximum length of data stored on-chain. + #[pallet::constant] + type StringLimit: Get; + + /// The maximum length of an attribute key. + #[pallet::constant] + type KeyLimit: Get; + + /// The maximum length of an attribute value. + #[pallet::constant] + type ValueLimit: Get; + + /// The maximum approvals an item could have. + #[pallet::constant] + type ApprovalsLimit: Get; + + /// The maximum attributes approvals an item could have. + #[pallet::constant] + type ItemAttributesApprovalsLimit: Get; + + /// The max number of tips a user could send. + #[pallet::constant] + type MaxTips: Get; + + /// The max duration in blocks for deadlines. + #[pallet::constant] + type MaxDeadlineDuration: Get>; + + /// The max number of attributes a user could set per call. + #[pallet::constant] + type MaxAttributesPerCall: Get; + + /// Disables some of pallet's features. + #[pallet::constant] + type Features: Get; + + /// Off-Chain signature type. + /// + /// Can verify whether an `Self::OffchainPublic` created a signature. + type OffchainSignature: Verify + Parameter; + + /// Off-Chain public key. + /// + /// Must identify as an on-chain `Self::AccountId`. + type OffchainPublic: IdentifyAccount; + + #[cfg(feature = "runtime-benchmarks")] + /// A set of helper functions for benchmarking. + type Helper: BenchmarkHelper< + Self::CollectionId, + Self::ItemId, + Self::OffchainPublic, + Self::AccountId, + Self::OffchainSignature, + >; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + /// Details of a collection. + #[pallet::storage] + pub type Collection, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::CollectionId, + CollectionDetails>, + >; + + /// The collection, if any, of which an account is willing to take ownership. + #[pallet::storage] + pub type OwnershipAcceptance, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, T::CollectionId>; + + /// The items held by any given account; set out this way so that items owned by a single + /// account can be enumerated. + #[pallet::storage] + pub type Account, I: 'static = ()> = StorageNMap< + _, + ( + NMapKey, // owner + NMapKey, + NMapKey, + ), + (), + OptionQuery, + >; + + /// The collections owned by any given account; set out this way so that collections owned by + /// a single account can be enumerated. + #[pallet::storage] + pub type CollectionAccount, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::CollectionId, + (), + OptionQuery, + >; + + /// The items in existence and their ownership details. + #[pallet::storage] + /// Stores collection roles as per account. + pub type CollectionRoleOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + CollectionRoles, + OptionQuery, + >; + + /// The items in existence and their ownership details. + #[pallet::storage] + pub type Item, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemDetails, ApprovalsOf>, + OptionQuery, + >; + + /// Metadata of a collection. + #[pallet::storage] + pub type CollectionMetadataOf, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::CollectionId, + CollectionMetadata, T::StringLimit>, + OptionQuery, + >; + + /// Metadata of an item. + #[pallet::storage] + pub type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemMetadata, T::StringLimit>, + OptionQuery, + >; + + /// Attributes of a collection. + #[pallet::storage] + pub type Attribute, I: 'static = ()> = StorageNMap< + _, + ( + NMapKey, + NMapKey>, + NMapKey>, + NMapKey>, + ), + (BoundedVec, AttributeDepositOf), + OptionQuery, + >; + + /// A price of an item. + #[pallet::storage] + pub type ItemPriceOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + (ItemPrice, Option), + OptionQuery, + >; + + /// Item attribute approvals. + #[pallet::storage] + pub type ItemAttributesApprovalsOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemAttributesApprovals, + ValueQuery, + >; + + /// Stores the `CollectionId` that is going to be used for the next collection. + /// This gets incremented whenever a new collection is created. + #[pallet::storage] + pub type NextCollectionId, I: 'static = ()> = + StorageValue<_, T::CollectionId, OptionQuery>; + + /// Handles all the pending swaps. + #[pallet::storage] + pub type PendingSwapOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + PendingSwap< + T::CollectionId, + T::ItemId, + PriceWithDirection>, + BlockNumberFor, + >, + OptionQuery, + >; + + /// Config of a collection. + #[pallet::storage] + pub type CollectionConfigOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; + + /// Config of an item. + #[pallet::storage] + pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemConfig, + OptionQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A `collection` was created. + Created { collection: T::CollectionId, creator: T::AccountId, owner: T::AccountId }, + /// A `collection` was force-created. + ForceCreated { collection: T::CollectionId, owner: T::AccountId }, + /// A `collection` was destroyed. + Destroyed { collection: T::CollectionId }, + /// An `item` was issued. + Issued { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// An `item` was transferred. + Transferred { + collection: T::CollectionId, + item: T::ItemId, + from: T::AccountId, + to: T::AccountId, + }, + /// An `item` was destroyed. + Burned { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// An `item` became non-transferable. + ItemTransferLocked { collection: T::CollectionId, item: T::ItemId }, + /// An `item` became transferable. + ItemTransferUnlocked { collection: T::CollectionId, item: T::ItemId }, + /// `item` metadata or attributes were locked. + ItemPropertiesLocked { + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + }, + /// Some `collection` was locked. + CollectionLocked { collection: T::CollectionId }, + /// The owner changed. + OwnerChanged { collection: T::CollectionId, new_owner: T::AccountId }, + /// The management team changed. + TeamChanged { + collection: T::CollectionId, + issuer: Option, + admin: Option, + freezer: Option, + }, + /// An `item` of a `collection` has been approved by the `owner` for transfer by + /// a `delegate`. + TransferApproved { + collection: T::CollectionId, + item: T::ItemId, + owner: T::AccountId, + delegate: T::AccountId, + deadline: Option>, + }, + /// An approval for a `delegate` account to transfer the `item` of an item + /// `collection` was cancelled by its `owner`. + ApprovalCancelled { + collection: T::CollectionId, + item: T::ItemId, + owner: T::AccountId, + delegate: T::AccountId, + }, + /// All approvals of an item got cancelled. + AllApprovalsCancelled { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// A `collection` has had its config changed by the `Force` origin. + CollectionConfigChanged { collection: T::CollectionId }, + /// New metadata has been set for a `collection`. + CollectionMetadataSet { collection: T::CollectionId, data: BoundedVec }, + /// Metadata has been cleared for a `collection`. + CollectionMetadataCleared { collection: T::CollectionId }, + /// New metadata has been set for an item. + ItemMetadataSet { + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + }, + /// Metadata has been cleared for an item. + ItemMetadataCleared { collection: T::CollectionId, item: T::ItemId }, + /// The deposit for a set of `item`s within a `collection` has been updated. + Redeposited { collection: T::CollectionId, successful_items: Vec }, + /// New attribute metadata has been set for a `collection` or `item`. + AttributeSet { + collection: T::CollectionId, + maybe_item: Option, + key: BoundedVec, + value: BoundedVec, + namespace: AttributeNamespace, + }, + /// Attribute metadata has been cleared for a `collection` or `item`. + AttributeCleared { + collection: T::CollectionId, + maybe_item: Option, + key: BoundedVec, + namespace: AttributeNamespace, + }, + /// A new approval to modify item attributes was added. + ItemAttributesApprovalAdded { + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + }, + /// A new approval to modify item attributes was removed. + ItemAttributesApprovalRemoved { + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + }, + /// Ownership acceptance has changed for an account. + OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option }, + /// Max supply has been set for a collection. + CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 }, + /// Mint settings for a collection had changed. + CollectionMintSettingsUpdated { collection: T::CollectionId }, + /// Event gets emitted when the `NextCollectionId` gets incremented. + NextCollectionIdIncremented { next_id: Option }, + /// The price was set for the item. + ItemPriceSet { + collection: T::CollectionId, + item: T::ItemId, + price: ItemPrice, + whitelisted_buyer: Option, + }, + /// The price for the item was removed. + ItemPriceRemoved { collection: T::CollectionId, item: T::ItemId }, + /// An item was bought. + ItemBought { + collection: T::CollectionId, + item: T::ItemId, + price: ItemPrice, + seller: T::AccountId, + buyer: T::AccountId, + }, + /// A tip was sent. + TipSent { + collection: T::CollectionId, + item: T::ItemId, + sender: T::AccountId, + receiver: T::AccountId, + amount: DepositBalanceOf, + }, + /// An `item` swap intent was created. + SwapCreated { + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + desired_item: Option, + price: Option>>, + deadline: BlockNumberFor, + }, + /// The swap was cancelled. + SwapCancelled { + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + desired_item: Option, + price: Option>>, + deadline: BlockNumberFor, + }, + /// The swap has been claimed. + SwapClaimed { + sent_collection: T::CollectionId, + sent_item: T::ItemId, + sent_item_owner: T::AccountId, + received_collection: T::CollectionId, + received_item: T::ItemId, + received_item_owner: T::AccountId, + price: Option>>, + deadline: BlockNumberFor, + }, + /// New attributes have been set for an `item` of the `collection`. + PreSignedAttributesSet { + collection: T::CollectionId, + item: T::ItemId, + namespace: AttributeNamespace, + }, + /// A new attribute in the `Pallet` namespace was set for the `collection` or an `item` + /// within that `collection`. + PalletAttributeSet { + collection: T::CollectionId, + item: Option, + attribute: PalletAttributes, + value: BoundedVec, + }, + } + + #[pallet::error] + pub enum Error { + /// The signing account has no permission to do the operation. + NoPermission, + /// The given item ID is unknown. + UnknownCollection, + /// The item ID has already been used for an item. + AlreadyExists, + /// The approval had a deadline that expired, so the approval isn't valid anymore. + ApprovalExpired, + /// The owner turned out to be different to what was expected. + WrongOwner, + /// The witness data given does not match the current state of the chain. + BadWitness, + /// Collection ID is already taken. + CollectionIdInUse, + /// Items within that collection are non-transferable. + ItemsNonTransferable, + /// The provided account is not a delegate. + NotDelegate, + /// The delegate turned out to be different to what was expected. + WrongDelegate, + /// No approval exists that would allow the transfer. + Unapproved, + /// The named owner has not signed ownership acceptance of the collection. + Unaccepted, + /// The item is locked (non-transferable). + ItemLocked, + /// Item's attributes are locked. + LockedItemAttributes, + /// Collection's attributes are locked. + LockedCollectionAttributes, + /// Item's metadata is locked. + LockedItemMetadata, + /// Collection's metadata is locked. + LockedCollectionMetadata, + /// All items have been minted. + MaxSupplyReached, + /// The max supply is locked and can't be changed. + MaxSupplyLocked, + /// The provided max supply is less than the number of items a collection already has. + MaxSupplyTooSmall, + /// The given item ID is unknown. + UnknownItem, + /// Swap doesn't exist. + UnknownSwap, + /// The given item has no metadata set. + MetadataNotFound, + /// The provided attribute can't be found. + AttributeNotFound, + /// Item is not for sale. + NotForSale, + /// The provided bid is too low. + BidTooLow, + /// The item has reached its approval limit. + ReachedApprovalLimit, + /// The deadline has already expired. + DeadlineExpired, + /// The duration provided should be less than or equal to `MaxDeadlineDuration`. + WrongDuration, + /// The method is disabled by system settings. + MethodDisabled, + /// The provided setting can't be set. + WrongSetting, + /// Item's config already exists and should be equal to the provided one. + InconsistentItemConfig, + /// Config for a collection or an item can't be found. + NoConfig, + /// Some roles were not cleared. + RolesNotCleared, + /// Mint has not started yet. + MintNotStarted, + /// Mint has already ended. + MintEnded, + /// The provided Item was already used for claiming. + AlreadyClaimed, + /// The provided data is incorrect. + IncorrectData, + /// The extrinsic was sent by the wrong origin. + WrongOrigin, + /// The provided signature is incorrect. + WrongSignature, + /// The provided metadata might be too long. + IncorrectMetadata, + /// Can't set more attributes per one call. + MaxAttributesLimitReached, + /// The provided namespace isn't supported in this call. + WrongNamespace, + /// Can't delete non-empty collections. + CollectionNotEmpty, + /// The witness data should be provided. + WitnessRequired, + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Issue a new collection of non-fungible items from a public origin. + /// + /// This new collection has no items initially and its owner is the origin. + /// + /// The origin must be Signed and the sender must have sufficient funds free. + /// + /// `CollectionDeposit` funds of sender are reserved. + /// + /// Parameters: + /// - `admin`: The admin of this collection. The admin is the initial address of each + /// member of the collection's admin team. + /// + /// Emits `Created` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::create())] + pub fn create( + origin: OriginFor, + admin: AccountIdLookupOf, + config: CollectionConfigFor, + ) -> DispatchResult { + let collection = NextCollectionId::::get() + .or(T::CollectionId::initial_value()) + .ok_or(Error::::UnknownCollection)?; + + let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; + let admin = T::Lookup::lookup(admin)?; + + // DepositRequired can be disabled by calling the force_create() only + ensure!( + !config.has_disabled_setting(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + + Self::do_create_collection( + collection, + owner.clone(), + admin.clone(), + config, + T::CollectionDeposit::get(), + Event::Created { collection, creator: owner, owner: admin }, + )?; + + Self::set_next_collection_id(collection); + Ok(()) + } + + /// Issue a new collection of non-fungible items from a privileged origin. + /// + /// This new collection has no items initially. + /// + /// The origin must conform to `ForceOrigin`. + /// + /// Unlike `create`, no funds are reserved. + /// + /// - `owner`: The owner of this collection of items. The owner has full superuser + /// permissions over this item, but may later change and configure the permissions using + /// `transfer_ownership` and `set_team`. + /// + /// Emits `ForceCreated` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::force_create())] + pub fn force_create( + origin: OriginFor, + owner: AccountIdLookupOf, + config: CollectionConfigFor, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let owner = T::Lookup::lookup(owner)?; + + let collection = NextCollectionId::::get() + .or(T::CollectionId::initial_value()) + .ok_or(Error::::UnknownCollection)?; + + Self::do_create_collection( + collection, + owner.clone(), + owner.clone(), + config, + Zero::zero(), + Event::ForceCreated { collection, owner }, + )?; + + Self::set_next_collection_id(collection); + Ok(()) + } + + /// Destroy a collection of fungible items. + /// + /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the + /// owner of the `collection`. + /// + /// NOTE: The collection must have 0 items to be destroyed. + /// + /// - `collection`: The identifier of the collection to be destroyed. + /// - `witness`: Information on the items minted in the collection. This must be + /// correct. + /// + /// Emits `Destroyed` event when successful. + /// + /// Weight: `O(m + c + a)` where: + /// - `m = witness.item_metadatas` + /// - `c = witness.item_configs` + /// - `a = witness.attributes` + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::destroy( + witness.item_metadatas, + witness.item_configs, + witness.attributes, + ))] + pub fn destroy( + origin: OriginFor, + collection: T::CollectionId, + witness: DestroyWitness, + ) -> DispatchResultWithPostInfo { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let details = Self::do_destroy_collection(collection, witness, maybe_check_owner)?; + + Ok(Some(T::WeightInfo::destroy( + details.item_metadatas, + details.item_configs, + details.attributes, + )) + .into()) + } + + /// Mint an item of a particular collection. + /// + /// The origin must be Signed and the sender must comply with the `mint_settings` rules. + /// + /// - `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`. + /// + /// Note: the deposit will be taken from the `origin` and not the `owner` of the `item`. + /// + /// Emits `Issued` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::mint())] + pub fn mint( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + mint_to: AccountIdLookupOf, + witness_data: Option>>, + ) -> DispatchResult { + let caller = ensure_signed(origin)?; + let mint_to = T::Lookup::lookup(mint_to)?; + let item_config = + ItemConfig { settings: Self::get_default_item_settings(&collection)? }; + + Self::do_mint( + collection, + item, + Some(caller.clone()), + mint_to.clone(), + item_config, + |collection_details, collection_config| { + let mint_settings = collection_config.mint_settings; + let now = frame_system::Pallet::::block_number(); + + if let Some(start_block) = mint_settings.start_block { + ensure!(start_block <= now, Error::::MintNotStarted); + } + if let Some(end_block) = mint_settings.end_block { + ensure!(end_block >= now, Error::::MintEnded); + } + + match mint_settings.mint_type { + MintType::Issuer => { + ensure!( + Self::has_role(&collection, &caller, CollectionRole::Issuer), + Error::::NoPermission + ); + }, + MintType::HolderOf(collection_id) => { + let MintWitness { owned_item, .. } = + witness_data.clone().ok_or(Error::::WitnessRequired)?; + let owned_item = owned_item.ok_or(Error::::BadWitness)?; + + let owns_item = Account::::contains_key(( + &caller, + &collection_id, + &owned_item, + )); + ensure!(owns_item, Error::::BadWitness); + + let pallet_attribute = + PalletAttributes::::UsedToClaim(collection); + + let key = ( + &collection_id, + Some(owned_item), + AttributeNamespace::Pallet, + &Self::construct_attribute_key(pallet_attribute.encode())?, + ); + let already_claimed = Attribute::::contains_key(key.clone()); + ensure!(!already_claimed, Error::::AlreadyClaimed); + + let attribute_value = Self::construct_attribute_value(vec![])?; + Attribute::::insert( + key, + ( + attribute_value.clone(), + AttributeDeposit { account: None, amount: Zero::zero() }, + ), + ); + Self::deposit_event(Event::PalletAttributeSet { + collection: collection_id, + item: Some(owned_item), + attribute: pallet_attribute, + value: attribute_value, + }); + }, + _ => {}, + } + + if let Some(price) = mint_settings.price { + let MintWitness { mint_price, .. } = + witness_data.clone().ok_or(Error::::WitnessRequired)?; + let mint_price = mint_price.ok_or(Error::::BadWitness)?; + ensure!(mint_price >= price, Error::::BadWitness); + T::Currency::transfer( + &caller, + &collection_details.owner, + price, + ExistenceRequirement::KeepAlive, + )?; + } + + Ok(()) + }, + ) + } + + /// Mint an item of a particular collection from a privileged origin. + /// + /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the + /// Issuer of the `collection`. + /// + /// - `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. + /// - `item_config`: A config of the new item. + /// + /// Emits `Issued` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::force_mint())] + pub fn force_mint( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + mint_to: AccountIdLookupOf, + item_config: ItemConfig, + ) -> 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 mint_to = T::Lookup::lookup(mint_to)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Issuer), + Error::::NoPermission + ); + } + Self::do_mint(collection, item, None, mint_to, item_config, |_, _| Ok(())) + } + + /// Destroy a single item. + /// + /// The origin must conform to `ForceOrigin` or must be Signed and the signing account must + /// be the owner of the `item`. + /// + /// - `collection`: The collection of the item to be burned. + /// - `item`: The item to be burned. + /// + /// Emits `Burned`. + /// + /// Weight: `O(1)` + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::burn())] + pub fn burn( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + + Self::do_burn(collection, item, |details| { + if let Some(check_origin) = maybe_check_origin { + ensure!(details.owner == check_origin, Error::::NoPermission); + } + Ok(()) + }) + } + + /// Move an item from the sender account to another. + /// + /// Origin must be Signed and the signing account must be either: + /// - the Owner of the `item`; + /// - the approved delegate for the `item` (in this case, the approval is reset). + /// + /// Arguments: + /// - `collection`: The collection of the item to be transferred. + /// - `item`: The item to be transferred. + /// - `dest`: The account to receive ownership of the item. + /// + /// Emits `Transferred`. + /// + /// Weight: `O(1)` + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::transfer())] + pub fn transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + dest: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + + 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); + } + } + Ok(()) + }) + } + + /// Re-evaluate the deposits on some items. + /// + /// Origin must be Signed and the sender should be the Owner of the `collection`. + /// + /// - `collection`: The collection of the items to be reevaluated. + /// - `items`: The items of the collection whose deposits will be reevaluated. + /// + /// NOTE: This exists as a best-effort function. Any items which are unknown or + /// in the case that the owner account does not have reservable funds to pay for a + /// deposit increase are ignored. Generally the owner isn't going to call this on items + /// whose existing deposit is less than the refreshed deposit as it would only cost them, + /// so it's of little consequence. + /// + /// It will still return an error in the case that the collection is unknown or the signer + /// is not permitted to call it. + /// + /// Weight: `O(items.len())` + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::redeposit(items.len() as u32))] + pub fn redeposit( + origin: OriginFor, + collection: T::CollectionId, + items: Vec, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.owner == origin, Error::::NoPermission); + + let config = Self::get_collection_config(&collection)?; + let deposit = match config.is_setting_enabled(CollectionSetting::DepositRequired) { + true => T::ItemDeposit::get(), + false => Zero::zero(), + }; + + let mut successful = Vec::with_capacity(items.len()); + for item in items.into_iter() { + let mut details = match Item::::get(&collection, &item) { + Some(x) => x, + None => continue, + }; + let old = details.deposit.amount; + if old > deposit { + T::Currency::unreserve(&details.deposit.account, old - deposit); + } else if deposit > old { + 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 + } + } else { + continue + } + details.deposit.amount = deposit; + Item::::insert(&collection, &item, &details); + successful.push(item); + } + + Self::deposit_event(Event::::Redeposited { + collection, + successful_items: successful, + }); + + Ok(()) + } + + /// Disallow further unprivileged transfer of an item. + /// + /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// + /// - `collection`: The collection of the item to be changed. + /// - `item`: The item to become non-transferable. + /// + /// Emits `ItemTransferLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::lock_item_transfer())] + pub fn lock_item_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_lock_item_transfer(origin, collection, item) + } + + /// Re-allow unprivileged transfer of an item. + /// + /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// + /// - `collection`: The collection of the item to be changed. + /// - `item`: The item to become transferable. + /// + /// Emits `ItemTransferUnlocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(9)] + #[pallet::weight(T::WeightInfo::unlock_item_transfer())] + pub fn unlock_item_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_unlock_item_transfer(origin, collection, item) + } + + /// Disallows specified settings for the whole collection. + /// + /// Origin must be Signed and the sender should be the Owner of the `collection`. + /// + /// - `collection`: The collection to be locked. + /// - `lock_settings`: The settings to be locked. + /// + /// Note: it's possible to only lock(set) the setting, but not to unset it. + /// + /// Emits `CollectionLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(10)] + #[pallet::weight(T::WeightInfo::lock_collection())] + pub fn lock_collection( + origin: OriginFor, + collection: T::CollectionId, + lock_settings: CollectionSettings, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_lock_collection(origin, collection, lock_settings) + } + + /// Change the Owner of a collection. + /// + /// Origin must be Signed and the sender should be the Owner of the `collection`. + /// + /// - `collection`: The collection whose owner should be changed. + /// - `owner`: The new Owner of this collection. They must have called + /// `set_accept_ownership` with `collection` in order for this operation to succeed. + /// + /// Emits `OwnerChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::transfer_ownership())] + pub fn transfer_ownership( + origin: OriginFor, + collection: T::CollectionId, + new_owner: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let new_owner = T::Lookup::lookup(new_owner)?; + Self::do_transfer_ownership(origin, collection, new_owner) + } + + /// Change the Issuer, Admin and Freezer of a collection. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `collection`. + /// + /// Note: by setting the role to `None` only the `ForceOrigin` will be able to change it + /// after to `Some(account)`. + /// + /// - `collection`: The collection whose team should be changed. + /// - `issuer`: The new Issuer of this collection. + /// - `admin`: The new Admin of this collection. + /// - `freezer`: The new Freezer of this collection. + /// + /// Emits `TeamChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(12)] + #[pallet::weight(T::WeightInfo::set_team())] + pub fn set_team( + origin: OriginFor, + collection: T::CollectionId, + issuer: Option>, + admin: Option>, + freezer: Option>, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let issuer = issuer.map(T::Lookup::lookup).transpose()?; + let admin = admin.map(T::Lookup::lookup).transpose()?; + let freezer = freezer.map(T::Lookup::lookup).transpose()?; + Self::do_set_team(maybe_check_owner, collection, issuer, admin, freezer) + } + + /// Change the Owner of a collection. + /// + /// Origin must be `ForceOrigin`. + /// + /// - `collection`: The identifier of the collection. + /// - `owner`: The new Owner of this collection. + /// + /// Emits `OwnerChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(13)] + #[pallet::weight(T::WeightInfo::force_collection_owner())] + pub fn force_collection_owner( + origin: OriginFor, + collection: T::CollectionId, + owner: AccountIdLookupOf, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let new_owner = T::Lookup::lookup(owner)?; + Self::do_force_collection_owner(collection, new_owner) + } + + /// Change the config of a collection. + /// + /// Origin must be `ForceOrigin`. + /// + /// - `collection`: The identifier of the collection. + /// - `config`: The new config of this collection. + /// + /// Emits `CollectionConfigChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::force_collection_config())] + pub fn force_collection_config( + origin: OriginFor, + collection: T::CollectionId, + config: CollectionConfigFor, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + Self::do_force_collection_config(collection, config) + } + + /// 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. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::approve_transfer())] + pub fn approve_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + maybe_deadline: Option>, + ) -> 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( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) + } + + /// 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(16)] + #[pallet::weight(T::WeightInfo::cancel_approval())] + pub fn cancel_approval( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + 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) + } + + /// Cancel all the approvals of 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 approvals will be cleared. + /// - `item`: The item of the collection of whose approvals will be cleared. + /// + /// Emits `AllApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + pub fn clear_all_transfer_approvals( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) + } + + /// Disallows changing the metadata or attributes of the item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin + /// of the `collection`. + /// + /// - `collection`: The collection if the `item`. + /// - `item`: An item to be locked. + /// - `lock_metadata`: Specifies whether the metadata should be locked. + /// - `lock_attributes`: Specifies whether the attributes in the `CollectionOwner` namespace + /// should be locked. + /// + /// Note: `lock_attributes` affects the attributes in the `CollectionOwner` namespace only. + /// When the metadata or attributes are locked, it won't be possible the unlock them. + /// + /// Emits `ItemPropertiesLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(18)] + #[pallet::weight(T::WeightInfo::lock_item_properties())] + pub fn lock_item_properties( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_lock_item_properties( + maybe_check_origin, + collection, + item, + lock_metadata, + lock_attributes, + ) + } + + /// Set an attribute for a collection or item. + /// + /// Origin must be Signed and must conform to the namespace ruleset: + /// - `CollectionOwner` namespace could be modified by the `collection` Admin only; + /// - `ItemOwner` namespace could be modified by the `maybe_item` owner only. `maybe_item` + /// should be set in that case; + /// - `Account(AccountId)` namespace could be modified only when the `origin` was given a + /// permission to do so; + /// + /// The funds of `origin` are reserved according to the formula: + /// `AttributeDepositBase + DepositPerByte * (key.len + value.len)` taking into + /// account any already reserved funds. + /// + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `maybe_item`: The identifier of 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. + /// + /// Emits `AttributeSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(19)] + #[pallet::weight(T::WeightInfo::set_attribute())] + pub fn set_attribute( + origin: OriginFor, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let depositor = match namespace { + AttributeNamespace::CollectionOwner => + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?, + _ => origin.clone(), + }; + Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value, depositor) + } + + /// Force-set an attribute for a collection or item. + /// + /// Origin must be `ForceOrigin`. + /// + /// If the attribute already exists and it was set by another account, the deposit + /// will be returned to the previous owner. + /// + /// - `set_as`: An optional owner of the attribute. + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `maybe_item`: The identifier of 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. + /// + /// Emits `AttributeSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(20)] + #[pallet::weight(T::WeightInfo::force_set_attribute())] + pub fn force_set_attribute( + origin: OriginFor, + set_as: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + Self::do_force_set_attribute(set_as, collection, maybe_item, namespace, key, value) + } + + /// Clear an attribute for a collection or item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// attribute. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `maybe_item`: The identifier of the item whose metadata to clear. + /// - `namespace`: Attribute's namespace. + /// - `key`: The key of the attribute. + /// + /// Emits `AttributeCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(21)] + #[pallet::weight(T::WeightInfo::clear_attribute())] + pub fn clear_attribute( + origin: OriginFor, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_attribute(maybe_check_owner, collection, maybe_item, namespace, key) + } + + /// Approve item's attributes to be changed by a delegated third-party account. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: A collection of the item. + /// - `item`: The item that holds attributes. + /// - `delegate`: The account to delegate permission to change attributes of the item. + /// + /// Emits `ItemAttributesApprovalAdded` on success. + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::approve_item_attributes())] + pub fn approve_item_attributes( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_item_attributes(origin, collection, item, delegate) + } + + /// Cancel the previously provided approval to change item's attributes. + /// All the previously set attributes by the `delegate` will be removed. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: Collection that the item is contained within. + /// - `item`: The item that holds attributes. + /// - `delegate`: The previously approved account to remove. + /// + /// Emits `ItemAttributesApprovalRemoved` on success. + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::cancel_item_attributes_approval( + witness.account_attributes + ))] + pub fn cancel_item_attributes_approval( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_item_attributes_approval(origin, collection, item, delegate, witness) + } + + /// Set the metadata for an item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the + /// `collection`. + /// + /// If the origin is Signed, then funds of signer are reserved according to the formula: + /// `MetadataDepositBase + DepositPerByte * data.len` taking into + /// account any already reserved funds. + /// + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `item`: The identifier of the item whose metadata to set. + /// - `data`: The general information of this item. Limited in length by `StringLimit`. + /// + /// Emits `ItemMetadataSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(24)] + #[pallet::weight(T::WeightInfo::set_metadata())] + pub fn set_metadata( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_set_item_metadata(maybe_check_origin, collection, item, data, None) + } + + /// Clear the metadata for an item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the + /// `collection`. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `item`: The identifier of the item whose metadata to clear. + /// + /// Emits `ItemMetadataCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(25)] + #[pallet::weight(T::WeightInfo::clear_metadata())] + pub fn clear_metadata( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_item_metadata(maybe_check_origin, collection, item) + } + + /// Set the metadata for a collection. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of + /// the `collection`. + /// + /// If the origin is `Signed`, then funds of signer are reserved according to the formula: + /// `MetadataDepositBase + DepositPerByte * data.len` taking into + /// account any already reserved funds. + /// + /// - `collection`: The identifier of the item whose metadata to update. + /// - `data`: The general information of this item. Limited in length by `StringLimit`. + /// + /// Emits `CollectionMetadataSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(26)] + #[pallet::weight(T::WeightInfo::set_collection_metadata())] + pub fn set_collection_metadata( + origin: OriginFor, + collection: T::CollectionId, + data: BoundedVec, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_set_collection_metadata(maybe_check_origin, collection, data) + } + + /// Clear the metadata for a collection. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of + /// the `collection`. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose metadata to clear. + /// + /// Emits `CollectionMetadataCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(27)] + #[pallet::weight(T::WeightInfo::clear_collection_metadata())] + pub fn clear_collection_metadata( + origin: OriginFor, + collection: T::CollectionId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_collection_metadata(maybe_check_origin, collection) + } + + /// Set (or reset) the acceptance of ownership for a particular account. + /// + /// Origin must be `Signed` and if `maybe_collection` is `Some`, then the signer must have a + /// provider reference. + /// + /// - `maybe_collection`: The identifier of the collection whose ownership the signer is + /// willing to accept, or if `None`, an indication that the signer is willing to accept no + /// ownership transferal. + /// + /// Emits `OwnershipAcceptanceChanged`. + #[pallet::call_index(28)] + #[pallet::weight(T::WeightInfo::set_accept_ownership())] + pub fn set_accept_ownership( + origin: OriginFor, + maybe_collection: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_set_accept_ownership(who, maybe_collection) + } + + /// Set the maximum number of items a collection could have. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// the `collection`. + /// + /// - `collection`: The identifier of the collection to change. + /// - `max_supply`: The maximum number of items a collection could have. + /// + /// Emits `CollectionMaxSupplySet` event when successful. + #[pallet::call_index(29)] + #[pallet::weight(T::WeightInfo::set_collection_max_supply())] + pub fn set_collection_max_supply( + origin: OriginFor, + collection: T::CollectionId, + max_supply: u32, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_set_collection_max_supply(maybe_check_owner, collection, max_supply) + } + + /// Update mint settings. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Issuer + /// of the `collection`. + /// + /// - `collection`: The identifier of the collection to change. + /// - `mint_settings`: The new mint settings. + /// + /// Emits `CollectionMintSettingsUpdated` event when successful. + #[pallet::call_index(30)] + #[pallet::weight(T::WeightInfo::update_mint_settings())] + pub fn update_mint_settings( + origin: OriginFor, + collection: T::CollectionId, + mint_settings: MintSettings, BlockNumberFor, T::CollectionId>, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_update_mint_settings(maybe_check_origin, collection, mint_settings) + } + + /// Set (or reset) the price for an item. + /// + /// Origin must be Signed and must be the owner of the `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item to set the price for. + /// - `price`: The price for the item. Pass `None`, to reset the price. + /// - `buyer`: Restricts the buy operation to a specific account. + /// + /// Emits `ItemPriceSet` on success if the price is not `None`. + /// Emits `ItemPriceRemoved` on success if the price is `None`. + #[pallet::call_index(31)] + #[pallet::weight(T::WeightInfo::set_price())] + pub fn set_price( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + price: Option>, + whitelisted_buyer: Option>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let whitelisted_buyer = whitelisted_buyer.map(T::Lookup::lookup).transpose()?; + Self::do_set_price(collection, item, origin, price, whitelisted_buyer) + } + + /// Allows to buy an item if it's up for sale. + /// + /// Origin must be Signed and must not be the owner of the `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item the sender wants to buy. + /// - `bid_price`: The price the sender is willing to pay. + /// + /// Emits `ItemBought` on success. + #[pallet::call_index(32)] + #[pallet::weight(T::WeightInfo::buy_item())] + pub fn buy_item( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + bid_price: ItemPrice, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_buy_item(collection, item, origin, bid_price) + } + + /// Allows to pay the tips. + /// + /// Origin must be Signed. + /// + /// - `tips`: Tips array. + /// + /// Emits `TipSent` on every tip transfer. + #[pallet::call_index(33)] + #[pallet::weight(T::WeightInfo::pay_tips(tips.len() as u32))] + pub fn pay_tips( + origin: OriginFor, + tips: BoundedVec, T::MaxTips>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_pay_tips(origin, tips) + } + + /// Register a new atomic swap, declaring an intention to send an `item` in exchange for + /// `desired_item` from origin to target on the current blockchain. + /// The target can execute the swap during the specified `duration` of blocks (if set). + /// Additionally, the price could be set for the desired `item`. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item an owner wants to give. + /// - `desired_collection`: The collection of the desired item. + /// - `desired_item`: The desired item an owner wants to receive. + /// - `maybe_price`: The price an owner is willing to pay or receive for the desired `item`. + /// - `duration`: A deadline for the swap. Specified by providing the number of blocks + /// after which the swap will expire. + /// + /// Emits `SwapCreated` on success. + #[pallet::call_index(34)] + #[pallet::weight(T::WeightInfo::create_swap())] + pub fn create_swap( + origin: OriginFor, + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + maybe_desired_item: Option, + maybe_price: Option>>, + duration: BlockNumberFor, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_create_swap( + origin, + offered_collection, + offered_item, + desired_collection, + maybe_desired_item, + maybe_price, + duration, + ) + } + + /// Cancel an atomic swap. + /// + /// Origin must be Signed. + /// Origin must be an owner of the `item` if the deadline hasn't expired. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item an owner wants to give. + /// + /// Emits `SwapCancelled` on success. + #[pallet::call_index(35)] + #[pallet::weight(T::WeightInfo::cancel_swap())] + pub fn cancel_swap( + origin: OriginFor, + offered_collection: T::CollectionId, + offered_item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_cancel_swap(origin, offered_collection, offered_item) + } + + /// Claim an atomic swap. + /// This method executes a pending swap, that was created by a counterpart before. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `send_collection`: The collection of the item to be sent. + /// - `send_item`: The item to be sent. + /// - `receive_collection`: The collection of the item to be received. + /// - `receive_item`: The item to be received. + /// - `witness_price`: A price that was previously agreed on. + /// + /// Emits `SwapClaimed` on success. + #[pallet::call_index(36)] + #[pallet::weight(T::WeightInfo::claim_swap())] + pub fn claim_swap( + origin: OriginFor, + send_collection: T::CollectionId, + send_item: T::ItemId, + receive_collection: T::CollectionId, + receive_item: T::ItemId, + witness_price: Option>>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_claim_swap( + origin, + send_collection, + send_item, + receive_collection, + receive_item, + witness_price, + ) + } + + /// Mint an item by providing the pre-signed approval. + /// + /// Origin must be Signed. + /// + /// - `mint_data`: The pre-signed approval that consists of the information about the item, + /// its metadata, attributes, who can mint it (`None` for anyone) and until what block + /// number. + /// - `signature`: The signature of the `data` object. + /// - `signer`: The `data` object's signer. Should be an Issuer of the collection. + /// + /// Emits `Issued` on success. + /// Emits `AttributeSet` if the attributes were provided. + /// Emits `ItemMetadataSet` if the metadata was not empty. + #[pallet::call_index(37)] + #[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))] + pub fn mint_pre_signed( + origin: OriginFor, + mint_data: Box>, + signature: T::OffchainSignature, + signer: T::AccountId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::validate_signature(&Encode::encode(&mint_data), &signature, &signer)?; + Self::do_mint_pre_signed(origin, *mint_data, signer) + } + + /// Set attributes for an item by providing the pre-signed approval. + /// + /// Origin must be Signed and must be an owner of the `data.item`. + /// + /// - `data`: The pre-signed approval that consists of the information about the item, + /// attributes to update and until what block number. + /// - `signature`: The signature of the `data` object. + /// - `signer`: The `data` object's signer. Should be an Admin of the collection for the + /// `CollectionOwner` namespace. + /// + /// Emits `AttributeSet` for each provided attribute. + /// Emits `ItemAttributesApprovalAdded` if the approval wasn't set before. + /// Emits `PreSignedAttributesSet` on success. + #[pallet::call_index(38)] + #[pallet::weight(T::WeightInfo::set_attributes_pre_signed(data.attributes.len() as u32))] + pub fn set_attributes_pre_signed( + origin: OriginFor, + data: PreSignedAttributesOf, + signature: T::OffchainSignature, + signer: T::AccountId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; + Self::do_set_attributes_pre_signed(origin, data, signer) + } + } +} + +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); diff --git a/pallets/nfts/src/macros.rs b/pallets/nfts/src/macros.rs new file mode 100644 index 00000000..d313c878 --- /dev/null +++ b/pallets/nfts/src/macros.rs @@ -0,0 +1,66 @@ +// 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. + +/// 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 MaxEncodedLen for $wrapper { + fn max_encoded_len() -> usize { + <$size>::max_encoded_len() + } + } + impl Encode for $wrapper { + fn using_encoded R>(&self, f: F) -> R { + self.0.bits().using_encoded(f) + } + } + impl EncodeLike for $wrapper {} + impl 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")?)) + } + } + + impl TypeInfo for $wrapper { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("BitFlags", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::<$bitflag_enum>()))]) + .composite( + Fields::unnamed() + .field(|f| f.ty::<$size>().type_name(stringify!($bitflag_enum))), + ) + } + } + }; +} +pub(crate) use impl_codec_bitflags; diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs new file mode 100644 index 00000000..af611bf1 --- /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 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/mock.rs b/pallets/nfts/src/mock.rs new file mode 100644 index 00000000..5532be8f --- /dev/null +++ b/pallets/nfts/src/mock.rs @@ -0,0 +1,104 @@ +// 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. + +//! Test environment for Nfts pallet. + +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, +}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; +use sp_runtime::{ + traits::{IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, MultiSignature, +}; + +use super::*; +use crate as pallet_nfts; + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Nfts: pallet_nfts, + } +); + +pub type Signature = MultiSignature; +pub type AccountPublic = ::Signer; +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; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type AccountStore = System; +} + +parameter_types! { + pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); +} + +impl Config for Test { + type ApprovalsLimit = ConstU32<10>; + type AttributeDepositBase = ConstU64<1>; + type CollectionDeposit = ConstU64<2>; + type CollectionId = u32; + type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type DepositPerByte = ConstU64<1>; + type Features = Features; + type ForceOrigin = frame_system::EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type ItemAttributesApprovalsLimit = ConstU32<2>; + type ItemDeposit = ConstU64<1>; + type ItemId = u32; + type KeyLimit = ConstU32<50>; + type Locker = (); + type MaxAttributesPerCall = ConstU32<2>; + 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; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<50>; + type ValueLimit = ConstU32<50>; + type WeightInfo = (); +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs new file mode 100644 index 00000000..44f2f32a --- /dev/null +++ b/pallets/nfts/src/tests.rs @@ -0,0 +1,3878 @@ +// 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. + +//! Tests for Nfts pallet. + +use enumflags2::BitFlags; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, + Currency, Get, + }, +}; +use pallet_balances::Error as BalancesError; +use sp_core::{bounded::BoundedVec, Pair}; +use sp_runtime::{ + traits::{Dispatchable, IdentifyAccount}, + MultiSignature, MultiSigner, +}; + +use crate::{mock::*, Event, SystemConfig, *}; + +type AccountIdOf = ::AccountId; + +fn account(id: u8) -> AccountIdOf { + [id; 32].into() +} + +fn items() -> Vec<(AccountIdOf, u32, u32)> { + let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); + r.sort(); + let mut s: Vec<_> = Item::::iter().map(|x| (x.2.owner, x.0, x.1)).collect(); + s.sort(); + assert_eq!(r, s); + for collection in Item::::iter() + .map(|x| x.0) + .scan(None, |s, item| { + if s.map_or(false, |last| last == item) { + *s = Some(item); + Some(None) + } else { + Some(Some(item)) + } + }) + .flatten() + { + let details = Collection::::get(collection).unwrap(); + let items = Item::::iter_prefix(collection).count() as u32; + assert_eq!(details.items, items); + } + r +} + +fn collections() -> Vec<(AccountIdOf, u32)> { + let mut r: Vec<_> = CollectionAccount::::iter().map(|x| (x.0, x.1)).collect(); + r.sort(); + let mut s: Vec<_> = Collection::::iter().map(|x| (x.1.owner, x.0)).collect(); + s.sort(); + assert_eq!(r, s); + r +} + +macro_rules! bvec { + ($( $x:tt )*) => { + vec![$( $x )*].try_into().unwrap() + } +} + +fn attributes( + collection: u32, +) -> Vec<(Option, AttributeNamespace>, Vec, Vec)> { + let mut s: Vec<_> = Attribute::::iter_prefix((collection,)) + .map(|(k, v)| (k.0, k.1, k.2.into(), v.0.into())) + .collect(); + s.sort_by_key(|k: &(Option, AttributeNamespace>, Vec, Vec)| k.0); + s.sort_by_key(|k: &(Option, AttributeNamespace>, Vec, Vec)| { + k.2.clone() + }); + s +} + +fn approvals(collection_id: u32, item_id: u32) -> Vec<(AccountIdOf, Option)> { + let item = Item::::get(collection_id, item_id).unwrap(); + let s: Vec<_> = item.approvals.into_iter().collect(); + s +} + +fn item_attributes_approvals(collection_id: u32, item_id: u32) -> Vec> { + let approvals = ItemAttributesApprovalsOf::::get(collection_id, item_id); + let s: Vec<_> = approvals.into_iter().collect(); + s +} + +fn events() -> Vec> { + let result = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let mock::RuntimeEvent::Nfts(inner) = e { Some(inner) } else { None }) + .collect::>(); + + System::reset_events(); + + result +} + +fn collection_config_from_disabled_settings( + settings: BitFlags, +) -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::from_disabled(settings), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn collection_config_with_all_settings_enabled() -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn default_collection_config() -> CollectionConfigFor { + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()) +} + +fn default_item_config() -> ItemConfig { + ItemConfig { settings: ItemSettings::all_enabled() } +} + +fn item_config_from_disabled_settings(settings: BitFlags) -> ItemConfig { + ItemConfig { settings: ItemSettings::from_disabled(settings) } +} + +#[test] +fn basic_setup_works() { + new_test_ext().execute_with(|| { + assert_eq!(items(), vec![]); + }); +} + +#[test] +fn basic_minting_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(items(), vec![(account(1), 0, 42)]); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(2), + default_collection_config() + )); + 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!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); + }); +} + +#[test] +fn lifecycle_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_eq!(Balances::reserved_balance(&account(1)), 2); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0, 0] + )); + assert_eq!(Balances::reserved_balance(&account(1)), 5); + assert!(CollectionMetadataOf::::contains_key(0)); + + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(10), + default_item_config() + )); + assert_eq!(Balances::reserved_balance(&account(1)), 6); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(20), + default_item_config() + )); + assert_eq!(Balances::reserved_balance(&account(1)), 7); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); + 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); + assert_eq!(Collection::::get(0).unwrap().item_configs, 3); + + assert_eq!(Balances::reserved_balance(&account(1)), 8); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); + assert_eq!(Balances::reserved_balance(&account(1)), 8); + assert_eq!(Balances::reserved_balance(&account(2)), 0); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); + assert_eq!(Balances::reserved_balance(&account(1)), 11); + assert!(ItemMetadataOf::::contains_key(0, 42)); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); + assert_eq!(Balances::reserved_balance(&account(1)), 14); + assert!(ItemMetadataOf::::contains_key(0, 69)); + assert!(ItemConfigOf::::contains_key(0, 69)); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_eq!(w.item_metadatas, 2); + assert_eq!(w.item_configs, 3); + assert_noop!( + Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), + Error::::CollectionNotEmpty + ); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(69), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); + assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); + + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_eq!(w.attributes, 1); + assert_eq!(w.item_metadatas, 0); + assert_eq!(w.item_configs, 0); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); + assert_eq!(Balances::reserved_balance(&account(1)), 0); + + assert!(!Collection::::contains_key(0)); + assert!(!CollectionConfigOf::::contains_key(0)); + assert!(!Item::::contains_key(0, 42)); + assert!(!Item::::contains_key(0, 69)); + assert!(!CollectionMetadataOf::::contains_key(0)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 69)); + assert!(!ItemConfigOf::::contains_key(0, 69)); + assert_eq!(attributes(0), vec![]); + assert_eq!(collections(), vec![]); + assert_eq!(items(), vec![]); + }); +} + +#[test] +fn destroy_with_bad_witness_should_not_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + + let w = Collection::::get(0).unwrap().destroy_witness(); + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + DestroyWitness { item_configs: 1, ..w } + ), + Error::::BadWitness + ); + }); +} + +#[test] +fn destroy_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() + ), + Error::::CollectionNotEmpty + ); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42)); + assert_eq!(Collection::::get(0).unwrap().item_configs, 1); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); + assert!(ItemConfigOf::::contains_key(0, 42)); + assert_ok!(Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() + )); + assert!(!ItemConfigOf::::contains_key(0, 42)); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); + }); +} + +#[test] +fn mint_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_eq!(items(), vec![(account(1), 0, 42)]); + + // validate minting start and end settings + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(account(1)), + 0, + MintSettings { + start_block: Some(2), + end_block: Some(3), + mint_type: MintType::Public, + ..Default::default() + } + )); + + System::set_block_number(1); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(1), None), + Error::::MintNotStarted + ); + System::set_block_number(4); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(1), None), + Error::::MintEnded + ); + + // validate price + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(account(1)), + 0, + MintSettings { mint_type: MintType::Public, price: Some(1), ..Default::default() } + )); + Balances::make_free_balance_be(&account(2), 100); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(2), None,), + Error::::WitnessRequired + ); + assert_noop!( + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 0, + 43, + account(2), + Some(MintWitness { ..Default::default() }) + ), + Error::::BadWitness + ); + assert_noop!( + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 0, + 43, + account(2), + Some(MintWitness { mint_price: Some(0), ..Default::default() }) + ), + Error::::BadWitness + ); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(account(2)), + 0, + 43, + account(2), + Some(MintWitness { mint_price: Some(1), ..Default::default() }) + )); + assert_eq!(Balances::total_balance(&account(2)), 99); + + // validate types + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(account(1)), + 1, + MintSettings { mint_type: MintType::HolderOf(0), ..Default::default() } + )); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(3)), 1, 42, account(3), None), + Error::::WitnessRequired + ); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 42, account(2), None), + Error::::WitnessRequired + ); + assert_noop!( + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 1, + 42, + account(2), + Some(MintWitness { owned_item: Some(42), ..Default::default() }) + ), + Error::::BadWitness + ); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(account(2)), + 1, + 42, + account(2), + Some(MintWitness { owned_item: Some(43), ..Default::default() }) + )); + assert!(events().contains(&Event::::PalletAttributeSet { + collection: 0, + item: Some(43), + attribute: PalletAttributes::<::CollectionId>::UsedToClaim(1), + value: Nfts::construct_attribute_value(vec![]).unwrap(), + })); + + // can't mint twice + assert_noop!( + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 1, + 46, + account(2), + Some(MintWitness { owned_item: Some(43), ..Default::default() }) + ), + Error::::AlreadyClaimed + ); + }); +} + +#[test] +fn transfer_should_work() { + 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::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_eq!(items(), vec![(account(3), 0, 42)]); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Error::::NoPermission + ); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(3)), + 0, + 42, + account(2), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); + + // validate we can't transfer non-transferable items + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 1, + 1, + account(42), + default_item_config() + )); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(1)), collection_id, 42, account(3)), + Error::::ItemsNonTransferable + ); + }); +} + +#[test] +fn locking_transfer_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2)), + Error::::ItemLocked + ); + + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(account(1)), + 0, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2)), + Error::::ItemsNonTransferable + ); + + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + 0, + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); + }); +} + +#[test] +fn origin_guards_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + + Balances::make_free_balance_be(&account(2), 100); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(2)), + Error::::NoPermission + ); + assert_noop!( + Nfts::set_team( + RuntimeOrigin::signed(account(2)), + 0, + Some(account(2)), + Some(account(2)), + Some(account(2)), + ), + Error::::NoPermission + ); + assert_noop!( + Nfts::lock_item_transfer(RuntimeOrigin::signed(account(2)), 0, 42), + Error::::NoPermission + ); + assert_noop!( + Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(2)), 0, 42), + Error::::NoPermission + ); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 69, account(2), None), + Error::::NoPermission + ); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 43, account(2), None)); + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 43), + Error::::NoPermission + ); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_noop!( + Nfts::destroy(RuntimeOrigin::signed(account(2)), 0, w), + Error::::NoPermission + ); + }); +} + +#[test] +fn transfer_owner_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2)), + Error::::Unaccepted + ); + assert_eq!(System::consumers(&account(2)), 0); + + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); + assert_eq!(System::consumers(&account(2)), 1); + + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2))); + assert_eq!(System::consumers(&account(2)), 1); // one consumer is added due to deposit repatriation + + assert_eq!(collections(), vec![(account(2), 0)]); + assert_eq!(Balances::total_balance(&account(1)), 98); + assert_eq!(Balances::total_balance(&account(2)), 102); + assert_eq!(Balances::reserved_balance(&account(1)), 0); + assert_eq!(Balances::reserved_balance(&account(2)), 2); + + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(1)), Some(0))); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(1)), + Error::::NoPermission + ); + + // Mint and set metadata now and make sure that deposit gets transferred back. + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 20], + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(Balances::reserved_balance(&account(1)), 1); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(3)), Some(0))); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(3))); + assert_eq!(collections(), vec![(account(3), 0)]); + assert_eq!(Balances::total_balance(&account(2)), 58); + assert_eq!(Balances::total_balance(&account(3)), 144); + assert_eq!(Balances::reserved_balance(&account(2)), 0); + assert_eq!(Balances::reserved_balance(&account(3)), 44); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); + // reserved_balance of accounts 1 & 2 should be unchanged: + assert_eq!(Balances::reserved_balance(&account(1)), 1); + assert_eq!(Balances::reserved_balance(&account(2)), 0); + + // 2's acceptance from before is reset when it became an owner, so it cannot be transferred + // without a fresh acceptance. + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(account(3)), 0, account(2)), + Error::::Unaccepted + ); + }); +} + +#[test] +fn set_team_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config(), + )); + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + Some(account(4)), + )); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 42, account(2), None)); + + // admin can't transfer/burn items he doesn't own + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Error::::NoPermission + ); + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 42), + Error::::NoPermission + ); + + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + + // validate we can set any role to None + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + None, + )); + assert_noop!( + Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42), + Error::::NoPermission + ); + + // set all the roles to None + assert_ok!(Nfts::set_team(RuntimeOrigin::signed(account(1)), 0, None, None, None,)); + + // validate we can't set the roles back + assert_noop!( + Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + None, + ), + Error::::NoPermission + ); + + // only the root account can change the roles from None to Some() + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(3)), + None, + )); + }); +} + +#[test] +fn set_collection_metadata_should_work() { + new_test_ext().execute_with(|| { + // Cannot add metadata to unknown item + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 20]), + Error::::NoPermission, + ); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + // Cannot add metadata to unowned item + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(2)), 0, bvec![0u8; 20]), + Error::::NoPermission, + ); + + // Successfully add metadata and take deposit + Balances::make_free_balance_be(&account(1), 30); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 20] + )); + assert_eq!(Balances::free_balance(&account(1)), 9); + assert!(CollectionMetadataOf::::contains_key(0)); + + // Force origin works, too. + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 18])); + + // Update deposit + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 15] + )); + assert_eq!(Balances::free_balance(&account(1)), 14); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 25] + )); + assert_eq!(Balances::free_balance(&account(1)), 4); + + // Cannot over-reserve + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 40]), + BalancesError::::InsufficientBalance, + ); + + // Can't set or clear metadata once frozen + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 15] + )); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(account(1)), + 0, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMetadata.into()) + )); + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 15]), + Error::::LockedCollectionMetadata, + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0), + Error::::LockedCollectionMetadata + ); + + // Clear Metadata + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 15])); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(2)), 0), + Error::::NoPermission + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 1), + Error::::NoPermission + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0), + Error::::LockedCollectionMetadata + ); + assert_ok!(Nfts::clear_collection_metadata(RuntimeOrigin::root(), 0)); + assert!(!CollectionMetadataOf::::contains_key(0)); + }); +} + +#[test] +fn set_item_metadata_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 30); + + // Cannot add metadata to unknown item + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + // Cannot add metadata to unowned item + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(account(2)), 0, 42, bvec![0u8; 20]), + Error::::NoPermission, + ); + + // Successfully add metadata and take deposit + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); + assert_eq!(Balances::free_balance(&account(1)), 8); + assert!(ItemMetadataOf::::contains_key(0, 42)); + + // Force origin works, too. + assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 18])); + + // Update deposit + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15])); + assert_eq!(Balances::free_balance(&account(1)), 13); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 25])); + assert_eq!(Balances::free_balance(&account(1)), 3); + + // Cannot over-reserve + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 40]), + BalancesError::::InsufficientBalance, + ); + + // Can't set or clear metadata once frozen + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15])); + assert_ok!(Nfts::lock_item_properties( + RuntimeOrigin::signed(account(1)), + 0, + 42, + true, + false + )); + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15]), + Error::::LockedItemMetadata, + ); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(account(1)), 0, 42), + Error::::LockedItemMetadata, + ); + + // Clear Metadata + assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 15])); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(account(2)), 0, 42), + Error::::NoPermission, + ); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(account(1)), 1, 42), + Error::::NoPermission, + ); + assert_ok!(Nfts::clear_metadata(RuntimeOrigin::root(), 0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); + }); +} + +#[test] +fn set_collection_owner_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![1], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(1)), 10); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 9); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0; 10], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(1)), 19); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 18); + + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![1], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(1)), 16); + + assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 0)); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); + assert_eq!(attributes(0), vec![]); + assert_eq!(Balances::reserved_balance(account(1)), 0); + }); +} + +#[test] +fn set_collection_system_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + + let collection_id = 0; + let attribute_key = [0u8]; + let attribute_value = [0u8]; + + assert_ok!(, ItemConfig>>::set_collection_attribute( + &collection_id, + &attribute_key, + &attribute_value + )); + + assert_eq!(attributes(0), vec![(None, AttributeNamespace::Pallet, bvec![0], bvec![0])]); + + assert_eq!( + >>::system_attribute( + &collection_id, + None, + &attribute_key + ), + Some(attribute_value.to_vec()) + ); + + // test typed system attribute + let typed_attribute_key = [0u8; 32]; + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] + struct TypedAttributeValue(u32); + let typed_attribute_value = TypedAttributeValue(42); + + assert_ok!( + , ItemConfig>>::set_typed_collection_attribute( + &collection_id, + &typed_attribute_key, + &typed_attribute_value + ) + ); + + assert_eq!( + >>::typed_system_attribute( + &collection_id, + None, + &typed_attribute_key + ), + Some(typed_attribute_value) + ); + + // check storage + assert_eq!( + attributes(collection_id), + [ + (None, AttributeNamespace::Pallet, bvec![0], bvec![0]), + ( + None, + AttributeNamespace::Pallet, + bvec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + ], + bvec![42, 0, 0, 0] + ) + ] + ); + + assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 0)); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), collection_id, w)); + assert_eq!(attributes(collection_id), vec![]); + }) +} + +#[test] +fn set_item_owner_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + )); + + // can't set for the collection + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + None, + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + // can't set for the non-owned item + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![2], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(2)), 9); + + // validate an attribute can be updated + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0; 10], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(2)), 18); + + // validate only item's owner (or the root) can remove an attribute + assert_noop!( + Nfts::clear_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + assert_eq!(Balances::reserved_balance(account(2)), 15); + + // transfer item + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 0, account(3))); + + // validate the attribute are still here & the deposit belongs to the previous owner + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + let key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = + Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); + assert_eq!(deposit.account, Some(account(2))); + assert_eq!(deposit.amount, 12); + + // on attribute update the deposit should be returned to the previous owner + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(3)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0; 11], + )); + let (_, deposit) = + Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); + assert_eq!(deposit.account, Some(account(3))); + assert_eq!(deposit.amount, 13); + assert_eq!(Balances::reserved_balance(account(2)), 3); + assert_eq!(Balances::reserved_balance(account(3)), 13); + + // validate attributes on item deletion + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 0)); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 11]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(account(3)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + )); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![2], + )); + assert_eq!(Balances::reserved_balance(account(2)), 0); + assert_eq!(Balances::reserved_balance(account(3)), 0); + }); +} + +#[test] +fn set_external_account_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(1), + default_item_config() + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2) + )); + + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::Account(account(1)), + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::Account(account(2)), + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::Account(account(2)), + bvec![1], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::Account(account(2)), bvec![0], bvec![0]), + (Some(0), AttributeNamespace::Account(account(2)), bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(2)), 6); + + // remove permission to set attributes + assert_ok!(Nfts::cancel_item_attributes_approval( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + CancelAttributesApprovalWitness { account_attributes: 2 }, + )); + assert_eq!(attributes(0), vec![]); + assert_eq!(Balances::reserved_balance(account(2)), 0); + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::Account(account(2)), + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + }); +} + +#[test] +fn validate_deposit_required_setting() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); + + // with the disabled DepositRequired setting, only the collection's owner can set the + // attributes for free. + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(account(2)), + 0, + 0, + account(3) + )); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(2)), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(3)), + 0, + Some(0), + AttributeNamespace::Account(account(3)), + bvec![2], + bvec![0], + )); + assert_ok!(::AccountId, ItemConfig>>::set_attribute( + &0, + &0, + &[3], + &[0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::Account(account(3)), bvec![2], bvec![0]), + (Some(0), AttributeNamespace::Pallet, bvec![3], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(1)), 0); + assert_eq!(Balances::reserved_balance(account(2)), 3); + assert_eq!(Balances::reserved_balance(account(3)), 3); + + assert_ok!( + ::AccountId, ItemConfig>>::clear_attribute( + &0, + &0, + &[3], + ) + ); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::Account(account(3)), bvec![2], bvec![0]), + ] + ); + }); +} + +#[test] +fn set_attribute_should_respect_lock() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 1, account(1), None)); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(1), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(1), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(account(1)), 11); + + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![])); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(account(1)), + 0, + CollectionSettings::from_disabled(CollectionSetting::UnlockedAttributes.into()) + )); + + let e = Error::::LockedCollectionAttributes; + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + ), + e + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + + assert_ok!(Nfts::lock_item_properties( + RuntimeOrigin::signed(account(1)), + 0, + 0, + false, + true + )); + let e = Error::::LockedItemAttributes; + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + ), + e + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(1), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + }); +} + +#[test] +fn preserve_config_for_frozen_items() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 1, account(1), None)); + + // if the item is not locked/frozen then the config gets deleted on item burn + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 1)); + assert!(!ItemConfigOf::::contains_key(0, 1)); + + // lock the item and ensure the config stays unchanged + assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(account(1)), 0, 0, true, true)); + + let expect_config = item_config_from_disabled_settings( + ItemSetting::UnlockedAttributes | ItemSetting::UnlockedMetadata, + ); + let config = ItemConfigOf::::get(0, 0).unwrap(); + assert_eq!(config, expect_config); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 0)); + let config = ItemConfigOf::::get(0, 0).unwrap(); + assert_eq!(config, expect_config); + + // can't mint with the different config + assert_noop!( + Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + ), + Error::::InconsistentItemConfig + ); + + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(account(1)), + 0, + MintSettings { + default_item_settings: ItemSettings::from_disabled( + ItemSetting::UnlockedAttributes | ItemSetting::UnlockedMetadata + ), + ..Default::default() + } + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + }); +} + +#[test] +fn force_update_collection_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(2), + default_item_config(), + )); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0; 20] + )); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(1)), 65); + + // force item status to be free holding + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + 0, + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()), + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 142, account(1), None)); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 169, + account(2), + default_item_config(), + )); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 142, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 169, bvec![0; 20])); + + Balances::make_free_balance_be(&account(5), 100); + assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, account(5))); + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(5)), + Some(account(4)), + )); + assert_eq!(collections(), vec![(account(5), 0)]); + assert_eq!(Balances::reserved_balance(account(1)), 2); + assert_eq!(Balances::reserved_balance(account(5)), 63); + + assert_ok!(Nfts::redeposit( + RuntimeOrigin::signed(account(5)), + 0, + bvec![0, 42, 50, 69, 100] + )); + assert_eq!(Balances::reserved_balance(account(1)), 0); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(5)), 0, 42, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(5)), 42); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(5)), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(5)), 21); + + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(5)), + 0, + bvec![0; 20] + )); + assert_eq!(Balances::reserved_balance(account(5)), 0); + + // validate new roles + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(3)), + Some(account(4)), + )); + assert_eq!( + CollectionRoleOf::::get(0, account(2)).unwrap(), + CollectionRoles(CollectionRole::Issuer.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, account(3)).unwrap(), + CollectionRoles(CollectionRole::Admin.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, account(4)).unwrap(), + CollectionRoles(CollectionRole::Freezer.into()) + ); + + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(3)), + Some(account(2)), + Some(account(3)), + )); + + assert_eq!( + CollectionRoleOf::::get(0, account(2)).unwrap(), + CollectionRoles(CollectionRole::Admin.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, account(3)).unwrap(), + CollectionRoles(CollectionRole::Issuer | CollectionRole::Freezer) + ); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + Some(account(4)), + )); + + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42), + Error::::UnknownItem + ); + + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(5), + default_item_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(2)), + 0, + 69, + account(5), + default_item_config() + )); + 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_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); + assert_eq!(Balances::reserved_balance(account(1)), 0); + }); +} + +#[test] +fn approval_lifecycle_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, + 42, + account(3), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Error::::NoPermission + ); + assert!(Item::::get(0, 42).unwrap().approvals.is_empty()); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(4)), + 0, + 42, + account(2), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(2))); + + // ensure we can't buy an item when the collection has a NonTransferableItems flag + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(account(1)), + 1, + collection_id, + account(1), + None, + )); + + assert_noop!( + Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + collection_id, + 1, + account(2), + None + ), + Error::::ItemsNonTransferable + ); + }); +} + +#[test] +fn cancel_approval_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, + 42, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Error::::NoPermission + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), + Error::::NotDelegate + ); + + let current_block = 1; + System::set_block_number(current_block); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(2), + default_item_config() + )); + // approval expires after 2 blocks. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + Some(2) + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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_eq!(approvals(0, 69), vec![]); + }); +} + +#[test] +fn approving_multiple_accounts_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() + )); + + let current_block = 1; + System::set_block_number(current_block); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(4), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(5), + Some(2) + )); + assert_eq!( + approvals(0, 42), + vec![(account(3), None), (account(4), None), (account(5), Some(current_block + 2))] + ); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(6))); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(7)), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(5)), 0, 42, account(8)), + Error::::NoPermission + ); + }); +} + +#[test] +fn approvals_limit_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() + )); + + for i in 3..13 { + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(i), + None + )); + } + // the limit is 10 + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), + Error::::ReachedApprovalLimit + ); + }); +} + +#[test] +fn approval_deadline_works() { + new_test_ext().execute_with(|| { + System::set_block_number(0); + assert!(System::block_number().is_zero()); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()) + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + + // the approval expires after the 2nd block. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + Some(2) + )); + + System::set_block_number(3); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), + Error::::ApprovalExpired + ); + System::set_block_number(1); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); + + assert_eq!(System::block_number(), 1); + // make a new approval with a deadline after 4 blocks, so it will expire after the 5th + // block. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(4)), + 0, + 42, + account(6), + Some(4) + )); + // this should still work. + System::set_block_number(5); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(6)), 0, 42, account(5))); + }); +} + +#[test] +fn cancel_approval_works_with_admin() { + 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, + 42, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), + Error::::NotDelegate + ); + }); +} + +#[test] +fn cancel_approval_works_with_force() { + 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, + 42, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), + Error::::NotDelegate + ); + }); +} + +#[test] +fn clear_all_transfer_approvals_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, + 42, + account(3), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(4), + None + )); + + assert_noop!( + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), + Error::::NoPermission + ); + + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); + + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: 0, + item: 42, + owner: account(2), + })); + assert_eq!(approvals(0, 42), vec![]); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), + Error::::NoPermission + ); + }); +} + +#[test] +fn max_supply_should_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = account(1); + let max_supply = 1; + + // validate set_collection_max_supply + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); + assert!(!events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + max_supply + )); + assert_eq!( + CollectionConfigOf::::get(collection_id).unwrap().max_supply, + Some(max_supply) + ); + + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + max_supply + 1 + )); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMaxSupply.into()) + )); + assert_noop!( + Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + max_supply + 2 + ), + Error::::MaxSupplyLocked + ); + + // validate we can't mint more to max supply + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 0, + user_id.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 1, + user_id.clone(), + None + )); + assert_noop!( + Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 2, + user_id.clone(), + None + ), + Error::::MaxSupplyReached + ); + + // validate the event gets emitted when we set the max supply on collection create + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + CollectionConfig { max_supply: Some(max_supply), ..default_collection_config() } + )); + assert_eq!( + CollectionConfigOf::::get(collection_id).unwrap().max_supply, + Some(max_supply) + ); + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + }); +} + +#[test] +fn mint_settings_should_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = account(1); + let item_id = 0; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + user_id.clone(), + None, + )); + assert_eq!( + ItemConfigOf::::get(collection_id, item_id) + .unwrap() + .settings + .get_disabled(), + ItemSettings::all_enabled().get_disabled() + ); + + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + CollectionConfig { + mint_settings: MintSettings { + default_item_settings: ItemSettings::from_disabled( + ItemSetting::Transferable | ItemSetting::UnlockedMetadata + ), + ..Default::default() + }, + ..default_collection_config() + } + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + user_id.clone(), + None, + )); + assert_eq!( + ItemConfigOf::::get(collection_id, item_id) + .unwrap() + .settings + .get_disabled(), + ItemSettings::from_disabled(ItemSetting::Transferable | ItemSetting::UnlockedMetadata) + .get_disabled() + ); + }); +} + +#[test] +fn set_price_should_work() { + new_test_ext().execute_with(|| { + let user_id = account(1); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + user_id.clone(), + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_2, + user_id.clone(), + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + Some(1), + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_2, + Some(2), + Some(account(3)), + )); + + let item = ItemPriceOf::::get(collection_id, item_1).unwrap(); + assert_eq!(item.0, 1); + assert_eq!(item.1, None); + + let item = ItemPriceOf::::get(collection_id, item_2).unwrap(); + assert_eq!(item.0, 2); + assert_eq!(item.1, Some(account(3))); + + assert!(events().contains(&Event::::ItemPriceSet { + collection: collection_id, + item: item_1, + price: 1, + whitelisted_buyer: None, + })); + + // validate we can unset the price + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_2, + None, + None + )); + assert!(events().contains(&Event::::ItemPriceRemoved { + collection: collection_id, + item: item_2 + })); + assert!(!ItemPriceOf::::contains_key(collection_id, item_2)); + + // ensure we can't set price when the items are non-transferable + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + user_id.clone(), + None, + )); + + assert_noop!( + Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + Some(2), + None + ), + Error::::ItemsNonTransferable + ); + }); +} + +#[test] +fn buy_item_should_work() { + new_test_ext().execute_with(|| { + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let item_3 = 3; + let price_1 = 20; + let price_2 = 30; + let initial_balance = 100; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + Balances::make_free_balance_be(&user_3, initial_balance); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + user_1.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_3, + user_1.clone(), + None + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + Some(price_1), + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + Some(price_2), + Some(user_3.clone()), + )); + + // can't buy for less + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_1, 1), + Error::::BidTooLow + ); + + // pass the higher price to validate it will still deduct correctly + assert_ok!(Nfts::buy_item( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_1, + price_1 + 1, + )); + + // validate the new owner & balances + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_2.clone()); + assert_eq!(Balances::total_balance(&user_1.clone()), initial_balance + price_1); + assert_eq!(Balances::total_balance(&user_2.clone()), initial_balance - price_1); + + // can't buy from yourself + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_1.clone()), collection_id, item_2, price_2), + Error::::NoPermission + ); + + // can't buy when the item is listed for a specific buyer + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, price_2), + Error::::NoPermission + ); + + // can buy when I'm a whitelisted buyer + assert_ok!(Nfts::buy_item( + RuntimeOrigin::signed(user_3.clone()), + collection_id, + item_2, + price_2 + )); + + assert!(events().contains(&Event::::ItemBought { + collection: collection_id, + item: item_2, + price: price_2, + seller: user_1.clone(), + buyer: user_3.clone(), + })); + + // ensure we reset the buyer field + assert!(!ItemPriceOf::::contains_key(collection_id, item_2)); + + // can't buy when item is not for sale + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_3, price_2), + Error::::NotForSale + ); + + // ensure we can't buy an item when the collection or an item are frozen + { + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_3, + Some(price_1), + None, + )); + + // lock the collection + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + + let buy_item_call = mock::RuntimeCall::Nfts(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2.clone())), + Error::::ItemsNonTransferable + ); + + // unlock the collection + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + collection_id, + collection_config_with_all_settings_enabled(), + )); + + // lock the transfer + assert_ok!(Nfts::lock_item_transfer( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_3, + )); + + let buy_item_call = mock::RuntimeCall::Nfts(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::ItemLocked + ); + } + }); +} + +#[test] +fn pay_tips_should_work() { + new_test_ext().execute_with(|| { + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); + let collection_id = 0; + let item_id = 1; + let tip = 2; + let initial_balance = 100; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + Balances::make_free_balance_be(&user_3, initial_balance); + + assert_ok!(Nfts::pay_tips( + RuntimeOrigin::signed(user_1.clone()), + bvec![ + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_2.clone(), + amount: tip + }, + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_3.clone(), + amount: tip + }, + ] + )); + + assert_eq!(Balances::total_balance(&user_1), initial_balance - tip * 2); + assert_eq!(Balances::total_balance(&user_2), initial_balance + tip); + assert_eq!(Balances::total_balance(&user_3), initial_balance + tip); + + let events = events(); + assert!(events.contains(&Event::::TipSent { + collection: collection_id, + item: item_id, + sender: user_1.clone(), + receiver: user_2.clone(), + amount: tip, + })); + assert!(events.contains(&Event::::TipSent { + collection: collection_id, + item: item_id, + sender: user_1.clone(), + receiver: user_3.clone(), + amount: tip, + })); + }); +} + +#[test] +fn create_cancel_swap_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_id = account(1); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let price = 1; + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = 2; + let expect_deadline = 3; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + user_id.clone(), + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_2, + user_id.clone(), + None, + )); + + // validate desired item and the collection exists + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + collection_id, + Some(item_2 + 1), + Some(price_with_direction.clone()), + duration, + ), + Error::::UnknownItem + ); + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + collection_id + 1, + None, + Some(price_with_direction.clone()), + duration, + ), + Error::::UnknownCollection + ); + + let max_duration: u64 = ::MaxDeadlineDuration::get(); + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + max_duration.saturating_add(1), + ), + Error::::WrongDuration + ); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + + let swap = PendingSwapOf::::get(collection_id, item_1).unwrap(); + assert_eq!(swap.desired_collection, collection_id); + assert_eq!(swap.desired_item, Some(item_2)); + assert_eq!(swap.price, Some(price_with_direction.clone())); + assert_eq!(swap.deadline, expect_deadline); + + assert!(events().contains(&Event::::SwapCreated { + offered_collection: collection_id, + offered_item: item_1, + desired_collection: collection_id, + desired_item: Some(item_2), + price: Some(price_with_direction.clone()), + deadline: expect_deadline, + })); + + // validate we can cancel the swap + assert_ok!(Nfts::cancel_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1 + )); + assert!(events().contains(&Event::::SwapCancelled { + offered_collection: collection_id, + offered_item: item_1, + desired_collection: collection_id, + desired_item: Some(item_2), + price: Some(price_with_direction.clone()), + deadline: expect_deadline, + })); + assert!(!PendingSwapOf::::contains_key(collection_id, item_1)); + + // validate anyone can cancel the expired swap + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + assert_noop!( + Nfts::cancel_swap(RuntimeOrigin::signed(account(2)), collection_id, item_1), + Error::::NoPermission + ); + System::set_block_number(expect_deadline + 1); + assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(account(2)), collection_id, item_1)); + + // validate optional desired_item param + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + None, + Some(price_with_direction), + duration, + )); + + let swap = PendingSwapOf::::get(collection_id, item_1).unwrap(); + assert_eq!(swap.desired_item, None); + }); +} + +#[test] +fn claim_swap_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_1 = account(1); + let user_2 = account(2); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let item_3 = 3; + let item_4 = 4; + let item_5 = 5; + let price = 100; + let price_direction = PriceDirection::Receive; + let price_with_direction = + PriceWithDirection { amount: price, direction: price_direction.clone() }; + let duration = 2; + let initial_balance = 1000; + let deadline = 1 + duration; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + user_2.clone(), + default_item_config(), + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_3, + user_2.clone(), + default_item_config(), + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_4, + user_1.clone(), + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_5, + user_2.clone(), + default_item_config(), + )); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + + // validate the deadline + System::set_block_number(5); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate edge cases + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_4, // no swap was created for that asset + Some(price_with_direction.clone()), + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_4, // not my item + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::NoPermission + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_5, // my item, but not the one another part wants + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(PriceWithDirection { amount: price + 1, direction: price_direction.clone() }), // wrong price + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(PriceWithDirection { amount: price, direction: PriceDirection::Send }), // wrong direction + ), + Error::::UnknownSwap + ); + + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction.clone()), + )); + + // validate the new owner + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_2.clone()); + let item = Item::::get(collection_id, item_2).unwrap(); + assert_eq!(item.owner, user_1.clone()); + + // validate the balances + assert_eq!(Balances::total_balance(&user_1), initial_balance + price); + assert_eq!(Balances::total_balance(&user_2), initial_balance - price); + + // ensure we reset the swap + assert!(!PendingSwapOf::::contains_key(collection_id, item_1)); + + // validate the event + assert!(events().contains(&Event::::SwapClaimed { + sent_collection: collection_id, + sent_item: item_2, + sent_item_owner: user_2.clone(), + received_collection: collection_id, + received_item: item_1, + received_item_owner: user_1.clone(), + price: Some(price_with_direction.clone()), + deadline, + })); + + // validate the optional desired_item param and another price direction + let price_direction = PriceDirection::Send; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_4, + collection_id, + None, + Some(price_with_direction.clone()), + duration, + )); + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_1, + collection_id, + item_4, + Some(price_with_direction), + )); + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_1); + let item = Item::::get(collection_id, item_4).unwrap(); + assert_eq!(item.owner, user_2); + + assert_eq!(Balances::total_balance(&user_1), initial_balance - price); + assert_eq!(Balances::total_balance(&user_2), initial_balance + price); + }); +} + +#[test] +fn various_collection_settings() { + new_test_ext().execute_with(|| { + // when we set only one value it's required to call .into() on it + let config = + collection_config_from_disabled_settings(CollectionSetting::TransferableItems.into()); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), account(1), config)); + + let config = CollectionConfigOf::::get(0).unwrap(); + assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); + assert!(config.is_setting_enabled(CollectionSetting::UnlockedMetadata)); + + // no need to call .into() for multiple values + let config = collection_config_from_disabled_settings( + CollectionSetting::UnlockedMetadata | CollectionSetting::TransferableItems, + ); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), account(1), config)); + + let config = CollectionConfigOf::::get(1).unwrap(); + assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); + assert!(!config.is_setting_enabled(CollectionSetting::UnlockedMetadata)); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + }); +} + +#[test] +fn collection_locking_should_work() { + new_test_ext().execute_with(|| { + let user_id = account(1); + let collection_id = 0; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + collection_config_with_all_settings_enabled() + )); + + let lock_config = + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()); + assert_noop!( + Nfts::lock_collection( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + lock_config.settings, + ), + Error::::WrongSetting + ); + + // validate partial lock + let lock_config = collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::UnlockedAttributes, + ); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + lock_config.settings, + )); + + let stored_config = CollectionConfigOf::::get(collection_id).unwrap(); + assert_eq!(stored_config, lock_config); + + // validate full lock + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMetadata.into()), + )); + + let stored_config = CollectionConfigOf::::get(collection_id).unwrap(); + let full_lock_config = collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | + CollectionSetting::UnlockedMetadata | + CollectionSetting::UnlockedAttributes, + ); + assert_eq!(stored_config, full_lock_config); + }); +} + +#[test] +fn pallet_level_feature_flags_should_work() { + new_test_ext().execute_with(|| { + Features::set(&PalletFeatures::from_disabled( + PalletFeature::Trading | PalletFeature::Approvals | PalletFeature::Attributes, + )); + + let user_id = account(1); + let collection_id = 0; + let item_id = 1; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + user_id.clone(), + None, + )); + + // PalletFeature::Trading + assert_noop!( + Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + Some(1), + None + ), + Error::::MethodDisabled + ); + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_id.clone()), collection_id, item_id, 1), + Error::::MethodDisabled + ); + + // PalletFeature::Approvals + assert_noop!( + Nfts::approve_transfer( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + account(2), + None + ), + Error::::MethodDisabled + ); + + // PalletFeature::Attributes + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(user_id), + collection_id, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + ), + Error::::MethodDisabled + ); + }) +} + +#[test] +fn group_roles_by_account_should_work() { + new_test_ext().execute_with(|| { + assert_eq!(Nfts::group_roles_by_account(vec![]), vec![]); + + let account_to_role = Nfts::group_roles_by_account(vec![ + (account(3), CollectionRole::Freezer), + (account(1), CollectionRole::Issuer), + (account(2), CollectionRole::Admin), + ]); + let expect = vec![ + (account(1), CollectionRoles(CollectionRole::Issuer.into())), + (account(2), CollectionRoles(CollectionRole::Admin.into())), + (account(3), CollectionRoles(CollectionRole::Freezer.into())), + ]; + assert_eq!(account_to_role, expect); + + let account_to_role = Nfts::group_roles_by_account(vec![ + (account(3), CollectionRole::Freezer), + (account(2), CollectionRole::Issuer), + (account(2), CollectionRole::Admin), + ]); + let expect = vec![ + (account(2), CollectionRoles(CollectionRole::Issuer | CollectionRole::Admin)), + (account(3), CollectionRoles(CollectionRole::Freezer.into())), + ]; + assert_eq!(account_to_role, expect); + }) +} + +#[test] +fn add_remove_item_attributes_approval_should_work() { + new_test_ext().execute_with(|| { + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); + let user_4 = account(4); + let collection_id = 0; + let item_id = 0; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_1.clone(), + None + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_2.clone(), + )); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2.clone()]); + + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_3.clone(), + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_2.clone(), + )); + assert_eq!( + item_attributes_approvals(collection_id, item_id), + vec![user_2.clone(), user_3.clone()] + ); + + assert_noop!( + Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_4, + ), + Error::::ReachedApprovalLimit + ); + + assert_ok!(Nfts::cancel_item_attributes_approval( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_2, + CancelAttributesApprovalWitness { account_attributes: 1 }, + )); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_3]); + }) +} + +#[test] +fn validate_signature() { + new_test_ext().execute_with(|| { + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: None, + deadline: 100000, + mint_price: None, + }; + let encoded_data = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&encoded_data)); + assert_ok!(Nfts::validate_signature(&encoded_data, &signature, &user_1)); + + let mut wrapped_data: Vec = Vec::new(); + wrapped_data.extend(b""); + wrapped_data.extend(&encoded_data); + wrapped_data.extend(b""); + + let signature = MultiSignature::Sr25519(user_1_pair.sign(&wrapped_data)); + assert_ok!(Nfts::validate_signature(&encoded_data, &signature, &user_1)); + }) +} + +#[test] +fn pre_signed_mints_should_work() { + new_test_ext().execute_with(|| { + let user_0 = account(0); + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + metadata: vec![0, 1], + only_account: None, + deadline: 10000000, + mint_price: Some(10), + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + let user_2 = account(2); + let user_3 = account(3); + + Balances::make_free_balance_be(&user_0, 100); + Balances::make_free_balance_be(&user_2, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(user_0.clone()), + user_1.clone(), + collection_config_with_all_settings_enabled(), + )); + + assert_ok!(Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + )); + assert_eq!(items(), vec![(user_2.clone(), 0, 0)]); + let metadata = ItemMetadataOf::::get(0, 0).unwrap(); + assert_eq!( + metadata.deposit, + ItemMetadataDeposit { account: Some(user_2.clone()), amount: 3 } + ); + assert_eq!(metadata.data, vec![0, 1]); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_0), 100 - 2 + 10); // 2 - collection deposit, 10 - mint price + assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6 - 10); // 1 - item deposit, 3 - metadata, 6 - attributes, 10 - mint price + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + Box::new(mint_data), + signature.clone(), + user_1.clone(), + ), + Error::::AlreadyExists + ); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(user_2.clone()), 0, 0)); + assert_eq!(Balances::free_balance(&user_2), 100 - 6 - 10); + + // validate the `only_account` field + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: Some(account(2)), + deadline: 10000000, + mint_price: None, + }; + + // can't mint with the wrong signature + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + ), + Error::::WrongSignature + ); + + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_3), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + ), + Error::::WrongOrigin + ); + + // validate signature's expiration + System::set_block_number(10000001); + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + Box::new(mint_data), + signature, + user_1.clone(), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate the collection + let mint_data = PreSignedMint { + collection: 1, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: Some(account(2)), + deadline: 10000000, + mint_price: None, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + Box::new(mint_data), + signature, + user_1.clone(), + ), + Error::::NoPermission + ); + + // validate max attributes limit + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3]), (vec![2], vec![3])], + metadata: vec![0, 1], + only_account: None, + deadline: 10000000, + mint_price: None, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2), + Box::new(mint_data), + signature, + user_1.clone(), + ), + Error::::MaxAttributesLimitReached + ); + }) +} + +#[test] +fn pre_signed_attributes_should_work() { + new_test_ext().execute_with(|| { + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let user_2 = account(2); + let user_3_pair = sp_core::sr25519::Pair::from_string("//Bob", None).unwrap(); + let user_3_signer = MultiSigner::Sr25519(user_3_pair.public()); + let user_3 = user_3_signer.clone().into_account(); + let collection_id = 0; + let item_id = 0; + + Balances::make_free_balance_be(&user_1, 100); + Balances::make_free_balance_be(&user_2, 100); + Balances::make_free_balance_be(&user_3, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(user_1.clone()), + user_1.clone(), + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_2.clone(), + None, + )); + + // validate the CollectionOwner namespace + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_ok!(Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + )); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_1), 100 - 2 - 1); // 2 - collection deposit, 1 - item deposit + assert_eq!(Balances::free_balance(&user_2), 100 - 6); // 6 - attributes + + // validate the deposit gets returned on attribute update from collection's owner + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + Some(item_id), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, None); + assert_eq!(deposit.amount, 3); + + // validate we don't partially modify the state + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![]); + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2; 51], vec![3])], + namespace: AttributeNamespace::Account(user_3.clone()), + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::IncorrectData + ); + + // no new approval was set + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![]); + + // no new attributes were added + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + + // validate the Account namespace + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::Account(user_3.clone()), + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_ok!(Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + )); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::Account(user_3.clone()), bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + (Some(0), AttributeNamespace::Account(user_3.clone()), bvec![2], bvec![3]), + ] + ); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_3.clone()]); + + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::Account(user_3.clone()), + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_2), 100 - 9); + assert_eq!(Balances::free_balance(&user_3), 100); + + // validate the deposit gets returned on attribute update from user_3 + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(user_3.clone()), + collection_id, + Some(item_id), + AttributeNamespace::Account(user_3.clone()), + bvec![0], + bvec![1], + )); + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::Account(user_3.clone()), + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_3.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_2), 100 - 6); + assert_eq!(Balances::free_balance(&user_3), 100 - 3); + + // can't update with the wrong signature + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::WrongSignature + ); + + // can't update if I don't own that item + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_3.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::NoPermission + ); + + // can't update the CollectionOwner namespace if the signer is not an owner of that + // collection + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::NoPermission + ); + + // validate signature's expiration + System::set_block_number(10000001); + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate item & collection + let pre_signed_data = PreSignedAttributes { + collection: 1, + item: 1, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::UnknownItem + ); + + // validate max attributes limit + let pre_signed_data = PreSignedAttributes { + collection: 1, + item: 1, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::MaxAttributesLimitReached + ); + + // validate the attribute's value length + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3; 51])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::IncorrectData + ); + }) +} + +#[test] +fn basic_create_collection_with_id_should_work() { + new_test_ext().execute_with(|| { + assert_noop!( + Nfts::create_collection_with_id( + 0u32, + &account(1), + &account(1), + &default_collection_config(), + ), + Error::::WrongSetting + ); + + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + + assert_ok!(Nfts::create_collection_with_id( + 0u32, + &account(1), + &account(1), + &collection_config_with_all_settings_enabled(), + )); + + assert_eq!(collections(), vec![(account(1), 0)]); + + // CollectionId already taken. + assert_noop!( + Nfts::create_collection_with_id( + 0u32, + &account(2), + &account(2), + &collection_config_with_all_settings_enabled(), + ), + Error::::CollectionIdInUse + ); + }); +} + +#[test] +fn clear_collection_metadata_works() { + new_test_ext().execute_with(|| { + // Start with an account with 100 tokens, 10 of which are reserved + Balances::make_free_balance_be(&account(1), 100); + Balances::reserve(&account(1), 10).unwrap(); + + // Creating a collection increases owner deposit by 2 + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 2); + assert_eq!(Balances::reserved_balance(&account(1)), 12); + + // Setting collection metadata increases owner deposit by 10 + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0, 0, 0, 0, 0, 0, 0, 0, 0], + )); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 12); + assert_eq!(Balances::reserved_balance(&account(1)), 22); + + // Clearing collection metadata decreases owner deposit by 10 + assert_ok!(Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0)); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 2); + assert_eq!(Balances::reserved_balance(&account(1)), 12); + + // Destroying the collection removes it from storage + assert_ok!(Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 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 new file mode 100644 index 00000000..f08f1d09 --- /dev/null +++ b/pallets/nfts/src/types.rs @@ -0,0 +1,568 @@ +// 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. + +//! This module contains various basic types and data structures used in the NFTs pallet. + +use alloc::{vec, vec::Vec}; + +use codec::EncodeLike; +use enumflags2::{bitflags, BitFlags}; +use frame_support::{ + pallet_prelude::{BoundedVec, MaxEncodedLen}, + traits::Get, + BoundedBTreeMap, BoundedBTreeSet, +}; +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; +/// A type alias representing the details of a collection. +pub(super) type CollectionDetailsFor = + CollectionDetails<::AccountId, DepositBalanceOf>; +/// A type alias for keeping track of approvals used by a single item. +pub(super) type ApprovalsOf = BoundedBTreeMap< + ::AccountId, + Option>, + >::ApprovalsLimit, +>; +/// A type alias for keeping track of approvals for an item's attributes. +pub(super) type ItemAttributesApprovals = + BoundedBTreeSet<::AccountId, >::ItemAttributesApprovalsLimit>; +/// A type that holds the deposit for a single item. +pub(super) type ItemDepositOf = + ItemDeposit, ::AccountId>; +/// A type that holds the deposit amount for an item's attribute. +pub(super) type AttributeDepositOf = + AttributeDeposit, ::AccountId>; +/// A type that holds the deposit amount for an item's metadata. +pub(super) type ItemMetadataDepositOf = + ItemMetadataDeposit, ::AccountId>; +/// A type that holds the details of a single item. +pub(super) type ItemDetailsFor = + ItemDetails<::AccountId, ItemDepositOf, ApprovalsOf>; +/// A type alias for an accounts balance. +pub(super) type BalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +/// A type alias to represent the price of an item. +pub(super) type ItemPrice = BalanceOf; +/// A type alias for the tips held by a single item. +pub(super) type ItemTipOf = ItemTip< + >::CollectionId, + >::ItemId, + ::AccountId, + BalanceOf, +>; +/// A type alias for the settings configuration of a collection. +pub(super) type CollectionConfigFor = + CollectionConfig, BlockNumberFor, >::CollectionId>; +/// A type alias for the pre-signed minting configuration for a specified collection. +pub(super) type PreSignedMintOf = PreSignedMint< + >::CollectionId, + >::ItemId, + ::AccountId, + BlockNumberFor, + BalanceOf, +>; +/// A type alias for the pre-signed minting configuration on the attribute level of an item. +pub(super) type PreSignedAttributesOf = PreSignedAttributes< + >::CollectionId, + >::ItemId, + ::AccountId, + BlockNumberFor, +>; + +/// Information about a collection. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectionDetails { + /// Collection's owner. + pub(super) 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, + /// The total number of outstanding items of this collection. + pub(super) items: u32, + /// The total number of outstanding item metadata of this collection. + pub(super) item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + pub(super) item_configs: u32, + /// The total number of attributes for this collection. + pub(super) attributes: u32, +} + +/// Witness data for the destroy transactions. +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +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, +} + +impl CollectionDetails { + pub fn destroy_witness(&self) -> DestroyWitness { + DestroyWitness { + item_metadatas: self.item_metadatas, + item_configs: self.item_configs, + attributes: self.attributes, + } + } +} + +/// Witness data for items mint transactions. +#[derive(Clone, Encode, Decode, Default, Eq, PartialEq, RuntimeDebug, 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, +} + +/// Information concerning the ownership of a single unique item. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +pub struct ItemDetails { + /// The owner of this item. + pub(super) owner: AccountId, + /// The approved transferrer of this item, if one is set. + 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(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(super) account: AccountId, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + +/// Information about the collection's metadata. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(StringLimit))] +#[codec(mel_bound(Deposit: MaxEncodedLen))] +pub struct CollectionMetadata> { + /// The balance deposited for this metadata. + /// + /// This pays for the data stored in this struct. + pub(super) deposit: Deposit, + /// General information concerning this collection. Limited in length by `StringLimit`. This + /// will generally be either a JSON dump or the hash of some JSON which can be found on a + /// hash-addressable global publication system such as IPFS. + pub(super) data: BoundedVec, +} + +/// Information about the item's metadata. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(StringLimit))] +pub struct ItemMetadata> { + /// The balance deposited for this metadata. + /// + /// This pays for the data stored in this struct. + pub(super) deposit: Deposit, + /// General information concerning this item. Limited in length by `StringLimit`. This will + /// generally be either a JSON dump or the hash of some JSON which can be found on a + /// hash-addressable global publication system such as IPFS. + pub(super) data: BoundedVec, +} + +/// Information about the tip. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemTip { + /// The collection of the item. + pub(super) collection: CollectionId, + /// An item of which the tip is sent for. + pub(super) item: ItemId, + /// A sender of the tip. + pub(super) receiver: AccountId, + /// An amount the sender is willing to tip. + pub(super) amount: Amount, +} + +/// Information about the pending swap. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +pub struct PendingSwap { + /// The collection that contains the item that the user wants to receive. + pub(super) desired_collection: CollectionId, + /// The item the user wants to receive. + pub(super) desired_item: Option, + /// A price for the desired `item` with the direction. + pub(super) price: Option, + /// A deadline for the swap. + pub(super) deadline: Deadline, +} + +/// Information about the reserved attribute deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct AttributeDeposit { + /// A depositor account. + pub(super) account: Option, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + +/// Information about the reserved item's metadata deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemMetadataDeposit { + /// A depositor account, None means the deposit is collection's owner. + pub(super) account: Option, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + +/// Specifies whether the tokens will be sent or received. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum PriceDirection { + /// Tokens will be sent. + Send, + /// Tokens will be received. + Receive, +} + +/// Holds the details about the price. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct PriceWithDirection { + /// An amount. + pub(super) amount: Amount, + /// A direction (send or receive). + pub(super) direction: PriceDirection, +} + +/// Support for up to 64 user-enabled features on a collection. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, 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, PartialEq, Eq, Default, RuntimeDebug)] +pub struct CollectionSettings(pub BitFlags); + +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) + } +} + +impl_codec_bitflags!(CollectionSettings, u64, CollectionSetting); + +/// Mint type. Can the NFT be create by anyone, or only the creator of the collection, +/// or only by wallets that already hold an NFT from a certain collection? +/// The ownership of a privately minted NFT is still publicly visible. +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +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), +} + +/// Holds the information about minting. +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +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, +} + +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(), + } + } +} + +/// Attribute namespaces for non-fungible tokens. +#[derive( + Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] +pub enum AttributeNamespace { + /// An attribute was set by the pallet. + Pallet, + /// An attribute was set by collection's owner. + CollectionOwner, + /// An attribute was set by item's owner. + ItemOwner, + /// An attribute was set by pre-approved account. + Account(AccountId), +} + +/// A witness data to cancel attributes approval operation. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct CancelAttributesApprovalWitness { + /// An amount of attributes previously created by account. + pub account_attributes: u32, +} + +/// A list of possible pallet-level attributes. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum PalletAttributes { + /// Marks an item as being used in order to claim another item. + UsedToClaim(CollectionId), + /// Marks an item as being restricted from transferring. + TransferDisabled, +} + +/// Collection's configuration. +#[derive( + Clone, Copy, Decode, Default, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, 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, +} + +impl CollectionConfig { + pub fn is_setting_enabled(&self, setting: CollectionSetting) -> 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); + } +} + +/// Support for up to 64 user-enabled features on an item. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, 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, PartialEq, Eq, Default, RuntimeDebug)] +pub struct ItemSettings(pub BitFlags); + +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) + } +} + +impl_codec_bitflags!(ItemSettings, u64, ItemSetting); + +/// Item's configuration. +#[derive( + Encode, Decode, Default, PartialEq, RuntimeDebug, Clone, Copy, MaxEncodedLen, TypeInfo, +)] +pub struct ItemConfig { + /// Item's settings. + pub settings: ItemSettings, +} + +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); + } +} + +/// Support for up to 64 system-enabled features on a collection. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum PalletFeature { + /// Enable/disable trading operations. + Trading, + /// Allow/disallow setting attributes. + Attributes, + /// Allow/disallow transfer approvals. + Approvals, + /// Allow/disallow atomic items swap. + Swaps, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Default, RuntimeDebug)] +pub struct PalletFeatures(pub BitFlags); + +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) + } +} +impl_codec_bitflags!(PalletFeatures, u64, PalletFeature); + +/// Support for up to 8 different roles for collections. +#[bitflags] +#[repr(u8)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum CollectionRole { + /// Can mint items. + Issuer, + /// Can freeze items. + Freezer, + /// Can thaw items, force transfers and burn items from any account. + Admin, +} + +/// A wrapper type that implements `Codec`. +#[derive(Clone, Copy, PartialEq, Eq, Default, RuntimeDebug)] +pub struct CollectionRoles(pub BitFlags); + +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 + } +} +impl_codec_bitflags!(CollectionRoles, u8, CollectionRole); + +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PreSignedMint { + /// A collection of the item to be minted. + pub(super) collection: CollectionId, + /// Item's ID. + pub(super) item: ItemId, + /// Additional item's key-value attributes. + pub(super) attributes: Vec<(Vec, Vec)>, + /// Additional item's metadata. + pub(super) metadata: Vec, + /// Restrict the claim to a particular account. + pub(super) only_account: Option, + /// A deadline for the signature. + pub(super) deadline: Deadline, + /// An optional price the claimer would need to pay for the mint. + pub(super) mint_price: Option, +} + +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PreSignedAttributes { + /// Collection's ID. + pub(super) collection: CollectionId, + /// Item's ID. + pub(super) item: ItemId, + /// Key-value attributes. + pub(super) attributes: Vec<(Vec, Vec)>, + /// Attributes' namespace. + pub(super) namespace: AttributeNamespace, + /// A deadline for the signature. + pub(super) deadline: Deadline, +} diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs new file mode 100644 index 00000000..c5fb60a2 --- /dev/null +++ b/pallets/nfts/src/weights.rs @@ -0,0 +1,1468 @@ +// 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/production/substrate-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_nfts +// --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 + +#![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 `pallet_nfts`. +pub trait WeightInfo { + fn create() -> Weight; + fn force_create() -> Weight; + fn destroy(m: u32, c: u32, a: u32, ) -> Weight; + fn mint() -> Weight; + fn force_mint() -> Weight; + fn burn() -> Weight; + fn transfer() -> Weight; + fn redeposit(i: u32, ) -> Weight; + fn lock_item_transfer() -> Weight; + fn unlock_item_transfer() -> Weight; + fn lock_collection() -> Weight; + fn transfer_ownership() -> Weight; + fn set_team() -> Weight; + fn force_collection_owner() -> Weight; + fn force_collection_config() -> Weight; + fn lock_item_properties() -> Weight; + fn set_attribute() -> Weight; + fn force_set_attribute() -> Weight; + fn clear_attribute() -> Weight; + fn approve_item_attributes() -> Weight; + fn cancel_item_attributes_approval(n: u32, ) -> Weight; + fn set_metadata() -> Weight; + fn clear_metadata() -> Weight; + fn set_collection_metadata() -> Weight; + fn clear_collection_metadata() -> Weight; + fn approve_transfer() -> Weight; + fn cancel_approval() -> Weight; + fn clear_all_transfer_approvals() -> Weight; + fn set_accept_ownership() -> Weight; + fn set_collection_max_supply() -> Weight; + fn update_mint_settings() -> Weight; + fn set_price() -> Weight; + fn buy_item() -> Weight; + fn pay_tips(n: u32, ) -> Weight; + fn create_swap() -> Weight; + fn cancel_swap() -> Weight; + fn claim_swap() -> Weight; + fn mint_pre_signed(n: u32, ) -> Weight; + fn set_attributes_pre_signed(n: u32, ) -> Weight; +} + +/// Weights for `pallet_nfts` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) + .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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// 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` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) + .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`) + /// 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) + /// 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::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) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// 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 { + // Proof Size summary in bytes: + // Measured: `32204 + 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)) + .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()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) + } + /// 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: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`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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` + // 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)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) + /// 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::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` + // 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)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, 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`) + /// 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` + // 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)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) + /// 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::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// 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)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// 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::Item` (r:5000 w:5000) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `763 + 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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`) + /// 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: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) + .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`) + /// 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: `562` + // Estimated: `3593` + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) + .saturating_add(T::DbWeight::get().reads(3_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`) + /// 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: `369` + // Estimated: `6078` + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) + .saturating_add(T::DbWeight::get().reads(3_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`) + /// 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: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) + .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`) + /// 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: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) + .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(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::CollectionConfigOf` (r:1 w:0) + /// 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::Attribute` (r:1 w:1) + /// 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` + // Estimated: `3944` + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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`) + /// 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: `344` + // Estimated: `3944` + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::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`) + fn clear_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `983` + // Estimated: `3944` + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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`) + 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) + .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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// 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())) + .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)) + .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::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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// 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` + // Estimated: `3812` + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) + .saturating_add(T::DbWeight::get().reads(5_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::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`) + /// 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: `849` + // Estimated: `3812` + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) + .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::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`) + /// 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: `398` + // Estimated: `3759` + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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`) + /// 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: `716` + // Estimated: `3759` + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// 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: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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` + // Estimated: `4326` + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_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`) + fn set_accept_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3517` + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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`) + fn set_collection_max_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// 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:1) + /// 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` + // Estimated: `3538` + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) + .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::CollectionConfigOf` (r:1 w:0) + /// 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::ItemPriceOf` (r:0 w:1) + /// 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` + // Estimated: `4326` + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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::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) + /// 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::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)) + } + /// 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())) + } + /// Storage: `Nfts::Item` (r:2 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// 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` + // Estimated: `7662` + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// 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` + // Estimated: `4326` + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:2 w:2) + /// 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::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) + /// 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::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` + // 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)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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: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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 10]`. + fn mint_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `629` + // 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)) + .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((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`) + /// 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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// 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())) + .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)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + } +} + +// For backwards compatibility and tests. +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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) + .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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// 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` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) + .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`) + /// 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) + /// 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::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) + /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionAccount` (r:0 w:1) + /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// 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 { + // Proof Size summary in bytes: + // Measured: `32204 + 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)) + .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()))) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) + } + /// 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: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`) + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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` + // 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)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) + /// 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::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` + // 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)) + } + /// Storage: `Nfts::Attribute` (r:1 w:0) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, 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`) + /// 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` + // 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)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) + /// 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::Item` (r:1 w:1) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, 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) + /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// 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)) + } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// 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::Item` (r:5000 w:5000) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `763 + 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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`) + /// 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: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) + .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`) + /// 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: `562` + // Estimated: `3593` + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) + .saturating_add(RocksDbWeight::get().reads(3_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`) + /// 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: `369` + // Estimated: `6078` + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) + .saturating_add(RocksDbWeight::get().reads(3_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`) + /// 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: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) + .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`) + /// 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: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) + /// 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` + // Estimated: `3534` + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) + .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(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::CollectionConfigOf` (r:1 w:0) + /// 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::Attribute` (r:1 w:1) + /// 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` + // Estimated: `3944` + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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`) + /// 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: `344` + // Estimated: `3944` + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Nfts::Attribute` (r:1 w:1) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::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`) + fn clear_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `983` + // Estimated: `3944` + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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`) + 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) + .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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// 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())) + .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())) + } + /// 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`) + /// 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) + /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// 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` + // Estimated: `3812` + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) + .saturating_add(RocksDbWeight::get().reads(5_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::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`) + /// 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: `849` + // Estimated: `3812` + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) + .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::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`) + /// 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: `398` + // Estimated: `3759` + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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`) + /// 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: `716` + // Estimated: `3759` + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// 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: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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` + // Estimated: `4326` + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_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`) + fn set_accept_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3517` + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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`) + fn set_collection_max_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// 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:1) + /// 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` + // Estimated: `3538` + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) + .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::CollectionConfigOf` (r:1 w:0) + /// 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::ItemPriceOf` (r:0 w:1) + /// 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` + // Estimated: `4326` + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:1 w:1) + /// 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::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) + /// 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::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)) + } + /// 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())) + } + /// Storage: `Nfts::Item` (r:2 w:0) + /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) + /// 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` + // Estimated: `7662` + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) + /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Item` (r:1 w:0) + /// 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` + // Estimated: `4326` + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::Item` (r:2 w:2) + /// 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::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) + /// 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::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` + // 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)) + } + /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) + /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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: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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Attribute` (r:10 w:10) + /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) + /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Account` (r:0 w:1) + /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 10]`. + fn mint_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `629` + // 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)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(6_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`) + /// 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`) + /// 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) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// 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())) + .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())) + } +} From b9fe4d8264288d58f5475cbb3a63ee01e65ca732 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 02/99] chore: resolve feedback --- pallets/nfts/Cargo.toml | 11 ++++++----- pallets/nfts/runtime-api/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index f23b50f0..bef584b8 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" ] @@ -28,8 +27,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" ] @@ -46,9 +45,11 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "scale-info/std", "sp-core/std", "sp-io/std", + "sp-keystore/std", "sp-runtime/std", ] try-runtime = [ 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 b63eda93c737f1e3cc8c2b4acce85184ae53b055 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:36:51 +0700 Subject: [PATCH 03/99] feat: nfts pallet optimization --- pallets/nfts/src/benchmarking.rs | 64 +- pallets/nfts/src/common_functions.rs | 20 +- pallets/nfts/src/features/approvals.rs | 105 ++- .../src/features/create_delete_collection.rs | 12 + .../nfts/src/features/create_delete_item.rs | 16 + pallets/nfts/src/features/transfer.rs | 25 +- pallets/nfts/src/lib.rs | 79 +- pallets/nfts/src/migration.rs | 120 --- pallets/nfts/src/tests.rs | 370 +++++++- pallets/nfts/src/types.rs | 24 +- pallets/nfts/src/weights.rs | 889 +++++++++--------- 11 files changed, 1097 insertions(+), 627 deletions(-) delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..d8876d52 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); + } 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, 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, 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, item, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, 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, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -603,7 +651,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 f51de192..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,6 +34,24 @@ 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) + } + + /// 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, + 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 @@ -46,7 +64,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..2647492c 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,102 @@ impl, I: 'static> Pallet { Ok(()) } + + pub(crate) fn do_approve_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + 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 + ); + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + 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, + item: None, + owner, + delegate, + deadline: None, + }); + Ok(()) + } + + pub(crate) fn do_cancel_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + 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 }); + + Ok(()) + } + + pub fn check_allowance( + 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)) { + 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. + 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); + } + return Ok(()); + }; + Err(Error::::NoPermission.into()) + } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..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,6 +144,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); @@ -147,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 e9843b2e..08cf5f95 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -70,6 +70,15 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + *balance + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config .is_setting_enabled(CollectionSetting::DepositRequired) @@ -254,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; @@ -263,6 +276,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..3f2dae3b 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,6 +87,24 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + *balance + }); + 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 + }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); @@ -100,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); @@ -137,7 +156,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. @@ -212,7 +231,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 89bfb963..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)] @@ -402,6 +401,34 @@ 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 = ()> = StorageDoubleMap< + _, + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + 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 +487,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 +496,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, }, @@ -804,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -819,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1030,12 +1061,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::check_allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1090,10 +1116,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); @@ -1288,11 +1314,11 @@ 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, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1300,13 +1326,16 @@ 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel one of the transfer approvals for a specific item. @@ -1324,18 +1353,22 @@ 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, - 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel all the approvals of a specific item. 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 44f2f32a..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,6 +164,8 @@ 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( @@ -173,10 +175,38 @@ 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(|| { @@ -204,6 +234,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,15 +243,20 @@ 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); 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))); + 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 +274,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 +285,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 +295,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 +345,15 @@ 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, + None, + account(3), + None + )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -323,6 +372,8 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); + 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); }); @@ -337,7 +388,9 @@ 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!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -402,6 +455,8 @@ fn mint_should_work() { account(2), 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 @@ -440,6 +495,8 @@ fn mint_should_work() { account(2), 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), @@ -476,8 +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)), @@ -487,12 +547,15 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - 42, + Some(42), account(2), 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!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1746,15 +1809,20 @@ fn burn_works() { account(5), 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!( 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_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); }); } @@ -1777,7 +1845,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); @@ -1791,7 +1859,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(2), None )); @@ -1819,7 +1887,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - 1, + Some(1), account(2), None ), @@ -1829,7 +1897,7 @@ fn approval_lifecycle_works() { } #[test] -fn cancel_approval_works() { +fn check_allowance_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -1844,33 +1912,95 @@ fn cancel_approval_works() { 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(&1, &None, &account(1), &account(2)), + Error::::NoPermission + ); + assert_noop!( + 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))); + + // 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(|| { + 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, + 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,22 +2017,72 @@ 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![]); }); } +#[test] +fn cancel_approval_collection_works_with_admin() { + 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_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: 0, + item: None, + owner: account(1), + 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)), + Error::::NoPermission + ); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -1924,21 +2104,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,19 +2159,83 @@ 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 ); }); } +#[test] +fn approval_collection_works_with_admin() { + 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), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(1), + default_item_config() + )); + + // 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::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(1)), + 0, + None, + account(3), + None + )); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: account(1), + delegate: account(3), + 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))); + }); +} + #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2015,7 +2259,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); @@ -2034,7 +2278,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(6), Some(4) )); @@ -2063,26 +2307,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 +2356,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 +2400,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 )); @@ -2188,6 +2437,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(|| { @@ -2524,6 +2803,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(); @@ -2891,6 +3171,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, @@ -2981,6 +3263,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(); @@ -3169,7 +3453,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 ), @@ -3870,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 f08f1d09..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,18 +94,22 @@ 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 accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + 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 c5fb60a2..b3307503 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-11-16, 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)] @@ -53,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; @@ -76,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; @@ -98,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) @@ -107,17 +90,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -126,21 +109,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -152,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -171,72 +160,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(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) @@ -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)` - // 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())) + // 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()))) @@ -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: 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)) } @@ -299,79 +296,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -381,15 +378,15 @@ 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)) } /// 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) @@ -400,23 +397,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -427,33 +424,33 @@ 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: `983` + // Measured: `951` // 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(37_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: 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)) @@ -476,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) @@ -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: `507` // 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)) } @@ -497,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -514,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -547,34 +544,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +591,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,10 +617,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(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -625,10 +634,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: 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)) } @@ -636,36 +645,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -673,10 +684,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: 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)) } @@ -686,10 +697,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: 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)) } @@ -697,26 +708,28 @@ 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) /// 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: `915` // 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: 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(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -725,7 +738,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -739,26 +754,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -766,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: `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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) @@ -785,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) @@ -794,17 +809,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -813,21 +828,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -839,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -858,72 +879,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -932,6 +959,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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(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) @@ -956,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: `763 + 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())) + // 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()))) @@ -973,10 +1002,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: 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)) } @@ -986,79 +1015,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1068,15 +1097,15 @@ 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)) } /// 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) @@ -1087,23 +1116,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -1114,33 +1143,33 @@ 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: `983` + // Measured: `951` // 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(37_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 +1177,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: 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)) @@ -1163,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) @@ -1172,10 +1201,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: `507` // 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)) } @@ -1184,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -1201,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1234,34 +1263,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +1310,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1295,10 +1336,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(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1312,10 +1353,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: 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)) } @@ -1323,36 +1364,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -1360,10 +1403,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: 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)) } @@ -1373,10 +1416,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: 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)) } @@ -1384,26 +1427,28 @@ 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) /// 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: `915` // 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: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(11_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`) @@ -1412,7 +1457,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1426,26 +1473,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -1453,12 +1500,12 @@ 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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) From 2c1fe5b3d5f6c38af53911439da3cf5b1f1b3dc3 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:04:57 +0700 Subject: [PATCH 04/99] chore: fork pallet nfts (#382) --- pallets/nfts/src/benchmarking.rs | 64 +- pallets/nfts/src/common_functions.rs | 20 +- pallets/nfts/src/features/approvals.rs | 105 +-- .../src/features/create_delete_collection.rs | 12 - .../nfts/src/features/create_delete_item.rs | 16 - pallets/nfts/src/features/transfer.rs | 25 +- pallets/nfts/src/lib.rs | 79 +- pallets/nfts/src/migration.rs | 120 +++ pallets/nfts/src/tests.rs | 370 +------- pallets/nfts/src/types.rs | 24 +- pallets/nfts/src/weights.rs | 889 +++++++++--------- 11 files changed, 627 insertions(+), 1097 deletions(-) create mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index d8876d52..8fa87557 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -64,27 +64,6 @@ 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) { @@ -98,7 +77,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(), @@ -271,8 +250,6 @@ 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::(); @@ -290,13 +267,6 @@ 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); - } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { @@ -603,45 +573,27 @@ 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 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) + let deadline = BlockNumberFor::::max_value(); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); + assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(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(); - 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) + Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -651,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, Some(item), delegate_lookup.clone(), Some(deadline))?; + Nfts::::approve_transfer(origin, collection, 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 abd8b61d..f51de192 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,24 +34,6 @@ 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) - } - - /// 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, - 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 @@ -64,7 +46,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 2647492c..ad5d93c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -65,6 +65,7 @@ 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)); @@ -73,13 +74,15 @@ 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: Some(item), + item, owner: details.owner, delegate, deadline, }); + Ok(()) } @@ -126,7 +129,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::ApprovalCancelled { collection, - item: Some(item), + item, owner: details.owner, delegate, }); @@ -170,102 +173,4 @@ impl, I: 'static> Pallet { Ok(()) } - - pub(crate) fn do_approve_collection( - maybe_check_origin: Option, - collection: T::CollectionId, - delegate: T::AccountId, - ) -> DispatchResult { - ensure!( - Self::is_pallet_feature_enabled(PalletFeature::Approvals), - Error::::MethodDisabled - ); - 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 - ); - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - - 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, - item: None, - owner, - delegate, - deadline: None, - }); - Ok(()) - } - - pub(crate) fn do_cancel_collection( - maybe_check_origin: Option, - collection: T::CollectionId, - delegate: T::AccountId, - ) -> DispatchResult { - let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - 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 }); - - Ok(()) - } - - pub fn check_allowance( - 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)) { - 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. - 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); - } - return Ok(()); - }; - Err(Error::::NoPermission.into()) - } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 1d08cd1b..348ec6b9 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,9 +54,7 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, - item_holders: 0, attributes: 0, - allowances: 0, }, ); CollectionRoleOf::::insert( @@ -121,11 +119,6 @@ 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 { @@ -144,9 +137,6 @@ 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); @@ -157,9 +147,7 @@ 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 08cf5f95..e9843b2e 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -70,15 +70,6 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); - let account_balance = - AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { - balance.saturating_inc(); - *balance - }); - if account_balance == 1 { - collection_details.item_holders.saturating_inc(); - } - let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config .is_setting_enabled(CollectionSetting::DepositRequired) @@ -263,10 +254,6 @@ impl, I: 'static> Pallet { } } - if AccountBalance::::get(collection, &details.owner) == 1 { - collection_details.item_holders.saturating_dec(); - } - Ok(details.owner) }, )?; @@ -276,9 +263,6 @@ 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 3f2dae3b..b7223a7c 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 mut collection_details = + let collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,24 +87,6 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balance of the owner. - let owner_balance = - AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { - balance.saturating_dec(); - *balance - }); - 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 - }); - if dest_balance == 1 { - collection_details.item_holders.saturating_inc(); - } - // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); @@ -118,7 +100,6 @@ 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); @@ -156,7 +137,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. @@ -231,7 +212,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 37e8b29c..89bfb963 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -401,34 +402,6 @@ 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 = ()> = StorageDoubleMap< - _, - Twox64Concat, - T::CollectionId, - Blake2_128Concat, - T::AccountId, - 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< @@ -487,7 +460,7 @@ pub mod pallet { /// a `delegate`. TransferApproved { collection: T::CollectionId, - item: Option, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, deadline: Option>, @@ -496,7 +469,7 @@ pub mod pallet { /// `collection` was cancelled by its `owner`. ApprovalCancelled { collection: T::CollectionId, - item: Option, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, }, @@ -831,8 +804,6 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, - witness.item_holders, - witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -848,8 +819,6 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, - details.item_holders, - details.allowances, )) .into()) } @@ -1061,7 +1030,12 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_allowance(&collection, &Some(item), &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); + } } Ok(()) }) @@ -1116,10 +1090,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); @@ -1314,11 +1288,11 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] + #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1326,16 +1300,13 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - match maybe_item { - Some(item) => Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ), - None => Self::do_approve_collection(maybe_check_origin, collection, delegate), - } + Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) } /// Cancel one of the transfer approvals for a specific item. @@ -1353,22 +1324,18 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] + #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, 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)?; - match maybe_item { - Some(item) => - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), - None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), - } + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) } /// Cancel all the approvals of a specific item. diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs new file mode 100644 index 00000000..af611bf1 --- /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 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 6d0c894a..44f2f32a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,8 +164,6 @@ 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,38 +173,10 @@ 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(|| { @@ -234,7 +204,6 @@ 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)), @@ -243,20 +212,15 @@ 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); 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))); - 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); @@ -274,7 +238,6 @@ 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)), @@ -285,9 +248,7 @@ 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(); @@ -295,7 +256,6 @@ 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)); @@ -345,15 +305,6 @@ 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, - None, - account(3), - None - )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -372,8 +323,6 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - 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); }); @@ -388,9 +337,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!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -455,8 +402,6 @@ fn mint_should_work() { account(2), 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 @@ -495,8 +440,6 @@ fn mint_should_work() { account(2), 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), @@ -533,11 +476,8 @@ 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)), @@ -547,15 +487,12 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - Some(42), + 42, account(2), 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!(Collection::::get(0).unwrap().item_holders, 1); + // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1809,20 +1746,15 @@ fn burn_works() { account(5), 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!( 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_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); }); } @@ -1845,7 +1777,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); @@ -1859,7 +1791,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(2), None )); @@ -1887,7 +1819,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - Some(1), + 1, account(2), None ), @@ -1896,63 +1828,6 @@ fn approval_lifecycle_works() { }); } -#[test] -fn check_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(&1, &None, &account(1), &account(2)), - Error::::NoPermission - ); - assert_noop!( - 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))); - - // 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(|| { @@ -1972,35 +1847,30 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); @@ -2017,72 +1887,22 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); assert_eq!(approvals(0, 69), vec![]); }); } -#[test] -fn cancel_approval_collection_works_with_admin() { - 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_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), - Error::::UnknownCollection - ); - - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: 0, - item: None, - owner: account(1), - 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)), - Error::::NoPermission - ); - }); -} - #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -2104,21 +1924,21 @@ fn approving_multiple_accounts_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(5), Some(2) )); @@ -2159,83 +1979,19 @@ fn approvals_limit_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(i), None )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(14), - None - ), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), Error::::ReachedApprovalLimit ); }); } -#[test] -fn approval_collection_works_with_admin() { - 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), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(1), - default_item_config() - )); - - // 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::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(1)), - 0, - None, - account(3), - None - )); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: account(1), - delegate: account(3), - 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))); - }); -} - #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2259,7 +2015,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); @@ -2278,7 +2034,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(6), Some(4) )); @@ -2307,31 +2063,26 @@ fn cancel_approval_works_with_admin() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2356,26 +2107,26 @@ fn cancel_approval_works_with_force() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2400,14 +2151,14 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); @@ -2437,36 +2188,6 @@ 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(|| { @@ -2803,7 +2524,6 @@ 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(); @@ -3171,8 +2891,6 @@ 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, @@ -3263,8 +2981,6 @@ 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(); @@ -3453,7 +3169,7 @@ fn pallet_level_feature_flags_should_work() { Nfts::approve_transfer( RuntimeOrigin::signed(user_id.clone()), collection_id, - Some(item_id), + item_id, account(2), None ), @@ -4154,13 +3870,7 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { - item_configs: 0, - item_metadatas: 0, - attributes: 0, - allowances: 0, - item_holders: 0 - } + DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 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 46148d63..f08f1d09 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,22 +94,18 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Collection's owner. - pub owner: AccountId, + pub(super) 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, + pub(super) owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub items: u32, + pub(super) items: u32, /// The total number of outstanding item metadata of this collection. - pub item_metadatas: u32, + pub(super) 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, + pub(super) item_configs: 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, + pub(super) attributes: u32, } /// Witness data for the destroy transactions. @@ -121,15 +117,9 @@ 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 { @@ -137,9 +127,7 @@ 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 b3307503..c5fb60a2 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -1,14 +1,30 @@ +// 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 40.0.0 -//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `R0GUE`, CPU: `` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/release/pop-node +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -18,11 +34,12 @@ // --no-storage-info // --no-median-slopes // --no-min-squares +// --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./pallets/nfts/src/weights.rs -// --template=./scripts/pallet-weights-template.hbs -// --extrinsic= +// --output=./substrate/frame/nfts/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -36,7 +53,7 @@ use core::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(m: u32, c: u32, a: u32, h: u32, l: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -59,8 +76,8 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer(i: u32, ) -> Weight; - fn cancel_approval(i: u32, ) -> Weight; + fn approve_transfer() -> Weight; + fn cancel_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; @@ -81,7 +98,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -90,17 +107,17 @@ 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: `105` - // Estimated: `3557` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -109,25 +126,21 @@ 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: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Measured: `76` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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::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) @@ -139,17 +152,15 @@ 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]`. - /// 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 { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // 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)) .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,78 +171,72 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `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)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // 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)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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: `584` + // Measured: `564` // Estimated: `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)) + // 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)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) @@ -240,8 +245,6 @@ 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) @@ -250,15 +253,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: `613` - // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -266,12 +269,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // 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())) + // Measured: `763 + 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())) .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()))) @@ -283,10 +286,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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -296,79 +299,79 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `425` + // Measured: `562` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) .saturating_add(T::DbWeight::get().reads(3_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `304` + // Measured: `369` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) .saturating_add(T::DbWeight::get().reads(3_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `246` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + // Measured: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3557` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + // Measured: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -378,15 +381,15 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3534) + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) .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`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -397,23 +400,23 @@ 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: `507` + // Measured: `539` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `279` + // Measured: `344` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -424,33 +427,33 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `983` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Measured: `381` + // Estimated: `4326` + // Minimum execution time: 15_710_000 picoseconds. + Weight::from_parts(16_191_000, 4326) .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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) @@ -458,12 +461,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: `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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // 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())) .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 +476,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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,10 +485,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: `507` + // Measured: `539` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -494,15 +497,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `817` + // Measured: `849` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,32 +514,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `333` + // Measured: `398` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::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: `651` + // Measured: `716` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,46 +547,34 @@ 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`) - /// 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())) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(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(14_000_000, 3557) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:1) /// 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: `345` + // Measured: `418` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 4326) + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -591,23 +582,23 @@ 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: `3` + // Measured: `76` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -617,10 +608,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: `250` + // Measured: `323` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -634,10 +625,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: `478` + // Measured: `518` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -645,38 +636,36 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `725` - // Estimated: `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(8_u64)) + // 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)) } /// 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: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + // 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())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -684,10 +673,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: `421` + // Measured: `494` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -697,10 +686,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: `440` + // Measured: `513` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -708,28 +697,26 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `915` + // Measured: `834` // Estimated: `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(13_u64)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -738,9 +725,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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -754,26 +739,26 @@ 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: `493` + // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // 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)) + // 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)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -781,12 +766,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: `522` - // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // 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())) .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)) @@ -800,7 +785,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -809,17 +794,17 @@ 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: `105` - // Estimated: `3557` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -828,25 +813,21 @@ 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: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Measured: `76` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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::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) @@ -858,17 +839,15 @@ 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]`. - /// 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 { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // 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)) .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()))) @@ -879,78 +858,72 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `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)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // 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)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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: `584` + // Measured: `564` // Estimated: `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)) + // 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)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) @@ -959,8 +932,6 @@ 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) @@ -969,15 +940,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: `613` - // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -985,12 +956,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // 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())) + // Measured: `763 + 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())) .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()))) @@ -1002,10 +973,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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1015,79 +986,79 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `425` + // Measured: `562` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `304` + // Measured: `369` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `246` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + // Measured: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3557` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + // Measured: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1097,15 +1068,15 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3534) + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) .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`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -1116,23 +1087,23 @@ 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: `507` + // Measured: `539` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `279` + // Measured: `344` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1143,33 +1114,33 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `983` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Measured: `381` + // Estimated: `4326` + // Minimum execution time: 15_710_000 picoseconds. + Weight::from_parts(16_191_000, 4326) .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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) @@ -1177,12 +1148,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: `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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // 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())) .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)) @@ -1192,7 +1163,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1201,10 +1172,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: `507` + // Measured: `539` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1213,15 +1184,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `817` + // Measured: `849` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1230,32 +1201,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `333` + // Measured: `398` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::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: `651` + // Measured: `716` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1263,46 +1234,34 @@ 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`) - /// 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())) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(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(14_000_000, 3557) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:1) /// 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: `345` + // Measured: `418` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 4326) + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1310,23 +1269,23 @@ 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: `3` + // Measured: `76` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1336,10 +1295,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: `250` + // Measured: `323` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1353,10 +1312,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: `478` + // Measured: `518` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1364,38 +1323,36 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `725` - // Estimated: `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(8_u64)) + // 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)) } /// 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: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + // 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())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1403,10 +1360,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: `421` + // Measured: `494` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1416,10 +1373,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: `440` + // Measured: `513` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1427,28 +1384,26 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `915` + // Measured: `834` // Estimated: `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(13_u64)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1457,9 +1412,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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1473,26 +1426,26 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `493` + // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // 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)) + // 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)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1500,12 +1453,12 @@ 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: `522` - // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // 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())) .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)) From b0fbeb3dbeb3e34388700357ad79f1b4ce1a87b9 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 05/99] chore: fork pallet nfts --- pallets/nfts/Cargo.toml | 11 +++++------ pallets/nfts/runtime-api/Cargo.toml | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index bef584b8..f23b50f0 100644 --- a/pallets/nfts/Cargo.toml +++ b/pallets/nfts/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = [ "Parity Technologies ", "R0GUE " ] -description = "Fork of FRAME NFTs pallet" +authors.workspace = true +description = "Fork of FRAME NFTs pallet (polkadot v1.15.0)" edition.workspace = true homepage = "https://substrate.io" license.workspace = true @@ -9,6 +9,7 @@ readme = "README.md" repository.workspace = true version = "31.0.0" + [package.metadata.docs.rs] targets = [ "x86_64-unknown-linux-gnu" ] @@ -27,8 +28,8 @@ sp-io.workspace = true sp-runtime.workspace = true [dev-dependencies] -pallet-balances.workspace = true -sp-keystore.workspace = true +pallet-balances = { default-features = true, workspace = true } +sp-keystore = { default-features = true, workspace = true } [features] default = [ "std" ] @@ -45,11 +46,9 @@ std = [ "frame-support/std", "frame-system/std", "log/std", - "pallet-balances/std", "scale-info/std", "sp-core/std", "sp-io/std", - "sp-keystore/std", "sp-runtime/std", ] try-runtime = [ diff --git a/pallets/nfts/runtime-api/Cargo.toml b/pallets/nfts/runtime-api/Cargo.toml index 503642ef..17fd68f2 100644 --- a/pallets/nfts/runtime-api/Cargo.toml +++ b/pallets/nfts/runtime-api/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = [ "Parity Technologies ", "R0GUE " ] -description = "Runtime API for the FRAME NFTs pallet." +authors.workspace = true +description = "Runtime API for the FRAME NFTs pallet. (polkadot v1.15.0)" edition.workspace = true homepage = "https://substrate.io" license = "Apache-2.0" From 98217ae06438fb8e7859a5f1da07512947db9bca 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 06/99] chore: resolve feedback --- pallets/nfts/Cargo.toml | 11 ++++++----- pallets/nfts/runtime-api/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pallets/nfts/Cargo.toml b/pallets/nfts/Cargo.toml index f23b50f0..bef584b8 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" ] @@ -28,8 +27,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" ] @@ -46,9 +45,11 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "scale-info/std", "sp-core/std", "sp-io/std", + "sp-keystore/std", "sp-runtime/std", ] try-runtime = [ 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 d954c70f97a1180e23ae534f31b020bfeb2272b6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:36:51 +0700 Subject: [PATCH 07/99] feat: nfts pallet optimization --- pallets/nfts/src/benchmarking.rs | 64 +- pallets/nfts/src/common_functions.rs | 20 +- pallets/nfts/src/features/approvals.rs | 105 ++- .../src/features/create_delete_collection.rs | 12 + .../nfts/src/features/create_delete_item.rs | 16 + pallets/nfts/src/features/transfer.rs | 25 +- pallets/nfts/src/lib.rs | 79 +- pallets/nfts/src/migration.rs | 120 --- pallets/nfts/src/tests.rs | 370 +++++++- pallets/nfts/src/types.rs | 24 +- pallets/nfts/src/weights.rs | 889 +++++++++--------- 11 files changed, 1097 insertions(+), 627 deletions(-) delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..d8876d52 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); + } 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, 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, 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, item, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, 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, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -603,7 +651,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 f51de192..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,6 +34,24 @@ 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) + } + + /// 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, + 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 @@ -46,7 +64,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..2647492c 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,102 @@ impl, I: 'static> Pallet { Ok(()) } + + pub(crate) fn do_approve_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + 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 + ); + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + 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, + item: None, + owner, + delegate, + deadline: None, + }); + Ok(()) + } + + pub(crate) fn do_cancel_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + 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 }); + + Ok(()) + } + + pub fn check_allowance( + 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)) { + 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. + 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); + } + return Ok(()); + }; + Err(Error::::NoPermission.into()) + } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..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,6 +144,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); @@ -147,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 e9843b2e..08cf5f95 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -70,6 +70,15 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + *balance + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config .is_setting_enabled(CollectionSetting::DepositRequired) @@ -254,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; @@ -263,6 +276,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..3f2dae3b 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,6 +87,24 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + *balance + }); + 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 + }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); @@ -100,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); @@ -137,7 +156,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. @@ -212,7 +231,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 89bfb963..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)] @@ -402,6 +401,34 @@ 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 = ()> = StorageDoubleMap< + _, + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + 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 +487,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 +496,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, }, @@ -804,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -819,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1030,12 +1061,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::check_allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1090,10 +1116,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); @@ -1288,11 +1314,11 @@ 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, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1300,13 +1326,16 @@ 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel one of the transfer approvals for a specific item. @@ -1324,18 +1353,22 @@ 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, - 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel all the approvals of a specific item. 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 44f2f32a..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,6 +164,8 @@ 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( @@ -173,10 +175,38 @@ 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(|| { @@ -204,6 +234,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,15 +243,20 @@ 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); 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))); + 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 +274,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 +285,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 +295,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 +345,15 @@ 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, + None, + account(3), + None + )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -323,6 +372,8 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); + 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); }); @@ -337,7 +388,9 @@ 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!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -402,6 +455,8 @@ fn mint_should_work() { account(2), 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 @@ -440,6 +495,8 @@ fn mint_should_work() { account(2), 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), @@ -476,8 +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)), @@ -487,12 +547,15 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - 42, + Some(42), account(2), 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!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1746,15 +1809,20 @@ fn burn_works() { account(5), 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!( 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_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); }); } @@ -1777,7 +1845,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); @@ -1791,7 +1859,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(2), None )); @@ -1819,7 +1887,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - 1, + Some(1), account(2), None ), @@ -1829,7 +1897,7 @@ fn approval_lifecycle_works() { } #[test] -fn cancel_approval_works() { +fn check_allowance_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -1844,33 +1912,95 @@ fn cancel_approval_works() { 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(&1, &None, &account(1), &account(2)), + Error::::NoPermission + ); + assert_noop!( + 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))); + + // 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(|| { + 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, + 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,22 +2017,72 @@ 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![]); }); } +#[test] +fn cancel_approval_collection_works_with_admin() { + 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_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: 0, + item: None, + owner: account(1), + 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)), + Error::::NoPermission + ); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -1924,21 +2104,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,19 +2159,83 @@ 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 ); }); } +#[test] +fn approval_collection_works_with_admin() { + 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), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(1), + default_item_config() + )); + + // 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::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(1)), + 0, + None, + account(3), + None + )); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: account(1), + delegate: account(3), + 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))); + }); +} + #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2015,7 +2259,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); @@ -2034,7 +2278,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(6), Some(4) )); @@ -2063,26 +2307,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 +2356,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 +2400,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 )); @@ -2188,6 +2437,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(|| { @@ -2524,6 +2803,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(); @@ -2891,6 +3171,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, @@ -2981,6 +3263,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(); @@ -3169,7 +3453,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 ), @@ -3870,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 f08f1d09..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,18 +94,22 @@ 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 accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + 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 c5fb60a2..b3307503 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-11-16, 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)] @@ -53,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; @@ -76,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; @@ -98,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) @@ -107,17 +90,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -126,21 +109,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -152,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -171,72 +160,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(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) @@ -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)` - // 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())) + // 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()))) @@ -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: 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)) } @@ -299,79 +296,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -381,15 +378,15 @@ 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)) } /// 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) @@ -400,23 +397,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -427,33 +424,33 @@ 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: `983` + // Measured: `951` // 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(37_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: 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)) @@ -476,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) @@ -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: `507` // 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)) } @@ -497,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -514,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -547,34 +544,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +591,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,10 +617,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(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -625,10 +634,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: 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)) } @@ -636,36 +645,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -673,10 +684,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: 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)) } @@ -686,10 +697,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: 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)) } @@ -697,26 +708,28 @@ 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) /// 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: `915` // 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: 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(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -725,7 +738,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -739,26 +754,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -766,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: `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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) @@ -785,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) @@ -794,17 +809,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -813,21 +828,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -839,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -858,72 +879,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -932,6 +959,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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(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) @@ -956,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: `763 + 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())) + // 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()))) @@ -973,10 +1002,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: 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)) } @@ -986,79 +1015,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1068,15 +1097,15 @@ 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)) } /// 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) @@ -1087,23 +1116,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -1114,33 +1143,33 @@ 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: `983` + // Measured: `951` // 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(37_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 +1177,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: 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)) @@ -1163,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) @@ -1172,10 +1201,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: `507` // 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)) } @@ -1184,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -1201,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1234,34 +1263,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +1310,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1295,10 +1336,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(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1312,10 +1353,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: 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)) } @@ -1323,36 +1364,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -1360,10 +1403,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: 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)) } @@ -1373,10 +1416,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: 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)) } @@ -1384,26 +1427,28 @@ 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) /// 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: `915` // 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: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(11_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`) @@ -1412,7 +1457,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1426,26 +1473,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -1453,12 +1500,12 @@ 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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) From b76dc4d55cdd88a855fc7b47ca2357bf8152bdb2 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:04:57 +0700 Subject: [PATCH 08/99] chore: fork pallet nfts (#382) --- pallets/nfts/src/benchmarking.rs | 64 +- pallets/nfts/src/common_functions.rs | 20 +- pallets/nfts/src/features/approvals.rs | 105 +-- .../src/features/create_delete_collection.rs | 12 - .../nfts/src/features/create_delete_item.rs | 16 - pallets/nfts/src/features/transfer.rs | 25 +- pallets/nfts/src/lib.rs | 79 +- pallets/nfts/src/migration.rs | 120 +++ pallets/nfts/src/tests.rs | 370 +------- pallets/nfts/src/types.rs | 24 +- pallets/nfts/src/weights.rs | 889 +++++++++--------- 11 files changed, 627 insertions(+), 1097 deletions(-) create mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index d8876d52..8fa87557 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -64,27 +64,6 @@ 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) { @@ -98,7 +77,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(), @@ -271,8 +250,6 @@ 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::(); @@ -290,13 +267,6 @@ 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); - } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { @@ -603,45 +573,27 @@ 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 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) + let deadline = BlockNumberFor::::max_value(); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); + assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(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(); - 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) + Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -651,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, Some(item), delegate_lookup.clone(), Some(deadline))?; + Nfts::::approve_transfer(origin, collection, 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 abd8b61d..f51de192 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,24 +34,6 @@ 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) - } - - /// 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, - 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 @@ -64,7 +46,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 2647492c..ad5d93c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -65,6 +65,7 @@ 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)); @@ -73,13 +74,15 @@ 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: Some(item), + item, owner: details.owner, delegate, deadline, }); + Ok(()) } @@ -126,7 +129,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::ApprovalCancelled { collection, - item: Some(item), + item, owner: details.owner, delegate, }); @@ -170,102 +173,4 @@ impl, I: 'static> Pallet { Ok(()) } - - pub(crate) fn do_approve_collection( - maybe_check_origin: Option, - collection: T::CollectionId, - delegate: T::AccountId, - ) -> DispatchResult { - ensure!( - Self::is_pallet_feature_enabled(PalletFeature::Approvals), - Error::::MethodDisabled - ); - 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 - ); - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - - 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, - item: None, - owner, - delegate, - deadline: None, - }); - Ok(()) - } - - pub(crate) fn do_cancel_collection( - maybe_check_origin: Option, - collection: T::CollectionId, - delegate: T::AccountId, - ) -> DispatchResult { - let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - 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 }); - - Ok(()) - } - - pub fn check_allowance( - 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)) { - 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. - 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); - } - return Ok(()); - }; - Err(Error::::NoPermission.into()) - } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 1d08cd1b..348ec6b9 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,9 +54,7 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, - item_holders: 0, attributes: 0, - allowances: 0, }, ); CollectionRoleOf::::insert( @@ -121,11 +119,6 @@ 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 { @@ -144,9 +137,6 @@ 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); @@ -157,9 +147,7 @@ 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 08cf5f95..e9843b2e 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -70,15 +70,6 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); - let account_balance = - AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { - balance.saturating_inc(); - *balance - }); - if account_balance == 1 { - collection_details.item_holders.saturating_inc(); - } - let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config .is_setting_enabled(CollectionSetting::DepositRequired) @@ -263,10 +254,6 @@ impl, I: 'static> Pallet { } } - if AccountBalance::::get(collection, &details.owner) == 1 { - collection_details.item_holders.saturating_dec(); - } - Ok(details.owner) }, )?; @@ -276,9 +263,6 @@ 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 3f2dae3b..b7223a7c 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 mut collection_details = + let collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,24 +87,6 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balance of the owner. - let owner_balance = - AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { - balance.saturating_dec(); - *balance - }); - 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 - }); - if dest_balance == 1 { - collection_details.item_holders.saturating_inc(); - } - // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); @@ -118,7 +100,6 @@ 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); @@ -156,7 +137,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. @@ -231,7 +212,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 37e8b29c..89bfb963 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -401,34 +402,6 @@ 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 = ()> = StorageDoubleMap< - _, - Twox64Concat, - T::CollectionId, - Blake2_128Concat, - T::AccountId, - 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< @@ -487,7 +460,7 @@ pub mod pallet { /// a `delegate`. TransferApproved { collection: T::CollectionId, - item: Option, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, deadline: Option>, @@ -496,7 +469,7 @@ pub mod pallet { /// `collection` was cancelled by its `owner`. ApprovalCancelled { collection: T::CollectionId, - item: Option, + item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, }, @@ -831,8 +804,6 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, - witness.item_holders, - witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -848,8 +819,6 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, - details.item_holders, - details.allowances, )) .into()) } @@ -1061,7 +1030,12 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_allowance(&collection, &Some(item), &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); + } } Ok(()) }) @@ -1116,10 +1090,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); @@ -1314,11 +1288,11 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] + #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1326,16 +1300,13 @@ pub mod pallet { .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; - match maybe_item { - Some(item) => Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ), - None => Self::do_approve_collection(maybe_check_origin, collection, delegate), - } + Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) } /// Cancel one of the transfer approvals for a specific item. @@ -1353,22 +1324,18 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] + #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, 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)?; - match maybe_item { - Some(item) => - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), - None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), - } + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) } /// Cancel all the approvals of a specific item. diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs new file mode 100644 index 00000000..af611bf1 --- /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 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 6d0c894a..44f2f32a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,8 +164,6 @@ 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,38 +173,10 @@ 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(|| { @@ -234,7 +204,6 @@ 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)), @@ -243,20 +212,15 @@ 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); 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))); - 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); @@ -274,7 +238,6 @@ 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)), @@ -285,9 +248,7 @@ 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(); @@ -295,7 +256,6 @@ 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)); @@ -345,15 +305,6 @@ 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, - None, - account(3), - None - )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -372,8 +323,6 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - 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); }); @@ -388,9 +337,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!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -455,8 +402,6 @@ fn mint_should_work() { account(2), 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 @@ -495,8 +440,6 @@ fn mint_should_work() { account(2), 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), @@ -533,11 +476,8 @@ 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)), @@ -547,15 +487,12 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - Some(42), + 42, account(2), 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!(Collection::::get(0).unwrap().item_holders, 1); + // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1809,20 +1746,15 @@ fn burn_works() { account(5), 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!( 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_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); }); } @@ -1845,7 +1777,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); @@ -1859,7 +1791,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(2), None )); @@ -1887,7 +1819,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - Some(1), + 1, account(2), None ), @@ -1896,63 +1828,6 @@ fn approval_lifecycle_works() { }); } -#[test] -fn check_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(&1, &None, &account(1), &account(2)), - Error::::NoPermission - ); - assert_noop!( - 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))); - - // 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(|| { @@ -1972,35 +1847,30 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); @@ -2017,72 +1887,22 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); assert_eq!(approvals(0, 69), vec![]); }); } -#[test] -fn cancel_approval_collection_works_with_admin() { - 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_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), - Error::::UnknownCollection - ); - - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: 0, - item: None, - owner: account(1), - 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)), - Error::::NoPermission - ); - }); -} - #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -2104,21 +1924,21 @@ fn approving_multiple_accounts_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(5), Some(2) )); @@ -2159,83 +1979,19 @@ fn approvals_limit_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(i), None )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(14), - None - ), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), Error::::ReachedApprovalLimit ); }); } -#[test] -fn approval_collection_works_with_admin() { - 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), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(1), - default_item_config() - )); - - // 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::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(1)), - 0, - None, - account(3), - None - )); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: account(1), - delegate: account(3), - 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))); - }); -} - #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2259,7 +2015,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); @@ -2278,7 +2034,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(6), Some(4) )); @@ -2307,31 +2063,26 @@ fn cancel_approval_works_with_admin() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2356,26 +2107,26 @@ fn cancel_approval_works_with_force() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2400,14 +2151,14 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); @@ -2437,36 +2188,6 @@ 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(|| { @@ -2803,7 +2524,6 @@ 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(); @@ -3171,8 +2891,6 @@ 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, @@ -3263,8 +2981,6 @@ 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(); @@ -3453,7 +3169,7 @@ fn pallet_level_feature_flags_should_work() { Nfts::approve_transfer( RuntimeOrigin::signed(user_id.clone()), collection_id, - Some(item_id), + item_id, account(2), None ), @@ -4154,13 +3870,7 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { - item_configs: 0, - item_metadatas: 0, - attributes: 0, - allowances: 0, - item_holders: 0 - } + DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 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 46148d63..f08f1d09 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,22 +94,18 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Collection's owner. - pub owner: AccountId, + pub(super) 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, + pub(super) owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub items: u32, + pub(super) items: u32, /// The total number of outstanding item metadata of this collection. - pub item_metadatas: u32, + pub(super) 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, + pub(super) item_configs: 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, + pub(super) attributes: u32, } /// Witness data for the destroy transactions. @@ -121,15 +117,9 @@ 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 { @@ -137,9 +127,7 @@ 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 b3307503..c5fb60a2 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -1,14 +1,30 @@ +// 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 40.0.0 -//! DATE: 2024-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `R0GUE`, CPU: `` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/release/pop-node +// ./target/production/substrate-node // benchmark // pallet // --chain=dev @@ -18,11 +34,12 @@ // --no-storage-info // --no-median-slopes // --no-min-squares +// --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./pallets/nfts/src/weights.rs -// --template=./scripts/pallet-weights-template.hbs -// --extrinsic= +// --output=./substrate/frame/nfts/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -36,7 +53,7 @@ use core::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(m: u32, c: u32, a: u32, h: u32, l: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -59,8 +76,8 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer(i: u32, ) -> Weight; - fn cancel_approval(i: u32, ) -> Weight; + fn approve_transfer() -> Weight; + fn cancel_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; @@ -81,7 +98,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -90,17 +107,17 @@ 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: `105` - // Estimated: `3557` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -109,25 +126,21 @@ 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: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Measured: `76` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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::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) @@ -139,17 +152,15 @@ 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]`. - /// 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 { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // 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)) .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,78 +171,72 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `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)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // 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)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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: `584` + // Measured: `564` // Estimated: `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)) + // 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)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) @@ -240,8 +245,6 @@ 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) @@ -250,15 +253,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: `613` - // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -266,12 +269,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // 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())) + // Measured: `763 + 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())) .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()))) @@ -283,10 +286,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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -296,79 +299,79 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `425` + // Measured: `562` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) .saturating_add(T::DbWeight::get().reads(3_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `304` + // Measured: `369` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) .saturating_add(T::DbWeight::get().reads(3_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `246` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + // Measured: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3557` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + // Measured: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -378,15 +381,15 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3534) + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) .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`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -397,23 +400,23 @@ 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: `507` + // Measured: `539` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `279` + // Measured: `344` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -424,33 +427,33 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `983` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Measured: `381` + // Estimated: `4326` + // Minimum execution time: 15_710_000 picoseconds. + Weight::from_parts(16_191_000, 4326) .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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) @@ -458,12 +461,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: `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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // 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())) .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 +476,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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,10 +485,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: `507` + // Measured: `539` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -494,15 +497,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `817` + // Measured: `849` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,32 +514,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `333` + // Measured: `398` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::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: `651` + // Measured: `716` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,46 +547,34 @@ 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`) - /// 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())) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// 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(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(14_000_000, 3557) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:1) /// 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: `345` + // Measured: `418` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 4326) + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -591,23 +582,23 @@ 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: `3` + // Measured: `76` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -617,10 +608,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: `250` + // Measured: `323` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -634,10 +625,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: `478` + // Measured: `518` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -645,38 +636,36 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `725` - // Estimated: `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(8_u64)) + // 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)) } /// 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: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + // 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())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -684,10 +673,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: `421` + // Measured: `494` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -697,10 +686,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: `440` + // Measured: `513` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -708,28 +697,26 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `915` + // Measured: `834` // Estimated: `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(13_u64)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -738,9 +725,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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -754,26 +739,26 @@ 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: `493` + // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // 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)) + // 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)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -781,12 +766,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: `522` - // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // 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())) .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)) @@ -800,7 +785,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -809,17 +794,17 @@ 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: `105` - // Estimated: `3557` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + // Measured: `216` + // Estimated: `3549` + // Minimum execution time: 34_863_000 picoseconds. + Weight::from_parts(36_679_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -828,25 +813,21 @@ 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: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Measured: `76` + // Estimated: `3549` + // Minimum execution time: 19_631_000 picoseconds. + Weight::from_parts(20_384_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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::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) @@ -858,17 +839,15 @@ 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]`. - /// 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 { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // 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)) .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()))) @@ -879,78 +858,72 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `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)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `390` + // Measured: `455` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // 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)) } /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, 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::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) /// 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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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: `584` + // Measured: `564` // Estimated: `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)) + // 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)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) @@ -959,8 +932,6 @@ 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) @@ -969,15 +940,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: `613` - // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -985,12 +956,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // 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())) + // Measured: `763 + 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())) .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()))) @@ -1002,10 +973,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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_307_000 picoseconds. + Weight::from_parts(18_966_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1015,79 +986,79 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 18_078_000 picoseconds. + Weight::from_parts(18_593_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_762_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `425` + // Measured: `562` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + // Minimum execution time: 26_164_000 picoseconds. + Weight::from_parts(27_117_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `304` + // Measured: `369` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_486_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `246` - // Estimated: `3557` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + // Measured: `311` + // Estimated: `3549` + // Minimum execution time: 15_733_000 picoseconds. + Weight::from_parts(16_227_000, 3549) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3557` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + // Measured: `276` + // Estimated: `3549` + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_690_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1097,15 +1068,15 @@ 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: `395` + // Measured: `435` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3534) + // Minimum execution time: 17_165_000 picoseconds. + Weight::from_parts(17_769_000, 3534) .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`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -1116,23 +1087,23 @@ 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: `507` + // Measured: `539` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 48_862_000 picoseconds. + Weight::from_parts(50_584_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `279` + // Measured: `344` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 24_665_000 picoseconds. + Weight::from_parts(25_465_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1143,33 +1114,33 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `983` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 44_617_000 picoseconds. + Weight::from_parts(46_458_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Measured: `381` + // Estimated: `4326` + // Minimum execution time: 15_710_000 picoseconds. + Weight::from_parts(16_191_000, 4326) .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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) @@ -1177,12 +1148,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: `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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // 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())) .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)) @@ -1192,7 +1163,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1201,10 +1172,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: `507` + // Measured: `539` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_098_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1213,15 +1184,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `817` + // Measured: `849` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 38_030_000 picoseconds. + Weight::from_parts(39_842_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1230,32 +1201,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `333` + // Measured: `398` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_778_000 picoseconds. + Weight::from_parts(38_088_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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::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: `651` + // Measured: `716` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + // Minimum execution time: 36_887_000 picoseconds. + Weight::from_parts(38_406_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1263,46 +1234,34 @@ 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`) - /// 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())) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `410` + // Estimated: `4326` + // Minimum execution time: 18_734_000 picoseconds. + Weight::from_parts(19_267_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// 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(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(14_000_000, 3557) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `4326` + // Minimum execution time: 16_080_000 picoseconds. + Weight::from_parts(16_603_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nfts::Item` (r:1 w:1) /// 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: `345` + // Measured: `418` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 4326) + // Minimum execution time: 15_013_000 picoseconds. + Weight::from_parts(15_607_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1310,23 +1269,23 @@ 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: `3` + // Measured: `76` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + // Minimum execution time: 13_077_000 picoseconds. + Weight::from_parts(13_635_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(92), added: 2567, mode: `MaxEncodedLen`) + /// 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: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `340` + // Estimated: `3549` + // Minimum execution time: 17_146_000 picoseconds. + Weight::from_parts(17_453_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1336,10 +1295,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: `250` + // Measured: `323` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 16_102_000 picoseconds. + Weight::from_parts(16_629_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1353,10 +1312,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: `478` + // Measured: `518` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 22_118_000 picoseconds. + Weight::from_parts(22_849_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1364,38 +1323,36 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `725` - // Estimated: `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(8_u64)) + // 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)) } /// 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: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + // 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())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1403,10 +1360,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: `421` + // Measured: `494` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 18_893_000 picoseconds. + Weight::from_parts(19_506_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1416,10 +1373,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: `440` + // Measured: `513` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 19_086_000 picoseconds. + Weight::from_parts(19_609_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1427,28 +1384,26 @@ 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, 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::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) /// 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: `915` + // Measured: `834` // Estimated: `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(13_u64)) + // 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -1457,9 +1412,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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1473,26 +1426,26 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `493` + // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // 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)) + // 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)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_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(1001), added: 3476, mode: `MaxEncodedLen`) + /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, 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) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1500,12 +1453,12 @@ 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: `522` - // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // 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())) .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)) From 9d1658e93d555eb55ef672f19407e72231d1ae4b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:02:14 +0700 Subject: [PATCH 09/99] feat: add new storage items and optimize --- pallets/nfts/src/benchmarking.rs | 64 +- pallets/nfts/src/common_functions.rs | 20 +- pallets/nfts/src/features/approvals.rs | 105 ++- .../src/features/create_delete_collection.rs | 12 + .../nfts/src/features/create_delete_item.rs | 16 + pallets/nfts/src/features/transfer.rs | 25 +- pallets/nfts/src/lib.rs | 79 +- pallets/nfts/src/migration.rs | 120 --- pallets/nfts/src/tests.rs | 370 +++++++- pallets/nfts/src/types.rs | 24 +- pallets/nfts/src/weights.rs | 889 +++++++++--------- 11 files changed, 1097 insertions(+), 627 deletions(-) delete mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..d8876d52 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); + } 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, 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, 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, item, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, 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, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); } clear_all_transfer_approvals { @@ -603,7 +651,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 f51de192..abd8b61d 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -34,6 +34,24 @@ 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) + } + + /// 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, + 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 @@ -46,7 +64,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..2647492c 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,102 @@ impl, I: 'static> Pallet { Ok(()) } + + pub(crate) fn do_approve_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + 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 + ); + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + 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, + item: None, + owner, + delegate, + deadline: None, + }); + Ok(()) + } + + pub(crate) fn do_cancel_collection( + maybe_check_origin: Option, + collection: T::CollectionId, + delegate: T::AccountId, + ) -> DispatchResult { + let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + 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 }); + + Ok(()) + } + + pub fn check_allowance( + 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)) { + 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. + 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); + } + return Ok(()); + }; + Err(Error::::NoPermission.into()) + } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..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,6 +144,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); @@ -147,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 e9843b2e..08cf5f95 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -70,6 +70,15 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + *balance + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = match collection_config .is_setting_enabled(CollectionSetting::DepositRequired) @@ -254,6 +263,10 @@ impl, I: 'static> Pallet { } } + if AccountBalance::::get(collection, &details.owner) == 1 { + collection_details.item_holders.saturating_dec(); + } + Ok(details.owner) }, )?; @@ -263,6 +276,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..3f2dae3b 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,6 +87,24 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; + // Update account balance of the owner. + let owner_balance = + AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { + balance.saturating_dec(); + *balance + }); + 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 + }); + if dest_balance == 1 { + collection_details.item_holders.saturating_inc(); + } + // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); @@ -100,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); @@ -137,7 +156,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. @@ -212,7 +231,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 89bfb963..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)] @@ -402,6 +401,34 @@ 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 = ()> = StorageDoubleMap< + _, + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + 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 +487,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 +496,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, }, @@ -804,6 +831,8 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, + witness.item_holders, + witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -819,6 +848,8 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, + details.item_holders, + details.allowances, )) .into()) } @@ -1030,12 +1061,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::check_allowance(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1090,10 +1116,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); @@ -1288,11 +1314,11 @@ 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, - item: T::ItemId, + maybe_item: Option, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { @@ -1300,13 +1326,16 @@ 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel one of the transfer approvals for a specific item. @@ -1324,18 +1353,22 @@ 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, - 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_collection(maybe_check_origin, collection, delegate), + } } /// Cancel all the approvals of a specific item. 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 44f2f32a..6d0c894a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -164,6 +164,8 @@ 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( @@ -173,10 +175,38 @@ 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(|| { @@ -204,6 +234,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,15 +243,20 @@ 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); 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))); + 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 +274,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 +285,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 +295,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 +345,15 @@ 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, + None, + account(3), + None + )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -323,6 +372,8 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); + 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); }); @@ -337,7 +388,9 @@ 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!(Collection::::get(0).unwrap().item_holders, 1); assert_eq!(collections(), vec![(account(1), 0)]); assert_eq!(items(), vec![(account(1), 0, 42)]); @@ -402,6 +455,8 @@ fn mint_should_work() { account(2), 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 @@ -440,6 +495,8 @@ fn mint_should_work() { account(2), 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), @@ -476,8 +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)), @@ -487,12 +547,15 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - 42, + Some(42), account(2), 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!(Collection::::get(0).unwrap().item_holders, 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -1746,15 +1809,20 @@ fn burn_works() { account(5), 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!( 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_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); }); } @@ -1777,7 +1845,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), None )); @@ -1791,7 +1859,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(2), None )); @@ -1819,7 +1887,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - 1, + Some(1), account(2), None ), @@ -1829,7 +1897,7 @@ fn approval_lifecycle_works() { } #[test] -fn cancel_approval_works() { +fn check_allowance_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -1844,33 +1912,95 @@ fn cancel_approval_works() { 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(&1, &None, &account(1), &account(2)), + Error::::NoPermission + ); + assert_noop!( + 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))); + + // 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(|| { + 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, + 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,22 +2017,72 @@ 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![]); }); } +#[test] +fn cancel_approval_collection_works_with_admin() { + 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_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: 0, + item: None, + owner: account(1), + 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)), + Error::::NoPermission + ); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -1924,21 +2104,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,19 +2159,83 @@ 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 ); }); } +#[test] +fn approval_collection_works_with_admin() { + 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), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(1), + default_item_config() + )); + + // 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::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(1)), + 0, + None, + account(3), + None + )); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: account(1), + delegate: account(3), + 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))); + }); +} + #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2015,7 +2259,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - 42, + Some(42), account(3), Some(2) )); @@ -2034,7 +2278,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - 42, + Some(42), account(6), Some(4) )); @@ -2063,26 +2307,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 +2356,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 +2400,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 )); @@ -2188,6 +2437,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(|| { @@ -2524,6 +2803,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(); @@ -2891,6 +3171,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, @@ -2981,6 +3263,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(); @@ -3169,7 +3453,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 ), @@ -3870,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 f08f1d09..46148d63 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -94,18 +94,22 @@ 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 accounts that hold items of the collection. + pub item_holders: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + 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 c5fb60a2..b3307503 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-11-16, 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)] @@ -53,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; @@ -76,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; @@ -98,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) @@ -107,17 +90,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -126,21 +109,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -152,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -171,72 +160,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(T::DbWeight::get().reads(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) @@ -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)` - // 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())) + // 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()))) @@ -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: 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)) } @@ -299,79 +296,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -381,15 +378,15 @@ 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)) } /// 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) @@ -400,23 +397,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -427,33 +424,33 @@ 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: `983` + // Measured: `951` // 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(37_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: 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)) @@ -476,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) @@ -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: `507` // 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)) } @@ -497,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -514,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -547,34 +544,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +591,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -608,10 +617,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(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -625,10 +634,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: 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)) } @@ -636,36 +645,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -673,10 +684,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: 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)) } @@ -686,10 +697,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: 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)) } @@ -697,26 +708,28 @@ 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) /// 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: `915` // 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: 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(13_u64)) } /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) @@ -725,7 +738,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -739,26 +754,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -766,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: `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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) @@ -785,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) @@ -794,17 +809,17 @@ 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` - // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Measured: `105` + // 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) @@ -813,21 +828,25 @@ 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` - // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Measured: `3` + // 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) /// 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::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) @@ -839,15 +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: `32204 + a * (366 ±0)` + // Measured: `32875 + 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(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()))) @@ -858,72 +879,78 @@ 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) + /// 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: `390` // 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: 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)) } /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, 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::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) + /// 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: `390` // 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(39_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`) /// 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) /// 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: `584` // 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: 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) @@ -932,6 +959,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,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: `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: `613` + // Estimated: `6068` + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(38_000_000, 6068) + .saturating_add(RocksDbWeight::get().reads(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) @@ -956,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: `763 + 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())) + // 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()))) @@ -973,10 +1002,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: 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)) } @@ -986,79 +1015,79 @@ 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: 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: `340` - // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `562` + // Measured: `425` // 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)) } /// 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: `369` + // Measured: `304` // 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)) } /// 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: `311` - // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Measured: `246` + // Estimated: `3557` + // Minimum execution time: 11_000_000 picoseconds. + 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: `276` - // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Measured: `203` + // Estimated: `3557` + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1068,15 +1097,15 @@ 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)) } /// 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) @@ -1087,23 +1116,23 @@ 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: `507` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_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: `344` + // Measured: `279` // 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)) } @@ -1114,33 +1143,33 @@ 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: `983` + // Measured: `951` // 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(37_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 +1177,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: 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)) @@ -1163,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) @@ -1172,10 +1201,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: `507` // 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)) } @@ -1184,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: `849` + // Measured: `817` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_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)) } @@ -1201,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: `398` + // Measured: `333` // 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(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: `716` + // Measured: `651` // 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(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1234,34 +1263,46 @@ 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: `410` - // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_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: `418` - // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 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(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`) 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,23 +1310,23 @@ 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(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: `340` - // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Measured: `275` + // Estimated: `3557` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 3557) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1295,10 +1336,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(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1312,10 +1353,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: 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)) } @@ -1323,36 +1364,38 @@ 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) /// 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: `725` + // Estimated: `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(8_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(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`) @@ -1360,10 +1403,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: 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)) } @@ -1373,10 +1416,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: 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)) } @@ -1384,26 +1427,28 @@ 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) /// 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: `915` // 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: 78_000_000 picoseconds. + Weight::from_parts(79_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(11_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`) @@ -1412,7 +1457,9 @@ 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) /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1426,26 +1473,26 @@ 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: `493` // 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: 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(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) - /// 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) @@ -1453,12 +1500,12 @@ 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: `522` + // Estimated: `4466 + n * (2954 ±0)` + // 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)) From 69dd5f85453abf1fce74e8a939cb591d235b0951 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 20 Nov 2024 00:37:09 +0700 Subject: [PATCH 10/99] chore: resolve feedback --- pallets/nfts/src/common_functions.rs | 2 +- pallets/nfts/src/features/approvals.rs | 22 +++++++++++----------- pallets/nfts/src/tests.rs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index abd8b61d..6158eab8 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -64,7 +64,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 2647492c..3e3d5e63 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -180,7 +180,6 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -188,20 +187,21 @@ impl, I: 'static> Pallet { Error::::ItemsNonTransferable ); - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - - Allowances::::mutate((&collection, &owner, &delegate), |allowance| { - *allowance = true; - }); - Collection::::try_mutate( + let owner = Collection::::try_mutate( &collection, - |maybe_collection_details| -> Result<(), DispatchError> { + |maybe_collection_details| -> Result { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + let owner = collection_details.clone().owner; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + Allowances::::mutate((&collection, &owner, &delegate), |allowance| { + *allowance = true; + }); collection_details.allowances.saturating_inc(); - Ok(()) + Ok(owner) }, )?; diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 6d0c894a..0a77aa8c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2213,7 +2213,7 @@ fn approval_collection_works_with_admin() { // Error::UnknownCollection. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), - Error::::UnknownCollection + Error::::NoConfig ); assert_ok!(Nfts::approve_transfer( From 4a5f17c347f89c1261a27ad16f3dd992de22eab6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:13:50 +0700 Subject: [PATCH 11/99] fix(nfts): clippy warnings --- pallets/nfts/src/benchmarking.rs | 16 ++-- pallets/nfts/src/common_functions.rs | 4 +- pallets/nfts/src/features/approvals.rs | 14 ++- pallets/nfts/src/features/atomic_swap.rs | 22 ++--- pallets/nfts/src/features/attributes.rs | 29 +++--- pallets/nfts/src/features/buy_sell.rs | 10 +-- .../src/features/create_delete_collection.rs | 14 +-- .../nfts/src/features/create_delete_item.rs | 90 +++++++++---------- pallets/nfts/src/features/lock.rs | 8 +- pallets/nfts/src/features/metadata.rs | 24 ++--- pallets/nfts/src/features/roles.rs | 16 ++-- pallets/nfts/src/features/settings.rs | 16 ++-- pallets/nfts/src/features/transfer.rs | 19 ++-- pallets/nfts/src/impl_nonfungibles.rs | 4 +- pallets/nfts/src/lib.rs | 8 +- pallets/nfts/src/migration.rs | 2 +- 16 files changed, 145 insertions(+), 151 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 8fa87557..bc25602c 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -17,8 +17,6 @@ //! Nfts pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] - use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -74,8 +72,8 @@ fn mint_item, I: 'static>( whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); - let item_exists = Item::::contains_key(&collection, &item); - let item_config = ItemConfigOf::::get(&collection, &item); + let item_exists = Item::::contains_key(collection, item); + let item_config = ItemConfigOf::::get(collection, item); if item_exists { return (item, caller, caller_lookup) } else if let Some(item_config) = item_config { @@ -682,7 +680,7 @@ benchmarks_instance_pallet! { } pay_tips { - let n in 0 .. T::MaxTips::get() as u32; + let n in 0 .. T::MaxTips::get(); let amount = BalanceOf::::from(100u32); let caller: T::AccountId = whitelisted_caller(); let collection = T::Helper::collection(0); @@ -788,7 +786,7 @@ benchmarks_instance_pallet! { } mint_pre_signed { - let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let n in 0 .. T::MaxAttributesPerCall::get(); let (caller_public, caller) = T::Helper::signer(); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let caller_lookup = T::Lookup::unlookup(caller.clone()); @@ -823,14 +821,14 @@ benchmarks_instance_pallet! { let target: T::AccountId = account("target", 0, SEED); T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); frame_system::Pallet::::set_block_number(One::one()); - }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature.into(), caller) + }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature, caller) verify { let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); } set_attributes_pre_signed { - let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let n in 0 .. T::MaxAttributesPerCall::get(); let (collection, _, _) = create_collection::(); let item_owner: T::AccountId = account("item_owner", 0, SEED); @@ -866,7 +864,7 @@ benchmarks_instance_pallet! { let signature = T::Helper::sign(&signer_public, &message); frame_system::Pallet::::set_block_number(One::one()); - }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature.into(), signer.clone()) + }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature, signer.clone()) verify { assert_last_event::( Event::PreSignedAttributesSet { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index f51de192..c13293b3 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -45,7 +45,7 @@ impl, I: 'static> Pallet { signature: &T::OffchainSignature, signer: &T::AccountId, ) -> DispatchResult { - if signature.verify(&**data, &signer) { + if signature.verify(&**data, signer) { return Ok(()) } @@ -58,7 +58,7 @@ impl, I: 'static> Pallet { wrapped.extend(data); wrapped.extend(suffix); - ensure!(signature.verify(&*wrapped, &signer), Error::::WrongSignature); + ensure!(signature.verify(&*wrapped, signer), Error::::WrongSignature); Ok(()) } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ad5d93c2..5ffaeea7 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -53,8 +53,7 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -73,7 +72,7 @@ impl, I: 'static> Pallet { .approvals .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::TransferApproved { collection, @@ -106,8 +105,7 @@ impl, I: 'static> Pallet { item: T::ItemId, delegate: T::AccountId, ) -> DispatchResult { - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; @@ -125,7 +123,7 @@ impl, I: 'static> Pallet { } details.approvals.remove(&delegate); - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::ApprovalCancelled { collection, @@ -156,14 +154,14 @@ impl, I: 'static> Pallet { item: T::ItemId, ) -> DispatchResult { let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; if let Some(check_origin) = maybe_check_origin { ensure!(check_origin == details.owner, Error::::NoPermission); } details.approvals.clear(); - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::AllApprovalsCancelled { collection, diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 31c93fba..6c15f15a 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -62,17 +62,17 @@ impl, I: 'static> Pallet { ); ensure!(duration <= T::MaxDeadlineDuration::get(), Error::::WrongDuration); - let item = Item::::get(&offered_collection_id, &offered_item_id) + let item = Item::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownItem)?; ensure!(item.owner == caller, Error::::NoPermission); match maybe_desired_item_id { Some(desired_item_id) => ensure!( - Item::::contains_key(&desired_collection_id, &desired_item_id), + Item::::contains_key(desired_collection_id, desired_item_id), Error::::UnknownItem ), None => ensure!( - Collection::::contains_key(&desired_collection_id), + Collection::::contains_key(desired_collection_id), Error::::UnknownCollection ), }; @@ -81,8 +81,8 @@ impl, I: 'static> Pallet { let deadline = duration.saturating_add(now); PendingSwapOf::::insert( - &offered_collection_id, - &offered_item_id, + offered_collection_id, + offered_item_id, PendingSwap { desired_collection: desired_collection_id, desired_item: maybe_desired_item_id, @@ -118,17 +118,17 @@ impl, I: 'static> Pallet { offered_collection_id: T::CollectionId, offered_item_id: T::ItemId, ) -> DispatchResult { - let swap = PendingSwapOf::::get(&offered_collection_id, &offered_item_id) + let swap = PendingSwapOf::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownSwap)?; let now = frame_system::Pallet::::block_number(); if swap.deadline > now { - let item = Item::::get(&offered_collection_id, &offered_item_id) + let item = Item::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownItem)?; ensure!(item.owner == caller, Error::::NoPermission); } - PendingSwapOf::::remove(&offered_collection_id, &offered_item_id); + PendingSwapOf::::remove(offered_collection_id, offered_item_id); Self::deposit_event(Event::SwapCancelled { offered_collection: offered_collection_id, @@ -172,11 +172,11 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let send_item = Item::::get(&send_collection_id, &send_item_id) + let send_item = Item::::get(send_collection_id, send_item_id) .ok_or(Error::::UnknownItem)?; - let receive_item = Item::::get(&receive_collection_id, &receive_item_id) + let receive_item = Item::::get(receive_collection_id, receive_item_id) .ok_or(Error::::UnknownItem)?; - let swap = PendingSwapOf::::get(&receive_collection_id, &receive_item_id) + let swap = PendingSwapOf::::get(receive_collection_id, receive_item_id) .ok_or(Error::::UnknownSwap)?; ensure!(send_item.owner == caller, Error::::NoPermission); diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index ab0cdc68..d3e9520f 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -87,7 +87,7 @@ impl, I: 'static> Pallet { } let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); let attribute_exists = attribute.is_some(); @@ -183,7 +183,7 @@ impl, I: 'static> Pallet { value: BoundedVec, ) -> DispatchResult { let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); if let Some((_, deposit)) = attribute { @@ -229,8 +229,7 @@ impl, I: 'static> Pallet { let now = frame_system::Pallet::::block_number(); ensure!(deadline >= now, Error::::DeadlineExpired); - let item_details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let item_details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!(item_details.owner == origin, Error::::NoPermission); // Only the CollectionOwner and Account() namespaces could be updated in this way. @@ -239,7 +238,7 @@ impl, I: 'static> Pallet { AttributeNamespace::CollectionOwner => {}, AttributeNamespace::Account(account) => { ensure!(account == &signer, Error::::NoPermission); - let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); + let approvals = ItemAttributesApprovalsOf::::get(collection, item); if !approvals.contains(account) { Self::do_approve_item_attributes( origin.clone(), @@ -274,7 +273,7 @@ impl, I: 'static> Pallet { /// `depositor` account. The deposit associated with the attribute, if any, will be unreserved. /// /// - `maybe_check_origin`: An optional account that acts as an additional security check when - /// clearing the attribute. This can be `None` if no additional check is required. + /// clearing the attribute. This can be `None` if no additional check is required. /// - `collection`: The identifier of the collection to which the item belongs, or the /// collection itself if clearing a collection attribute. /// - `maybe_item`: The identifier of the item to which the attribute belongs, or `None` if @@ -298,7 +297,7 @@ impl, I: 'static> Pallet { // the same as the `deposit.account` (e.g. the deposit was paid by different account) if deposit.account != maybe_check_origin { ensure!( - Self::is_valid_namespace(&check_origin, &namespace, &collection, &maybe_item)?, + Self::is_valid_namespace(check_origin, &namespace, &collection, &maybe_item)?, Error::::NoPermission ); } @@ -327,7 +326,7 @@ impl, I: 'static> Pallet { // e.g. in off-chain mints, the attribute's depositor will be the item's // owner, that's why we need to do this extra check. ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } @@ -338,7 +337,7 @@ impl, I: 'static> Pallet { } let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; collection_details.attributes.saturating_dec(); @@ -381,7 +380,7 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!(check_origin == details.owner, Error::::NoPermission); ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { @@ -422,7 +421,7 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!(check_origin == details.owner, Error::::NoPermission); ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { @@ -463,17 +462,17 @@ impl, I: 'static> Pallet { let mut result = false; match namespace { AttributeNamespace::CollectionOwner => - result = Self::has_role(&collection, &origin, CollectionRole::Admin), + result = Self::has_role(collection, origin, CollectionRole::Admin), AttributeNamespace::ItemOwner => if let Some(item) = maybe_item { let item_details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + Item::::get(collection, item).ok_or(Error::::UnknownItem)?; result = origin == &item_details.owner }, AttributeNamespace::Account(account_id) => if let Some(item) = maybe_item { - let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); - result = account_id == origin && approvals.contains(&origin) + let approvals = ItemAttributesApprovalsOf::::get(collection, item); + result = account_id == origin && approvals.contains(origin) }, _ => (), }; diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index 8cf86f79..476053ee 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -82,7 +82,7 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!(details.owner == sender, Error::::NoPermission); let collection_config = Self::get_collection_config(&collection)?; @@ -98,7 +98,7 @@ impl, I: 'static> Pallet { ); if let Some(ref price) = price { - ItemPriceOf::::insert(&collection, &item, (price, whitelisted_buyer.clone())); + ItemPriceOf::::insert(collection, item, (price, whitelisted_buyer.clone())); Self::deposit_event(Event::ItemPriceSet { collection, item, @@ -106,7 +106,7 @@ impl, I: 'static> Pallet { whitelisted_buyer, }); } else { - ItemPriceOf::::remove(&collection, &item); + ItemPriceOf::::remove(collection, item); Self::deposit_event(Event::ItemPriceRemoved { collection, item }); } @@ -137,11 +137,11 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!(details.owner != buyer, Error::::NoPermission); let price_info = - ItemPriceOf::::get(&collection, &item).ok_or(Error::::NotForSale)?; + ItemPriceOf::::get(collection, item).ok_or(Error::::NotForSale)?; ensure!(bid_price >= price_info.0, Error::::BidTooLow); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 348ec6b9..60286d70 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -65,8 +65,8 @@ impl, I: 'static> Pallet { ), ); - CollectionConfigOf::::insert(&collection, config); - CollectionAccount::::insert(&owner, &collection, ()); + CollectionConfigOf::::insert(collection, config); + CollectionAccount::::insert(&owner, collection, ()); Self::deposit_event(event); @@ -120,13 +120,13 @@ impl, I: 'static> Pallet { Error::::BadWitness ); - for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { + for (_, metadata) in ItemMetadataOf::::drain_prefix(collection) { if let Some(depositor) = metadata.deposit.account { T::Currency::unreserve(&depositor, metadata.deposit.amount); } } - CollectionMetadataOf::::remove(&collection); + CollectionMetadataOf::::remove(collection); Self::clear_roles(&collection)?; for (_, (_, deposit)) in Attribute::::drain_prefix((&collection,)) { @@ -137,10 +137,10 @@ impl, I: 'static> Pallet { } } - CollectionAccount::::remove(&collection_details.owner, &collection); + CollectionAccount::::remove(&collection_details.owner, collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); - CollectionConfigOf::::remove(&collection); - let _ = ItemConfigOf::::clear_prefix(&collection, witness.item_configs, None); + CollectionConfigOf::::remove(collection); + let _ = ItemConfigOf::::clear_prefix(collection, witness.item_configs, None); Self::deposit_event(Event::Destroyed { collection }); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9843b2e..7a69de9e 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -55,55 +55,51 @@ impl, I: 'static> Pallet { ) -> DispatchResult { ensure!(!Item::::contains_key(collection, item), Error::::AlreadyExists); - Collection::::try_mutate( - &collection, - |maybe_collection_details| -> DispatchResult { - let collection_details = - maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + Collection::::try_mutate(collection, |maybe_collection_details| -> DispatchResult { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let collection_config = Self::get_collection_config(&collection)?; - with_details_and_config(collection_details, &collection_config)?; + let collection_config = Self::get_collection_config(&collection)?; + with_details_and_config(collection_details, &collection_config)?; - if let Some(max_supply) = collection_config.max_supply { - ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); - } + if let Some(max_supply) = collection_config.max_supply { + ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); + } - collection_details.items.saturating_inc(); + collection_details.items.saturating_inc(); - let collection_config = Self::get_collection_config(&collection)?; - let deposit_amount = match collection_config - .is_setting_enabled(CollectionSetting::DepositRequired) - { + let collection_config = Self::get_collection_config(&collection)?; + let deposit_amount = + match collection_config.is_setting_enabled(CollectionSetting::DepositRequired) { true => T::ItemDeposit::get(), false => Zero::zero(), }; - let deposit_account = match maybe_depositor { - None => collection_details.owner.clone(), - Some(depositor) => depositor, - }; + let deposit_account = match maybe_depositor { + None => collection_details.owner.clone(), + Some(depositor) => depositor, + }; - let item_owner = mint_to.clone(); - Account::::insert((&item_owner, &collection, &item), ()); + let item_owner = mint_to.clone(); + Account::::insert((&item_owner, &collection, &item), ()); - if let Ok(existing_config) = ItemConfigOf::::try_get(&collection, &item) { - ensure!(existing_config == item_config, Error::::InconsistentItemConfig); - } else { - ItemConfigOf::::insert(&collection, &item, item_config); - collection_details.item_configs.saturating_inc(); - } + if let Ok(existing_config) = ItemConfigOf::::try_get(collection, item) { + ensure!(existing_config == item_config, Error::::InconsistentItemConfig); + } else { + ItemConfigOf::::insert(collection, item, item_config); + collection_details.item_configs.saturating_inc(); + } - T::Currency::reserve(&deposit_account, deposit_amount)?; + T::Currency::reserve(&deposit_account, deposit_amount)?; - let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; - let details = ItemDetails { - owner: item_owner, - approvals: ApprovalsOf::::default(), - deposit, - }; - Item::::insert(&collection, &item, details); - Ok(()) - }, - )?; + let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; + let details = ItemDetails { + owner: item_owner, + approvals: ApprovalsOf::::default(), + deposit, + }; + Item::::insert(collection, item, details); + Ok(()) + })?; Self::deposit_event(Event::Issued { collection, item, owner: mint_to }); Ok(()) @@ -221,12 +217,12 @@ impl, I: 'static> Pallet { // then we keep the config record and don't remove it let remove_config = !item_config.has_disabled_settings(); let owner = Collection::::try_mutate( - &collection, + collection, |maybe_collection_details| -> Result { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let details = Item::::get(&collection, &item) - .ok_or(Error::::UnknownCollection)?; + let details = + Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; with_details(&details)?; // Return the deposit. @@ -239,7 +235,7 @@ impl, I: 'static> Pallet { // Clear the metadata if it's not locked. if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) { - if let Some(metadata) = ItemMetadataOf::::take(&collection, &item) { + if let Some(metadata) = ItemMetadataOf::::take(collection, item) { let depositor_account = metadata.deposit.account.unwrap_or(collection_details.owner.clone()); @@ -258,14 +254,14 @@ impl, I: 'static> Pallet { }, )?; - Item::::remove(&collection, &item); + Item::::remove(collection, item); Account::::remove((&owner, &collection, &item)); - ItemPriceOf::::remove(&collection, &item); - PendingSwapOf::::remove(&collection, &item); - ItemAttributesApprovalsOf::::remove(&collection, &item); + ItemPriceOf::::remove(collection, item); + PendingSwapOf::::remove(collection, item); + ItemAttributesApprovalsOf::::remove(collection, item); if remove_config { - ItemConfigOf::::remove(&collection, &item); + ItemConfigOf::::remove(collection, item); } Self::deposit_event(Event::Burned { collection, item, owner }); diff --git a/pallets/nfts/src/features/lock.rs b/pallets/nfts/src/features/lock.rs index 4649f4a0..a013d014 100644 --- a/pallets/nfts/src/features/lock.rs +++ b/pallets/nfts/src/features/lock.rs @@ -29,7 +29,7 @@ impl, I: 'static> Pallet { /// settings on the collection. The only setting that can't be disabled is `DepositRequired`. /// /// 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. @@ -80,7 +80,7 @@ impl, I: 'static> Pallet { if !config.has_disabled_setting(ItemSetting::Transferable) { config.disable_setting(ItemSetting::Transferable); } - ItemConfigOf::::insert(&collection, &item, config); + ItemConfigOf::::insert(collection, item, config); Self::deposit_event(Event::::ItemTransferLocked { collection, item }); Ok(()) @@ -110,7 +110,7 @@ impl, I: 'static> Pallet { if config.has_disabled_setting(ItemSetting::Transferable) { config.enable_setting(ItemSetting::Transferable); } - ItemConfigOf::::insert(&collection, &item, config); + ItemConfigOf::::insert(collection, item, config); Self::deposit_event(Event::::ItemTransferUnlocked { collection, item }); Ok(()) @@ -140,7 +140,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index b3d16b12..3cb18f85 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -50,14 +50,14 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } let is_root = maybe_check_origin.is_none(); let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; let item_config = Self::get_item_config(&collection, &item)?; ensure!( @@ -106,7 +106,7 @@ impl, I: 'static> Pallet { data: data.clone(), }); - Collection::::insert(&collection, &collection_details); + Collection::::insert(collection, &collection_details); Self::deposit_event(Event::ItemMetadataSet { collection, item, data }); Ok(()) }) @@ -132,7 +132,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } @@ -141,7 +141,7 @@ impl, I: 'static> Pallet { let metadata = ItemMetadataOf::::take(collection, item) .ok_or(Error::::MetadataNotFound)?; let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; let depositor_account = metadata.deposit.account.unwrap_or(collection_details.owner.clone()); @@ -159,7 +159,7 @@ impl, I: 'static> Pallet { collection_details.owner_deposit.saturating_reduce(metadata.deposit.amount); } - Collection::::insert(&collection, &collection_details); + Collection::::insert(collection, &collection_details); Self::deposit_event(Event::ItemMetadataCleared { collection, item }); Ok(()) @@ -185,7 +185,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } @@ -198,7 +198,7 @@ impl, I: 'static> Pallet { ); let mut details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); @@ -217,7 +217,7 @@ impl, I: 'static> Pallet { } details.owner_deposit.saturating_accrue(deposit); - Collection::::insert(&collection, details); + Collection::::insert(collection, details); *metadata = Some(CollectionMetadata { deposit, data: data.clone() }); @@ -245,13 +245,13 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Self::has_role(&collection, check_origin, CollectionRole::Admin), Error::::NoPermission ); } let mut details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -264,7 +264,7 @@ impl, I: 'static> Pallet { let deposit = metadata.take().ok_or(Error::::UnknownCollection)?.deposit; T::Currency::unreserve(&details.owner, deposit); details.owner_deposit.saturating_reduce(deposit); - Collection::::insert(&collection, details); + Collection::::insert(collection, details); Self::deposit_event(Event::CollectionMetadataCleared { collection }); Ok(()) }) diff --git a/pallets/nfts/src/features/roles.rs b/pallets/nfts/src/features/roles.rs index 053eaf0b..8ddec338 100644 --- a/pallets/nfts/src/features/roles.rs +++ b/pallets/nfts/src/features/roles.rs @@ -81,7 +81,7 @@ impl, I: 'static> Pallet { // Insert new records. for (account, roles) in account_to_role { - CollectionRoleOf::::insert(&collection, &account, roles); + CollectionRoleOf::::insert(collection, &account, roles); } Self::deposit_event(Event::TeamChanged { collection, issuer, admin, freezer }); @@ -98,7 +98,7 @@ impl, I: 'static> Pallet { /// may need to be adjusted. pub(crate) fn clear_roles(collection_id: &T::CollectionId) -> Result<(), DispatchError> { let res = CollectionRoleOf::::clear_prefix( - &collection_id, + collection_id, CollectionRoles::max_roles() as u32, None, ); @@ -118,7 +118,7 @@ impl, I: 'static> Pallet { account_id: &T::AccountId, role: CollectionRole, ) -> bool { - CollectionRoleOf::::get(&collection_id, &account_id) + CollectionRoleOf::::get(collection_id, account_id) .map_or(false, |roles| roles.has_role(role)) } @@ -132,9 +132,13 @@ impl, I: 'static> Pallet { collection_id: &T::CollectionId, role: CollectionRole, ) -> Option { - CollectionRoleOf::::iter_prefix(&collection_id).into_iter().find_map( - |(account, roles)| if roles.has_role(role) { Some(account.clone()) } else { None }, - ) + CollectionRoleOf::::iter_prefix(collection_id).find_map(|(account, roles)| { + if roles.has_role(role) { + Some(account.clone()) + } else { + None + } + }) } /// Groups provided roles by account, given one account could have multiple roles. diff --git a/pallets/nfts/src/features/settings.rs b/pallets/nfts/src/features/settings.rs index 9c7ac7ca..22495bc9 100644 --- a/pallets/nfts/src/features/settings.rs +++ b/pallets/nfts/src/features/settings.rs @@ -33,8 +33,8 @@ impl, I: 'static> Pallet { collection: T::CollectionId, config: CollectionConfigFor, ) -> DispatchResult { - ensure!(Collection::::contains_key(&collection), Error::::UnknownCollection); - CollectionConfigOf::::insert(&collection, config); + ensure!(Collection::::contains_key(collection), Error::::UnknownCollection); + CollectionConfigOf::::insert(collection, config); Self::deposit_event(Event::CollectionConfigChanged { collection }); Ok(()) } @@ -67,7 +67,7 @@ impl, I: 'static> Pallet { ); let details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &details.owner, Error::::NoPermission); } @@ -105,7 +105,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( - Self::has_role(&collection, &check_origin, CollectionRole::Issuer), + Self::has_role(&collection, check_origin, CollectionRole::Issuer), Error::::NoPermission ); } @@ -129,7 +129,7 @@ impl, I: 'static> Pallet { collection_id: &T::CollectionId, ) -> Result, DispatchError> { let config = - CollectionConfigOf::::get(&collection_id).ok_or(Error::::NoConfig)?; + CollectionConfigOf::::get(collection_id).ok_or(Error::::NoConfig)?; Ok(config) } @@ -145,8 +145,8 @@ impl, I: 'static> Pallet { collection_id: &T::CollectionId, item_id: &T::ItemId, ) -> Result { - let config = ItemConfigOf::::get(&collection_id, &item_id) - .ok_or(Error::::UnknownItem)?; + let config = + ItemConfigOf::::get(collection_id, item_id).ok_or(Error::::UnknownItem)?; Ok(config) } @@ -174,6 +174,6 @@ impl, I: 'static> Pallet { /// otherwise it returns `false`. pub(crate) fn is_pallet_feature_enabled(feature: PalletFeature) -> bool { let features = T::Features::get(); - return features.is_enabled(feature) + features.is_enabled(feature) } } diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index b7223a7c..e0ae770a 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -55,7 +55,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { // Retrieve collection details. let collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); @@ -81,8 +81,7 @@ impl, I: 'static> Pallet { ); // Retrieve the item details. - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; @@ -99,9 +98,9 @@ impl, I: 'static> Pallet { details.approvals.clear(); // Update item details. - Item::::insert(&collection, &item, &details); - ItemPriceOf::::remove(&collection, &item); - PendingSwapOf::::remove(&collection, &item); + Item::::insert(collection, item, &details); + ItemPriceOf::::remove(collection, item); + PendingSwapOf::::remove(collection, item); // Emit `Transferred` event. Self::deposit_event(Event::Transferred { @@ -149,8 +148,8 @@ impl, I: 'static> Pallet { )?; // Update account ownership information. - CollectionAccount::::remove(&details.owner, &collection); - CollectionAccount::::insert(&new_owner, &collection, ()); + CollectionAccount::::remove(&details.owner, collection); + CollectionAccount::::insert(&new_owner, collection, ()); details.owner = new_owner.clone(); OwnershipAcceptance::::remove(&new_owner); @@ -224,8 +223,8 @@ impl, I: 'static> Pallet { )?; // Update collection accounts and set the new owner. - CollectionAccount::::remove(&details.owner, &collection); - CollectionAccount::::insert(&owner, &collection, ()); + CollectionAccount::::remove(&details.owner, collection); + CollectionAccount::::insert(&owner, collection, ()); details.owner = owner.clone(); // Emit `OwnerChanged` event. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index 362cccd9..cf3cbb61 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -120,7 +120,7 @@ impl, I: 'static> Inspect<::AccountId> for Palle /// Default implementation is that all items are transferable. fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool { use PalletAttributes::TransferDisabled; - match Self::has_system_attribute(&collection, &item, TransferDisabled) { + match Self::has_system_attribute(collection, item, TransferDisabled) { Ok(transfer_disabled) if transfer_disabled => return false, _ => (), } @@ -421,7 +421,7 @@ impl, I: 'static> Transfer for Pallet { fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { let transfer_disabled = - Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?; + Self::has_system_attribute(collection, item, PalletAttributes::TransferDisabled)?; // Can't lock the item twice if transfer_disabled { return Err(Error::::ItemLocked.into()) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 89bfb963..8aaee260 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -67,7 +67,7 @@ pub use types::*; pub use weights::WeightInfo; /// The log target of this pallet. -pub const LOG_TARGET: &'static str = "runtime::nfts"; +pub const LOG_TARGET: &str = "runtime::nfts"; /// A type alias for the account ID type used in the dispatchable functions of this pallet. type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; @@ -1068,7 +1068,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; ensure!(collection_details.owner == origin, Error::::NoPermission); let config = Self::get_collection_config(&collection)?; @@ -1079,7 +1079,7 @@ pub mod pallet { let mut successful = Vec::with_capacity(items.len()); for item in items.into_iter() { - let mut details = match Item::::get(&collection, &item) { + let mut details = match Item::::get(collection, item) { Some(x) => x, None => continue, }; @@ -1096,7 +1096,7 @@ pub mod pallet { continue } details.deposit.amount = deposit; - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); successful.push(item); } diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index af611bf1..ae7e88a7 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -71,7 +71,7 @@ pub mod v1 { OldCollectionDetails>, _, >(|key, old_value| { - let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; + 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)) From 37ec9abb4c9c625b4a8fa1d92e3e9c1d5a1568a1 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 21 Nov 2024 23:28:48 +0700 Subject: [PATCH 12/99] fix: clippy warnings --- pallets/nfts/src/features/attributes.rs | 14 ++++++-------- pallets/nfts/src/impl_nonfungibles.rs | 15 +++++---------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/pallets/nfts/src/features/attributes.rs b/pallets/nfts/src/features/attributes.rs index d3e9520f..b7ba769a 100644 --- a/pallets/nfts/src/features/attributes.rs +++ b/pallets/nfts/src/features/attributes.rs @@ -69,8 +69,8 @@ impl, I: 'static> Pallet { let collection_config = Self::get_collection_config(&collection)?; // for the `CollectionOwner` namespace we need to check if the collection/item is not locked - match namespace { - AttributeNamespace::CollectionOwner => match maybe_item { + if namespace == AttributeNamespace::CollectionOwner { + match maybe_item { None => { ensure!( collection_config.is_setting_enabled(CollectionSetting::UnlockedAttributes), @@ -82,8 +82,7 @@ impl, I: 'static> Pallet { .map(|c| c.has_disabled_setting(ItemSetting::UnlockedAttributes))?; ensure!(!maybe_is_locked, Error::::LockedItemAttributes); }, - }, - _ => (), + } } let mut collection_details = @@ -303,8 +302,8 @@ impl, I: 'static> Pallet { } // can't clear `CollectionOwner` type attributes if the collection/item is locked - match namespace { - AttributeNamespace::CollectionOwner => match maybe_item { + if namespace == AttributeNamespace::CollectionOwner { + match maybe_item { None => { let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -331,8 +330,7 @@ impl, I: 'static> Pallet { ); } }, - }, - _ => (), + } }; } diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index cf3cbb61..b014e3ed 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -124,16 +124,11 @@ impl, I: 'static> Inspect<::AccountId> for Palle Ok(transfer_disabled) if transfer_disabled => return false, _ => (), } - match ( - CollectionConfigOf::::get(collection), - ItemConfigOf::::get(collection, item), - ) { - (Some(cc), Some(ic)) - if cc.is_setting_enabled(CollectionSetting::TransferableItems) && - ic.is_setting_enabled(ItemSetting::Transferable) => - true, - _ => false, - } + matches!( + (CollectionConfigOf::::get(collection), ItemConfigOf::::get(collection, item)), + (Some(cc), Some(ic)) if cc.is_setting_enabled(CollectionSetting::TransferableItems) + && ic.is_setting_enabled(ItemSetting::Transferable) + ) } } From 3e886a92ea775e59da015216043787d8325a45d7 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:06:29 +0700 Subject: [PATCH 13/99] fix: warnings --- pallets/nfts/src/common_functions.rs | 1 + pallets/nfts/src/features/metadata.rs | 13 +++++++++---- pallets/nfts/src/lib.rs | 27 +++++++++++++++++---------- pallets/nfts/src/migration.rs | 2 ++ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index c13293b3..f9224046 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -69,6 +69,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); } + #[allow(missing_docs)] #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_next_id(id: T::CollectionId) { NextCollectionId::::set(Some(id)); diff --git a/pallets/nfts/src/features/metadata.rs b/pallets/nfts/src/features/metadata.rs index 3cb18f85..8c630832 100644 --- a/pallets/nfts/src/features/metadata.rs +++ b/pallets/nfts/src/features/metadata.rs @@ -18,6 +18,7 @@ //! This module contains helper methods to configure the metadata of collections and items. use alloc::vec::Vec; +use core::cmp::Ordering; use frame_support::pallet_prelude::*; @@ -210,10 +211,14 @@ impl, I: 'static> Pallet { .saturating_mul(((data.len()) as u32).into()) .saturating_add(T::MetadataDepositBase::get()); } - if deposit > old_deposit { - T::Currency::reserve(&details.owner, deposit - old_deposit)?; - } else if deposit < old_deposit { - T::Currency::unreserve(&details.owner, old_deposit - deposit); + match deposit.cmp(&old_deposit) { + Ordering::Greater => { + T::Currency::reserve(&details.owner, deposit - old_deposit)?; + }, + Ordering::Less => { + T::Currency::unreserve(&details.owner, old_deposit - deposit); + }, + _ => {}, } details.owner_deposit.saturating_accrue(deposit); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 8aaee260..90d2a622 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +#[allow(missing_docs)] pub mod migration; #[cfg(test)] pub mod mock; @@ -45,12 +46,14 @@ mod features; mod impl_nonfungibles; mod types; +#[allow(missing_docs)] pub mod macros; pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; +use core::cmp::Ordering; use codec::{Decode, Encode}; use frame_support::traits::{ @@ -87,6 +90,7 @@ pub mod pallet { pub struct Pallet(PhantomData<(T, I)>); #[cfg(feature = "runtime-benchmarks")] + #[allow(missing_docs)] pub trait BenchmarkHelper { fn collection(i: u16) -> CollectionId; fn item(i: u16) -> ItemId; @@ -416,6 +420,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[allow(missing_docs)] pub enum Event, I: 'static = ()> { /// A `collection` was created. Created { collection: T::CollectionId, creator: T::AccountId, owner: T::AccountId }, @@ -1084,16 +1089,18 @@ pub mod pallet { None => continue, }; let old = details.deposit.amount; - if old > deposit { - T::Currency::unreserve(&details.deposit.account, old - deposit); - } else if deposit > old { - 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 - } - } else { - continue + match old.cmp(&deposit) { + Ordering::Greater => { + T::Currency::unreserve(&details.deposit.account, old - deposit); + }, + Ordering::Less => { + 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, } details.deposit.amount = deposit; Item::::insert(collection, item, &details); diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs index ae7e88a7..7d59b481 100644 --- a/pallets/nfts/src/migration.rs +++ b/pallets/nfts/src/migration.rs @@ -22,12 +22,14 @@ use sp_runtime::TryRuntimeError; use super::*; +#[allow(missing_docs)] pub mod v1 { use frame_support::{pallet_prelude::*, weights::Weight}; use super::*; #[derive(Decode)] + #[allow(missing_docs)] pub struct OldCollectionDetails { pub owner: AccountId, pub owner_deposit: DepositBalance, From 8170b269e04cb834c3a79d635577f52e9872d9c0 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:20:06 +0700 Subject: [PATCH 14/99] fix(nfts): rebase `feat-nfts` branch to fix clippy warnings (#392) --- pallets/nfts/src/benchmarking.rs | 16 ++- pallets/nfts/src/common_functions.rs | 7 +- pallets/nfts/src/features/approvals.rs | 14 +-- pallets/nfts/src/features/atomic_swap.rs | 22 ++-- .../src/features/create_delete_collection.rs | 12 +- .../nfts/src/features/create_delete_item.rs | 104 +++++++++--------- pallets/nfts/src/features/transfer.rs | 19 ++-- pallets/nfts/src/impl_nonfungibles.rs | 23 ++-- pallets/nfts/src/lib.rs | 34 +++--- 9 files changed, 122 insertions(+), 129 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index d8876d52..9533bade 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -17,8 +17,6 @@ //! Nfts pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] - use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, @@ -95,8 +93,8 @@ fn mint_item, I: 'static>( whitelist_account!(caller); } let caller_lookup = T::Lookup::unlookup(caller.clone()); - let item_exists = Item::::contains_key(&collection, &item); - let item_config = ItemConfigOf::::get(&collection, &item); + let item_exists = Item::::contains_key(collection, item); + let item_config = ItemConfigOf::::get(collection, item); if item_exists { return (item, caller, caller_lookup); } else if let Some(item_config) = item_config { @@ -730,7 +728,7 @@ benchmarks_instance_pallet! { } pay_tips { - let n in 0 .. T::MaxTips::get() as u32; + let n in 0 .. T::MaxTips::get(); let amount = BalanceOf::::from(100u32); let caller: T::AccountId = whitelisted_caller(); let collection = T::Helper::collection(0); @@ -836,7 +834,7 @@ benchmarks_instance_pallet! { } mint_pre_signed { - let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let n in 0 .. T::MaxAttributesPerCall::get(); let (caller_public, caller) = T::Helper::signer(); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); let caller_lookup = T::Lookup::unlookup(caller.clone()); @@ -871,14 +869,14 @@ benchmarks_instance_pallet! { let target: T::AccountId = account("target", 0, SEED); T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); frame_system::Pallet::::set_block_number(One::one()); - }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature.into(), caller) + }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature, caller) verify { let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); } set_attributes_pre_signed { - let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let n in 0 .. T::MaxAttributesPerCall::get(); let (collection, _, _) = create_collection::(); let item_owner: T::AccountId = account("item_owner", 0, SEED); @@ -914,7 +912,7 @@ benchmarks_instance_pallet! { let signature = T::Helper::sign(&signer_public, &message); frame_system::Pallet::::set_block_number(One::one()); - }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature.into(), signer.clone()) + }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature, signer.clone()) verify { assert_last_event::( Event::PreSignedAttributesSet { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 6158eab8..38a488b9 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -63,8 +63,8 @@ impl, I: 'static> Pallet { signature: &T::OffchainSignature, signer: &T::AccountId, ) -> DispatchResult { - if signature.verify(&**data, &signer) { - return Ok(()) + if signature.verify(&**data, signer) { + return Ok(()); } // NOTE: for security reasons modern UIs implicitly wrap the data requested to sign into @@ -76,7 +76,7 @@ impl, I: 'static> Pallet { wrapped.extend(data); wrapped.extend(suffix); - ensure!(signature.verify(&*wrapped, &signer), Error::::WrongSignature); + ensure!(signature.verify(&*wrapped, signer), Error::::WrongSignature); Ok(()) } @@ -87,6 +87,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); } + #[allow(missing_docs)] #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_next_id(id: T::CollectionId) { NextCollectionId::::set(Some(id)); diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 3e3d5e63..a75ec57f 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -53,8 +53,7 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -72,7 +71,7 @@ impl, I: 'static> Pallet { .approvals .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::TransferApproved { collection, item: Some(item), @@ -103,8 +102,7 @@ impl, I: 'static> Pallet { item: T::ItemId, delegate: T::AccountId, ) -> DispatchResult { - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; @@ -122,7 +120,7 @@ impl, I: 'static> Pallet { } details.approvals.remove(&delegate); - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::ApprovalCancelled { collection, @@ -153,14 +151,14 @@ impl, I: 'static> Pallet { item: T::ItemId, ) -> DispatchResult { let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; if let Some(check_origin) = maybe_check_origin { ensure!(check_origin == details.owner, Error::::NoPermission); } details.approvals.clear(); - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); Self::deposit_event(Event::AllApprovalsCancelled { collection, diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 31c93fba..6c15f15a 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -62,17 +62,17 @@ impl, I: 'static> Pallet { ); ensure!(duration <= T::MaxDeadlineDuration::get(), Error::::WrongDuration); - let item = Item::::get(&offered_collection_id, &offered_item_id) + let item = Item::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownItem)?; ensure!(item.owner == caller, Error::::NoPermission); match maybe_desired_item_id { Some(desired_item_id) => ensure!( - Item::::contains_key(&desired_collection_id, &desired_item_id), + Item::::contains_key(desired_collection_id, desired_item_id), Error::::UnknownItem ), None => ensure!( - Collection::::contains_key(&desired_collection_id), + Collection::::contains_key(desired_collection_id), Error::::UnknownCollection ), }; @@ -81,8 +81,8 @@ impl, I: 'static> Pallet { let deadline = duration.saturating_add(now); PendingSwapOf::::insert( - &offered_collection_id, - &offered_item_id, + offered_collection_id, + offered_item_id, PendingSwap { desired_collection: desired_collection_id, desired_item: maybe_desired_item_id, @@ -118,17 +118,17 @@ impl, I: 'static> Pallet { offered_collection_id: T::CollectionId, offered_item_id: T::ItemId, ) -> DispatchResult { - let swap = PendingSwapOf::::get(&offered_collection_id, &offered_item_id) + let swap = PendingSwapOf::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownSwap)?; let now = frame_system::Pallet::::block_number(); if swap.deadline > now { - let item = Item::::get(&offered_collection_id, &offered_item_id) + let item = Item::::get(offered_collection_id, offered_item_id) .ok_or(Error::::UnknownItem)?; ensure!(item.owner == caller, Error::::NoPermission); } - PendingSwapOf::::remove(&offered_collection_id, &offered_item_id); + PendingSwapOf::::remove(offered_collection_id, offered_item_id); Self::deposit_event(Event::SwapCancelled { offered_collection: offered_collection_id, @@ -172,11 +172,11 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let send_item = Item::::get(&send_collection_id, &send_item_id) + let send_item = Item::::get(send_collection_id, send_item_id) .ok_or(Error::::UnknownItem)?; - let receive_item = Item::::get(&receive_collection_id, &receive_item_id) + let receive_item = Item::::get(receive_collection_id, receive_item_id) .ok_or(Error::::UnknownItem)?; - let swap = PendingSwapOf::::get(&receive_collection_id, &receive_item_id) + let swap = PendingSwapOf::::get(receive_collection_id, receive_item_id) .ok_or(Error::::UnknownSwap)?; ensure!(send_item.owner == caller, Error::::NoPermission); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 1d08cd1b..9be73a3b 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -67,8 +67,8 @@ impl, I: 'static> Pallet { ), ); - CollectionConfigOf::::insert(&collection, config); - CollectionAccount::::insert(&owner, &collection, ()); + CollectionConfigOf::::insert(collection, config); + CollectionAccount::::insert(&owner, collection, ()); Self::deposit_event(event); @@ -127,13 +127,13 @@ impl, I: 'static> Pallet { ); ensure!(collection_details.allowances == witness.allowances, Error::::BadWitness); - for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { + for (_, metadata) in ItemMetadataOf::::drain_prefix(collection) { if let Some(depositor) = metadata.deposit.account { T::Currency::unreserve(&depositor, metadata.deposit.amount); } } - CollectionMetadataOf::::remove(&collection); + CollectionMetadataOf::::remove(collection); Self::clear_roles(&collection)?; for (_, (_, deposit)) in Attribute::::drain_prefix((&collection,)) { @@ -149,8 +149,8 @@ impl, I: 'static> Pallet { 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); - let _ = ItemConfigOf::::clear_prefix(&collection, witness.item_configs, None); + CollectionConfigOf::::remove(collection); + let _ = ItemConfigOf::::clear_prefix(collection, witness.item_configs, None); Self::deposit_event(Event::Destroyed { collection }); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 08cf5f95..aed2c204 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -55,64 +55,60 @@ impl, I: 'static> Pallet { ) -> DispatchResult { ensure!(!Item::::contains_key(collection, item), Error::::AlreadyExists); - Collection::::try_mutate( - &collection, - |maybe_collection_details| -> DispatchResult { - let collection_details = - maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + Collection::::try_mutate(collection, |maybe_collection_details| -> DispatchResult { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let collection_config = Self::get_collection_config(&collection)?; - with_details_and_config(collection_details, &collection_config)?; + let collection_config = Self::get_collection_config(&collection)?; + with_details_and_config(collection_details, &collection_config)?; - if let Some(max_supply) = collection_config.max_supply { - ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); - } + if let Some(max_supply) = collection_config.max_supply { + ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); + } - collection_details.items.saturating_inc(); + collection_details.items.saturating_inc(); - let account_balance = - AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { - balance.saturating_inc(); - *balance - }); - if account_balance == 1 { - collection_details.item_holders.saturating_inc(); - } + let account_balance = + AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { + balance.saturating_inc(); + *balance + }); + if account_balance == 1 { + collection_details.item_holders.saturating_inc(); + } - let collection_config = Self::get_collection_config(&collection)?; - let deposit_amount = match collection_config - .is_setting_enabled(CollectionSetting::DepositRequired) - { + let collection_config = Self::get_collection_config(&collection)?; + let deposit_amount = + match collection_config.is_setting_enabled(CollectionSetting::DepositRequired) { true => T::ItemDeposit::get(), false => Zero::zero(), }; - let deposit_account = match maybe_depositor { - None => collection_details.owner.clone(), - Some(depositor) => depositor, - }; - - let item_owner = mint_to.clone(); - Account::::insert((&item_owner, &collection, &item), ()); - - if let Ok(existing_config) = ItemConfigOf::::try_get(&collection, &item) { - ensure!(existing_config == item_config, Error::::InconsistentItemConfig); - } else { - ItemConfigOf::::insert(&collection, &item, item_config); - collection_details.item_configs.saturating_inc(); - } + let deposit_account = match maybe_depositor { + None => collection_details.owner.clone(), + Some(depositor) => depositor, + }; + + let item_owner = mint_to.clone(); + Account::::insert((&item_owner, &collection, &item), ()); + + if let Ok(existing_config) = ItemConfigOf::::try_get(collection, item) { + ensure!(existing_config == item_config, Error::::InconsistentItemConfig); + } else { + ItemConfigOf::::insert(collection, item, item_config); + collection_details.item_configs.saturating_inc(); + } - T::Currency::reserve(&deposit_account, deposit_amount)?; + T::Currency::reserve(&deposit_account, deposit_amount)?; - let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; - let details = ItemDetails { - owner: item_owner, - approvals: ApprovalsOf::::default(), - deposit, - }; - Item::::insert(&collection, &item, details); - Ok(()) - }, - )?; + let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; + let details = ItemDetails { + owner: item_owner, + approvals: ApprovalsOf::::default(), + deposit, + }; + Item::::insert(collection, item, details); + Ok(()) + })?; Self::deposit_event(Event::Issued { collection, item, owner: mint_to }); Ok(()) @@ -230,12 +226,12 @@ impl, I: 'static> Pallet { // then we keep the config record and don't remove it let remove_config = !item_config.has_disabled_settings(); let owner = Collection::::try_mutate( - &collection, + collection, |maybe_collection_details| -> Result { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let details = Item::::get(&collection, &item) - .ok_or(Error::::UnknownCollection)?; + let details = + Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; with_details(&details)?; // Return the deposit. @@ -248,7 +244,7 @@ impl, I: 'static> Pallet { // Clear the metadata if it's not locked. if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) { - if let Some(metadata) = ItemMetadataOf::::take(&collection, &item) { + if let Some(metadata) = ItemMetadataOf::::take(collection, item) { let depositor_account = metadata.deposit.account.unwrap_or(collection_details.owner.clone()); @@ -271,7 +267,7 @@ impl, I: 'static> Pallet { }, )?; - Item::::remove(&collection, &item); + Item::::remove(collection, item); Account::::remove((&owner, &collection, &item)); ItemPriceOf::::remove(&collection, &item); PendingSwapOf::::remove(&collection, &item); @@ -281,7 +277,7 @@ impl, I: 'static> Pallet { }); if remove_config { - ItemConfigOf::::remove(&collection, &item); + ItemConfigOf::::remove(collection, item); } Self::deposit_event(Event::Burned { collection, item, owner }); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 3f2dae3b..af34c471 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -81,8 +81,7 @@ impl, I: 'static> Pallet { ); // Retrieve the item details. - let mut details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; @@ -117,10 +116,10 @@ impl, I: 'static> Pallet { details.approvals.clear(); // Update item details. - Item::::insert(&collection, &item, &details); - Collection::::insert(&collection, &collection_details); - ItemPriceOf::::remove(&collection, &item); - PendingSwapOf::::remove(&collection, &item); + Item::::insert(collection, item, &details); + Collection::::insert(collection, &collection_details); + ItemPriceOf::::remove(collection, item); + PendingSwapOf::::remove(collection, item); // Emit `Transferred` event. Self::deposit_event(Event::Transferred { @@ -168,8 +167,8 @@ impl, I: 'static> Pallet { )?; // Update account ownership information. - CollectionAccount::::remove(&details.owner, &collection); - CollectionAccount::::insert(&new_owner, &collection, ()); + CollectionAccount::::remove(&details.owner, collection); + CollectionAccount::::insert(&new_owner, collection, ()); details.owner = new_owner.clone(); OwnershipAcceptance::::remove(&new_owner); @@ -243,8 +242,8 @@ impl, I: 'static> Pallet { )?; // Update collection accounts and set the new owner. - CollectionAccount::::remove(&details.owner, &collection); - CollectionAccount::::insert(&owner, &collection, ()); + CollectionAccount::::remove(&details.owner, collection); + CollectionAccount::::insert(&owner, collection, ()); details.owner = owner.clone(); // Emit `OwnerChanged` event. diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index 362cccd9..0c54f0b7 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -120,20 +120,15 @@ impl, I: 'static> Inspect<::AccountId> for Palle /// Default implementation is that all items are transferable. fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool { use PalletAttributes::TransferDisabled; - match Self::has_system_attribute(&collection, &item, TransferDisabled) { + match Self::has_system_attribute(collection, item, TransferDisabled) { Ok(transfer_disabled) if transfer_disabled => return false, _ => (), } - match ( - CollectionConfigOf::::get(collection), - ItemConfigOf::::get(collection, item), - ) { - (Some(cc), Some(ic)) - if cc.is_setting_enabled(CollectionSetting::TransferableItems) && - ic.is_setting_enabled(ItemSetting::Transferable) => - true, - _ => false, - } + matches!( + (CollectionConfigOf::::get(collection), ItemConfigOf::::get(collection, item)), + (Some(cc), Some(ic)) if cc.is_setting_enabled(CollectionSetting::TransferableItems) + && ic.is_setting_enabled(ItemSetting::Transferable) + ) } } @@ -259,7 +254,7 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig Self::do_burn(*collection, *item, |d| { if let Some(check_owner) = maybe_check_owner { if &d.owner != check_owner { - return Err(Error::::NoPermission.into()) + return Err(Error::::NoPermission.into()); } } Ok(()) @@ -421,10 +416,10 @@ impl, I: 'static> Transfer for Pallet { fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { let transfer_disabled = - Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?; + Self::has_system_attribute(collection, item, PalletAttributes::TransferDisabled)?; // Can't lock the item twice if transfer_disabled { - return Err(Error::::ItemLocked.into()) + return Err(Error::::ItemLocked.into()); } >::set_attribute( diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 37e8b29c..e86410c5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -44,12 +44,14 @@ mod features; mod impl_nonfungibles; mod types; +#[allow(missing_docs)] pub mod macros; pub mod weights; extern crate alloc; use alloc::{boxed::Box, vec, vec::Vec}; +use core::cmp::Ordering; use codec::{Decode, Encode}; use frame_support::traits::{ @@ -66,7 +68,7 @@ pub use types::*; pub use weights::WeightInfo; /// The log target of this pallet. -pub const LOG_TARGET: &'static str = "runtime::nfts"; +pub const LOG_TARGET: &str = "runtime::nfts"; /// A type alias for the account ID type used in the dispatchable functions of this pallet. type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; @@ -86,6 +88,7 @@ pub mod pallet { pub struct Pallet(PhantomData<(T, I)>); #[cfg(feature = "runtime-benchmarks")] + #[allow(missing_docs)] pub trait BenchmarkHelper { fn collection(i: u16) -> CollectionId; fn item(i: u16) -> ItemId; @@ -443,6 +446,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[allow(missing_docs)] pub enum Event, I: 'static = ()> { /// A `collection` was created. Created { collection: T::CollectionId, creator: T::AccountId, owner: T::AccountId }, @@ -1094,7 +1098,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; ensure!(collection_details.owner == origin, Error::::NoPermission); let config = Self::get_collection_config(&collection)?; @@ -1105,24 +1109,26 @@ pub mod pallet { let mut successful = Vec::with_capacity(items.len()); for item in items.into_iter() { - let mut details = match Item::::get(&collection, &item) { + let mut details = match Item::::get(collection, item) { Some(x) => x, None => continue, }; let old = details.deposit.amount; - if old > deposit { - T::Currency::unreserve(&details.deposit.account, old - deposit); - } else if deposit > old { - 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; - } - } else { - continue; + match old.cmp(&deposit) { + Ordering::Greater => { + T::Currency::unreserve(&details.deposit.account, old - deposit); + }, + Ordering::Less => { + 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, } details.deposit.amount = deposit; - Item::::insert(&collection, &item, &details); + Item::::insert(collection, item, &details); successful.push(item); } From f815bf2b56353b41bc1320e14d1bba4f9f49bd2f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:28:06 +0700 Subject: [PATCH 15/99] fix: reformatting --- pallets/nfts/src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 8756c85c..e86410c5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1371,9 +1371,8 @@ pub mod pallet { .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; let delegate = T::Lookup::lookup(delegate)?; match maybe_item { - Some(item) => { - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) - }, + Some(item) => + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), } } @@ -1476,9 +1475,8 @@ pub mod pallet { ) -> DispatchResult { let origin = ensure_signed(origin)?; let depositor = match namespace { - AttributeNamespace::CollectionOwner => { - Self::collection_owner(collection).ok_or(Error::::UnknownCollection)? - }, + AttributeNamespace::CollectionOwner => + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?, _ => origin.clone(), }; Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value, depositor) From 51bc52f3e5d69f71807761ac9b64b4182dcd8deb Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:03:17 +0700 Subject: [PATCH 16/99] fix: remove unused storage fields from CollectionDetails (#393) --- pallets/nfts/src/benchmarking.rs | 30 - .../src/features/create_delete_collection.rs | 10 +- .../nfts/src/features/create_delete_item.rs | 15 +- pallets/nfts/src/features/transfer.rs | 19 +- pallets/nfts/src/lib.rs | 6 +- pallets/nfts/src/tests.rs | 58 +- pallets/nfts/src/types.rs | 6 - pallets/nfts/src/weights.rs | 526 +++++++++--------- 8 files changed, 283 insertions(+), 387 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 9533bade..1dcf79b9 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -62,27 +62,6 @@ 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) { @@ -269,8 +248,6 @@ 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::(); @@ -288,13 +265,6 @@ 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); - } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) verify { diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 9be73a3b..86dec992 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -54,7 +54,6 @@ impl, I: 'static> Pallet { items: 0, item_metadatas: 0, item_configs: 0, - item_holders: 0, attributes: 0, allowances: 0, }, @@ -112,6 +111,7 @@ impl, I: 'static> Pallet { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); + ensure!(collection_details.allowances == 0, Error::::AllowancesNotEmpty); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, @@ -121,10 +121,6 @@ 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) { @@ -144,9 +140,6 @@ 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); @@ -157,7 +150,6 @@ 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 aed2c204..4d04f033 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -68,14 +68,9 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); - let account_balance = - AccountBalance::::mutate(collection, &mint_to, |balance| -> u32 { - balance.saturating_inc(); - *balance - }); - if account_balance == 1 { - collection_details.item_holders.saturating_inc(); - } + AccountBalance::::mutate(collection, &mint_to, |balance| { + balance.saturating_inc(); + }); let collection_config = Self::get_collection_config(&collection)?; let deposit_amount = @@ -259,10 +254,6 @@ 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 af34c471..2a73cf23 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 mut collection_details = + let collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; // Ensure the item is not locked. @@ -87,22 +87,13 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balance of the owner. - let owner_balance = - AccountBalance::::mutate(collection, &details.owner, |balance| -> u32 { - balance.saturating_dec(); - *balance - }); - if owner_balance == 0 { - collection_details.item_holders.saturating_dec(); - } + AccountBalance::::mutate(collection, &details.owner, |balance| { + balance.saturating_dec(); + }); // Update account balance of the destination account. - let dest_balance = AccountBalance::::mutate(collection, &dest, |balance| -> u32 { + AccountBalance::::mutate(collection, &dest, |balance| { balance.saturating_inc(); - *balance }); - if dest_balance == 1 { - collection_details.item_holders.saturating_inc(); - } // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index e86410c5..d3f29fea 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -719,6 +719,8 @@ pub mod pallet { CollectionNotEmpty, /// The witness data should be provided. WitnessRequired, + /// Cant' delete collections whose allowances. + AllowancesNotEmpty, } #[pallet::call] @@ -835,8 +837,6 @@ pub mod pallet { witness.item_metadatas, witness.item_configs, witness.attributes, - witness.item_holders, - witness.allowances, ))] pub fn destroy( origin: OriginFor, @@ -852,8 +852,6 @@ pub mod pallet { details.item_metadatas, details.item_configs, details.attributes, - details.item_holders, - details.allowances, )) .into()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 0a77aa8c..eddacc0b 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -165,7 +165,6 @@ 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( @@ -176,37 +175,10 @@ 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(|| { @@ -251,7 +223,6 @@ 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))); @@ -346,7 +317,6 @@ 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, @@ -367,12 +337,21 @@ fn destroy_should_work() { assert_eq!(Collection::::get(0).unwrap().item_configs, 1); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); assert!(ItemConfigOf::::contains_key(0, 42)); + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() + ), + Error::::AllowancesNotEmpty + ); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, Nfts::get_destroy_witness(&0).unwrap() )); - assert_eq!(AccountBalance::::iter_prefix(0).count(), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 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); @@ -390,7 +369,6 @@ 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)]); @@ -456,7 +434,6 @@ 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 @@ -496,7 +473,6 @@ 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), @@ -533,11 +509,9 @@ 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)), @@ -555,7 +529,6 @@ 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( @@ -1810,7 +1783,6 @@ 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!( @@ -1819,10 +1791,8 @@ 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); }); } @@ -4154,13 +4124,7 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { - item_configs: 0, - item_metadatas: 0, - attributes: 0, - allowances: 0, - item_holders: 0 - } + DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0, allowances: 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 46148d63..0da303b1 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -104,8 +104,6 @@ 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. @@ -121,9 +119,6 @@ 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, @@ -137,7 +132,6 @@ 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 b3307503..0abd73dc 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-11-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-20, 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` @@ -20,7 +20,7 @@ // --no-min-squares // --wasm-execution=compiled // --heap-pages=4096 -// --output=./pallets/nfts/src/weights.rs +// --output=./pallets/nfts/src/weights_temp.rs // --template=./scripts/pallet-weights-template.hbs // --extrinsic= @@ -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, h: u32, l: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `3557` + // Estimated: `3553` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + Weight::from_parts(29_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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,24 +110,20 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Estimated: `3553` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) /// 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::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) @@ -139,17 +135,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]`. - /// 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 { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32169 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // Minimum execution time: 976_000_000 picoseconds. + Weight::from_parts(489_392_768, 2523990) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(2_634, 0).saturating_mul(m.into())) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(406_042, 0).saturating_mul(c.into())) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(5_358_742, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1004_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 +158,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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 +169,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: `390` + // Measured: `386` // Estimated: `4326` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4326) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(91_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,7 +181,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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 +192,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: `390` + // Measured: `386` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(64_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -206,7 +204,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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 +221,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: `584` + // Measured: `580` // Estimated: `4326` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 4326) + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(66_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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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 +248,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: `613` + // Measured: `609` // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(41_000_000, 6068) .saturating_add(T::DbWeight::get().reads(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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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 +264,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `698 + i * (108 ±0)` - // Estimated: `3557 + i * (3336 ±0)` + // Measured: `694 + i * (108 ±0)` + // Estimated: `3553 + 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())) + Weight::from_parts(11_000_000, 3553) + // Standard Error: 24_164 + .saturating_add(Weight::from_parts(16_322_691, 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()))) @@ -299,76 +297,76 @@ impl WeightInfo for SubstrateWeight { // Measured: `395` // Estimated: `3534` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + Weight::from_parts(15_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `275` - // Estimated: `3557` + // Measured: `271` + // Estimated: `3553` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + Weight::from_parts(12_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `425` + // Measured: `421` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. + // Minimum execution time: 19_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)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `304` + // Measured: `300` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(32_000_000, 6078) .saturating_add(T::DbWeight::get().reads(3_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `246` - // Estimated: `3557` + // Measured: `242` + // Estimated: `3553` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + Weight::from_parts(12_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `3557` + // Estimated: `3553` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + Weight::from_parts(10_000_000, 3553) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -380,13 +378,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_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)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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,23 +395,23 @@ 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: `507` + // Measured: `503` // Estimated: `3944` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + Weight::from_parts(40_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `279` + // Measured: `275` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(20_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -424,10 +422,10 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `947` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. Weight::from_parts(37_000_000, 3944) @@ -442,8 +440,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4466) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -462,8 +460,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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // Standard Error: 6_818 + .saturating_add(Weight::from_parts(5_055_243, 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 +471,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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,9 +480,9 @@ 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: `507` + // Measured: `503` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. + // Minimum execution time: 31_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)) @@ -494,12 +492,12 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `817` + // Measured: `813` // Estimated: `3812` // Minimum execution time: 29_000_000 picoseconds. Weight::from_parts(30_000_000, 3812) @@ -511,31 +509,31 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `333` + // Measured: `329` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + Weight::from_parts(29_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `651` + // Measured: `647` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. + // Minimum execution time: 28_000_000 picoseconds. Weight::from_parts(28_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -545,16 +543,16 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, 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) + // Measured: `304 + i * (33 ±0)` + // Estimated: `4266 + i * (2163 ±0)` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_371_428, 4266) .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())) @@ -562,17 +560,17 @@ 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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, 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)` + // Measured: `397` + // Estimated: `4266 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(14_000_000, 3557) - .saturating_add(T::DbWeight::get().reads(1_u64)) + Weight::from_parts(17_800_000, 4266) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } @@ -594,20 +592,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + Weight::from_parts(10_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `271` + // Estimated: `3553` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3553) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -620,7 +618,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + Weight::from_parts(13_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -636,8 +634,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_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)) } @@ -646,7 +644,7 @@ impl WeightInfo for SubstrateWeight { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -661,10 +659,10 @@ 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: `725` + // Measured: `721` // Estimated: `6068` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(44_000_000, 6068) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -674,9 +672,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + Weight::from_parts(2_185_779, 0) + // Standard Error: 5_205 + .saturating_add(Weight::from_parts(1_740_314, 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`) @@ -686,7 +684,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_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)) @@ -709,7 +707,7 @@ impl WeightInfo for SubstrateWeight { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -724,7 +722,7 @@ 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: `915` + // Measured: `911` // Estimated: `7662` // Minimum execution time: 78_000_000 picoseconds. Weight::from_parts(79_000_000, 7662) @@ -738,7 +736,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -754,12 +752,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: `493` + // Measured: `489` // Estimated: `6078 + n * (2954 ±0)` - // 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())) + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(106_829_596, 6078) + // Standard Error: 67_259 + .saturating_add(Weight::from_parts(28_340_797, 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)) @@ -773,7 +771,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -781,12 +779,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: `522` + // Measured: `518` // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(62_235_731, 4466) + // Standard Error: 78_176 + .saturating_add(Weight::from_parts(26_600_501, 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)) @@ -800,7 +798,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -810,16 +808,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3557` + // Estimated: `3553` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3557) + Weight::from_parts(29_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -829,24 +827,20 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3557` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_000, 3557) + // Estimated: `3553` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) /// 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::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) @@ -858,17 +852,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]`. - /// 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 { + fn destroy(m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32875 + a * (366 ±0)` + // Measured: `32169 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 982_000_000 picoseconds. - 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)) + // Minimum execution time: 976_000_000 picoseconds. + Weight::from_parts(489_392_768, 2523990) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(2_634, 0).saturating_mul(m.into())) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(406_042, 0).saturating_mul(c.into())) + // Standard Error: 29_146 + .saturating_add(Weight::from_parts(5_358_742, 0).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1004_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()))) @@ -879,7 +875,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -890,10 +886,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: `390` + // Measured: `386` // Estimated: `4326` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4326) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(91_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -902,7 +898,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -913,10 +909,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: `390` + // Measured: `386` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(64_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -925,7 +921,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -942,15 +938,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: `584` + // Measured: `580` // Estimated: `4326` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 4326) + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(66_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -969,15 +965,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: `613` + // Measured: `609` // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(38_000_000, 6068) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(41_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -985,12 +981,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `698 + i * (108 ±0)` - // Estimated: `3557 + i * (3336 ±0)` + // Measured: `694 + i * (108 ±0)` + // Estimated: `3553 + 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())) + Weight::from_parts(11_000_000, 3553) + // Standard Error: 24_164 + .saturating_add(Weight::from_parts(16_322_691, 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()))) @@ -1018,76 +1014,76 @@ impl WeightInfo for () { // Measured: `395` // Estimated: `3534` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + Weight::from_parts(15_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `275` - // Estimated: `3557` + // Measured: `271` + // Estimated: `3553` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_000_000, 3557) + Weight::from_parts(12_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `425` + // Measured: `421` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. + // Minimum execution time: 19_000_000 picoseconds. Weight::from_parts(19_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `304` + // Measured: `300` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(32_000_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `246` - // Estimated: `3557` + // Measured: `242` + // Estimated: `3553` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3557) + Weight::from_parts(12_000_000, 3553) .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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `3557` + // Estimated: `3553` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3557) + Weight::from_parts(10_000_000, 3553) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1099,13 +1095,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(13_000_000, 3534) .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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1116,23 +1112,23 @@ 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: `507` + // Measured: `503` // Estimated: `3944` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + Weight::from_parts(40_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `279` + // Measured: `275` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(20_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1143,10 +1139,10 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `951` + // Measured: `947` // Estimated: `3944` // Minimum execution time: 35_000_000 picoseconds. Weight::from_parts(37_000_000, 3944) @@ -1161,8 +1157,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4466) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1181,8 +1177,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: 10_431 - .saturating_add(Weight::from_parts(4_776_454, 0).saturating_mul(n.into())) + // Standard Error: 6_818 + .saturating_add(Weight::from_parts(5_055_243, 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)) @@ -1192,7 +1188,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1201,9 +1197,9 @@ 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: `507` + // Measured: `503` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. + // Minimum execution time: 31_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1213,12 +1209,12 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `817` + // Measured: `813` // Estimated: `3812` // Minimum execution time: 29_000_000 picoseconds. Weight::from_parts(30_000_000, 3812) @@ -1230,31 +1226,31 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `333` + // Measured: `329` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + Weight::from_parts(29_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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: `651` + // Measured: `647` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. + // Minimum execution time: 28_000_000 picoseconds. Weight::from_parts(28_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1264,16 +1260,16 @@ 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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(109), added: 2584, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, 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) + // Measured: `304 + i * (33 ±0)` + // Estimated: `4266 + i * (2163 ±0)` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_371_428, 4266) .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())) @@ -1281,17 +1277,17 @@ 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(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`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: `Nfts::Allowances` (r:1 w:1) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, 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)` + // Measured: `397` + // Estimated: `4266 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(14_000_000, 3557) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + Weight::from_parts(17_800_000, 4266) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } @@ -1313,20 +1309,20 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + Weight::from_parts(10_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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `3557` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3557) + // Measured: `271` + // Estimated: `3553` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3553) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1339,7 +1335,7 @@ impl WeightInfo for () { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + Weight::from_parts(13_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1355,8 +1351,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_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)) } @@ -1365,7 +1361,7 @@ impl WeightInfo for () { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1380,10 +1376,10 @@ 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: `725` + // Measured: `721` // Estimated: `6068` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(44_000_000, 6068) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(46_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1393,9 +1389,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_101_372, 0) - // Standard Error: 5_552 - .saturating_add(Weight::from_parts(1_704_563, 0).saturating_mul(n.into())) + Weight::from_parts(2_185_779, 0) + // Standard Error: 5_205 + .saturating_add(Weight::from_parts(1_740_314, 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`) @@ -1405,7 +1401,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. + // Minimum execution time: 14_000_000 picoseconds. Weight::from_parts(14_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1428,7 +1424,7 @@ impl WeightInfo for () { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1443,7 +1439,7 @@ 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: `915` + // Measured: `911` // Estimated: `7662` // Minimum execution time: 78_000_000 picoseconds. Weight::from_parts(79_000_000, 7662) @@ -1457,7 +1453,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1473,12 +1469,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: `493` + // Measured: `489` // Estimated: `6078 + n * (2954 ±0)` - // 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())) + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(106_829_596, 6078) + // Standard Error: 67_259 + .saturating_add(Weight::from_parts(28_340_797, 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)) @@ -1492,7 +1488,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(92), added: 2567, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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) @@ -1500,12 +1496,12 @@ 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: `522` + // Measured: `518` // Estimated: `4466 + n * (2954 ±0)` - // 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())) + // Minimum execution time: 51_000_000 picoseconds. + Weight::from_parts(62_235_731, 4466) + // Standard Error: 78_176 + .saturating_add(Weight::from_parts(26_600_501, 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)) From d1450294997b6e0f0b23c8d93bd3e5e8dd2ba808 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:11:45 +0700 Subject: [PATCH 17/99] fix: add comment & refactor cancel_collection --- pallets/nfts/src/benchmarking.rs | 10 +--- pallets/nfts/src/features/approvals.rs | 57 +++++++++++++------ .../nfts/src/features/create_delete_item.rs | 6 +- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 1dcf79b9..7b384130 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -577,19 +577,15 @@ benchmarks_instance_pallet! { let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let maybe_deadline = if i == 0 { - None - } else { - Some(BlockNumberFor::::max_value()) - }; + let deadline = BlockNumberFor::::max_value(); let maybe_item = if i == 0 { None } else { Some(item) }; - }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, maybe_deadline) + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: maybe_deadline }.into()); + assert_last_event::(Event::TransferApproved { collection, item: maybe_item, owner: caller, delegate, deadline: Some(deadline) }.into()); } cancel_approval { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index a75ec57f..feb85d36 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -169,6 +169,19 @@ impl, I: 'static> Pallet { Ok(()) } + /// Approves the transfer of all items within the collection to a delegate. + /// + /// This function is used to approve the transfer of all items within the `collection` to + /// a `delegate`. If `maybe_check_origin` is specified, the function ensures that the + /// `check_origin` account is the owner of the collection, granting them permission to approve + /// the transfer. The `delegate` is the account that will be allowed to take control of all + /// items within the collection. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, + /// granting permission to approve the transfer. If `None`, no permission check is performed. + /// - `collection`: The identifier of the collection. + /// - `delegate`: The account that will be allowed to take control of all items within the + /// collection. pub(crate) fn do_approve_collection( maybe_check_origin: Option, collection: T::CollectionId, @@ -186,7 +199,7 @@ impl, I: 'static> Pallet { ); let owner = Collection::::try_mutate( - &collection, + collection, |maybe_collection_details| -> Result { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; @@ -213,29 +226,42 @@ impl, I: 'static> Pallet { Ok(()) } + /// Cancels the approval for the transfer of all items within the collection to a delegate. + /// + /// This function is used to cancel the approval for the transfer of all items in the + /// `collection` to a `delegate`. If `maybe_check_origin` is specified, the function ensures + /// that the `check_origin` account is the owner of the item or that the approval is past its + /// deadline, granting permission to cancel the approval. After canceling the approval, the + /// function emits the `ApprovalCancelled` event. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the + /// collection, granting permission to cancel the approval. If `None`, no permission check is + /// performed. + /// - `collection`: The identifier of the collection + /// - `delegate`: The account that was previously allowed to take control of all items within + /// the collection. pub(crate) fn do_cancel_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let owner = Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - Allowances::::remove((&collection, &owner, &delegate)); - Collection::::try_mutate( - &collection, - |maybe_collection_details| -> Result<(), DispatchError> { + let owner = Collection::::try_mutate( + collection, + |maybe_collection_details| -> Result { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + let owner = collection_details.clone().owner; + + Allowances::::remove((&collection, &owner, &delegate)); + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } collection_details.allowances.saturating_dec(); - Ok(()) + Ok(owner) }, )?; Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); - Ok(()) } @@ -248,16 +274,15 @@ impl, I: 'static> Pallet { // 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)?; + Item::::get(collection, item).ok_or(Error::::UnknownItem)?; }; return Ok(()); } // Check if a `delegate` has a permission to spend the collection item. if let Some(item) = item { - let details = - Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - let deadline = details.approvals.get(&delegate).ok_or(Error::::NoPermission)?; + 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); diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 4d04f033..ea8cb5b4 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -260,9 +260,9 @@ impl, I: 'static> Pallet { Item::::remove(collection, item); Account::::remove((&owner, &collection, &item)); - ItemPriceOf::::remove(&collection, &item); - PendingSwapOf::::remove(&collection, &item); - ItemAttributesApprovalsOf::::remove(&collection, &item); + ItemPriceOf::::remove(collection, item); + PendingSwapOf::::remove(collection, item); + ItemAttributesApprovalsOf::::remove(collection, item); AccountBalance::::mutate(collection, &owner, |balance| { balance.saturating_dec(); }); From 0e1c2ab75790ded9d9aaa017cb7a76722b545011 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:17:06 +0700 Subject: [PATCH 18/99] chore: remove newline changes --- pallets/nfts/src/features/approvals.rs | 3 +++ pallets/nfts/src/features/create_delete_collection.rs | 2 -- pallets/nfts/src/types.rs | 4 ---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index feb85d36..3e422730 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -64,6 +64,7 @@ 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)); @@ -71,7 +72,9 @@ impl, I: 'static> Pallet { .approvals .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; + Item::::insert(collection, item, &details); + Self::deposit_event(Event::TransferApproved { collection, item: Some(item), diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index b7a83a91..f5a01ebe 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -121,7 +121,6 @@ impl, I: 'static> Pallet { collection_details.item_configs == witness.item_configs, Error::::BadWitness ); - ensure!(collection_details.allowances == witness.allowances, Error::::BadWitness); for (_, metadata) in ItemMetadataOf::::drain_prefix(collection) { if let Some(depositor) = metadata.deposit.account { @@ -151,7 +150,6 @@ impl, I: 'static> Pallet { item_metadatas: collection_details.item_metadatas, item_configs: collection_details.item_configs, attributes: collection_details.attributes, - allowances: collection_details.allowances, }) }) } diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 0da303b1..56c9cbaf 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -122,9 +122,6 @@ pub struct DestroyWitness { /// 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 { @@ -133,7 +130,6 @@ impl CollectionDetails { item_metadatas: self.item_metadatas, item_configs: self.item_configs, attributes: self.attributes, - allowances: self.allowances, } } } From 73f04daf4409562f54fd4f3c4ead758e493cc904 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:39:01 +0700 Subject: [PATCH 19/99] chore: add comment for check allowance --- pallets/nfts/src/features/approvals.rs | 11 +++++++++++ pallets/nfts/src/lib.rs | 7 +++++-- pallets/nfts/src/tests.rs | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 3e422730..22848f9d 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -268,6 +268,17 @@ impl, I: 'static> Pallet { Ok(()) } + /// Checks whether the `delegate` has the necessary allowance to transfer items within the + /// collection or a specific item in the collection. If the `delegate` has approval to transfer + /// all items in the collection, they can transfer a specific item without requiring explicit + /// approval for that item. + /// + /// - `collection`: The identifier of the collection + /// - `maybe_item`: The optional item of the collection that the delegated account has an + /// approval to transfer. If not provided, an approval to transfer all items within the + /// collection will be checked. + /// - `delegate`: The account that was previously allowed to take control of all items within + /// the collection. pub fn check_allowance( collection: &T::CollectionId, item: &Option, diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 1c5206b8..28b0c414 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1309,7 +1309,8 @@ pub mod pallet { /// `item`. /// /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `item`: The item to be approved for delegated transfer. + /// - `maybe_item`: The optional item to be approved for delegated transfer. If not + /// provided, all items within the collection will be approved. /// - `delegate`: The account to delegate permission to transfer the item. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire @@ -1350,7 +1351,9 @@ pub mod pallet { /// /// 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. + /// - `item`: The optional item of the collection of whose approval will be cancelled. If + /// not provided, an allowance to transfer all items within the collection will be + /// cancelled. /// - `delegate`: The account that is going to loose their approval. /// /// Emits `ApprovalCancelled` on success. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index eddacc0b..1f63a192 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4124,7 +4124,7 @@ fn clear_collection_metadata_works() { assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, - DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0, allowances: 0 } + DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0 } )); assert_eq!(Collection::::get(0), None); assert_eq!(Balances::reserved_balance(&account(1)), 10); From e8c5685c73170463dfe6f1ddc80c1fc96a2d9a91 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:45:13 +0700 Subject: [PATCH 20/99] chore: register pallet_nfts benchmark --- runtime/devnet/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index f539cbde..caeb4414 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -648,6 +648,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 a66ea2a4146338ba96099b0c97291237ab8eb8f6 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:01:45 +0700 Subject: [PATCH 21/99] refactor(nfts): mapping with `ApprovalsOf` in the `Allowances` storage item (#390) --- pallets/nfts/src/benchmarking.rs | 54 ++++- pallets/nfts/src/common_functions.rs | 5 - pallets/nfts/src/features/approvals.rs | 155 +++++++++++--- .../src/features/create_delete_collection.rs | 7 +- pallets/nfts/src/features/transfer.rs | 9 + pallets/nfts/src/lib.rs | 66 ++++-- pallets/nfts/src/tests.rs | 168 +++++++++++++++- pallets/nfts/src/types.rs | 2 - pallets/nfts/src/weights.rs | 190 ++++++++++-------- 9 files changed, 507 insertions(+), 149 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 7b384130..bcdbcc51 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -62,6 +62,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", index, SEED); + 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) { @@ -571,7 +592,7 @@ benchmarks_instance_pallet! { } approve_transfer { - let i in 0..1; + let i in 0 .. 1; let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -589,7 +610,7 @@ benchmarks_instance_pallet! { } cancel_approval { - let i in 0..1; + let i in 0 .. 1; let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -598,9 +619,9 @@ benchmarks_instance_pallet! { let origin = SystemOrigin::Signed(caller.clone()).into(); let deadline = BlockNumberFor::::max_value(); let maybe_item = if i == 0 { - None + None } else { - Some(item) + Some(item) }; Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup) @@ -609,16 +630,27 @@ benchmarks_instance_pallet! { } clear_all_transfer_approvals { + let i in 0 .. 1; + let n in 0 .. T::ApprovalsLimit::get(); + 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, item) + let (maybe_item, witness_allowances) = if i == 0 { + for i in 0 .. n { + approve_collection::(i); + } + (None, Some(n)) + } else { + 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))?; + (Some(item), None) + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, witness_allowances) verify { - assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); + assert_last_event::(Event::AllApprovalsCancelled {collection, item: maybe_item, owner: caller}.into()); } set_accept_ownership { diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 9cc7d3b4..1aa151c3 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -39,11 +39,6 @@ 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 22848f9d..df62a327 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -20,6 +20,7 @@ //! to have the functionality defined in this module. use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::BlockNumberFor; use crate::*; @@ -153,6 +154,14 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, ) -> DispatchResult { + let collection_details = + Collection::::get(collection).ok_or(Error::::UnknownCollection)?; + + ensure!( + AccountAllowances::::get(collection, collection_details.owner) == 0, + Error::::DelegateApprovalConflict + ); + let mut details = Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; @@ -165,7 +174,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::AllApprovalsCancelled { collection, - item, + item: Some(item), owner: details.owner, }); @@ -178,17 +187,23 @@ impl, I: 'static> Pallet { /// a `delegate`. If `maybe_check_origin` is specified, the function ensures that the /// `check_origin` account is the owner of the collection, granting them permission to approve /// the transfer. The `delegate` is the account that will be allowed to take control of all - /// items within the collection. + /// items within the collection. Optionally, a `deadline` can be specified to set a time limit + /// for the approval. The `deadline` is expressed in block numbers and is added to the current + /// block number to determine the absolute deadline for the approval. After approving the + /// transfer, the function emits the `TransferApproved` event. /// /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, /// granting permission to approve the transfer. If `None`, no permission check is performed. /// - `collection`: The identifier of the collection. /// - `delegate`: The account that will be allowed to take control of all items within the /// collection. + /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for + /// the approval. pub(crate) fn do_approve_collection( maybe_check_origin: Option, collection: T::CollectionId, delegate: T::AccountId, + maybe_deadline: Option>, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Approvals), @@ -201,9 +216,9 @@ impl, I: 'static> Pallet { Error::::ItemsNonTransferable ); - let owner = Collection::::try_mutate( + let (owner, deadline) = Collection::::try_mutate( collection, - |maybe_collection_details| -> Result { + |maybe_collection_details| -> Result<(T::AccountId, Option>), DispatchError> { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; let owner = collection_details.clone().owner; @@ -211,11 +226,21 @@ impl, I: 'static> Pallet { if let Some(check_origin) = maybe_check_origin { ensure!(check_origin == owner, Error::::NoPermission); } - Allowances::::mutate((&collection, &owner, &delegate), |allowance| { - *allowance = true; - }); - collection_details.allowances.saturating_inc(); - Ok(owner) + let now = frame_system::Pallet::::block_number(); + let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + + AccountAllowances::::try_mutate(collection, &owner, |allowances| -> Result<(), DispatchError> { + ensure!(*allowances < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit); + Allowances::::mutate( + (&collection, &owner, &delegate), + |maybe_deadline| { + *maybe_deadline = Some(deadline); + }, + ); + allowances.saturating_inc(); + Ok(()) + })?; + Ok((owner, deadline)) }, )?; @@ -224,8 +249,9 @@ impl, I: 'static> Pallet { item: None, owner, delegate, - deadline: None, + deadline, }); + Ok(()) } @@ -238,8 +264,8 @@ impl, I: 'static> Pallet { /// function emits the `ApprovalCancelled` event. /// /// - `maybe_check_origin`: The optional account that is required to be the owner of the - /// collection, granting permission to cancel the approval. If `None`, no permission check is - /// performed. + /// collection or that the approval is past its deadline, granting permission to cancel the + /// approval. If `None`, no permission check is performed. /// - `collection`: The identifier of the collection /// - `delegate`: The account that was previously allowed to take control of all items within /// the collection. @@ -254,17 +280,98 @@ impl, I: 'static> Pallet { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; let owner = collection_details.clone().owner; + let maybe_deadline = Allowances::::get((&collection, &owner, &delegate)) + .ok_or(Error::::NotDelegate)?; + + let is_past_deadline = if let Some(deadline) = maybe_deadline { + let now = frame_system::Pallet::::block_number(); + now > deadline + } else { + false + }; + + if !is_past_deadline { + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + } Allowances::::remove((&collection, &owner, &delegate)); + AccountAllowances::::mutate(collection, &owner, |allowances| { + allowances.saturating_dec(); + }); + Ok(owner) + }, + )?; + + Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); + + Ok(()) + } + + /// Clears all collection approvals. + /// + /// This function is used to clear all approvals to transfer all items within the collections. + /// If `maybe_check_origin` is specified, the function ensures that the `check_origin` account + /// is the owner of the item, granting permission to clear all collection approvals. After + /// clearing all approvals, the function emits the `AllApprovalsCancelled` event. + /// + /// - `maybe_check_origin`: The optional account that is required to be the owner of the + /// collection, granting permission to clear all collection approvals. If `None`, no + /// permission check is performed. + /// - `collection`: The collection ID containing the item. + pub(crate) fn do_clear_all_collection_approvals( + maybe_check_origin: Option, + collection: T::CollectionId, + witness_allowances: u32, + ) -> DispatchResult { + let owner = Collection::::try_mutate( + collection, + |maybe_collection_details| -> Result { + let collection_details = + maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; + let owner = collection_details.clone().owner; + if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); + ensure!(check_origin == owner.clone(), Error::::NoPermission); } - collection_details.allowances.saturating_dec(); + + AccountAllowances::::try_mutate( + collection, + &owner, + |allowances| -> Result<(), DispatchError> { + ensure!(*allowances == witness_allowances, Error::::BadWitness); + let _ = Allowances::::clear_prefix( + (collection, owner.clone()), + *allowances, + None, + ); + *allowances = 0; + + Ok(()) + }, + )?; Ok(owner) }, )?; - Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); + Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner }); + + Ok(()) + } + + // Check if a `delegate` has a permission to spend the collection. + fn check_collection_allowance( + collection: &T::CollectionId, + owner: &T::AccountId, + delegate: &T::AccountId, + ) -> Result<(), DispatchError> { + let maybe_deadline = Allowances::::get((&collection, &owner, &delegate)) + .ok_or(Error::::NoPermission)?; + if let Some(deadline) = maybe_deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= deadline, Error::::ApprovalExpired); + } Ok(()) } @@ -286,23 +393,23 @@ impl, I: 'static> Pallet { delegate: &T::AccountId, ) -> 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)?; + let check_collection_allowance_error = + match Self::check_collection_allowance(collection, owner, delegate) { + Ok(()) => return Ok(()), + Err(error) => error, }; - return Ok(()); - } // Check if a `delegate` has a permission to spend the collection item. 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 maybe_deadline = + details.approvals.get(delegate).ok_or(Error::::NoPermission)?; + if let Some(deadline) = maybe_deadline { let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *d, Error::::ApprovalExpired); + ensure!(block_number <= *deadline, Error::::ApprovalExpired); } return Ok(()); }; - Err(Error::::NoPermission.into()) + Err(check_collection_allowance_error) } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index f5a01ebe..5be73fc9 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -55,7 +55,6 @@ impl, I: 'static> Pallet { item_metadatas: 0, item_configs: 0, attributes: 0, - allowances: 0, }, ); CollectionRoleOf::::insert( @@ -97,6 +96,9 @@ impl, I: 'static> Pallet { /// ([`NoPermission`](crate::Error::NoPermission)). /// - If the collection is not empty (contains items) /// ([`CollectionNotEmpty`](crate::Error::CollectionNotEmpty)). + /// - If the collection approvals is not empty (contains permissions to transfer all items + /// within the collection) + /// ([`CollectionApprovalsNotEmpty`](crate::Error::CollectionApprovalsNotEmpty)). /// - If the `witness` does not match the actual collection details /// ([`BadWitness`](crate::Error::BadWitness)). pub fn do_destroy_collection( @@ -110,8 +112,9 @@ impl, I: 'static> Pallet { if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } + let allowances = AccountAllowances::::get(collection, &collection_details.owner); ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); - ensure!(collection_details.allowances == 0, Error::::AllowancesNotEmpty); + ensure!(allowances == 0, Error::::CollectionApprovalsNotEmpty); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index c0896335..c8f66e4f 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -149,6 +149,15 @@ impl, I: 'static> Pallet { return Ok(()); } + // All collection approvals need to be removed because otherwise + // pre-approve attack would be possible, where the owner can approve their + // second account before making the transaction and then claiming all items + // within the collection back. + ensure!( + AccountAllowances::::get(collection, &details.owner) == 0, + Error::::CollectionApprovalsNotEmpty + ); + // Move the deposit to the new owner. T::Currency::repatriate_reserved( &details.owner, diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 28b0c414..d3dfbce2 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -428,7 +428,19 @@ pub mod pallet { // Delegate Id. NMapKey, ), - bool, + Option>, + OptionQuery, + >; + + /// Number of collection approvals that owners granted. + #[pallet::storage] + pub type AccountAllowances, I: 'static = ()> = StorageDoubleMap< + _, + Twox64Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + u32, ValueQuery, >; @@ -504,8 +516,12 @@ pub mod pallet { owner: T::AccountId, delegate: T::AccountId, }, - /// All approvals of an item got cancelled. - AllApprovalsCancelled { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// All approvals of an item or a collection got cancelled. + AllApprovalsCancelled { + collection: T::CollectionId, + item: Option, + owner: T::AccountId, + }, /// A `collection` has had its config changed by the `Force` origin. CollectionConfigChanged { collection: T::CollectionId }, /// New metadata has been set for a `collection`. @@ -681,7 +697,7 @@ pub mod pallet { NotForSale, /// The provided bid is too low. BidTooLow, - /// The item has reached its approval limit. + /// The collection or item has reached its approval limit. ReachedApprovalLimit, /// The deadline has already expired. DeadlineExpired, @@ -719,8 +735,10 @@ pub mod pallet { CollectionNotEmpty, /// The witness data should be provided. WitnessRequired, - /// Cant' delete collections whose allowances. - AllowancesNotEmpty, + /// Cant' delete collections whose approvals. + CollectionApprovalsNotEmpty, + /// Collection approval and item approval conflicts. + DelegateApprovalConflict, } #[pallet::call] @@ -1339,7 +1357,12 @@ pub mod pallet { delegate, maybe_deadline, ), - None => Self::do_approve_collection(maybe_check_origin, collection, delegate), + None => Self::do_approve_collection( + maybe_check_origin, + collection, + delegate, + maybe_deadline, + ), } } @@ -1351,8 +1374,8 @@ pub mod pallet { /// /// Arguments: /// - `collection`: The collection of the item of whose approval will be cancelled. - /// - `item`: The optional item of the collection of whose approval will be cancelled. If - /// not provided, an allowance to transfer all items within the collection will be + /// - `maybe_item`: The optional item of the collection of whose approval will be cancelled. + /// If not provided, an allowance to transfer all items within the collection will be /// cancelled. /// - `delegate`: The account that is going to loose their approval. /// @@ -1386,22 +1409,39 @@ pub mod pallet { /// /// Arguments: /// - `collection`: The collection of the item of whose approvals will be cleared. - /// - `item`: The item of the collection of whose approvals will be cleared. + /// - `maybe_item`: The item of the collection of whose approvals will be cleared. The + /// optional item of the collection of whose approval will be cleared. If not provided, + /// all approvals to transfer items within collection /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + #[pallet::weight( + T::WeightInfo::clear_all_transfer_approvals( + maybe_item.is_some() as u32, + witness_allowances.unwrap_or_default() + ) + )] pub fn clear_all_transfer_approvals( origin: OriginFor, collection: T::CollectionId, - item: T::ItemId, + maybe_item: Option, + witness_allowances: Option, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) + + match maybe_item { + Some(item) => + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item), + None => Self::do_clear_all_collection_approvals( + maybe_check_origin, + collection, + witness_allowances.unwrap_or_default(), + ), + } } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 1f63a192..ead3d353 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -343,7 +343,7 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() ), - Error::::AllowancesNotEmpty + Error::::CollectionApprovalsNotEmpty ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); assert_ok!(Nfts::destroy( @@ -661,6 +661,19 @@ fn transfer_owner_should_work() { assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); assert_eq!(System::consumers(&account(2)), 1); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(3), + None + )); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2)), + Error::::CollectionApprovalsNotEmpty + ); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3),)); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2))); assert_eq!(System::consumers(&account(2)), 1); // one consumer is added due to deposit repatriation @@ -1890,7 +1903,7 @@ fn check_allowance_works() { None )); - // collection transfer approved. + // transfer all items within the collection approved (without deadline). assert_noop!( Nfts::check_allowance(&1, &None, &account(1), &account(2)), Error::::NoPermission @@ -1902,7 +1915,7 @@ fn check_allowance_works() { 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. + // transfer a collection item approved (without deadline). assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, @@ -1920,6 +1933,39 @@ fn check_allowance_works() { Error::::NoPermission ); assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(2), &account(3))); + + // transfer all items within the collection approved (with deadline). + let current_block = 1; + let deadline = current_block + 10; + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + account(3), + Some(deadline) + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(3), + Some(deadline + 1) + )); + System::set_block_number(deadline + 2); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(2), &account(3)), + Error::::ApprovalExpired + ); + assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(3))); + System::set_block_number(deadline + 3); + assert_noop!( + Nfts::check_allowance(&0, &Some(42), &account(2), &account(3)), + Error::::ApprovalExpired + ); + assert_noop!( + Nfts::check_allowance(&0, &None, &account(1), &account(3)), + Error::::ApprovalExpired + ); }); } @@ -2043,8 +2089,8 @@ fn cancel_approval_collection_works_with_admin() { owner: account(1), delegate: account(3) })); - assert_eq!(Allowances::::get((0, account(2), account(3))), false); - assert_eq!(Nfts::collection_allowances(0).unwrap(), 0); + assert_eq!(Allowances::::get((0, account(2), account(3))).is_some(), false); + assert_eq!(AccountAllowances::::get(0, account(2)), 0); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2148,6 +2194,32 @@ fn approvals_limit_works() { }); } +#[test] +fn collection_approvals_limit_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + + for i in 3..13 { + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(i), + None + )); + } + // the limit is 10 + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 0, None, account(14), None), + Error::::ReachedApprovalLimit + ); + }); +} + #[test] fn approval_collection_works_with_admin() { new_test_ext().execute_with(|| { @@ -2200,8 +2272,8 @@ fn approval_collection_works_with_admin() { delegate: account(3), deadline: None })); - assert_eq!(Allowances::::get((0, account(1), account(3))), true); - assert_eq!(Nfts::collection_allowances(0).unwrap(), 1); + assert!(Allowances::::get((0, account(1), account(3))).is_some()); + assert_eq!(AccountAllowances::::get(0, account(1)), 1); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -2383,15 +2455,25 @@ fn clear_all_transfer_approvals_works() { )); assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), + Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(account(3)), + 0, + Some(42), + None + ), Error::::NoPermission ); - assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); + assert_ok!(Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(account(2)), + 0, + Some(42), + None + )); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, - item: 42, + item: Some(42), owner: account(2), })); assert_eq!(approvals(0, 42), vec![]); @@ -2407,6 +2489,72 @@ fn clear_all_transfer_approvals_works() { }); } +#[test] +fn clear_all_collection_approvals_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_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(4), + None + )); + + assert_noop!( + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, None, Some(2)), + Error::::NoPermission + ); + + assert_noop!( + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, None, Some(1)), + Error::::BadWitness + ); + + assert_ok!(Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(account(1)), + 0, + None, + Some(2) + )); + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: 0, + item: None, + owner: account(1), + })); + assert_eq!(Allowances::::iter_prefix((0, account(1))).count(), 0); + assert_eq!(AccountAllowances::::get(0, account(1)), 0); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), + Error::::NoPermission + ); + }); +} + #[test] fn total_supply_should_works() { new_test_ext().execute_with(|| { diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 56c9cbaf..941da6ca 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -106,8 +106,6 @@ pub struct CollectionDetails { pub item_configs: 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. diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 0abd73dc..28e7056c 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -61,7 +61,7 @@ pub trait WeightInfo { fn clear_collection_metadata() -> Weight; fn approve_transfer(i: u32, ) -> Weight; fn cancel_approval(i: u32, ) -> Weight; - fn clear_all_transfer_approvals() -> Weight; + fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -117,7 +117,9 @@ 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:0) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -135,19 +137,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 { + fn destroy(_m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32169 + a * (366 ±0)` + // Measured: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 976_000_000 picoseconds. - Weight::from_parts(489_392_768, 2523990) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(2_634, 0).saturating_mul(m.into())) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(406_042, 0).saturating_mul(c.into())) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(5_358_742, 0).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1004_u64)) + // Minimum execution time: 986_000_000 picoseconds. + Weight::from_parts(985_849_637, 2523990) + // Standard Error: 13_005 + .saturating_add(Weight::from_parts(6_541, 0).saturating_mul(c.into())) + // Standard Error: 13_005 + .saturating_add(Weight::from_parts(5_088_456, 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()))) @@ -228,8 +228,8 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, 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::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) @@ -248,10 +248,10 @@ 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: `609` + // Measured: `605` // Estimated: `6068` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(41_000_000, 6068) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 6068) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -317,16 +317,16 @@ impl WeightInfo for SubstrateWeight { /// 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `421` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 19_000_000 picoseconds. + // 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)) @@ -543,47 +543,60 @@ 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:1) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `304 + i * (33 ±0)` - // Estimated: `4266 + i * (2163 ±0)` + // Measured: `360` + // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_371_428, 4266) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + Weight::from_parts(18_575_510, 3578) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_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`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:1) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `397` - // Estimated: `4266 + i * (2163 ±0)` + // Measured: `496` + // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(17_800_000, 4266) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + Weight::from_parts(21_048_979, 3578) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:0) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn clear_all_transfer_approvals() -> Weight { + /// Storage: `Nfts::Allowances` (r:20 w:20) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + /// The range of component `n` is `[0, 20]`. + fn clear_all_transfer_approvals(i: u32, _n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `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)) + // Measured: `1614` + // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(35_525_221, 52750) + .saturating_add(T::DbWeight::get().reads(22_u64)) + .saturating_add(T::DbWeight::get().writes(22_u64)) + .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) @@ -834,7 +847,9 @@ 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:0) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -852,19 +867,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 { + fn destroy(_m: u32, c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32169 + a * (366 ±0)` + // Measured: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 976_000_000 picoseconds. - Weight::from_parts(489_392_768, 2523990) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(2_634, 0).saturating_mul(m.into())) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(406_042, 0).saturating_mul(c.into())) - // Standard Error: 29_146 - .saturating_add(Weight::from_parts(5_358_742, 0).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1004_u64)) + // Minimum execution time: 986_000_000 picoseconds. + Weight::from_parts(985_849_637, 2523990) + // Standard Error: 13_005 + .saturating_add(Weight::from_parts(6_541, 0).saturating_mul(c.into())) + // Standard Error: 13_005 + .saturating_add(Weight::from_parts(5_088_456, 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()))) @@ -946,7 +959,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -965,10 +978,10 @@ 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: `609` + // Measured: `605` // Estimated: `6068` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(41_000_000, 6068) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1034,16 +1047,16 @@ impl WeightInfo for () { /// 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `421` + // Measured: `417` // Estimated: `3593` - // Minimum execution time: 19_000_000 picoseconds. + // 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)) @@ -1260,47 +1273,60 @@ 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:1) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `304 + i * (33 ±0)` - // Estimated: `4266 + i * (2163 ±0)` + // Measured: `360` + // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_371_428, 4266) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + Weight::from_parts(18_575_510, 3578) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_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`) /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(801), added: 3276, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:1) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `397` - // Estimated: `4266 + i * (2163 ±0)` + // Measured: `496` + // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(17_800_000, 4266) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + Weight::from_parts(21_048_979, 3578) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountAllowances` (r:1 w:0) + /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - fn clear_all_transfer_approvals() -> Weight { + /// Storage: `Nfts::Allowances` (r:20 w:20) + /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 1]`. + /// The range of component `n` is `[0, 20]`. + fn clear_all_transfer_approvals(i: u32, _n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `345` - // Estimated: `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)) + // Measured: `1614` + // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(35_525_221, 52750) + .saturating_add(RocksDbWeight::get().reads(22_u64)) + .saturating_add(RocksDbWeight::get().writes(22_u64)) + .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) From cee5933a53850cc552b6ef419e0812df249b1728 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:02:39 +0700 Subject: [PATCH 22/99] fix: weight path --- pallets/nfts/src/weights.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 28e7056c..b87f8902 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -20,7 +20,7 @@ // --no-min-squares // --wasm-execution=compiled // --heap-pages=4096 -// --output=./pallets/nfts/src/weights_temp.rs +// --output=./pallets/nfts/src/weights.rs // --template=./scripts/pallet-weights-template.hbs // --extrinsic= From c7314c59a229348c26f9ef8d526132c458a931f2 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:08:26 +0700 Subject: [PATCH 23/99] test: update pallet tests --- pallets/nfts/src/tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index ead3d353..c5f574b6 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2091,6 +2091,10 @@ fn cancel_approval_collection_works_with_admin() { })); assert_eq!(Allowances::::get((0, account(2), account(3))).is_some(), false); assert_eq!(AccountAllowances::::get(0, account(2)), 0); + assert_eq!( + AccountAllowances::::get(0, account(2)), + Allowances::::iter_prefix((0, account(2))).count() as u32 + ); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2274,6 +2278,10 @@ fn approval_collection_works_with_admin() { })); assert!(Allowances::::get((0, account(1), account(3))).is_some()); assert_eq!(AccountAllowances::::get(0, account(1)), 1); + assert_eq!( + AccountAllowances::::get(0, account(1)), + Allowances::::iter_prefix((0, account(1))).count() as u32 + ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -2543,6 +2551,10 @@ fn clear_all_collection_approvals_works() { })); assert_eq!(Allowances::::iter_prefix((0, account(1))).count(), 0); assert_eq!(AccountAllowances::::get(0, account(1)), 0); + assert_eq!( + AccountAllowances::::get(0, account(1)), + Allowances::::iter_prefix((0, account(1))).count() as u32 + ); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), From 4b19ab5a7b9b2d33ea8b73d0e4329f3796b57284 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:21:37 +0700 Subject: [PATCH 24/99] test: expand cancel_approval test --- pallets/nfts/src/features/approvals.rs | 5 +++++ pallets/nfts/src/tests.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index df62a327..d6d6703c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -108,6 +108,11 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; + ensure!( + !Allowances::::contains_key((collection, &details.owner, &delegate)), + Error::::DelegateApprovalConflict + ); + let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; let is_past_deadline = if let Some(deadline) = maybe_deadline { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index c5f574b6..5c56ecc7 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2353,6 +2353,13 @@ fn cancel_approval_works_with_admin() { account(2), default_item_config() )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 50, + account(1), + default_item_config() + )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), @@ -2374,6 +2381,25 @@ fn cancel_approval_works_with_admin() { Error::::NotDelegate ); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + Some(50), + account(3), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + 0, + None, + account(3), + None + )); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(50), account(3)), + Error::::DelegateApprovalConflict + ); + assert_ok!(Nfts::cancel_approval( RuntimeOrigin::signed(account(2)), 0, From da2dc1c976ddd0f300aa783c0ed7073865be7a7f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:57:06 +0700 Subject: [PATCH 25/99] refactor: do_approve_collection --- pallets/nfts/src/features/approvals.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index d6d6703c..f444edb2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -236,12 +236,7 @@ impl, I: 'static> Pallet { AccountAllowances::::try_mutate(collection, &owner, |allowances| -> Result<(), DispatchError> { ensure!(*allowances < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit); - Allowances::::mutate( - (&collection, &owner, &delegate), - |maybe_deadline| { - *maybe_deadline = Some(deadline); - }, - ); + Allowances::::insert((&collection, &owner, &delegate), deadline); allowances.saturating_inc(); Ok(()) })?; From 9dfe652e181db9ade600a53475b6f11a5adf029c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 19:21:03 +0700 Subject: [PATCH 26/99] refactor: storate item names --- pallets/nfts/src/features/approvals.rs | 67 ++++++++++++------- .../src/features/create_delete_collection.rs | 2 +- pallets/nfts/src/features/transfer.rs | 2 +- pallets/nfts/src/lib.rs | 8 +-- pallets/nfts/src/tests.rs | 48 ++++++------- 5 files changed, 72 insertions(+), 55 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index f444edb2..b149374b 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -73,7 +73,6 @@ impl, I: 'static> Pallet { .approvals .try_insert(delegate.clone(), deadline) .map_err(|_| Error::::ReachedApprovalLimit)?; - Item::::insert(collection, item, &details); Self::deposit_event(Event::TransferApproved { @@ -109,7 +108,7 @@ impl, I: 'static> Pallet { let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; ensure!( - !Allowances::::contains_key((collection, &details.owner, &delegate)), + !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), Error::::DelegateApprovalConflict ); @@ -163,7 +162,7 @@ impl, I: 'static> Pallet { Collection::::get(collection).ok_or(Error::::UnknownCollection)?; ensure!( - AccountAllowances::::get(collection, collection_details.owner) == 0, + AccountApprovals::::get(collection, collection_details.owner) == 0, Error::::DelegateApprovalConflict ); @@ -234,12 +233,19 @@ impl, I: 'static> Pallet { let now = frame_system::Pallet::::block_number(); let deadline = maybe_deadline.map(|d| d.saturating_add(now)); - AccountAllowances::::try_mutate(collection, &owner, |allowances| -> Result<(), DispatchError> { - ensure!(*allowances < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit); - Allowances::::insert((&collection, &owner, &delegate), deadline); - allowances.saturating_inc(); - Ok(()) - })?; + AccountApprovals::::try_mutate( + collection, + &owner, + |allowances| -> Result<(), DispatchError> { + ensure!( + *allowances < T::ApprovalsLimit::get(), + Error::::ReachedApprovalLimit + ); + CollectionApprovals::::insert((&collection, &owner, &delegate), deadline); + allowances.saturating_inc(); + Ok(()) + }, + )?; Ok((owner, deadline)) }, )?; @@ -280,8 +286,9 @@ impl, I: 'static> Pallet { let collection_details = maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; let owner = collection_details.clone().owner; - let maybe_deadline = Allowances::::get((&collection, &owner, &delegate)) - .ok_or(Error::::NotDelegate)?; + let maybe_deadline = + CollectionApprovals::::get((&collection, &owner, &delegate)) + .ok_or(Error::::NotDelegate)?; let is_past_deadline = if let Some(deadline) = maybe_deadline { let now = frame_system::Pallet::::block_number(); @@ -296,8 +303,8 @@ impl, I: 'static> Pallet { } } - Allowances::::remove((&collection, &owner, &delegate)); - AccountAllowances::::mutate(collection, &owner, |allowances| { + CollectionApprovals::::remove((&collection, &owner, &delegate)); + AccountApprovals::::mutate(collection, &owner, |allowances| { allowances.saturating_dec(); }); Ok(owner) @@ -320,6 +327,8 @@ impl, I: 'static> Pallet { /// collection, granting permission to clear all collection approvals. If `None`, no /// permission check is performed. /// - `collection`: The collection ID containing the item. + /// - `witness_allowances`: Information on the collection approvals cleared. This must be + /// correct. pub(crate) fn do_clear_all_collection_approvals( maybe_check_origin: Option, collection: T::CollectionId, @@ -336,12 +345,12 @@ impl, I: 'static> Pallet { ensure!(check_origin == owner.clone(), Error::::NoPermission); } - AccountAllowances::::try_mutate( + AccountApprovals::::try_mutate( collection, &owner, |allowances| -> Result<(), DispatchError> { ensure!(*allowances == witness_allowances, Error::::BadWitness); - let _ = Allowances::::clear_prefix( + let _ = CollectionApprovals::::clear_prefix( (collection, owner.clone()), *allowances, None, @@ -360,13 +369,20 @@ impl, I: 'static> Pallet { Ok(()) } - // Check if a `delegate` has a permission to spend the collection. - fn check_collection_allowance( + /// Checks whether the `delegate` has the necessary allowance to transfer all items within the + /// collection. If the `delegate` has approval to transfer all items in the collection, they can + /// transfer every item without requiring explicit approval for that item. + /// + /// - `collection`: The identifier of the collection + /// - `owner`: The owner of the collection or the collection item. + /// - `delegate`: The account that was previously allowed to take control of all items within + /// the collection. + fn check_collection_approval( collection: &T::CollectionId, owner: &T::AccountId, delegate: &T::AccountId, ) -> Result<(), DispatchError> { - let maybe_deadline = Allowances::::get((&collection, &owner, &delegate)) + let maybe_deadline = CollectionApprovals::::get((&collection, &owner, &delegate)) .ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { let block_number = frame_system::Pallet::::block_number(); @@ -377,29 +393,30 @@ impl, I: 'static> Pallet { /// Checks whether the `delegate` has the necessary allowance to transfer items within the /// collection or a specific item in the collection. If the `delegate` has approval to transfer - /// all items in the collection, they can transfer a specific item without requiring explicit + /// all items in the collection, they can transfer every item without requiring explicit /// approval for that item. /// /// - `collection`: The identifier of the collection /// - `maybe_item`: The optional item of the collection that the delegated account has an /// approval to transfer. If not provided, an approval to transfer all items within the /// collection will be checked. + /// - `owner`: The owner of the collection or the collection item. /// - `delegate`: The account that was previously allowed to take control of all items within /// the collection. - pub fn check_allowance( + pub fn check_approval( collection: &T::CollectionId, - item: &Option, + maybe_item: &Option, owner: &T::AccountId, delegate: &T::AccountId, ) -> Result<(), DispatchError> { // Check if a `delegate` has a permission to spend the collection. - let check_collection_allowance_error = - match Self::check_collection_allowance(collection, owner, delegate) { + let check_collection_approval_error = + match Self::check_collection_approval(collection, owner, delegate) { Ok(()) => return Ok(()), Err(error) => error, }; // Check if a `delegate` has a permission to spend the collection item. - if let Some(item) = item { + if let Some(item) = maybe_item { let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let maybe_deadline = @@ -410,6 +427,6 @@ impl, I: 'static> Pallet { } return Ok(()); }; - Err(check_collection_allowance_error) + Err(check_collection_approval_error) } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 5be73fc9..c5bb74e1 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -112,7 +112,7 @@ impl, I: 'static> Pallet { if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } - let allowances = AccountAllowances::::get(collection, &collection_details.owner); + let allowances = AccountApprovals::::get(collection, &collection_details.owner); ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); ensure!(allowances == 0, Error::::CollectionApprovalsNotEmpty); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index c8f66e4f..bf710b6c 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -154,7 +154,7 @@ impl, I: 'static> Pallet { // second account before making the transaction and then claiming all items // within the collection back. ensure!( - AccountAllowances::::get(collection, &details.owner) == 0, + AccountApprovals::::get(collection, &details.owner) == 0, Error::::CollectionApprovalsNotEmpty ); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index d3dfbce2..a4fa4a61 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -418,7 +418,7 @@ pub mod pallet { /// Permission for the delegate to transfer all owner's items within a collection. #[pallet::storage] - pub type Allowances, I: 'static = ()> = StorageNMap< + pub type CollectionApprovals, I: 'static = ()> = StorageNMap< _, ( // Collection ID. @@ -434,7 +434,7 @@ pub mod pallet { /// Number of collection approvals that owners granted. #[pallet::storage] - pub type AccountAllowances, I: 'static = ()> = StorageDoubleMap< + pub type AccountApprovals, I: 'static = ()> = StorageDoubleMap< _, Twox64Concat, T::CollectionId, @@ -838,7 +838,7 @@ pub mod pallet { /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the /// owner of the `collection`. /// - /// NOTE: The collection must have 0 items to be destroyed. + /// NOTE: The collection must have 0 items and 0 collection approvals to be destroyed. /// /// - `collection`: The identifier of the collection to be destroyed. /// - `witness`: Information on the items minted in the collection. This must be @@ -1081,7 +1081,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_allowance(&collection, &Some(item), &details.owner, &origin)?; + Self::check_approval(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 5c56ecc7..27a44d8c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -352,7 +352,7 @@ fn destroy_should_work() { Nfts::get_destroy_witness(&0).unwrap() )); assert_eq!(AccountBalance::::get(0, account(1)), 0); - assert_eq!(Allowances::::iter_prefix((0,)).count(), 0); + assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -1905,15 +1905,15 @@ fn check_allowance_works() { // transfer all items within the collection approved (without deadline). assert_noop!( - Nfts::check_allowance(&1, &None, &account(1), &account(2)), + Nfts::check_approval(&1, &None, &account(1), &account(2)), Error::::NoPermission ); assert_noop!( - Nfts::check_allowance(&1, &Some(43), &account(1), &account(2)), + Nfts::check_approval(&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))); + assert_ok!(Nfts::check_approval(&0, &None, &account(1), &account(2))); + assert_ok!(Nfts::check_approval(&0, &Some(42), &account(1), &account(2))); // transfer a collection item approved (without deadline). assert_ok!(Nfts::approve_transfer( @@ -1925,14 +1925,14 @@ fn check_allowance_works() { )); assert_noop!( - Nfts::check_allowance(&0, &Some(43), &account(2), &account(3)), + Nfts::check_approval(&0, &Some(43), &account(2), &account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::check_allowance(&0, &Some(42), &account(2), &account(4)), + Nfts::check_approval(&0, &Some(42), &account(2), &account(4)), Error::::NoPermission ); - assert_ok!(Nfts::check_allowance(&0, &Some(42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); // transfer all items within the collection approved (with deadline). let current_block = 1; @@ -1953,17 +1953,17 @@ fn check_allowance_works() { )); System::set_block_number(deadline + 2); assert_noop!( - Nfts::check_allowance(&0, &Some(42), &account(2), &account(3)), + Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), Error::::ApprovalExpired ); - assert_ok!(Nfts::check_allowance(&0, &None, &account(1), &account(3))); + assert_ok!(Nfts::check_approval(&0, &None, &account(1), &account(3))); System::set_block_number(deadline + 3); assert_noop!( - Nfts::check_allowance(&0, &Some(42), &account(2), &account(3)), + Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_allowance(&0, &None, &account(1), &account(3)), + Nfts::check_approval(&0, &None, &account(1), &account(3)), Error::::ApprovalExpired ); }); @@ -2089,11 +2089,11 @@ fn cancel_approval_collection_works_with_admin() { owner: account(1), delegate: account(3) })); - assert_eq!(Allowances::::get((0, account(2), account(3))).is_some(), false); - assert_eq!(AccountAllowances::::get(0, account(2)), 0); + assert_eq!(CollectionApprovals::::get((0, account(2), account(3))).is_some(), false); + assert_eq!(AccountApprovals::::get(0, account(2)), 0); assert_eq!( - AccountAllowances::::get(0, account(2)), - Allowances::::iter_prefix((0, account(2))).count() as u32 + AccountApprovals::::get(0, account(2)), + CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 ); assert_noop!( @@ -2276,11 +2276,11 @@ fn approval_collection_works_with_admin() { delegate: account(3), deadline: None })); - assert!(Allowances::::get((0, account(1), account(3))).is_some()); - assert_eq!(AccountAllowances::::get(0, account(1)), 1); + assert!(CollectionApprovals::::get((0, account(1), account(3))).is_some()); + assert_eq!(AccountApprovals::::get(0, account(1)), 1); assert_eq!( - AccountAllowances::::get(0, account(1)), - Allowances::::iter_prefix((0, account(1))).count() as u32 + AccountApprovals::::get(0, account(1)), + CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); @@ -2575,11 +2575,11 @@ fn clear_all_collection_approvals_works() { item: None, owner: account(1), })); - assert_eq!(Allowances::::iter_prefix((0, account(1))).count(), 0); - assert_eq!(AccountAllowances::::get(0, account(1)), 0); + assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); + assert_eq!(AccountApprovals::::get(0, account(1)), 0); assert_eq!( - AccountAllowances::::get(0, account(1)), - Allowances::::iter_prefix((0, account(1))).count() as u32 + AccountApprovals::::get(0, account(1)), + CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 ); assert_noop!( From b39f1a1802d87ab61ccb738bedfa253146798280 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:26:54 +0700 Subject: [PATCH 27/99] refactor: allowances to approvals --- pallets/nfts/src/benchmarking.rs | 4 ++-- pallets/nfts/src/features/approvals.rs | 22 +++++++++---------- .../src/features/create_delete_collection.rs | 4 ++-- pallets/nfts/src/impl_nonfungibles.rs | 4 ++-- pallets/nfts/src/lib.rs | 6 ++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index bcdbcc51..239ea22b 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -635,7 +635,7 @@ benchmarks_instance_pallet! { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); - let (maybe_item, witness_allowances) = if i == 0 { + let (maybe_item, witness_approvals) = if i == 0 { for i in 0 .. n { approve_collection::(i); } @@ -648,7 +648,7 @@ benchmarks_instance_pallet! { Nfts::::approve_transfer(origin, collection, Some(item), delegate_lookup.clone(), Some(deadline))?; (Some(item), None) }; - }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, witness_allowances) + }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, witness_approvals) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item: maybe_item, owner: caller}.into()); } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index b149374b..36d2d75a 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -236,13 +236,13 @@ impl, I: 'static> Pallet { AccountApprovals::::try_mutate( collection, &owner, - |allowances| -> Result<(), DispatchError> { + |approvals| -> Result<(), DispatchError> { ensure!( - *allowances < T::ApprovalsLimit::get(), + *approvals < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit ); CollectionApprovals::::insert((&collection, &owner, &delegate), deadline); - allowances.saturating_inc(); + approvals.saturating_inc(); Ok(()) }, )?; @@ -304,8 +304,8 @@ impl, I: 'static> Pallet { } CollectionApprovals::::remove((&collection, &owner, &delegate)); - AccountApprovals::::mutate(collection, &owner, |allowances| { - allowances.saturating_dec(); + AccountApprovals::::mutate(collection, &owner, |approvals| { + approvals.saturating_dec(); }); Ok(owner) }, @@ -327,12 +327,12 @@ impl, I: 'static> Pallet { /// collection, granting permission to clear all collection approvals. If `None`, no /// permission check is performed. /// - `collection`: The collection ID containing the item. - /// - `witness_allowances`: Information on the collection approvals cleared. This must be + /// - `witness_approvals`: Information on the collection approvals cleared. This must be /// correct. pub(crate) fn do_clear_all_collection_approvals( maybe_check_origin: Option, collection: T::CollectionId, - witness_allowances: u32, + witness_approvals: u32, ) -> DispatchResult { let owner = Collection::::try_mutate( collection, @@ -348,14 +348,14 @@ impl, I: 'static> Pallet { AccountApprovals::::try_mutate( collection, &owner, - |allowances| -> Result<(), DispatchError> { - ensure!(*allowances == witness_allowances, Error::::BadWitness); + |approvals| -> Result<(), DispatchError> { + ensure!(*approvals == witness_approvals, Error::::BadWitness); let _ = CollectionApprovals::::clear_prefix( (collection, owner.clone()), - *allowances, + *approvals, None, ); - *allowances = 0; + *approvals = 0; Ok(()) }, diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index c5bb74e1..509d9709 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -112,9 +112,9 @@ impl, I: 'static> Pallet { if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } - let allowances = AccountApprovals::::get(collection, &collection_details.owner); + let approvals = AccountApprovals::::get(collection, &collection_details.owner); ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); - ensure!(allowances == 0, Error::::CollectionApprovalsNotEmpty); + ensure!(approvals == 0, Error::::CollectionApprovalsNotEmpty); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index 0c54f0b7..b014e3ed 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -254,7 +254,7 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig Self::do_burn(*collection, *item, |d| { if let Some(check_owner) = maybe_check_owner { if &d.owner != check_owner { - return Err(Error::::NoPermission.into()); + return Err(Error::::NoPermission.into()) } } Ok(()) @@ -419,7 +419,7 @@ impl, I: 'static> Transfer for Pallet { Self::has_system_attribute(collection, item, PalletAttributes::TransferDisabled)?; // Can't lock the item twice if transfer_disabled { - return Err(Error::::ItemLocked.into()); + return Err(Error::::ItemLocked.into()) } >::set_attribute( diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index a4fa4a61..a7d3f10d 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1420,14 +1420,14 @@ pub mod pallet { #[pallet::weight( T::WeightInfo::clear_all_transfer_approvals( maybe_item.is_some() as u32, - witness_allowances.unwrap_or_default() + witness_approvals.unwrap_or_default() ) )] pub fn clear_all_transfer_approvals( origin: OriginFor, collection: T::CollectionId, maybe_item: Option, - witness_allowances: Option, + witness_approvals: Option, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1439,7 +1439,7 @@ pub mod pallet { None => Self::do_clear_all_collection_approvals( maybe_check_origin, collection, - witness_allowances.unwrap_or_default(), + witness_approvals.unwrap_or_default(), ), } } From 37b869aa4977910e7aaef69c9ba716700f241c62 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:45:45 +0700 Subject: [PATCH 28/99] refactor: approval methods --- pallets/nfts/src/features/approvals.rs | 141 ++++++++++--------------- 1 file changed, 58 insertions(+), 83 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 36d2d75a..d3632520 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -20,7 +20,6 @@ //! to have the functionality defined in this module. use frame_support::pallet_prelude::*; -use frame_system::pallet_prelude::BlockNumberFor; use crate::*; @@ -220,33 +219,24 @@ impl, I: 'static> Pallet { Error::::ItemsNonTransferable ); - let (owner, deadline) = Collection::::try_mutate( + let owner = + Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + + let now = frame_system::Pallet::::block_number(); + let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + + AccountApprovals::::try_mutate( collection, - |maybe_collection_details| -> Result<(T::AccountId, Option>), DispatchError> { - let collection_details = - maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let owner = collection_details.clone().owner; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - let now = frame_system::Pallet::::block_number(); - let deadline = maybe_deadline.map(|d| d.saturating_add(now)); - - AccountApprovals::::try_mutate( - collection, - &owner, - |approvals| -> Result<(), DispatchError> { - ensure!( - *approvals < T::ApprovalsLimit::get(), - Error::::ReachedApprovalLimit - ); - CollectionApprovals::::insert((&collection, &owner, &delegate), deadline); - approvals.saturating_inc(); - Ok(()) - }, - )?; - Ok((owner, deadline)) + &owner, + |approvals| -> Result<(), DispatchError> { + ensure!(*approvals < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit); + CollectionApprovals::::insert((&collection, &owner, &delegate), deadline); + approvals.saturating_inc(); + Ok(()) }, )?; @@ -280,36 +270,29 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let owner = Collection::::try_mutate( - collection, - |maybe_collection_details| -> Result { - let collection_details = - maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let owner = collection_details.clone().owner; - let maybe_deadline = - CollectionApprovals::::get((&collection, &owner, &delegate)) - .ok_or(Error::::NotDelegate)?; - - let is_past_deadline = if let Some(deadline) = maybe_deadline { - let now = frame_system::Pallet::::block_number(); - now > deadline - } else { - false - }; - - if !is_past_deadline { - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - } - - CollectionApprovals::::remove((&collection, &owner, &delegate)); - AccountApprovals::::mutate(collection, &owner, |approvals| { - approvals.saturating_dec(); - }); - Ok(owner) - }, - )?; + let owner = + Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + let maybe_deadline = CollectionApprovals::::get((&collection, &owner, &delegate)) + .ok_or(Error::::NotDelegate)?; + + let is_past_deadline = if let Some(deadline) = maybe_deadline { + let now = frame_system::Pallet::::block_number(); + now > deadline + } else { + false + }; + + if !is_past_deadline { + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner, Error::::NoPermission); + } + } + + CollectionApprovals::::remove((&collection, &owner, &delegate)); + AccountApprovals::::mutate(collection, &owner, |approvals| { + approvals.saturating_dec(); + }); Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); @@ -334,33 +317,25 @@ impl, I: 'static> Pallet { collection: T::CollectionId, witness_approvals: u32, ) -> DispatchResult { - let owner = Collection::::try_mutate( + let owner = + Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!(check_origin == owner.clone(), Error::::NoPermission); + } + + AccountApprovals::::try_mutate( collection, - |maybe_collection_details| -> Result { - let collection_details = - maybe_collection_details.as_mut().ok_or(Error::::UnknownCollection)?; - let owner = collection_details.clone().owner; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner.clone(), Error::::NoPermission); - } - - AccountApprovals::::try_mutate( - collection, - &owner, - |approvals| -> Result<(), DispatchError> { - ensure!(*approvals == witness_approvals, Error::::BadWitness); - let _ = CollectionApprovals::::clear_prefix( - (collection, owner.clone()), - *approvals, - None, - ); - *approvals = 0; - - Ok(()) - }, - )?; - Ok(owner) + &owner, + |approvals| -> Result<(), DispatchError> { + ensure!(*approvals == witness_approvals, Error::::BadWitness); + let _ = CollectionApprovals::::clear_prefix( + (collection, owner.clone()), + *approvals, + None, + ); + *approvals = 0; + Ok(()) }, )?; From a96a1f5d3d8474007e86d7836e62facbd2251bae Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:59:13 +0700 Subject: [PATCH 29/99] refactor: benchmarking --- pallets/nfts/src/benchmarking.rs | 6 +++--- pallets/nfts/src/features/create_delete_collection.rs | 8 +++++--- pallets/nfts/src/lib.rs | 2 +- pallets/nfts/src/tests.rs | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 239ea22b..85a4d48d 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -595,13 +595,13 @@ benchmarks_instance_pallet! { 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(); let maybe_item = if i == 0 { None } else { + let (item, ..) = mint_item::(0); Some(item) }; }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, Some(deadline)) @@ -613,7 +613,6 @@ benchmarks_instance_pallet! { 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(); @@ -621,6 +620,7 @@ benchmarks_instance_pallet! { let maybe_item = if i == 0 { None } else { + let (item, ..) = mint_item::(0); Some(item) }; Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; @@ -634,13 +634,13 @@ benchmarks_instance_pallet! { let n in 0 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); - let (item, ..) = mint_item::(0); let (maybe_item, witness_approvals) = if i == 0 { for i in 0 .. n { approve_collection::(i); } (None, Some(n)) } else { + 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(); diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 509d9709..889e52ba 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -97,7 +97,7 @@ impl, I: 'static> Pallet { /// - If the collection is not empty (contains items) /// ([`CollectionNotEmpty`](crate::Error::CollectionNotEmpty)). /// - If the collection approvals is not empty (contains permissions to transfer all items - /// within the collection) + /// within the collection). /// ([`CollectionApprovalsNotEmpty`](crate::Error::CollectionApprovalsNotEmpty)). /// - If the `witness` does not match the actual collection details /// ([`BadWitness`](crate::Error::BadWitness)). @@ -112,9 +112,11 @@ impl, I: 'static> Pallet { if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } - let approvals = AccountApprovals::::get(collection, &collection_details.owner); ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); - ensure!(approvals == 0, Error::::CollectionApprovalsNotEmpty); + ensure!( + AccountApprovals::::get(collection, &collection_details.owner) == 0, + Error::::CollectionApprovalsNotEmpty + ); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index a7d3f10d..024c2262 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1411,7 +1411,7 @@ pub mod pallet { /// - `collection`: The collection of the item of whose approvals will be cleared. /// - `maybe_item`: The item of the collection of whose approvals will be cleared. The /// optional item of the collection of whose approval will be cleared. If not provided, - /// all approvals to transfer items within collection + /// all approvals to transfer items within collection. /// /// Emits `AllApprovalsCancelled` on success. /// diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 27a44d8c..c579054d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1880,7 +1880,7 @@ fn approval_lifecycle_works() { } #[test] -fn check_allowance_works() { +fn check_approval_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), From 5615f1b622de0c9675303a206d70f39defeb18a9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:04:31 +0700 Subject: [PATCH 30/99] chore: update weight file --- pallets/nfts/src/features/transfer.rs | 2 +- pallets/nfts/src/weights.rs | 577 +++++++++++++------------- 2 files changed, 296 insertions(+), 283 deletions(-) diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index bf710b6c..594df56d 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -146,7 +146,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(()) } // All collection approvals need to be removed because otherwise diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index b87f8902..d3fddb28 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-11-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-26, 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` @@ -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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3553` + // Estimated: `3549` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3553) + Weight::from_parts(29_000_000, 3549) .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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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,16 +110,16 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3553` + // Estimated: `3549` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3553) + Weight::from_parts(17_000_000, 3549) .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`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:0) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -137,16 +137,18 @@ 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: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 986_000_000 picoseconds. - Weight::from_parts(985_849_637, 2523990) - // Standard Error: 13_005 - .saturating_add(Weight::from_parts(6_541, 0).saturating_mul(c.into())) - // Standard Error: 13_005 - .saturating_add(Weight::from_parts(5_088_456, 0).saturating_mul(a.into())) + // Minimum execution time: 970_000_000 picoseconds. + Weight::from_parts(872_656_952, 2523990) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(62_901, 0).saturating_mul(m.into())) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(42_980, 0).saturating_mul(c.into())) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(5_175_457, 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)) @@ -158,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -169,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: `386` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(91_000_000, 4326) + // Minimum execution time: 42_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)) } @@ -181,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -192,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: `386` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(64_000_000, 4326) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -204,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -221,14 +223,14 @@ 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: `580` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(66_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:1) + /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -250,13 +252,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `605` // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 6068) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 6068) .saturating_add(T::DbWeight::get().reads(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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -264,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: `694 + i * (108 ±0)` - // Estimated: `3553 + i * (3336 ±0)` + // Measured: `690 + i * (108 ±0)` + // Estimated: `3549 + i * (3336 ±0)` // Minimum execution time: 10_000_000 picoseconds. - Weight::from_parts(11_000_000, 3553) - // Standard Error: 24_164 - .saturating_add(Weight::from_parts(16_322_691, 0).saturating_mul(i.into())) + Weight::from_parts(11_000_000, 3549) + // Standard Error: 23_461 + .saturating_add(Weight::from_parts(16_264_562, 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()))) @@ -283,7 +285,7 @@ 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)) @@ -297,20 +299,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `395` // Estimated: `3534` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `271` - // Estimated: `3553` + // Measured: `267` + // Estimated: `3549` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3553) + Weight::from_parts(12_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -318,6 +320,8 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -326,47 +330,47 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3593) + .saturating_add(T::DbWeight::get().reads(4_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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `300` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(32_000_000, 6078) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 6078) .saturating_add(T::DbWeight::get().reads(3_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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `242` - // Estimated: `3553` + // Measured: `238` + // Estimated: `3549` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3553) + Weight::from_parts(12_000_000, 3549) .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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3553` + // Estimated: `3549` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3553) + Weight::from_parts(9_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -378,13 +382,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -395,23 +399,23 @@ 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: `503` + // Measured: `499` // Estimated: `3944` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(40_000_000, 3944) + Weight::from_parts(41_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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(20_000_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)) } @@ -422,13 +426,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `947` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(35_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -440,8 +444,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 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)) } @@ -460,8 +464,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_818 - .saturating_add(Weight::from_parts(5_055_243, 0).saturating_mul(n.into())) + // Standard Error: 6_333 + .saturating_add(Weight::from_parts(4_993_618, 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)) @@ -471,7 +475,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -480,10 +484,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: `503` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(32_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -492,15 +496,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `813` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -509,32 +513,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `329` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + // Minimum execution time: 29_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)) } /// 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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::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: `647` + // Measured: `643` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + Weight::from_parts(29_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,56 +548,58 @@ impl WeightInfo for SubstrateWeight { /// 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`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:1) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:1) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:0 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `360` - // Estimated: `3578 + i * (2163 ±0)` + // Estimated: `3549 + i * (2163 ±0)` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(18_575_510, 3578) - .saturating_add(T::DbWeight::get().reads(4_u64)) + Weight::from_parts(18_000_000, 3549) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_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`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, 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::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:1) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:1) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `496` + // Measured: `495` // Estimated: `3578 + i * (2163 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(21_048_979, 3578) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(21_000_000, 3578) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:0) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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::Allowances` (r:20 w:20) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:20 w:20) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. - fn clear_all_transfer_approvals(i: u32, _n: u32, ) -> Weight { + fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1614` + // Measured: `1613` // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(35_525_221, 52750) + Weight::from_parts(35_412_495, 52750) + // Standard Error: 2_608 + .saturating_add(Weight::from_parts(89, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(22_u64)) .saturating_add(T::DbWeight::get().writes(22_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) @@ -605,20 +611,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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: `271` - // Estimated: `3553` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3553) + // Measured: `267` + // Estimated: `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)) } @@ -630,8 +636,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -647,8 +653,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)) } @@ -657,7 +663,7 @@ impl WeightInfo for SubstrateWeight { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -672,10 +678,10 @@ 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: `721` + // Measured: `717` // Estimated: `6068` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6068) + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -685,9 +691,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_185_779, 0) - // Standard Error: 5_205 - .saturating_add(Weight::from_parts(1_740_314, 0).saturating_mul(n.into())) + Weight::from_parts(2_072_685, 0) + // Standard Error: 5_703 + .saturating_add(Weight::from_parts(1_678_167, 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`) @@ -697,7 +703,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. + // 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)) @@ -720,7 +726,7 @@ impl WeightInfo for SubstrateWeight { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -735,10 +741,10 @@ 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: `911` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 78_000_000 picoseconds. - Weight::from_parts(79_000_000, 7662) + // Minimum execution time: 77_000_000 picoseconds. + Weight::from_parts(78_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -749,7 +755,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -765,12 +771,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: `489` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(106_829_596, 6078) - // Standard Error: 67_259 - .saturating_add(Weight::from_parts(28_340_797, 0).saturating_mul(n.into())) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(103_806_930, 6078) + // Standard Error: 121_521 + .saturating_add(Weight::from_parts(28_678_555, 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)) @@ -784,7 +790,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -792,12 +798,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: `518` + // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(62_235_731, 4466) - // Standard Error: 78_176 - .saturating_add(Weight::from_parts(26_600_501, 0).saturating_mul(n.into())) + Weight::from_parts(56_704_042, 4466) + // Standard Error: 54_119 + .saturating_add(Weight::from_parts(26_999_990, 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)) @@ -811,7 +817,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -821,16 +827,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `105` - // Estimated: `3553` + // Estimated: `3549` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3553) + Weight::from_parts(29_000_000, 3549) .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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -840,16 +846,16 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `3` - // Estimated: `3553` + // Estimated: `3549` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3553) + Weight::from_parts(17_000_000, 3549) .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`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:0) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -867,16 +873,18 @@ 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: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 986_000_000 picoseconds. - Weight::from_parts(985_849_637, 2523990) - // Standard Error: 13_005 - .saturating_add(Weight::from_parts(6_541, 0).saturating_mul(c.into())) - // Standard Error: 13_005 - .saturating_add(Weight::from_parts(5_088_456, 0).saturating_mul(a.into())) + // Minimum execution time: 970_000_000 picoseconds. + Weight::from_parts(872_656_952, 2523990) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(62_901, 0).saturating_mul(m.into())) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(42_980, 0).saturating_mul(c.into())) + // Standard Error: 22_341 + .saturating_add(Weight::from_parts(5_175_457, 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)) @@ -888,7 +896,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -899,10 +907,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: `386` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 43_000_000 picoseconds. - Weight::from_parts(91_000_000, 4326) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(42_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -911,7 +919,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -922,10 +930,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: `386` + // Measured: `382` // Estimated: `4326` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(64_000_000, 4326) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(39_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -934,7 +942,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -951,10 +959,10 @@ 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: `580` + // Measured: `576` // Estimated: `4326` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(66_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)) } @@ -980,13 +988,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `605` // Estimated: `6068` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 6068) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::Item` (r:5000 w:5000) @@ -994,12 +1002,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `694 + i * (108 ±0)` - // Estimated: `3553 + i * (3336 ±0)` + // Measured: `690 + i * (108 ±0)` + // Estimated: `3549 + i * (3336 ±0)` // Minimum execution time: 10_000_000 picoseconds. - Weight::from_parts(11_000_000, 3553) - // Standard Error: 24_164 - .saturating_add(Weight::from_parts(16_322_691, 0).saturating_mul(i.into())) + Weight::from_parts(11_000_000, 3549) + // Standard Error: 23_461 + .saturating_add(Weight::from_parts(16_264_562, 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()))) @@ -1013,7 +1021,7 @@ 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)) @@ -1027,20 +1035,20 @@ impl WeightInfo for () { // Measured: `395` // Estimated: `3534` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + 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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `271` - // Estimated: `3553` + // Measured: `267` + // Estimated: `3549` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3553) + Weight::from_parts(12_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1048,6 +1056,8 @@ impl WeightInfo for () { /// 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`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -1056,47 +1066,47 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3593) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `300` + // Measured: `296` // Estimated: `6078` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(32_000_000, 6078) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_000_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `242` - // Estimated: `3553` + // Measured: `238` + // Estimated: `3549` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3553) + Weight::from_parts(12_000_000, 3549) .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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `3553` + // Estimated: `3549` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3553) + Weight::from_parts(9_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1108,13 +1118,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. + // 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)) } /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::CollectionConfigOf` (r:1 w:0) @@ -1125,23 +1135,23 @@ 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: `503` + // Measured: `499` // Estimated: `3944` // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(40_000_000, 3944) + Weight::from_parts(41_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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `275` + // Measured: `271` // Estimated: `3944` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(20_000_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)) } @@ -1152,13 +1162,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `947` + // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(37_000_000, 3944) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(35_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1170,8 +1180,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 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)) } @@ -1190,8 +1200,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_818 - .saturating_add(Weight::from_parts(5_055_243, 0).saturating_mul(n.into())) + // Standard Error: 6_333 + .saturating_add(Weight::from_parts(4_993_618, 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)) @@ -1201,7 +1211,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1210,10 +1220,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: `503` + // Measured: `499` // Estimated: `3812` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(32_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1222,15 +1232,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `813` + // Measured: `809` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1239,32 +1249,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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: `329` + // Measured: `325` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(30_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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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::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: `647` + // Measured: `643` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 3759) + Weight::from_parts(29_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1274,56 +1284,58 @@ impl WeightInfo for () { /// 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`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:1) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:1) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:0 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `360` - // Estimated: `3578 + i * (2163 ±0)` + // Estimated: `3549 + i * (2163 ±0)` // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(18_575_510, 3578) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + Weight::from_parts(18_000_000, 3549) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_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`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, 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::Allowances` (r:1 w:1) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:1) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:1) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `496` + // Measured: `495` // Estimated: `3578 + i * (2163 ±0)` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(21_048_979, 3578) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(21_000_000, 3578) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountAllowances` (r:1 w:0) - /// Proof: `Nfts::AccountAllowances` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::AccountApprovals` (r:1 w:0) + /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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::Allowances` (r:20 w:20) - /// Proof: `Nfts::Allowances` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:20 w:20) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. - fn clear_all_transfer_approvals(i: u32, _n: u32, ) -> Weight { + fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1614` + // Measured: `1613` // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(35_525_221, 52750) + Weight::from_parts(35_412_495, 52750) + // Standard Error: 2_608 + .saturating_add(Weight::from_parts(89, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(22_u64)) .saturating_add(RocksDbWeight::get().writes(22_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) @@ -1335,20 +1347,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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: `271` - // Estimated: `3553` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3553) + // Measured: `267` + // Estimated: `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)) } @@ -1360,8 +1372,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1377,8 +1389,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)) } @@ -1387,7 +1399,7 @@ impl WeightInfo for () { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1402,10 +1414,10 @@ 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: `721` + // Measured: `717` // Estimated: `6068` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6068) + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(44_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1415,9 +1427,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_185_779, 0) - // Standard Error: 5_205 - .saturating_add(Weight::from_parts(1_740_314, 0).saturating_mul(n.into())) + Weight::from_parts(2_072_685, 0) + // Standard Error: 5_703 + .saturating_add(Weight::from_parts(1_678_167, 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`) @@ -1427,7 +1439,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 14_000_000 picoseconds. + // 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)) @@ -1450,7 +1462,7 @@ impl WeightInfo for () { /// 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:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1465,10 +1477,10 @@ 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: `911` + // Measured: `907` // Estimated: `7662` - // Minimum execution time: 78_000_000 picoseconds. - Weight::from_parts(79_000_000, 7662) + // Minimum execution time: 77_000_000 picoseconds. + Weight::from_parts(78_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -1479,7 +1491,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(88), added: 2563, mode: `MaxEncodedLen`) + /// 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) @@ -1495,12 +1507,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: `489` + // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(106_829_596, 6078) - // Standard Error: 67_259 - .saturating_add(Weight::from_parts(28_340_797, 0).saturating_mul(n.into())) + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(103_806_930, 6078) + // Standard Error: 121_521 + .saturating_add(Weight::from_parts(28_678_555, 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)) @@ -1514,7 +1526,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(88), added: 2563, mode: `MaxEncodedLen`) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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) @@ -1522,12 +1534,12 @@ 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: `518` + // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(62_235_731, 4466) - // Standard Error: 78_176 - .saturating_add(Weight::from_parts(26_600_501, 0).saturating_mul(n.into())) + Weight::from_parts(56_704_042, 4466) + // Standard Error: 54_119 + .saturating_add(Weight::from_parts(26_999_990, 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)) @@ -1535,3 +1547,4 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } + From b7d620eacb11fa26449a3e17e1b9e2e03f4a8e7c Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:01:41 +0700 Subject: [PATCH 31/99] fix: resolve comments & collection approvals logic (#395) --- pallets/nfts/src/features/approvals.rs | 229 ++++++++---------- .../src/features/create_delete_collection.rs | 13 +- .../nfts/src/features/create_delete_item.rs | 4 +- pallets/nfts/src/features/transfer.rs | 14 +- pallets/nfts/src/lib.rs | 121 +++++---- pallets/nfts/src/migration.rs | 122 ++++++++++ pallets/nfts/src/tests.rs | 177 +++++++------- pallets/nfts/src/types.rs | 12 +- 8 files changed, 411 insertions(+), 281 deletions(-) create mode 100644 pallets/nfts/src/migration.rs diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index d3632520..e98a2380 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -161,7 +161,7 @@ impl, I: 'static> Pallet { Collection::::get(collection).ok_or(Error::::UnknownCollection)?; ensure!( - AccountApprovals::::get(collection, collection_details.owner) == 0, + CollectionApprovalCount::::get(collection, Some(collection_details.owner)) == 0, Error::::DelegateApprovalConflict ); @@ -184,26 +184,23 @@ impl, I: 'static> Pallet { Ok(()) } - /// Approves the transfer of all items within the collection to a delegate. + /// Approves the transfer of items in the collection that owned by the origin to a delegate. /// - /// This function is used to approve the transfer of all items within the `collection` to - /// a `delegate`. If `maybe_check_origin` is specified, the function ensures that the - /// `check_origin` account is the owner of the collection, granting them permission to approve - /// the transfer. The `delegate` is the account that will be allowed to take control of all - /// items within the collection. Optionally, a `deadline` can be specified to set a time limit - /// for the approval. The `deadline` is expressed in block numbers and is added to the current - /// block number to determine the absolute deadline for the approval. After approving the - /// transfer, the function emits the `TransferApproved` event. + /// This function is used to approve the transfer of items in the `collection` that owned by the + /// `origin` to a `delegate`.The `delegate` is the account that will be allowed to take control + /// of items in the collection that owned by the `origin`. Optionally, a `deadline` can be + /// specified to set a time limit for the approval. The `deadline` is expressed in block + /// numbers and is added to the current block number to determine the absolute deadline for the + /// approval. After approving the transfer, the function emits the `TransferApproved` event. /// - /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, - /// granting permission to approve the transfer. If `None`, no permission check is performed. + /// - `origin`: The account grants permission to approve the transfer. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that will be allowed to take control of all items within the - /// collection. + /// - `delegate`: The account that will be allowed to take control of items in the collection + /// that owned by the `origin`. /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. - pub(crate) fn do_approve_collection( - maybe_check_origin: Option, + pub(crate) fn do_approve_collection_transfer( + origin: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, maybe_deadline: Option>, @@ -218,24 +215,36 @@ impl, I: 'static> Pallet { collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - - let owner = - Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - let now = frame_system::Pallet::::block_number(); let deadline = maybe_deadline.map(|d| d.saturating_add(now)); - AccountApprovals::::try_mutate( - collection, - &owner, - |approvals| -> Result<(), DispatchError> { - ensure!(*approvals < T::ApprovalsLimit::get(), Error::::ReachedApprovalLimit); - CollectionApprovals::::insert((&collection, &owner, &delegate), deadline); - approvals.saturating_inc(); + CollectionApprovals::::try_mutate_exists( + (&collection, &origin, &delegate), + |maybe_approval| -> Result<(), DispatchError> { + if maybe_approval.is_none() { + // Increment approval counts for the `origin`, ensuring limits are respected. + CollectionApprovalCount::::try_mutate( + collection, + Some(&origin), + |approvals| -> Result<(), DispatchError> { + ensure!( + *approvals < T::ApprovalsLimit::get(), + Error::::ReachedApprovalLimit + ); + approvals.saturating_inc(); + Ok(()) + }, + )?; + + // Increment the total approval count for the collection. + CollectionApprovalCount::::mutate( + collection, + Option::::None, + |approvals| approvals.saturating_inc(), + ); + } + *maybe_approval = Some(deadline); + Ok(()) }, )?; @@ -243,7 +252,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::TransferApproved { collection, item: None, - owner, + owner: origin, delegate, deadline, }); @@ -251,113 +260,88 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the approval for the transfer of all items within the collection to a delegate. + /// Cancels the transfer of items in the collection that owned by the origin to + /// a delegate. /// - /// This function is used to cancel the approval for the transfer of all items in the - /// `collection` to a `delegate`. If `maybe_check_origin` is specified, the function ensures - /// that the `check_origin` account is the owner of the item or that the approval is past its - /// deadline, granting permission to cancel the approval. After canceling the approval, the - /// function emits the `ApprovalCancelled` event. + /// This function is used to cancel the approval for the transfer of items in the `collection` + /// that owned by the `origin` to a `delegate`. After canceling the approval, the function emits + /// the `ApprovalCancelled` event. /// - /// - `maybe_check_origin`: The optional account that is required to be the owner of the - /// collection or that the approval is past its deadline, granting permission to cancel the - /// approval. If `None`, no permission check is performed. - /// - `collection`: The identifier of the collection - /// - `delegate`: The account that was previously allowed to take control of all items within - /// the collection. - pub(crate) fn do_cancel_collection( - maybe_check_origin: Option, + /// - `origin`: The account grants permission to cancel the transfer. + /// - `collection`: The identifier of the collection. + /// - `delegate`: The account that was previously allowed to take control of items in the + /// collection that owned by the origin. + pub(crate) fn do_cancel_collection_approval( + origin: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let owner = - Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - let maybe_deadline = CollectionApprovals::::get((&collection, &owner, &delegate)) - .ok_or(Error::::NotDelegate)?; - - let is_past_deadline = if let Some(deadline) = maybe_deadline { - let now = frame_system::Pallet::::block_number(); - now > deadline - } else { - false - }; - - if !is_past_deadline { - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner, Error::::NoPermission); - } - } - - CollectionApprovals::::remove((&collection, &owner, &delegate)); - AccountApprovals::::mutate(collection, &owner, |approvals| { + CollectionApprovals::::take((&collection, &origin, &delegate)) + .ok_or(Error::::UnknownCollection)?; + CollectionApprovalCount::::mutate(collection, Some(&origin), |approvals| { approvals.saturating_dec(); }); + CollectionApprovalCount::::mutate( + collection, + Option::::None, + |approvals| approvals.saturating_dec(), + ); - Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); + Self::deposit_event(Event::ApprovalCancelled { + collection, + owner: origin, + item: None, + delegate, + }); Ok(()) } /// Clears all collection approvals. /// - /// This function is used to clear all approvals to transfer all items within the collections. - /// If `maybe_check_origin` is specified, the function ensures that the `check_origin` account - /// is the owner of the item, granting permission to clear all collection approvals. After - /// clearing all approvals, the function emits the `AllApprovalsCancelled` event. + /// This function is used to clear all approvals to transfer items in the `collection` that + /// owned by the `origin` to a `delegate`. After clearing all approvals, the function emits the + /// `AllApprovalsCancelled` event. /// - /// - `maybe_check_origin`: The optional account that is required to be the owner of the - /// collection, granting permission to clear all collection approvals. If `None`, no - /// permission check is performed. + /// - `origin`: The account grants permission to clear the transfer. /// - `collection`: The collection ID containing the item. /// - `witness_approvals`: Information on the collection approvals cleared. This must be /// correct. pub(crate) fn do_clear_all_collection_approvals( - maybe_check_origin: Option, + origin: T::AccountId, collection: T::CollectionId, witness_approvals: u32, ) -> DispatchResult { - let owner = - Pallet::::collection_owner(collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!(check_origin == owner.clone(), Error::::NoPermission); - } - - AccountApprovals::::try_mutate( + let approvals = CollectionApprovalCount::::take(collection, Some(&origin)); + ensure!(approvals == witness_approvals, Error::::BadWitness); + let _ = CollectionApprovals::::clear_prefix((collection, &origin), approvals, None); + CollectionApprovalCount::::mutate( collection, - &owner, - |approvals| -> Result<(), DispatchError> { - ensure!(*approvals == witness_approvals, Error::::BadWitness); - let _ = CollectionApprovals::::clear_prefix( - (collection, owner.clone()), - *approvals, - None, - ); - *approvals = 0; - Ok(()) - }, - )?; + Option::::None, + |total_approvals| *total_approvals = total_approvals.saturating_sub(approvals), + ); - Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner }); + Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); Ok(()) } - /// Checks whether the `delegate` has the necessary allowance to transfer all items within the - /// collection. If the `delegate` has approval to transfer all items in the collection, they can - /// transfer every item without requiring explicit approval for that item. + /// Checks whether the `delegate` has the necessary allowance to transfer items in the + /// `collection` that owned by the `account`. If the `delegate` has an approval to + /// transfer items in the collection that owned by the `account`, they can transfer every item + /// without requiring explicit approval for that item. /// /// - `collection`: The identifier of the collection - /// - `owner`: The owner of the collection or the collection item. - /// - `delegate`: The account that was previously allowed to take control of all items within - /// the collection. + /// - `account`: The account that granted the permission for `delegate` to transfer items in the + /// `collection`. + /// - `delegate`: The account that was previously allowed to take control of items in the + /// collection that owned by the `account`. fn check_collection_approval( collection: &T::CollectionId, - owner: &T::AccountId, + account: &T::AccountId, delegate: &T::AccountId, ) -> Result<(), DispatchError> { - let maybe_deadline = CollectionApprovals::::get((&collection, &owner, &delegate)) + let maybe_deadline = CollectionApprovals::::get((&collection, &account, &delegate)) .ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { let block_number = frame_system::Pallet::::block_number(); @@ -367,30 +351,31 @@ impl, I: 'static> Pallet { } /// Checks whether the `delegate` has the necessary allowance to transfer items within the - /// collection or a specific item in the collection. If the `delegate` has approval to transfer - /// all items in the collection, they can transfer every item without requiring explicit - /// approval for that item. + /// collection or a specific item in the collection. If the `delegate` has an approval to + /// transfer items in the collection that owned by the `account`, they can transfer every item + /// without requiring explicit approval for that item. /// /// - `collection`: The identifier of the collection /// - `maybe_item`: The optional item of the collection that the delegated account has an - /// approval to transfer. If not provided, an approval to transfer all items within the - /// collection will be checked. - /// - `owner`: The owner of the collection or the collection item. - /// - `delegate`: The account that was previously allowed to take control of all items within - /// the collection. + /// approval to transfer. If not provided, an approval to transfer items in the collection + /// that owned by the `account` will be checked. + /// - `account`: The account that granted the permission for `delegate` to transfer items in the + /// `collection` or the owner of the specified collection item. + /// - `delegate`: The account that was previously allowed to take control of items in the + /// collection that owned by the `owner`. pub fn check_approval( collection: &T::CollectionId, maybe_item: &Option, - owner: &T::AccountId, + account: &T::AccountId, delegate: &T::AccountId, ) -> Result<(), DispatchError> { - // Check if a `delegate` has a permission to spend the collection. - let check_collection_approval_error = - match Self::check_collection_approval(collection, owner, delegate) { - Ok(()) => return Ok(()), - Err(error) => error, - }; - // Check if a `delegate` has a permission to spend the collection item. + // Check if a `delegate` has a permission to transfer items in the collection that owned by + // the `owner`. + let error = match Self::check_collection_approval(collection, account, delegate) { + Ok(()) => return Ok(()), + Err(error) => error, + }; + // Check if a `delegate` has a permission to transfer the collection item. if let Some(item) = maybe_item { let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; @@ -402,6 +387,6 @@ impl, I: 'static> Pallet { } return Ok(()); }; - Err(check_collection_approval_error) + Err(error) } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 889e52ba..4b5e9be5 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -96,9 +96,9 @@ impl, I: 'static> Pallet { /// ([`NoPermission`](crate::Error::NoPermission)). /// - If the collection is not empty (contains items) /// ([`CollectionNotEmpty`](crate::Error::CollectionNotEmpty)). - /// - If the collection approvals is not empty (contains permissions to transfer all items - /// within the collection). - /// ([`CollectionApprovalsNotEmpty`](crate::Error::CollectionApprovalsNotEmpty)). + /// - If there are collection approvals (contains permissions to transfer items in the + /// collection granted by accounts). + /// ([`CollectionApprovalsExist`](crate::Error::CollectionApprovalsExist)). /// - If the `witness` does not match the actual collection details /// ([`BadWitness`](crate::Error::BadWitness)). pub fn do_destroy_collection( @@ -109,14 +109,13 @@ impl, I: 'static> Pallet { Collection::::try_mutate_exists(collection, |maybe_details| { let collection_details = maybe_details.take().ok_or(Error::::UnknownCollection)?; + let collection_approvals = + CollectionApprovalCount::::take(collection, Option::::None); if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); - ensure!( - AccountApprovals::::get(collection, &collection_details.owner) == 0, - Error::::CollectionApprovalsNotEmpty - ); + ensure!(collection_approvals == 0, Error::::CollectionApprovalsExist); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index ea8cb5b4..966ebb1c 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -68,7 +68,7 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); - AccountBalance::::mutate(collection, &mint_to, |balance| { + AccountBalance::::mutate(&mint_to, collection, |balance| { balance.saturating_inc(); }); @@ -263,7 +263,7 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(collection, item); PendingSwapOf::::remove(collection, item); ItemAttributesApprovalsOf::::remove(collection, item); - AccountBalance::::mutate(collection, &owner, |balance| { + AccountBalance::::mutate(&owner, collection, |balance| { balance.saturating_dec(); }); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 594df56d..8dd76821 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -87,11 +87,11 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balance of the owner. - AccountBalance::::mutate(collection, &details.owner, |balance| { + AccountBalance::::mutate(&details.owner, collection, |balance| { balance.saturating_dec(); }); // Update account balance of the destination account. - AccountBalance::::mutate(collection, &dest, |balance| { + AccountBalance::::mutate(&dest, collection, |balance| { balance.saturating_inc(); }); @@ -108,7 +108,6 @@ 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); @@ -149,15 +148,6 @@ impl, I: 'static> Pallet { return Ok(()) } - // All collection approvals need to be removed because otherwise - // pre-approve attack would be possible, where the owner can approve their - // second account before making the transaction and then claiming all items - // within the collection back. - ensure!( - AccountApprovals::::get(collection, &details.owner) == 0, - Error::::CollectionApprovalsNotEmpty - ); - // Move the deposit to the new owner. T::Currency::repatriate_reserved( &details.owner, diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 024c2262..f367af50 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -30,6 +30,8 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +#[allow(missing_docs)] +pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -408,38 +410,37 @@ pub mod pallet { #[pallet::storage] pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< _, - Twox64Concat, - T::CollectionId, Blake2_128Concat, T::AccountId, + Blake2_128Concat, + T::CollectionId, u32, ValueQuery, >; - /// Permission for the delegate to transfer all owner's items within a collection. + /// Permission for a delegate to transfer all owner's items within a collection. #[pallet::storage] pub type CollectionApprovals, I: 'static = ()> = StorageNMap< _, ( // Collection ID. - NMapKey, + NMapKey, // Collection Owner Id. NMapKey, // Delegate Id. NMapKey, ), Option>, - OptionQuery, >; - /// Number of collection approvals that owners granted. + /// Total number approvals of a whole collection or a specified account. #[pallet::storage] - pub type AccountApprovals, I: 'static = ()> = StorageDoubleMap< + pub type CollectionApprovalCount, I: 'static = ()> = StorageDoubleMap< _, - Twox64Concat, + Blake2_128Concat, T::CollectionId, Blake2_128Concat, - T::AccountId, + Option, u32, ValueQuery, >; @@ -516,7 +517,7 @@ pub mod pallet { owner: T::AccountId, delegate: T::AccountId, }, - /// All approvals of an item or a collection got cancelled. + /// All approvals of a collection or item were cancelled. AllApprovalsCancelled { collection: T::CollectionId, item: Option, @@ -735,9 +736,9 @@ pub mod pallet { CollectionNotEmpty, /// The witness data should be provided. WitnessRequired, - /// Cant' delete collections whose approvals. - CollectionApprovalsNotEmpty, - /// Collection approval and item approval conflicts. + /// The collection has existing approvals. + CollectionApprovalsExist, + /// Collection and item approval conflicts. DelegateApprovalConflict, } @@ -838,7 +839,7 @@ pub mod pallet { /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the /// owner of the `collection`. /// - /// NOTE: The collection must have 0 items and 0 collection approvals to be destroyed. + /// NOTE: The collection must have 0 items and 0 approvals to be destroyed. /// /// - `collection`: The identifier of the collection to be destroyed. /// - `witness`: Information on the items minted in the collection. This must be @@ -1138,7 +1139,7 @@ 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; } }, _ => continue, @@ -1328,7 +1329,8 @@ pub mod pallet { /// /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `maybe_item`: The optional item to be approved for delegated transfer. If not - /// provided, all items within the collection will be approved. + /// provided, items in the collection that owned by the `origin` will be approved for + /// delegated transfer. /// - `delegate`: The account to delegate permission to transfer the item. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire @@ -1345,24 +1347,30 @@ pub mod pallet { delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> 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)?; match maybe_item { - Some(item) => Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ), - None => Self::do_approve_collection( - maybe_check_origin, - collection, - delegate, - maybe_deadline, - ), + Some(item) => { + let maybe_check_origin = + T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { + ensure_signed(origin).map(Some).map_err(DispatchError::from) + })?; + Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) + }, + None => { + let origin = ensure_signed(origin)?; + Self::do_approve_collection_transfer( + origin, + collection, + delegate, + maybe_deadline, + ) + }, } } @@ -1375,8 +1383,8 @@ pub mod pallet { /// Arguments: /// - `collection`: The collection of the item of whose approval will be cancelled. /// - `maybe_item`: The optional item of the collection of whose approval will be cancelled. - /// If not provided, an allowance to transfer all items within the collection will be - /// cancelled. + /// If not provided, approval to transfer items in the collection that owned by `origin` + /// will be cancelled. /// - `delegate`: The account that is going to loose their approval. /// /// Emits `ApprovalCancelled` on success. @@ -1390,14 +1398,19 @@ pub mod pallet { 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)?; match maybe_item { - Some(item) => - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate), - None => Self::do_cancel_collection(maybe_check_origin, collection, delegate), + Some(item) => { + let maybe_check_origin = + T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { + ensure_signed(origin).map(Some).map_err(DispatchError::from) + })?; + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) + }, + None => { + let origin = ensure_signed(origin)?; + Self::do_cancel_collection_approval(origin, collection, delegate) + }, } } @@ -1412,6 +1425,8 @@ pub mod pallet { /// - `maybe_item`: The item of the collection of whose approvals will be cleared. The /// optional item of the collection of whose approval will be cleared. If not provided, /// all approvals to transfer items within collection. + /// - `witness_approvals`: Information on the collection approvals cleared. This must be + /// correct. /// /// Emits `AllApprovalsCancelled` on success. /// @@ -1429,18 +1444,22 @@ pub mod pallet { maybe_item: Option, witness_approvals: Option, ) -> DispatchResult { - let maybe_check_origin = T::ForceOrigin::try_origin(origin) - .map(|_| None) - .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - match maybe_item { - Some(item) => - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item), - None => Self::do_clear_all_collection_approvals( - maybe_check_origin, - collection, - witness_approvals.unwrap_or_default(), - ), + Some(item) => { + let maybe_check_origin = + T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { + ensure_signed(origin).map(Some).map_err(DispatchError::from) + })?; + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) + }, + None => { + let origin = ensure_signed(origin)?; + Self::do_clear_all_collection_approvals( + origin, + collection, + witness_approvals.unwrap_or_default(), + ) + }, } } diff --git a/pallets/nfts/src/migration.rs b/pallets/nfts/src/migration.rs new file mode 100644 index 00000000..7d59b481 --- /dev/null +++ b/pallets/nfts/src/migration.rs @@ -0,0 +1,122 @@ +// 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::*; + +#[allow(missing_docs)] +pub mod v1 { + use frame_support::{pallet_prelude::*, weights::Weight}; + + use super::*; + + #[derive(Decode)] + #[allow(missing_docs)] + 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 c579054d..d6964c31 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(account(1), 0), 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(account(1), 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(account(10), 0), 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(account(20), 0), 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(account(1), 0), 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(account(1), 0), 0); + assert_eq!(AccountBalance::::get(account(2), 0), 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(account(1), 0), 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(account(10), 0), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert_eq!(AccountBalance::::get(0, account(10)), 0); + assert_eq!(AccountBalance::::get(account(10), 0), 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(account(1), 0), 0); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -316,7 +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_eq!(AccountBalance::::get(account(2), 0), 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), 0, @@ -343,7 +343,7 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() ), - Error::::CollectionApprovalsNotEmpty + Error::::CollectionApprovalsExist ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); assert_ok!(Nfts::destroy( @@ -351,7 +351,11 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - assert_eq!(AccountBalance::::get(0, account(1)), 0); + assert_eq!(AccountBalance::::get(account(1), 0), 0); + assert_eq!( + CollectionApprovalCount::::contains_key(0, Option::>::None), + false + ); assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); @@ -367,7 +371,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(account(1), 0), 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)]); @@ -433,7 +437,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(account(2), 0), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -472,7 +476,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(account(2), 1), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -510,8 +514,8 @@ fn transfer_should_work() { default_item_config() )); 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(account(2), 0), 0); + assert_eq!(AccountBalance::::get(account(3), 0), 1); assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), @@ -526,9 +530,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(account(2), 0), 0); + assert_eq!(AccountBalance::::get(account(3), 0), 0); + assert_eq!(AccountBalance::::get(account(4), 0), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( @@ -668,10 +672,6 @@ fn transfer_owner_should_work() { account(3), None )); - assert_noop!( - Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2)), - Error::::CollectionApprovalsNotEmpty - ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3),)); assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2))); @@ -1795,7 +1795,7 @@ fn burn_works() { account(5), default_item_config() )); - assert_eq!(AccountBalance::::get(0, account(5)), 2); + assert_eq!(AccountBalance::::get(account(5), 0), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1803,9 +1803,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(account(5), 0), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); - assert_eq!(AccountBalance::::get(0, account(5)), 0); + assert_eq!(AccountBalance::::get(account(5), 0), 0); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -1896,26 +1896,26 @@ fn check_approval_works() { )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), 0, None, - account(2), + account(3), None )); - // transfer all items within the collection approved (without deadline). + // Test collection approvals without deadline. assert_noop!( - Nfts::check_approval(&1, &None, &account(1), &account(2)), + Nfts::check_approval(&1, &None, &account(2), &account(3)), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&1, &Some(43), &account(1), &account(2)), + Nfts::check_approval(&1, &Some(43), &account(2), &account(3)), Error::::UnknownItem ); - assert_ok!(Nfts::check_approval(&0, &None, &account(1), &account(2))); - assert_ok!(Nfts::check_approval(&0, &Some(42), &account(1), &account(2))); + assert_ok!(Nfts::check_approval(&0, &None, &account(2), &account(3))); + assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); - // transfer a collection item approved (without deadline). + // Test collection item approvals without deadline. assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, @@ -1925,7 +1925,7 @@ fn check_approval_works() { )); assert_noop!( - Nfts::check_approval(&0, &Some(43), &account(2), &account(3)), + Nfts::check_approval(&0, &Some(43), &account(2), &account(4)), Error::::UnknownItem ); assert_noop!( @@ -1934,36 +1934,36 @@ fn check_approval_works() { ); assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); - // transfer all items within the collection approved (with deadline). - let current_block = 1; - let deadline = current_block + 10; + // Test collection approvals with deadline. + let deadline = 10; assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + None, account(3), Some(deadline) )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), 0, - None, + Some(42), account(3), - Some(deadline + 1) + Some(11) )); - System::set_block_number(deadline + 2); + System::set_block_number(12); + // The item approval deadline has passed, but the collection approval remains valid. assert_noop!( - Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), + Nfts::check_approval(&0, &None, &account(2), &account(3)), Error::::ApprovalExpired ); - assert_ok!(Nfts::check_approval(&0, &None, &account(1), &account(3))); - System::set_block_number(deadline + 3); + assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); + System::set_block_number(14); assert_noop!( - Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), + Nfts::check_approval(&0, &None, &account(2), &account(3)), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval(&0, &None, &account(1), &account(3)), + Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), Error::::ApprovalExpired ); }); @@ -2055,7 +2055,7 @@ fn cancel_approval_works() { } #[test] -fn cancel_approval_collection_works_with_admin() { +fn cancel_approval_collection_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2071,28 +2071,29 @@ fn cancel_approval_collection_works_with_admin() { )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), 0, None, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, None, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), Error::::UnknownCollection ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, item: None, - owner: account(1), + owner: account(2), delegate: account(3) })); assert_eq!(CollectionApprovals::::get((0, account(2), account(3))).is_some(), false); - assert_eq!(AccountApprovals::::get(0, account(2)), 0); + assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 0); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); assert_eq!( - AccountApprovals::::get(0, account(2)), + CollectionApprovalCount::::get(0, Some(account(2))), CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 ); @@ -2209,7 +2210,7 @@ fn collection_approvals_limit_works() { for i in 3..13 { assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), 0, None, account(i), @@ -2218,14 +2219,14 @@ fn collection_approvals_limit_works() { } // the limit is 10 assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 0, None, account(14), None), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, None, account(14), None), Error::::ReachedApprovalLimit ); }); } #[test] -fn approval_collection_works_with_admin() { +fn approve_transfer_collection_works() { new_test_ext().execute_with(|| { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -2241,7 +2242,7 @@ fn approval_collection_works_with_admin() { RuntimeOrigin::signed(account(1)), 0, 42, - account(1), + account(2), default_item_config() )); @@ -2252,7 +2253,7 @@ fn approval_collection_works_with_admin() { CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 1, None, account(2), None), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 1, None, account(3), None), Error::::ItemsNonTransferable ); @@ -2263,24 +2264,40 @@ fn approval_collection_works_with_admin() { ); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), + 0, + None, + account(3), + None + )); + // Must not update the total collection approvals + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), 0, None, account(3), None )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(3)), + 0, + None, + account(4), + None + )); assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, - owner: account(1), + owner: account(2), delegate: account(3), deadline: None })); - assert!(CollectionApprovals::::get((0, account(1), account(3))).is_some()); - assert_eq!(AccountApprovals::::get(0, account(1)), 1); + assert!(CollectionApprovals::::get((0, account(2), account(3))).is_some()); + assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 2); assert_eq!( - AccountApprovals::::get(0, account(1)), - CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 + CollectionApprovalCount::::get(0, Some(account(2))), + CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); @@ -2511,6 +2528,8 @@ fn clear_all_transfer_approvals_works() { owner: account(2), })); assert_eq!(approvals(0, 42), vec![]); + assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(2))), false); + assert_eq!(CollectionApprovals::::iter_prefix((0, account(2))).count(), 0); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), @@ -2554,11 +2573,6 @@ fn clear_all_collection_approvals_works() { None )); - assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, None, Some(2)), - Error::::NoPermission - ); - assert_noop!( Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, None, Some(1)), Error::::BadWitness @@ -2576,9 +2590,10 @@ fn clear_all_collection_approvals_works() { owner: account(1), })); assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); - assert_eq!(AccountApprovals::::get(0, account(1)), 0); + assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(1))), false); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); assert_eq!( - AccountApprovals::::get(0, account(1)), + CollectionApprovalCount::::get(0, Some(account(1))), CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 ); @@ -2959,7 +2974,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(user_2.clone(), collection_id), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -3327,8 +3342,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(user_1.clone(), collection_id), 2); + assert_eq!(AccountBalance::::get(user_2.clone(), collection_id), 3); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3419,8 +3434,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(user_1.clone(), collection_id), 2); + assert_eq!(AccountBalance::::get(user_2.clone(), collection_id), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index 941da6ca..f08f1d09 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 owner: AccountId, + pub(super) 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, + pub(super) owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub items: u32, + pub(super) items: u32, /// The total number of outstanding item metadata of this collection. - pub item_metadatas: u32, + pub(super) item_metadatas: u32, /// The total number of outstanding item configs of this collection. - pub item_configs: u32, + pub(super) item_configs: u32, /// The total number of attributes for this collection. - pub attributes: u32, + pub(super) attributes: u32, } /// Witness data for the destroy transactions. From 7b5e201a99a648f94f51d1cc4d042ea6d3d04676 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 27 Nov 2024 23:51:27 +0700 Subject: [PATCH 32/99] feat(nfts): collection approval deposit --- pallets/nfts/src/features/approvals.rs | 147 +++++---- .../nfts/src/features/create_delete_item.rs | 16 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/lib.rs | 36 ++- pallets/nfts/src/mock.rs | 1 + pallets/nfts/src/tests.rs | 99 +++--- pallets/nfts/src/weights.rs | 298 +++++++++--------- runtime/devnet/src/config/assets.rs | 2 + runtime/testnet/src/config/assets.rs | 2 + 9 files changed, 338 insertions(+), 267 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index e98a2380..135455d4 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,7 +19,7 @@ //! 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 frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError}; use crate::*; @@ -187,12 +187,15 @@ impl, I: 'static> Pallet { /// Approves the transfer of items in the collection that owned by the origin to a delegate. /// /// This function is used to approve the transfer of items in the `collection` that owned by the - /// `origin` to a `delegate`.The `delegate` is the account that will be allowed to take control + /// `origin` to a `delegate`. The `delegate` is the account that will be allowed to take control /// of items in the collection that owned by the `origin`. Optionally, a `deadline` can be /// specified to set a time limit for the approval. The `deadline` is expressed in block /// numbers and is added to the current block number to determine the absolute deadline for the /// approval. After approving the transfer, the function emits the `TransferApproved` event. /// + /// This function reserves the required deposit from the owner's account. If an approval already + /// exists, the new amount is added to such existing approval. + /// /// - `origin`: The account grants permission to approve the transfer. /// - `collection`: The identifier of the collection. /// - `delegate`: The account that will be allowed to take control of items in the collection @@ -220,31 +223,40 @@ impl, I: 'static> Pallet { CollectionApprovals::::try_mutate_exists( (&collection, &origin, &delegate), - |maybe_approval| -> Result<(), DispatchError> { - if maybe_approval.is_none() { - // Increment approval counts for the `origin`, ensuring limits are respected. - CollectionApprovalCount::::try_mutate( - collection, - Some(&origin), - |approvals| -> Result<(), DispatchError> { - ensure!( - *approvals < T::ApprovalsLimit::get(), - Error::::ReachedApprovalLimit - ); - approvals.saturating_inc(); - Ok(()) - }, - )?; - - // Increment the total approval count for the collection. - CollectionApprovalCount::::mutate( - collection, - Option::::None, - |approvals| approvals.saturating_inc(), - ); + |maybe_approval| -> DispatchResult { + let deposit_required = T::CollectionApprovalDeposit::get(); + let mut current_deposit = match maybe_approval.take() { + Some((_, deposit)) => deposit, + None => { + // Increment approval counts for the `origin`, ensuring limits are + // respected. + CollectionApprovalCount::::try_mutate( + collection, + Some(&origin), + |approvals| -> DispatchResult { + ensure!( + *approvals < T::ApprovalsLimit::get(), + Error::::ReachedApprovalLimit + ); + approvals.saturating_inc(); + Ok(()) + }, + )?; + // Increment the total approval count for the collection. + CollectionApprovalCount::::mutate( + collection, + Option::::None, + |approvals| approvals.saturating_inc(), + ); + Zero::zero() + }, + }; + + if current_deposit < deposit_required { + T::Currency::reserve(&origin, deposit_required - current_deposit)?; + current_deposit = deposit_required; } - *maybe_approval = Some(deadline); - + *maybe_approval = Some((deadline, current_deposit)); Ok(()) }, )?; @@ -264,8 +276,8 @@ impl, I: 'static> Pallet { /// a delegate. /// /// This function is used to cancel the approval for the transfer of items in the `collection` - /// that owned by the `origin` to a `delegate`. After canceling the approval, the function emits - /// the `ApprovalCancelled` event. + /// that owned by the `origin` to a `delegate`. After canceling the approval, the function + /// returns the `origin` back the deposited fund and emits the `ApprovalCancelled` event. /// /// - `origin`: The account grants permission to cancel the transfer. /// - `collection`: The identifier of the collection. @@ -276,16 +288,22 @@ impl, I: 'static> Pallet { collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - CollectionApprovals::::take((&collection, &origin, &delegate)) + let (_, deposit) = CollectionApprovals::::take((&collection, &origin, &delegate)) .ok_or(Error::::UnknownCollection)?; - CollectionApprovalCount::::mutate(collection, Some(&origin), |approvals| { - approvals.saturating_dec(); - }); - CollectionApprovalCount::::mutate( - collection, - Option::::None, - |approvals| approvals.saturating_dec(), - ); + + // Update the approval count for the `origin` account and the whole collection. + for key in vec![Some(&origin), Option::<&T::AccountId>::None] { + let count = CollectionApprovalCount::::get(collection, key) + .checked_sub(1) + .ok_or(ArithmeticError::Overflow)?; + if count == 0 { + CollectionApprovalCount::::remove(collection, key); + } else { + CollectionApprovalCount::::insert(collection, key, count); + } + } + + T::Currency::unreserve(&origin, deposit); Self::deposit_event(Event::ApprovalCancelled { collection, @@ -300,7 +318,8 @@ impl, I: 'static> Pallet { /// Clears all collection approvals. /// /// This function is used to clear all approvals to transfer items in the `collection` that - /// owned by the `origin` to a `delegate`. After clearing all approvals, the function emits the + /// owned by the `origin` to a `delegate`. After clearing all approvals, the function returns + /// the `origin` back the deposited fund of each collection approval and emits the /// `AllApprovalsCancelled` event. /// /// - `origin`: The account grants permission to clear the transfer. @@ -311,19 +330,40 @@ impl, I: 'static> Pallet { origin: T::AccountId, collection: T::CollectionId, witness_approvals: u32, - ) -> DispatchResult { - let approvals = CollectionApprovalCount::::take(collection, Some(&origin)); - ensure!(approvals == witness_approvals, Error::::BadWitness); - let _ = CollectionApprovals::::clear_prefix((collection, &origin), approvals, None); - CollectionApprovalCount::::mutate( + ) -> Result { + let mut removed_approvals: u32 = 0; + CollectionApprovalCount::::try_mutate_exists( collection, Option::::None, - |total_approvals| *total_approvals = total_approvals.saturating_sub(approvals), - ); - - Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); - - Ok(()) + |maybe_collection| -> DispatchResult { + let total_approvals = + maybe_collection.as_mut().ok_or(Error::::UnknownCollection)?; + + // Remove the total number of collection approvals from the `origin`. + let approvals = CollectionApprovalCount::::take(collection, Some(&origin)); + ensure!(approvals == witness_approvals, Error::::BadWitness); + + // Iterate and remove each collection approval, return the deposited fund back to + // the `origin`. + for (_, (_, deposit)) in + CollectionApprovals::::drain_prefix((collection, &origin)) + { + T::Currency::unreserve(&origin, deposit); + removed_approvals.saturating_inc(); + total_approvals.saturating_dec(); + if removed_approvals >= approvals { + break + } + } + Self::deposit_event(Event::AllApprovalsCancelled { + collection, + item: None, + owner: origin, + }); + Ok(()) + }, + )?; + Ok(removed_approvals) } /// Checks whether the `delegate` has the necessary allowance to transfer items in the @@ -340,9 +380,10 @@ impl, I: 'static> Pallet { collection: &T::CollectionId, account: &T::AccountId, delegate: &T::AccountId, - ) -> Result<(), DispatchError> { - let maybe_deadline = CollectionApprovals::::get((&collection, &account, &delegate)) - .ok_or(Error::::NoPermission)?; + ) -> DispatchResult { + let (maybe_deadline, _) = + CollectionApprovals::::get((&collection, &account, &delegate)) + .ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { let block_number = frame_system::Pallet::::block_number(); ensure!(block_number <= deadline, Error::::ApprovalExpired); @@ -368,7 +409,7 @@ impl, I: 'static> Pallet { maybe_item: &Option, account: &T::AccountId, delegate: &T::AccountId, - ) -> Result<(), DispatchError> { + ) -> DispatchResult { // Check if a `delegate` has a permission to transfer items in the collection that owned by // the `owner`. let error = match Self::check_collection_approval(collection, account, delegate) { diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 966ebb1c..e9ad74b0 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,7 +18,7 @@ //! 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 frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError, traits::ExistenceRequirement}; use crate::*; @@ -68,7 +68,7 @@ impl, I: 'static> Pallet { collection_details.items.saturating_inc(); - AccountBalance::::mutate(&mint_to, collection, |balance| { + AccountBalance::::mutate(collection, &mint_to, |balance| { balance.saturating_inc(); }); @@ -263,9 +263,15 @@ impl, I: 'static> Pallet { ItemPriceOf::::remove(collection, item); PendingSwapOf::::remove(collection, item); ItemAttributesApprovalsOf::::remove(collection, item); - AccountBalance::::mutate(&owner, collection, |balance| { - balance.saturating_dec(); - }); + + let balance = AccountBalance::::get(collection, &owner) + .checked_sub(1) + .ok_or(ArithmeticError::Overflow)?; + if balance == 0 { + AccountBalance::::remove(collection, &owner); + } else { + AccountBalance::::insert(collection, &owner, balance); + } if remove_config { ItemConfigOf::::remove(collection, item); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 8dd76821..79405517 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -87,11 +87,11 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balance of the owner. - AccountBalance::::mutate(&details.owner, collection, |balance| { + AccountBalance::::mutate(collection, &details.owner, |balance| { balance.saturating_dec(); }); // Update account balance of the destination account. - AccountBalance::::mutate(&dest, collection, |balance| { + AccountBalance::::mutate(collection, &dest, |balance| { balance.saturating_inc(); }); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index f367af50..ab910c5d 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -175,6 +175,10 @@ pub mod pallet { #[pallet::constant] type CollectionDeposit: Get>; + /// The basic amount of funds that must be reserved for collection approvals. + #[pallet::constant] + type CollectionApprovalDeposit: Get>; + /// The basic amount of funds that must be reserved for an item. #[pallet::constant] type ItemDeposit: Get>; @@ -411,9 +415,9 @@ pub mod pallet { pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, - T::AccountId, - Blake2_128Concat, T::CollectionId, + Blake2_128Concat, + T::AccountId, u32, ValueQuery, >; @@ -425,12 +429,12 @@ pub mod pallet { ( // Collection ID. NMapKey, - // Collection Owner Id. + // Collection Account Id. NMapKey, // Delegate Id. NMapKey, ), - Option>, + (Option>, DepositBalanceOf), >; /// Total number approvals of a whole collection or a specified account. @@ -1325,7 +1329,8 @@ pub mod pallet { /// 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`. + /// `item` if the `item` is provided. If not, the sender must have sufficient funds to grant + /// a collection approval. /// /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `maybe_item`: The optional item to be approved for delegated transfer. If not @@ -1378,7 +1383,7 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item`; + /// - `Signed` with the signer being the Owner of the `item` if the `item` is provided; /// /// Arguments: /// - `collection`: The collection of the item of whose approval will be cancelled. @@ -1418,7 +1423,7 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item`; + /// - `Signed` with the signer being the Owner of the `item` if the `item` is provided; /// /// Arguments: /// - `collection`: The collection of the item of whose approvals will be cleared. @@ -1435,7 +1440,7 @@ pub mod pallet { #[pallet::weight( T::WeightInfo::clear_all_transfer_approvals( maybe_item.is_some() as u32, - witness_approvals.unwrap_or_default() + T::ApprovalsLimit::get() ) )] pub fn clear_all_transfer_approvals( @@ -1443,24 +1448,27 @@ pub mod pallet { collection: T::CollectionId, maybe_item: Option, witness_approvals: Option, - ) -> DispatchResult { - match maybe_item { + ) -> DispatchResultWithPostInfo { + let weight = match maybe_item { Some(item) => { let maybe_check_origin = T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { ensure_signed(origin).map(Some).map_err(DispatchError::from) })?; - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; + T::WeightInfo::clear_all_transfer_approvals(1, 0) }, None => { let origin = ensure_signed(origin)?; - Self::do_clear_all_collection_approvals( + let removed_approvals = Self::do_clear_all_collection_approvals( origin, collection, witness_approvals.unwrap_or_default(), - ) + )?; + T::WeightInfo::clear_all_transfer_approvals(0, removed_approvals) }, - } + }; + Ok(Some(weight).into()) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index 5532be8f..c6e4211e 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -65,6 +65,7 @@ parameter_types! { impl Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU64<1>; + type CollectionApprovalDeposit = ConstU64<1>; type CollectionDeposit = ConstU64<2>; type CollectionId = u32; type CreateOrigin = AsEnsureOriginWithArg>; diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index d6964c31..e830b6e6 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(account(1), 0), 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(account(1), 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(account(10), 0), 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(account(20), 0), 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(account(1), 0), 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(account(1), 0), 0); - assert_eq!(AccountBalance::::get(account(2), 0), 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(account(1), 0), 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(account(10), 0), 0); + assert_eq!(AccountBalance::::get(0, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert_eq!(AccountBalance::::get(account(10), 0), 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(account(1), 0), 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,7 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); - assert_eq!(AccountBalance::::get(account(2), 0), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), 0, @@ -351,12 +351,18 @@ fn destroy_should_work() { 0, Nfts::get_destroy_witness(&0).unwrap() )); - assert_eq!(AccountBalance::::get(account(1), 0), 0); + assert_eq!(AccountBalance::::get(0, account(1)), 0); + assert_eq!(AccountBalance::::contains_key(0, account(5)), false); assert_eq!( CollectionApprovalCount::::contains_key(0, Option::>::None), false ); assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); + assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(5))), false); + assert_eq!( + CollectionApprovalCount::::contains_key(0, Option::>::None), + false + ); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -371,7 +377,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(account(1), 0), 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)]); @@ -437,7 +443,7 @@ fn mint_should_work() { account(2), Some(MintWitness { mint_price: Some(1), ..Default::default() }) )); - assert_eq!(AccountBalance::::get(account(2), 0), 1); + assert_eq!(AccountBalance::::get(0, account(2)), 1); assert_eq!(Balances::total_balance(&account(2)), 99); // validate types @@ -476,7 +482,7 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); - assert_eq!(AccountBalance::::get(account(2), 1), 1); + assert_eq!(AccountBalance::::get(1, account(2)), 1); assert!(events().contains(&Event::::PalletAttributeSet { collection: 0, item: Some(43), @@ -514,8 +520,8 @@ fn transfer_should_work() { default_item_config() )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); - assert_eq!(AccountBalance::::get(account(2), 0), 0); - assert_eq!(AccountBalance::::get(account(3), 0), 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)), @@ -530,9 +536,9 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - assert_eq!(AccountBalance::::get(account(2), 0), 0); - assert_eq!(AccountBalance::::get(account(3), 0), 0); - assert_eq!(AccountBalance::::get(account(4), 0), 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( @@ -1795,7 +1801,7 @@ fn burn_works() { account(5), default_item_config() )); - assert_eq!(AccountBalance::::get(account(5), 0), 2); + assert_eq!(AccountBalance::::get(0, account(5)), 2); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( @@ -1803,9 +1809,10 @@ fn burn_works() { Error::::NoPermission ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); - assert_eq!(AccountBalance::::get(account(5), 0), 1); + assert_eq!(AccountBalance::::get(0, account(5)), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); - assert_eq!(AccountBalance::::get(account(5), 0), 0); + assert_eq!(AccountBalance::::get(0, account(5)), 0); + assert_eq!(AccountBalance::::contains_key(0, account(5)), false); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -1882,6 +1889,7 @@ fn approval_lifecycle_works() { #[test] fn check_approval_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2057,6 +2065,7 @@ fn cancel_approval_works() { #[test] fn cancel_approval_collection_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2077,19 +2086,21 @@ fn cancel_approval_collection_works() { account(3), None )); + assert_eq!(Balances::reserved_balance(&account(2)), 1); 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_eq!(Balances::reserved_balance(&account(2)), 0); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, item: None, owner: account(2), delegate: account(3) })); - assert_eq!(CollectionApprovals::::get((0, account(2), account(3))).is_some(), false); + assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), None); assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 0); assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); assert_eq!( @@ -2202,24 +2213,24 @@ fn approvals_limit_works() { #[test] fn collection_approvals_limit_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), default_collection_config() )); - for i in 3..13 { assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, None, account(i), None )); } - // the limit is 10 + // Exceeds the approvals limit. assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, None, account(14), None), + Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 0, None, account(14), None), Error::::ReachedApprovalLimit ); }); @@ -2228,6 +2239,8 @@ fn collection_approvals_limit_works() { #[test] fn approve_transfer_collection_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2270,6 +2283,9 @@ fn approve_transfer_collection_works() { account(3), None )); + assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 1); + assert_eq!(Balances::reserved_balance(&account(2)), 1); // Must not update the total collection approvals assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), @@ -2278,6 +2294,9 @@ fn approve_transfer_collection_works() { account(3), None )); + assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 1); + assert_eq!(Balances::reserved_balance(&account(2)), 1); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, @@ -2285,6 +2304,9 @@ fn approve_transfer_collection_works() { account(4), None )); + assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(CollectionApprovalCount::::get(0, Some(account(3))), 1); + assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 2); assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, @@ -2292,9 +2314,7 @@ fn approve_transfer_collection_works() { delegate: account(3), deadline: None })); - assert!(CollectionApprovals::::get((0, account(2), account(3))).is_some()); - assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 2); + assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), Some((None, 1))); assert_eq!( CollectionApprovalCount::::get(0, Some(account(2))), CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 @@ -2358,6 +2378,7 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2416,7 +2437,6 @@ fn cancel_approval_works_with_admin() { Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(50), account(3)), Error::::DelegateApprovalConflict ); - assert_ok!(Nfts::cancel_approval( RuntimeOrigin::signed(account(2)), 0, @@ -2545,6 +2565,7 @@ fn clear_all_transfer_approvals_works() { #[test] fn clear_all_collection_approvals_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2572,6 +2593,7 @@ fn clear_all_collection_approvals_works() { account(4), None )); + assert_eq!(Balances::free_balance(&account(1)), 98); assert_noop!( Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, None, Some(1)), @@ -2589,6 +2611,7 @@ fn clear_all_collection_approvals_works() { item: None, owner: account(1), })); + assert_eq!(Balances::free_balance(&account(1)), 100); assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(1))), false); assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); @@ -2974,7 +2997,7 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); - assert_eq!(AccountBalance::::get(user_2.clone(), collection_id), 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(); @@ -3342,8 +3365,8 @@ fn claim_swap_should_work() { default_item_config(), )); - assert_eq!(AccountBalance::::get(user_1.clone(), collection_id), 2); - assert_eq!(AccountBalance::::get(user_2.clone(), collection_id), 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, @@ -3434,8 +3457,8 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); - assert_eq!(AccountBalance::::get(user_1.clone(), collection_id), 2); - assert_eq!(AccountBalance::::get(user_2.clone(), collection_id), 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(); diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index d3fddb28..bbfc0f17 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-11-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-27, 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` @@ -93,7 +93,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `105` // Estimated: `3549` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3549) + Weight::from_parts(28_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -111,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_000_000, 3549) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -137,18 +137,12 @@ 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: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 970_000_000 picoseconds. - Weight::from_parts(872_656_952, 2523990) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(62_901, 0).saturating_mul(m.into())) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(42_980, 0).saturating_mul(c.into())) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(5_175_457, 0).saturating_mul(a.into())) + // Minimum execution time: 1_024_000_000 picoseconds. + Weight::from_parts(88_737_815_163, 2523990) .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)) @@ -174,7 +168,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `382` // Estimated: `4326` // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + Weight::from_parts(44_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -196,8 +190,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(44_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -225,8 +219,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `576` // Estimated: `4326` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 4326) + // Minimum execution time: 47_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)) } @@ -252,7 +246,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `605` // Estimated: `6068` - // Minimum execution time: 39_000_000 picoseconds. + // Minimum execution time: 40_000_000 picoseconds. Weight::from_parts(40_000_000, 6068) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) @@ -268,10 +262,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 10_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 23_461 - .saturating_add(Weight::from_parts(16_264_562, 0).saturating_mul(i.into())) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_604_901_340, 3549) + // Standard Error: 500_419 + .saturating_add(Weight::from_parts(15_423_645, 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 +279,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,7 +292,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)) @@ -343,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `296` // Estimated: `6078` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_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)) } @@ -401,7 +395,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. + // Minimum execution time: 39_000_000 picoseconds. Weight::from_parts(41_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -415,7 +409,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `271` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + Weight::from_parts(20_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -431,7 +425,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 34_000_000 picoseconds. + // Minimum execution time: 35_000_000 picoseconds. Weight::from_parts(35_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -444,8 +438,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(15_000_000, 4466) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -464,8 +458,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_333 - .saturating_add(Weight::from_parts(4_993_618, 0).saturating_mul(n.into())) + // Standard Error: 17_434 + .saturating_add(Weight::from_parts(5_368_639, 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)) @@ -486,7 +480,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 32_000_000 picoseconds. + // Minimum execution time: 31_000_000 picoseconds. Weight::from_parts(32_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -503,7 +497,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. + // Minimum execution time: 29_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -520,8 +514,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `325` // Estimated: `3759` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 28_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)) } @@ -546,7 +540,7 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountApprovals` (r:1 w:1) /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) @@ -555,31 +549,31 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `360` + // Measured: `267 + i * (70 ±0)` // Estimated: `3549 + i * (2163 ±0)` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(18_000_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(17_363_265, 3549) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountApprovals` (r:1 w:1) /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `462` // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(21_000_000, 3578) + Weight::from_parts(21_128_571, 3578) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) @@ -594,14 +588,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1580` // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(35_412_495, 52750) - // Standard Error: 2_608 - .saturating_add(Weight::from_parts(89, 0).saturating_mul(n.into())) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(36_197_892, 52750) + // Standard Error: 7_606 + .saturating_add(Weight::from_parts(39_289, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(22_u64)) - .saturating_add(T::DbWeight::get().writes(22_u64)) + .saturating_add(T::DbWeight::get().writes(21_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -611,7 +605,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + Weight::from_parts(11_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -623,8 +617,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -636,8 +630,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -653,8 +647,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -680,8 +674,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `717` // Estimated: `6068` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(44_000_000, 6068) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(48_000_000, 6068) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -691,9 +685,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_072_685, 0) - // Standard Error: 5_703 - .saturating_add(Weight::from_parts(1_678_167, 0).saturating_mul(n.into())) + Weight::from_parts(1_883_857, 0) + // Standard Error: 25_643 + .saturating_add(Weight::from_parts(2_023_925, 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`) @@ -703,8 +697,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -716,8 +710,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -743,8 +737,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `907` // Estimated: `7662` - // Minimum execution time: 77_000_000 picoseconds. - Weight::from_parts(78_000_000, 7662) + // Minimum execution time: 80_000_000 picoseconds. + Weight::from_parts(89_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -773,10 +767,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(103_806_930, 6078) - // Standard Error: 121_521 - .saturating_add(Weight::from_parts(28_678_555, 0).saturating_mul(n.into())) + // Minimum execution time: 103_000_000 picoseconds. + Weight::from_parts(105_375_667, 6078) + // Standard Error: 184_085 + .saturating_add(Weight::from_parts(32_736_356, 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)) @@ -801,9 +795,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(56_704_042, 4466) - // Standard Error: 54_119 - .saturating_add(Weight::from_parts(26_999_990, 0).saturating_mul(n.into())) + Weight::from_parts(62_663_027, 4466) + // Standard Error: 102_598 + .saturating_add(Weight::from_parts(28_406_409, 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)) @@ -829,7 +823,7 @@ impl WeightInfo for () { // Measured: `105` // Estimated: `3549` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3549) + Weight::from_parts(28_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -847,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_000_000, 3549) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -873,18 +867,12 @@ 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: `32165 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 970_000_000 picoseconds. - Weight::from_parts(872_656_952, 2523990) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(62_901, 0).saturating_mul(m.into())) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(42_980, 0).saturating_mul(c.into())) - // Standard Error: 22_341 - .saturating_add(Weight::from_parts(5_175_457, 0).saturating_mul(a.into())) + // Minimum execution time: 1_024_000_000 picoseconds. + Weight::from_parts(88_737_815_163, 2523990) .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)) @@ -910,7 +898,7 @@ impl WeightInfo for () { // Measured: `382` // Estimated: `4326` // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(42_000_000, 4326) + Weight::from_parts(44_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -932,8 +920,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 4326) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(44_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -961,8 +949,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `576` // Estimated: `4326` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 4326) + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(59_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -988,7 +976,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `605` // Estimated: `6068` - // Minimum execution time: 39_000_000 picoseconds. + // Minimum execution time: 40_000_000 picoseconds. Weight::from_parts(40_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) @@ -1004,10 +992,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 10_000_000 picoseconds. - Weight::from_parts(11_000_000, 3549) - // Standard Error: 23_461 - .saturating_add(Weight::from_parts(16_264_562, 0).saturating_mul(i.into())) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_604_901_340, 3549) + // Standard Error: 500_419 + .saturating_add(Weight::from_parts(15_423_645, 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()))) @@ -1021,7 +1009,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)) @@ -1034,7 +1022,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)) @@ -1079,8 +1067,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `296` // Estimated: `6078` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_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)) } @@ -1137,7 +1125,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. + // Minimum execution time: 39_000_000 picoseconds. Weight::from_parts(41_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1151,7 +1139,7 @@ impl WeightInfo for () { // Measured: `271` // Estimated: `3944` // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3944) + Weight::from_parts(20_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1167,7 +1155,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 34_000_000 picoseconds. + // Minimum execution time: 35_000_000 picoseconds. Weight::from_parts(35_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1180,8 +1168,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(15_000_000, 4466) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1200,8 +1188,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_333 - .saturating_add(Weight::from_parts(4_993_618, 0).saturating_mul(n.into())) + // Standard Error: 17_434 + .saturating_add(Weight::from_parts(5_368_639, 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)) @@ -1222,7 +1210,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 32_000_000 picoseconds. + // Minimum execution time: 31_000_000 picoseconds. Weight::from_parts(32_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1239,7 +1227,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. + // Minimum execution time: 29_000_000 picoseconds. Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1256,8 +1244,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `325` // Estimated: `3759` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(29_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1282,7 +1270,7 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountApprovals` (r:1 w:1) /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) @@ -1291,31 +1279,31 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `360` + // Measured: `267 + i * (70 ±0)` // Estimated: `3549 + i * (2163 ±0)` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(18_000_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(17_363_265, 3549) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::AccountApprovals` (r:1 w:1) /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `462` // Estimated: `3578 + i * (2163 ±0)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(21_000_000, 3578) + Weight::from_parts(21_128_571, 3578) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) @@ -1330,14 +1318,14 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1580` // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(35_412_495, 52750) - // Standard Error: 2_608 - .saturating_add(Weight::from_parts(89, 0).saturating_mul(n.into())) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(36_197_892, 52750) + // Standard Error: 7_606 + .saturating_add(Weight::from_parts(39_289, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(22_u64)) - .saturating_add(RocksDbWeight::get().writes(22_u64)) + .saturating_add(RocksDbWeight::get().writes(21_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -1347,7 +1335,7 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3517) + Weight::from_parts(11_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1359,8 +1347,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1372,8 +1360,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(15_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1389,8 +1377,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1416,8 +1404,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `717` // Estimated: `6068` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(44_000_000, 6068) + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(48_000_000, 6068) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1427,9 +1415,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_072_685, 0) - // Standard Error: 5_703 - .saturating_add(Weight::from_parts(1_678_167, 0).saturating_mul(n.into())) + Weight::from_parts(1_883_857, 0) + // Standard Error: 25_643 + .saturating_add(Weight::from_parts(2_023_925, 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`) @@ -1439,8 +1427,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 7662) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1452,8 +1440,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(16_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1479,8 +1467,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `907` // Estimated: `7662` - // Minimum execution time: 77_000_000 picoseconds. - Weight::from_parts(78_000_000, 7662) + // Minimum execution time: 80_000_000 picoseconds. + Weight::from_parts(89_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -1509,10 +1497,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(103_806_930, 6078) - // Standard Error: 121_521 - .saturating_add(Weight::from_parts(28_678_555, 0).saturating_mul(n.into())) + // Minimum execution time: 103_000_000 picoseconds. + Weight::from_parts(105_375_667, 6078) + // Standard Error: 184_085 + .saturating_add(Weight::from_parts(32_736_356, 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)) @@ -1537,9 +1525,9 @@ impl WeightInfo for () { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(56_704_042, 4466) - // Standard Error: 54_119 - .saturating_add(Weight::from_parts(26_999_990, 0).saturating_mul(n.into())) + Weight::from_parts(62_663_027, 4466) + // Standard Error: 102_598 + .saturating_add(Weight::from_parts(28_406_409, 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)) diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 326b7e59..bb08be0d 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,6 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; + pub const NftsCollectionApprovalDeposit: Balance = UNIT / 100; pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); @@ -41,6 +42,7 @@ impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; + type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; type CollectionDeposit = NftsCollectionDeposit; // TODO: source from primitives type CollectionId = CollectionId; diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index 326b7e59..bb08be0d 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,6 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; + pub const NftsCollectionApprovalDeposit: Balance = UNIT / 100; pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); @@ -41,6 +42,7 @@ impl pallet_nfts::Config for Runtime { // TODO: source from primitives type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; + type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; type CollectionDeposit = NftsCollectionDeposit; // TODO: source from primitives type CollectionId = CollectionId; From 6cb7f0509c24157c7b7e8793a65394c5409f76a9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Nov 2024 00:07:30 +0700 Subject: [PATCH 33/99] refactor: update account balance in do_transfer() --- pallets/nfts/src/features/transfer.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 79405517..346f217a 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,7 +18,7 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError}; use crate::*; @@ -86,14 +86,19 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balance of the owner. - AccountBalance::::mutate(collection, &details.owner, |balance| { - balance.saturating_dec(); - }); // Update account balance of the destination account. AccountBalance::::mutate(collection, &dest, |balance| { balance.saturating_inc(); }); + // Update account balance of the owner. + let balance = AccountBalance::::get(collection, &details.owner) + .checked_sub(1) + .ok_or(ArithmeticError::Overflow)?; + if balance == 0 { + AccountBalance::::remove(collection, &details.owner); + } else { + AccountBalance::::insert(collection, &details.owner, balance); + } // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); From 056ebc3ed814243debdeced68426ad249b82ab5c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Nov 2024 00:36:03 +0700 Subject: [PATCH 34/99] fix: clippy warnings --- pallets/nfts/src/features/approvals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 135455d4..c6d0f8c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -292,7 +292,7 @@ impl, I: 'static> Pallet { .ok_or(Error::::UnknownCollection)?; // Update the approval count for the `origin` account and the whole collection. - for key in vec![Some(&origin), Option::<&T::AccountId>::None] { + for key in [Some(&origin), Option::<&T::AccountId>::None] { let count = CollectionApprovalCount::::get(collection, key) .checked_sub(1) .ok_or(ArithmeticError::Overflow)?; From 0cba5fc02065729a5f9f4c648d2493ee0e8a8f14 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:51:45 +0700 Subject: [PATCH 35/99] chore: update weights --- pallets/nfts/src/weights.rs | 436 ++++++++++++++++++------------------ 1 file changed, 214 insertions(+), 222 deletions(-) diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index bbfc0f17..518a5b7e 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -92,7 +92,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 28_000_000 picoseconds. + // Minimum execution time: 27_000_000 picoseconds. Weight::from_parts(28_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -111,15 +111,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(17_000_000, 3549) .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`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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) @@ -139,10 +139,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32165 + a * (366 ±0)` + // Measured: `32131 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_024_000_000 picoseconds. - Weight::from_parts(88_737_815_163, 2523990) + // Minimum execution time: 1_014_000_000 picoseconds. + Weight::from_parts(1_146_825_407, 2523990) + // Standard Error: 37_482 + .saturating_add(Weight::from_parts(5_348_736, 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)) @@ -158,7 +160,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -167,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(44_000_000, 4326) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(50_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -181,7 +183,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -190,8 +192,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(44_000_000, 4326) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -206,7 +208,7 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -217,14 +219,14 @@ 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: 47_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(47_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:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -235,7 +237,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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -244,12 +246,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: `605` - // Estimated: `6068` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(40_000_000, 6068) + // Measured: `613` + // Estimated: `6084` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 6084) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(8_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`) @@ -262,10 +264,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_604_901_340, 3549) - // Standard Error: 500_419 - .saturating_add(Weight::from_parts(15_423_645, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 35_916 + .saturating_add(Weight::from_parts(16_637_380, 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()))) @@ -279,7 +281,7 @@ 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)) @@ -292,7 +294,7 @@ 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)) @@ -314,8 +316,6 @@ impl WeightInfo for SubstrateWeight { /// 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`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -324,9 +324,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3593) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Minimum execution time: 19_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)) } /// Storage: `Nfts::Collection` (r:1 w:1) @@ -396,7 +396,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `499` // Estimated: `3944` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(41_000_000, 3944) + Weight::from_parts(45_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -408,7 +408,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. + // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(20_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -425,8 +425,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(35_000_000, 3944) + // Minimum execution time: 34_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)) } @@ -438,8 +438,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(15_000_000, 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)) } @@ -458,8 +458,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: 17_434 - .saturating_add(Weight::from_parts(5_368_639, 0).saturating_mul(n.into())) + // Standard Error: 12_409 + .saturating_add(Weight::from_parts(5_237_238, 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)) @@ -481,7 +481,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `499` // Estimated: `3812` // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(32_000_000, 3812) + Weight::from_parts(31_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -498,7 +498,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `809` // Estimated: `3812` // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + Weight::from_parts(30_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -531,7 +531,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. + // 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)) @@ -540,62 +540,58 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:1) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovals` (r:0 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `267 + i * (70 ±0)` - // Estimated: `3549 + i * (2163 ±0)` + // Measured: `192 + i * (145 ±0)` + // Estimated: `6086 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_363_265, 3549) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + Weight::from_parts(28_691_836, 6086) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, 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::AccountApprovals` (r:1 w:1) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `462` - // Estimated: `3578 + i * (2163 ±0)` + // Measured: `447` + // Estimated: `6086 + i * (2163 ±0)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(21_128_571, 3578) + Weight::from_parts(32_663_265, 6086) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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::CollectionApprovals` (r:20 w:20) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1580` - // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` + // Measured: `1889` + // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(36_197_892, 52750) - // Standard Error: 7_606 - .saturating_add(Weight::from_parts(39_289, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(22_u64)) - .saturating_add(T::DbWeight::get().writes(21_u64)) + Weight::from_parts(288_990_100, 55842) + // Standard Error: 50_286 + .saturating_add(Weight::from_parts(46_413, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(23_u64)) + .saturating_add(T::DbWeight::get().writes(22_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -605,7 +601,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(11_000_000, 3517) + Weight::from_parts(10_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -617,8 +613,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_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)) } @@ -630,8 +626,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -647,8 +643,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_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)) } @@ -656,7 +652,7 @@ 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:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -665,19 +661,19 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `717` - // Estimated: `6068` + // Measured: `725` + // Estimated: `6084` // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(48_000_000, 6068) + Weight::from_parts(48_000_000, 6084) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -685,9 +681,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_883_857, 0) - // Standard Error: 25_643 - .saturating_add(Weight::from_parts(2_023_925, 0).saturating_mul(n.into())) + Weight::from_parts(2_165_281, 0) + // Standard Error: 6_212 + .saturating_add(Weight::from_parts(1_751_486, 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`) @@ -697,8 +693,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(18_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -710,8 +706,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_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)) } @@ -719,7 +715,7 @@ 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:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -728,19 +724,19 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `907` + // Measured: `916` // Estimated: `7662` // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(89_000_000, 7662) + Weight::from_parts(85_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(13_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`) @@ -751,7 +747,7 @@ impl WeightInfo for SubstrateWeight { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -767,10 +763,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 103_000_000 picoseconds. - Weight::from_parts(105_375_667, 6078) - // Standard Error: 184_085 - .saturating_add(Weight::from_parts(32_736_356, 0).saturating_mul(n.into())) + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(111_267_023, 6078) + // Standard Error: 152_884 + .saturating_add(Weight::from_parts(29_566_587, 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)) @@ -795,9 +791,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(62_663_027, 4466) - // Standard Error: 102_598 - .saturating_add(Weight::from_parts(28_406_409, 0).saturating_mul(n.into())) + Weight::from_parts(59_990_513, 4466) + // Standard Error: 136_656 + .saturating_add(Weight::from_parts(28_171_567, 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)) @@ -822,7 +818,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 28_000_000 picoseconds. + // Minimum execution time: 27_000_000 picoseconds. Weight::from_parts(28_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -841,15 +837,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 3549) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(17_000_000, 3549) .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`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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) @@ -869,10 +865,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32165 + a * (366 ±0)` + // Measured: `32131 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_024_000_000 picoseconds. - Weight::from_parts(88_737_815_163, 2523990) + // Minimum execution time: 1_014_000_000 picoseconds. + Weight::from_parts(1_146_825_407, 2523990) + // Standard Error: 37_482 + .saturating_add(Weight::from_parts(5_348_736, 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)) @@ -888,7 +886,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -897,8 +895,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 42_000_000 picoseconds. - Weight::from_parts(44_000_000, 4326) + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(50_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -911,7 +909,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -920,8 +918,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(44_000_000, 4326) + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -936,7 +934,7 @@ impl WeightInfo for () { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -947,14 +945,14 @@ 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: 47_000_000 picoseconds. - Weight::from_parts(59_000_000, 4326) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(47_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -965,7 +963,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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -974,12 +972,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: `605` - // Estimated: `6068` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(40_000_000, 6068) + // Measured: `613` + // Estimated: `6084` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 6084) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(8_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`) @@ -992,10 +990,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `690 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_604_901_340, 3549) - // Standard Error: 500_419 - .saturating_add(Weight::from_parts(15_423_645, 0).saturating_mul(i.into())) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3549) + // Standard Error: 35_916 + .saturating_add(Weight::from_parts(16_637_380, 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()))) @@ -1009,7 +1007,7 @@ 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)) @@ -1022,7 +1020,7 @@ 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)) @@ -1044,8 +1042,6 @@ impl WeightInfo for () { /// 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`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, 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) @@ -1054,9 +1050,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3593) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(19_000_000, 3593) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Nfts::Collection` (r:1 w:1) @@ -1126,7 +1122,7 @@ impl WeightInfo for () { // Measured: `499` // Estimated: `3944` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(41_000_000, 3944) + Weight::from_parts(45_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1138,7 +1134,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3944` - // Minimum execution time: 19_000_000 picoseconds. + // Minimum execution time: 18_000_000 picoseconds. Weight::from_parts(20_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1155,8 +1151,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(35_000_000, 3944) + // Minimum execution time: 34_000_000 picoseconds. + Weight::from_parts(36_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1168,8 +1164,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(15_000_000, 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)) } @@ -1188,8 +1184,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: 17_434 - .saturating_add(Weight::from_parts(5_368_639, 0).saturating_mul(n.into())) + // Standard Error: 12_409 + .saturating_add(Weight::from_parts(5_237_238, 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)) @@ -1211,7 +1207,7 @@ impl WeightInfo for () { // Measured: `499` // Estimated: `3812` // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(32_000_000, 3812) + Weight::from_parts(31_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1228,7 +1224,7 @@ impl WeightInfo for () { // Measured: `809` // Estimated: `3812` // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + Weight::from_parts(30_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1261,7 +1257,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. + // 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)) @@ -1270,62 +1266,58 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:1) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovals` (r:0 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `267 + i * (70 ±0)` - // Estimated: `3549 + i * (2163 ±0)` + // Measured: `192 + i * (145 ±0)` + // Estimated: `6086 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_363_265, 3549) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + Weight::from_parts(28_691_836, 6086) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, 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::AccountApprovals` (r:1 w:1) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `462` - // Estimated: `3578 + i * (2163 ±0)` + // Measured: `447` + // Estimated: `6086 + i * (2163 ±0)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(21_128_571, 3578) + Weight::from_parts(32_663_265, 6086) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::AccountApprovals` (r:1 w:0) - /// Proof: `Nfts::AccountApprovals` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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::CollectionApprovals` (r:20 w:20) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(113), added: 2588, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1580` - // Estimated: `52750 + i * (4325 ±496_172_781_796_926)` + // Measured: `1889` + // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(36_197_892, 52750) - // Standard Error: 7_606 - .saturating_add(Weight::from_parts(39_289, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(22_u64)) - .saturating_add(RocksDbWeight::get().writes(21_u64)) + Weight::from_parts(288_990_100, 55842) + // Standard Error: 50_286 + .saturating_add(Weight::from_parts(46_413, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(23_u64)) + .saturating_add(RocksDbWeight::get().writes(22_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -1335,7 +1327,7 @@ impl WeightInfo for () { // Measured: `3` // Estimated: `3517` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(11_000_000, 3517) + Weight::from_parts(10_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1347,8 +1339,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_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)) } @@ -1360,8 +1352,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(15_000_000, 3538) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1377,8 +1369,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_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)) } @@ -1386,7 +1378,7 @@ 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:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -1395,19 +1387,19 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `717` - // Estimated: `6068` + // Measured: `725` + // Estimated: `6084` // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(48_000_000, 6068) + Weight::from_parts(48_000_000, 6084) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -1415,9 +1407,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_883_857, 0) - // Standard Error: 25_643 - .saturating_add(Weight::from_parts(2_023_925, 0).saturating_mul(n.into())) + Weight::from_parts(2_165_281, 0) + // Standard Error: 6_212 + .saturating_add(Weight::from_parts(1_751_486, 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`) @@ -1427,8 +1419,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `7662` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 7662) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(18_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1440,8 +1432,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_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)) } @@ -1449,7 +1441,7 @@ 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:1) + /// Storage: `Nfts::Collection` (r:1 w:0) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:2 w:0) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) @@ -1458,19 +1450,19 @@ impl WeightInfo for () { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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: `907` + // Measured: `916` // Estimated: `7662` // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(89_000_000, 7662) + Weight::from_parts(85_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(13_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`) @@ -1481,7 +1473,7 @@ impl WeightInfo for () { /// 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`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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) @@ -1497,10 +1489,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 103_000_000 picoseconds. - Weight::from_parts(105_375_667, 6078) - // Standard Error: 184_085 - .saturating_add(Weight::from_parts(32_736_356, 0).saturating_mul(n.into())) + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(111_267_023, 6078) + // Standard Error: 152_884 + .saturating_add(Weight::from_parts(29_566_587, 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)) @@ -1525,9 +1517,9 @@ impl WeightInfo for () { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(62_663_027, 4466) - // Standard Error: 102_598 - .saturating_add(Weight::from_parts(28_406_409, 0).saturating_mul(n.into())) + Weight::from_parts(59_990_513, 4466) + // Standard Error: 136_656 + .saturating_add(Weight::from_parts(28_171_567, 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)) From 096e09c84df319b5a1d4dadb35ee1693568f6c9a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:08:25 +0700 Subject: [PATCH 36/99] fix: comments --- pallets/nfts/src/features/approvals.rs | 23 +++++++++++------------ pallets/nfts/src/lib.rs | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index c6d0f8c2..a0cdde03 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -20,6 +20,7 @@ //! to have the functionality defined in this module. use frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError}; +use frame_system::pallet_prelude::BlockNumberFor; use crate::*; @@ -47,7 +48,7 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, delegate: T::AccountId, - maybe_deadline: Option>, + maybe_deadline: Option>, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Approvals), @@ -188,13 +189,13 @@ impl, I: 'static> Pallet { /// /// This function is used to approve the transfer of items in the `collection` that owned by the /// `origin` to a `delegate`. The `delegate` is the account that will be allowed to take control - /// of items in the collection that owned by the `origin`. Optionally, a `deadline` can be - /// specified to set a time limit for the approval. The `deadline` is expressed in block - /// numbers and is added to the current block number to determine the absolute deadline for the - /// approval. After approving the transfer, the function emits the `TransferApproved` event. + /// of items in the collection. Optionally, a `deadline` can be specified to set a time limit + /// for the approval. The `deadline` is expressed in block numbers and is added to the current + /// block number to determine the absolute deadline for the approval. After approving the + /// transfer, the function emits the `TransferApproved` event. /// - /// This function reserves the required deposit from the owner's account. If an approval already - /// exists, the new amount is added to such existing approval. + /// This function reserves the required deposit from the `origin` account. If an approval + /// already exists, the new amount is added to such existing approval. /// /// - `origin`: The account grants permission to approve the transfer. /// - `collection`: The identifier of the collection. @@ -206,7 +207,7 @@ impl, I: 'static> Pallet { origin: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, - maybe_deadline: Option>, + maybe_deadline: Option>, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Approvals), @@ -367,9 +368,7 @@ impl, I: 'static> Pallet { } /// Checks whether the `delegate` has the necessary allowance to transfer items in the - /// `collection` that owned by the `account`. If the `delegate` has an approval to - /// transfer items in the collection that owned by the `account`, they can transfer every item - /// without requiring explicit approval for that item. + /// `collection` that owned by the `account`. /// /// - `collection`: The identifier of the collection /// - `account`: The account that granted the permission for `delegate` to transfer items in the @@ -403,7 +402,7 @@ impl, I: 'static> Pallet { /// - `account`: The account that granted the permission for `delegate` to transfer items in the /// `collection` or the owner of the specified collection item. /// - `delegate`: The account that was previously allowed to take control of items in the - /// collection that owned by the `owner`. + /// collection that owned by the `account` or the specified collection item. pub fn check_approval( collection: &T::CollectionId, maybe_item: &Option, diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index ab910c5d..71942127 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1143,7 +1143,7 @@ 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 } }, _ => continue, From 6ef07eb66b349d46ebd5c308bbb4ad6c7976cc99 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:38:27 +0700 Subject: [PATCH 37/99] chore: test no_account constant --- pallets/nfts/src/features/approvals.rs | 11 ++++----- pallets/nfts/src/tests.rs | 32 ++++++++++++-------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index a0cdde03..09903316 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -273,8 +273,7 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the transfer of items in the collection that owned by the origin to - /// a delegate. + /// Cancels the transfer of items in the collection that owned by the origin to a delegate. /// /// This function is used to cancel the approval for the transfer of items in the `collection` /// that owned by the `origin` to a `delegate`. After canceling the approval, the function @@ -370,7 +369,7 @@ impl, I: 'static> Pallet { /// Checks whether the `delegate` has the necessary allowance to transfer items in the /// `collection` that owned by the `account`. /// - /// - `collection`: The identifier of the collection + /// - `collection`: The identifier of the collection. /// - `account`: The account that granted the permission for `delegate` to transfer items in the /// `collection`. /// - `delegate`: The account that was previously allowed to take control of items in the @@ -390,12 +389,12 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` has the necessary allowance to transfer items within the - /// collection or a specific item in the collection. If the `delegate` has an approval to + /// Checks whether the `delegate` has the necessary allowance to transfer items owned by the + /// `account` or a specific item in the collection. If the `delegate` has an approval to /// transfer items in the collection that owned by the `account`, they can transfer every item /// without requiring explicit approval for that item. /// - /// - `collection`: The identifier of the collection + /// - `collection`: The identifier of the collection. /// - `maybe_item`: The optional item of the collection that the delegated account has an /// approval to transfer. If not provided, an approval to transfer items in the collection /// that owned by the `account` will be checked. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index e830b6e6..bfe7a2f7 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -36,6 +36,8 @@ use crate::{mock::*, Event, SystemConfig, *}; type AccountIdOf = ::AccountId; +const NO_ACCOUNT: Option = Option::::None; + fn account(id: u8) -> AccountIdOf { [id; 32].into() } @@ -353,16 +355,10 @@ fn destroy_should_work() { )); assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_eq!(AccountBalance::::contains_key(0, account(5)), false); - assert_eq!( - CollectionApprovalCount::::contains_key(0, Option::>::None), - false - ); + assert_eq!(CollectionApprovalCount::::contains_key(0, NO_ACCOUNT), false); assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(5))), false); - assert_eq!( - CollectionApprovalCount::::contains_key(0, Option::>::None), - false - ); + assert_eq!(CollectionApprovalCount::::contains_key(0, NO_ACCOUNT), false); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -2102,7 +2098,7 @@ fn cancel_approval_collection_works() { })); assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), None); assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 0); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); + assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 0); assert_eq!( CollectionApprovalCount::::get(0, Some(account(2))), CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 @@ -2228,7 +2224,7 @@ fn collection_approvals_limit_works() { None )); } - // Exceeds the approvals limit. + // the limit is 10 assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 0, None, account(14), None), Error::::ReachedApprovalLimit @@ -2259,7 +2255,7 @@ fn approve_transfer_collection_works() { default_item_config() )); - // Error::ItemsNonTransferable. + // throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( RuntimeOrigin::signed(account(1)), 1, @@ -2270,7 +2266,7 @@ fn approve_transfer_collection_works() { Error::::ItemsNonTransferable ); - // Error::UnknownCollection. + // throws error `Error::NoConfig`. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), Error::::NoConfig @@ -2284,9 +2280,10 @@ fn approve_transfer_collection_works() { None )); assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 1); + assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 1); assert_eq!(Balances::reserved_balance(&account(2)), 1); - // Must not update the total collection approvals + + // must not update the total collection approvals. assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, @@ -2295,8 +2292,9 @@ fn approve_transfer_collection_works() { None )); assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 1); + assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 1); assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, @@ -2306,7 +2304,7 @@ fn approve_transfer_collection_works() { )); assert_eq!(Balances::reserved_balance(&account(2)), 1); assert_eq!(CollectionApprovalCount::::get(0, Some(account(3))), 1); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 2); + assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 2); assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, @@ -2614,7 +2612,7 @@ fn clear_all_collection_approvals_works() { assert_eq!(Balances::free_balance(&account(1)), 100); assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(1))), false); - assert_eq!(CollectionApprovalCount::::get(0, Option::>::None), 0); + assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 0); assert_eq!( CollectionApprovalCount::::get(0, Some(account(1))), CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 From 7f7a40f5ce965d54c533422648c2f82ed293044b Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:25:00 +0700 Subject: [PATCH 38/99] refactor: remove `CollectionApprovalCount` storage item (#396) --- pallets/nfts/src/features/approvals.rs | 96 ++---- .../src/features/create_delete_collection.rs | 7 +- .../nfts/src/features/create_delete_item.rs | 4 +- pallets/nfts/src/features/transfer.rs | 4 +- pallets/nfts/src/lib.rs | 37 +- pallets/nfts/src/tests.rs | 54 --- pallets/nfts/src/weights.rs | 320 +++++++++--------- runtime/devnet/src/config/assets.rs | 2 +- runtime/testnet/src/config/assets.rs | 2 +- 9 files changed, 197 insertions(+), 329 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 09903316..ec3646ba 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -19,7 +19,7 @@ //! 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::*, sp_runtime::ArithmeticError}; +use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; use crate::*; @@ -158,18 +158,17 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, ) -> DispatchResult { - let collection_details = - Collection::::get(collection).ok_or(Error::::UnknownCollection)?; - - ensure!( - CollectionApprovalCount::::get(collection, Some(collection_details.owner)) == 0, - Error::::DelegateApprovalConflict - ); - let mut details = Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; if let Some(check_origin) = maybe_check_origin { + ensure!( + CollectionApprovals::::iter_prefix((collection, &check_origin)) + .take(1) + .next() + .is_none(), + Error::::DelegateApprovalConflict + ); ensure!(check_origin == details.owner, Error::::NoPermission); } @@ -228,29 +227,7 @@ impl, I: 'static> Pallet { let deposit_required = T::CollectionApprovalDeposit::get(); let mut current_deposit = match maybe_approval.take() { Some((_, deposit)) => deposit, - None => { - // Increment approval counts for the `origin`, ensuring limits are - // respected. - CollectionApprovalCount::::try_mutate( - collection, - Some(&origin), - |approvals| -> DispatchResult { - ensure!( - *approvals < T::ApprovalsLimit::get(), - Error::::ReachedApprovalLimit - ); - approvals.saturating_inc(); - Ok(()) - }, - )?; - // Increment the total approval count for the collection. - CollectionApprovalCount::::mutate( - collection, - Option::::None, - |approvals| approvals.saturating_inc(), - ); - Zero::zero() - }, + None => Zero::zero(), }; if current_deposit < deposit_required { @@ -291,18 +268,6 @@ impl, I: 'static> Pallet { let (_, deposit) = CollectionApprovals::::take((&collection, &origin, &delegate)) .ok_or(Error::::UnknownCollection)?; - // Update the approval count for the `origin` account and the whole collection. - for key in [Some(&origin), Option::<&T::AccountId>::None] { - let count = CollectionApprovalCount::::get(collection, key) - .checked_sub(1) - .ok_or(ArithmeticError::Overflow)?; - if count == 0 { - CollectionApprovalCount::::remove(collection, key); - } else { - CollectionApprovalCount::::insert(collection, key, count); - } - } - T::Currency::unreserve(&origin, deposit); Self::deposit_event(Event::ApprovalCancelled { @@ -330,40 +295,17 @@ impl, I: 'static> Pallet { origin: T::AccountId, collection: T::CollectionId, witness_approvals: u32, - ) -> Result { + ) -> DispatchResult { let mut removed_approvals: u32 = 0; - CollectionApprovalCount::::try_mutate_exists( - collection, - Option::::None, - |maybe_collection| -> DispatchResult { - let total_approvals = - maybe_collection.as_mut().ok_or(Error::::UnknownCollection)?; - - // Remove the total number of collection approvals from the `origin`. - let approvals = CollectionApprovalCount::::take(collection, Some(&origin)); - ensure!(approvals == witness_approvals, Error::::BadWitness); - - // Iterate and remove each collection approval, return the deposited fund back to - // the `origin`. - for (_, (_, deposit)) in - CollectionApprovals::::drain_prefix((collection, &origin)) - { - T::Currency::unreserve(&origin, deposit); - removed_approvals.saturating_inc(); - total_approvals.saturating_dec(); - if removed_approvals >= approvals { - break - } - } - Self::deposit_event(Event::AllApprovalsCancelled { - collection, - item: None, - owner: origin, - }); - Ok(()) - }, - )?; - Ok(removed_approvals) + // Iterate and remove each collection approval, return the deposited fund back to the + // `origin`. + for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { + T::Currency::unreserve(&origin, deposit); + removed_approvals.saturating_inc(); + } + ensure!(removed_approvals == witness_approvals, Error::::BadWitness); + Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); + Ok(()) } /// Checks whether the `delegate` has the necessary allowance to transfer items in the diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index 4b5e9be5..c749a212 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -109,13 +109,14 @@ impl, I: 'static> Pallet { Collection::::try_mutate_exists(collection, |maybe_details| { let collection_details = maybe_details.take().ok_or(Error::::UnknownCollection)?; - let collection_approvals = - CollectionApprovalCount::::take(collection, Option::::None); if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); - ensure!(collection_approvals == 0, Error::::CollectionApprovalsExist); + ensure!( + CollectionApprovals::::iter_prefix((collection,)).take(1).next().is_none(), + Error::::CollectionApprovalsExist + ); ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index e9ad74b0..2694aa6d 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -265,9 +265,9 @@ impl, I: 'static> Pallet { ItemAttributesApprovalsOf::::remove(collection, item); let balance = AccountBalance::::get(collection, &owner) - .checked_sub(1) + .checked_sub(&One::one()) .ok_or(ArithmeticError::Overflow)?; - if balance == 0 { + if balance == Zero::zero() { AccountBalance::::remove(collection, &owner); } else { AccountBalance::::insert(collection, &owner, balance); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 346f217a..2671e7c9 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -92,9 +92,9 @@ impl, I: 'static> Pallet { }); // Update account balance of the owner. let balance = AccountBalance::::get(collection, &details.owner) - .checked_sub(1) + .checked_sub(&One::one()) .ok_or(ArithmeticError::Overflow)?; - if balance == 0 { + if balance == Zero::zero() { AccountBalance::::remove(collection, &details.owner); } else { AccountBalance::::insert(collection, &details.owner, balance); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 71942127..db8b1b53 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::traits::{ use frame_system::Config as SystemConfig; pub use pallet::*; use sp_runtime::{ - traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, + traits::{CheckedSub, IdentifyAccount, One, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; pub use types::*; @@ -151,7 +151,15 @@ pub mod pallet { type CollectionId: Member + Parameter + MaxEncodedLen + Copy + Incrementable; /// The type used to identify a unique item within a collection. - type ItemId: Member + Parameter + MaxEncodedLen + Copy; + type ItemId: Member + + Parameter + + MaxEncodedLen + + Copy + + Default + + One + + Zero + + CheckedSub + + Saturating; /// The currency mechanism, used for paying for reserves. type Currency: ReservableCurrency; @@ -418,7 +426,7 @@ pub mod pallet { T::CollectionId, Blake2_128Concat, T::AccountId, - u32, + T::ItemId, ValueQuery, >; @@ -437,18 +445,6 @@ pub mod pallet { (Option>, DepositBalanceOf), >; - /// Total number approvals of a whole collection or a specified account. - #[pallet::storage] - pub type CollectionApprovalCount, I: 'static = ()> = StorageDoubleMap< - _, - Blake2_128Concat, - T::CollectionId, - Blake2_128Concat, - Option, - u32, - ValueQuery, - >; - /// Config of an item. #[pallet::storage] pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< @@ -702,7 +698,7 @@ pub mod pallet { NotForSale, /// The provided bid is too low. BidTooLow, - /// The collection or item has reached its approval limit. + /// The item has reached its approval limit. ReachedApprovalLimit, /// The deadline has already expired. DeadlineExpired, @@ -1460,12 +1456,9 @@ pub mod pallet { }, None => { let origin = ensure_signed(origin)?; - let removed_approvals = Self::do_clear_all_collection_approvals( - origin, - collection, - witness_approvals.unwrap_or_default(), - )?; - T::WeightInfo::clear_all_transfer_approvals(0, removed_approvals) + let witness_approvals = witness_approvals.unwrap_or_default(); + Self::do_clear_all_collection_approvals(origin, collection, witness_approvals)?; + T::WeightInfo::clear_all_transfer_approvals(0, witness_approvals) }, }; Ok(Some(weight).into()) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index bfe7a2f7..37fbde39 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -36,8 +36,6 @@ use crate::{mock::*, Event, SystemConfig, *}; type AccountIdOf = ::AccountId; -const NO_ACCOUNT: Option = Option::::None; - fn account(id: u8) -> AccountIdOf { [id; 32].into() } @@ -355,10 +353,7 @@ fn destroy_should_work() { )); assert_eq!(AccountBalance::::get(0, account(1)), 0); assert_eq!(AccountBalance::::contains_key(0, account(5)), false); - assert_eq!(CollectionApprovalCount::::contains_key(0, NO_ACCOUNT), false); assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); - assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(5))), false); - assert_eq!(CollectionApprovalCount::::contains_key(0, NO_ACCOUNT), false); assert!(!ItemConfigOf::::contains_key(0, 42)); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); @@ -2097,12 +2092,6 @@ fn cancel_approval_collection_works() { delegate: account(3) })); assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), None); - assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 0); - assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 0); - assert_eq!( - CollectionApprovalCount::::get(0, Some(account(2))), - CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 - ); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), @@ -2206,32 +2195,6 @@ fn approvals_limit_works() { }); } -#[test] -fn collection_approvals_limit_works() { - new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - account(1), - default_collection_config() - )); - for i in 3..13 { - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), - 0, - None, - account(i), - None - )); - } - // the limit is 10 - assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(1)), 0, None, account(14), None), - Error::::ReachedApprovalLimit - ); - }); -} - #[test] fn approve_transfer_collection_works() { new_test_ext().execute_with(|| { @@ -2279,8 +2242,6 @@ fn approve_transfer_collection_works() { account(3), None )); - assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); - assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 1); assert_eq!(Balances::reserved_balance(&account(2)), 1); // must not update the total collection approvals. @@ -2291,8 +2252,6 @@ fn approve_transfer_collection_works() { account(3), None )); - assert_eq!(CollectionApprovalCount::::get(0, Some(account(2))), 1); - assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 1); assert_eq!(Balances::reserved_balance(&account(2)), 1); assert_ok!(Nfts::approve_transfer( @@ -2303,8 +2262,6 @@ fn approve_transfer_collection_works() { None )); assert_eq!(Balances::reserved_balance(&account(2)), 1); - assert_eq!(CollectionApprovalCount::::get(0, Some(account(3))), 1); - assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 2); assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, @@ -2313,10 +2270,6 @@ fn approve_transfer_collection_works() { deadline: None })); assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), Some((None, 1))); - assert_eq!( - CollectionApprovalCount::::get(0, Some(account(2))), - CollectionApprovals::::iter_prefix((0, account(2))).count() as u32 - ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); }); } @@ -2546,7 +2499,6 @@ fn clear_all_transfer_approvals_works() { owner: account(2), })); assert_eq!(approvals(0, 42), vec![]); - assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(2))), false); assert_eq!(CollectionApprovals::::iter_prefix((0, account(2))).count(), 0); assert_noop!( @@ -2611,12 +2563,6 @@ fn clear_all_collection_approvals_works() { })); assert_eq!(Balances::free_balance(&account(1)), 100); assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); - assert_eq!(CollectionApprovalCount::::contains_key(0, Some(account(1))), false); - assert_eq!(CollectionApprovalCount::::get(0, NO_ACCOUNT), 0); - assert_eq!( - CollectionApprovalCount::::get(0, Some(account(1))), - CollectionApprovals::::iter_prefix((0, account(1))).count() as u32 - ); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 518a5b7e..f9d8b331 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-11-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-29, 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` @@ -92,8 +92,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3549) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(37_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -111,15 +111,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_000_000, 3549) + // Minimum execution time: 15_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)) } /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, 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) @@ -139,12 +139,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32131 + a * (366 ±0)` + // Measured: `32137 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_014_000_000 picoseconds. - Weight::from_parts(1_146_825_407, 2523990) - // Standard Error: 37_482 - .saturating_add(Weight::from_parts(5_348_736, 0).saturating_mul(a.into())) + // Minimum execution time: 1_005_000_000 picoseconds. + Weight::from_parts(2_234_507_890, 2523990) + // Standard Error: 87_675 + .saturating_add(Weight::from_parts(5_794_302, 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)) @@ -169,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(50_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -192,8 +192,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(43_000_000, 4326) + // Minimum execution time: 38_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)) } @@ -249,7 +249,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `613` // Estimated: `6084` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 6084) + Weight::from_parts(45_000_000, 6084) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -266,8 +266,8 @@ impl WeightInfo for SubstrateWeight { // Estimated: `3549 + i * (3336 ±0)` // Minimum execution time: 11_000_000 picoseconds. Weight::from_parts(11_000_000, 3549) - // Standard Error: 35_916 - .saturating_add(Weight::from_parts(16_637_380, 0).saturating_mul(i.into())) + // Standard Error: 33_010 + .saturating_add(Weight::from_parts(17_115_197, 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()))) @@ -281,8 +281,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -294,8 +294,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -325,7 +325,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `417` // Estimated: `3593` // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + Weight::from_parts(21_000_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -364,7 +364,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `203` // Estimated: `3549` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(10_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -376,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_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)) } @@ -395,8 +395,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_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)) } @@ -425,7 +425,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 34_000_000 picoseconds. + // 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)) @@ -456,10 +456,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // 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: 12_409 - .saturating_add(Weight::from_parts(5_237_238, 0).saturating_mul(n.into())) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(20_000_000, 4466) + // Standard Error: 11_913 + .saturating_add(Weight::from_parts(5_265_987, 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)) @@ -480,8 +480,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(38_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -497,8 +497,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(33_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -515,7 +515,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `325` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(30_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -531,8 +531,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_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)) } @@ -542,56 +542,49 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `192 + i * (145 ±0)` - // Estimated: `6086 + i * (2163 ±0)` + // Estimated: `3602 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(28_691_836, 6086) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + Weight::from_parts(24_983_673, 3602) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `6086 + i * (2163 ±0)` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(32_663_265, 6086) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `322 + i * (23 ±0)` + // Estimated: `3602 + i * (2163 ±0)` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(22_891_836, 3602) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1889` + // Measured: `1770` // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(288_990_100, 55842) - // Standard Error: 50_286 - .saturating_add(Weight::from_parts(46_413, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(23_u64)) - .saturating_add(T::DbWeight::get().writes(22_u64)) + Weight::from_parts(289_694_442, 55842) + // Standard Error: 62_848 + .saturating_add(Weight::from_parts(21_298, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(21_u64)) + .saturating_add(T::DbWeight::get().writes(20_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -613,7 +606,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_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)) @@ -627,7 +620,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + Weight::from_parts(13_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -643,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: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -670,7 +663,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `725` // Estimated: `6084` - // Minimum execution time: 45_000_000 picoseconds. + // Minimum execution time: 46_000_000 picoseconds. Weight::from_parts(48_000_000, 6084) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -681,9 +674,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_165_281, 0) - // Standard Error: 6_212 - .saturating_add(Weight::from_parts(1_751_486, 0).saturating_mul(n.into())) + Weight::from_parts(1_971_321, 0) + // Standard Error: 11_267 + .saturating_add(Weight::from_parts(1_831_565, 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`) @@ -694,7 +687,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `421` // Estimated: `7662` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(18_000_000, 7662) + Weight::from_parts(15_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -706,7 +699,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. + // 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)) @@ -733,8 +726,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7662` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(85_000_000, 7662) + // Minimum execution time: 81_000_000 picoseconds. + Weight::from_parts(87_000_000, 7662) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -764,9 +757,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(111_267_023, 6078) - // Standard Error: 152_884 - .saturating_add(Weight::from_parts(29_566_587, 0).saturating_mul(n.into())) + Weight::from_parts(115_875_572, 6078) + // Standard Error: 214_394 + .saturating_add(Weight::from_parts(29_706_731, 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)) @@ -791,9 +784,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(59_990_513, 4466) - // Standard Error: 136_656 - .saturating_add(Weight::from_parts(28_171_567, 0).saturating_mul(n.into())) + Weight::from_parts(66_554_620, 4466) + // Standard Error: 115_497 + .saturating_add(Weight::from_parts(27_385_703, 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)) @@ -818,8 +811,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 3549) + // Minimum execution time: 29_000_000 picoseconds. + Weight::from_parts(37_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -837,15 +830,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(17_000_000, 3549) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3549) .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`) - /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, 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) @@ -865,12 +858,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32131 + a * (366 ±0)` + // Measured: `32137 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_014_000_000 picoseconds. - Weight::from_parts(1_146_825_407, 2523990) - // Standard Error: 37_482 - .saturating_add(Weight::from_parts(5_348_736, 0).saturating_mul(a.into())) + // Minimum execution time: 1_005_000_000 picoseconds. + Weight::from_parts(2_234_507_890, 2523990) + // Standard Error: 87_675 + .saturating_add(Weight::from_parts(5_794_302, 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)) @@ -895,8 +888,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 41_000_000 picoseconds. - Weight::from_parts(50_000_000, 4326) + // Minimum execution time: 40_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -918,8 +911,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(43_000_000, 4326) + // Minimum execution time: 38_000_000 picoseconds. + Weight::from_parts(40_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -975,7 +968,7 @@ impl WeightInfo for () { // Measured: `613` // Estimated: `6084` // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(40_000_000, 6084) + Weight::from_parts(45_000_000, 6084) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -992,8 +985,8 @@ impl WeightInfo for () { // Estimated: `3549 + i * (3336 ±0)` // Minimum execution time: 11_000_000 picoseconds. Weight::from_parts(11_000_000, 3549) - // Standard Error: 35_916 - .saturating_add(Weight::from_parts(16_637_380, 0).saturating_mul(i.into())) + // Standard Error: 33_010 + .saturating_add(Weight::from_parts(17_115_197, 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()))) @@ -1007,8 +1000,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1020,8 +1013,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1051,7 +1044,7 @@ impl WeightInfo for () { // Measured: `417` // Estimated: `3593` // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(19_000_000, 3593) + Weight::from_parts(21_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1090,7 +1083,7 @@ impl WeightInfo for () { // Measured: `203` // Estimated: `3549` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(9_000_000, 3549) + Weight::from_parts(10_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1102,8 +1095,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_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)) } @@ -1121,8 +1114,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_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)) } @@ -1151,7 +1144,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 34_000_000 picoseconds. + // 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)) @@ -1182,10 +1175,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // 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: 12_409 - .saturating_add(Weight::from_parts(5_237_238, 0).saturating_mul(n.into())) + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(20_000_000, 4466) + // Standard Error: 11_913 + .saturating_add(Weight::from_parts(5_265_987, 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)) @@ -1206,8 +1199,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(31_000_000, 3812) + // Minimum execution time: 32_000_000 picoseconds. + Weight::from_parts(38_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1223,8 +1216,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 3812) + // Minimum execution time: 30_000_000 picoseconds. + Weight::from_parts(33_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1241,7 +1234,7 @@ impl WeightInfo for () { // Measured: `325` // Estimated: `3759` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 3759) + Weight::from_parts(30_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1257,8 +1250,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(29_000_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)) } @@ -1268,56 +1261,49 @@ impl WeightInfo for () { /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `192 + i * (145 ±0)` - // Estimated: `6086 + i * (2163 ±0)` + // Estimated: `3602 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(28_691_836, 6086) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + Weight::from_parts(24_983_673, 3602) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:2 w:2) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `6086 + i * (2163 ±0)` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(32_663_265, 6086) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `322 + i * (23 ±0)` + // Estimated: `3602 + i * (2163 ±0)` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(22_891_836, 3602) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionApprovalCount` (r:1 w:0) - /// Proof: `Nfts::CollectionApprovalCount` (`max_values`: None, `max_size`: Some(73), added: 2548, 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::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1889` + // Measured: `1770` // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(288_990_100, 55842) - // Standard Error: 50_286 - .saturating_add(Weight::from_parts(46_413, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(23_u64)) - .saturating_add(RocksDbWeight::get().writes(22_u64)) + Weight::from_parts(289_694_442, 55842) + // Standard Error: 62_848 + .saturating_add(Weight::from_parts(21_298, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(21_u64)) + .saturating_add(RocksDbWeight::get().writes(20_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) @@ -1339,7 +1325,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 12_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(13_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1353,7 +1339,7 @@ impl WeightInfo for () { // Measured: `250` // Estimated: `3538` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 3538) + Weight::from_parts(13_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1369,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: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1396,7 +1382,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `725` // Estimated: `6084` - // Minimum execution time: 45_000_000 picoseconds. + // Minimum execution time: 46_000_000 picoseconds. Weight::from_parts(48_000_000, 6084) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -1407,9 +1393,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(2_165_281, 0) - // Standard Error: 6_212 - .saturating_add(Weight::from_parts(1_751_486, 0).saturating_mul(n.into())) + Weight::from_parts(1_971_321, 0) + // Standard Error: 11_267 + .saturating_add(Weight::from_parts(1_831_565, 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`) @@ -1420,7 +1406,7 @@ impl WeightInfo for () { // Measured: `421` // Estimated: `7662` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(18_000_000, 7662) + Weight::from_parts(15_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1432,7 +1418,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. + // 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)) @@ -1459,8 +1445,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7662` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(85_000_000, 7662) + // Minimum execution time: 81_000_000 picoseconds. + Weight::from_parts(87_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -1490,9 +1476,9 @@ impl WeightInfo for () { // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(111_267_023, 6078) - // Standard Error: 152_884 - .saturating_add(Weight::from_parts(29_566_587, 0).saturating_mul(n.into())) + Weight::from_parts(115_875_572, 6078) + // Standard Error: 214_394 + .saturating_add(Weight::from_parts(29_706_731, 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)) @@ -1517,9 +1503,9 @@ impl WeightInfo for () { // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(59_990_513, 4466) - // Standard Error: 136_656 - .saturating_add(Weight::from_parts(28_171_567, 0).saturating_mul(n.into())) + Weight::from_parts(66_554_620, 4466) + // Standard Error: 115_497 + .saturating_add(Weight::from_parts(27_385_703, 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)) diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index bb08be0d..3e5f11b4 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - pub const NftsCollectionApprovalDeposit: Balance = UNIT / 100; + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 0); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index bb08be0d..3e5f11b4 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - pub const NftsCollectionApprovalDeposit: Balance = UNIT / 100; + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 0); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); From 71d9d5ca5a0903a14d7d0e7d1ffb3d06f2a25c3a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:55:31 +0700 Subject: [PATCH 39/99] fix: comments & test --- pallets/nfts/src/features/approvals.rs | 29 +++++++++++++------------- pallets/nfts/src/tests.rs | 28 +++++-------------------- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index ec3646ba..31dbad42 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -107,11 +107,6 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let mut details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - ensure!( - !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), - Error::::DelegateApprovalConflict - ); - let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; let is_past_deadline = if let Some(deadline) = maybe_deadline { @@ -127,6 +122,13 @@ impl, I: 'static> Pallet { } } + // Cannot revoke approval for a specific collection item if the delegate already has + // permission to transfer all items owned by the origin in the collection. + ensure!( + !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), + Error::::DelegateApprovalConflict + ); + details.approvals.remove(&delegate); Item::::insert(collection, item, &details); @@ -308,14 +310,13 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` has the necessary allowance to transfer items in the - /// `collection` that owned by the `account`. + /// Checks whether the `delegate` is approved to transfer items in the `collection` that owned + /// by the `account`. /// /// - `collection`: The identifier of the collection. - /// - `account`: The account that granted the permission for `delegate` to transfer items in the - /// `collection`. + /// - `account`: The account that granted the permission for `delegate` to transfer items. /// - `delegate`: The account that was previously allowed to take control of items in the - /// collection that owned by the `account`. + /// `collection` that owned by the `account`. fn check_collection_approval( collection: &T::CollectionId, account: &T::AccountId, @@ -331,10 +332,10 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` has the necessary allowance to transfer items owned by the - /// `account` or a specific item in the collection. If the `delegate` has an approval to - /// transfer items in the collection that owned by the `account`, they can transfer every item - /// without requiring explicit approval for that item. + /// Checks whether the `delegate` is approved by the `account` to transfer items that owned by + /// the `account` or a specific item in the collection. If the `delegate` has + /// an approval to transfer items in the collection that owned by the `account`, they can + /// transfer every item without requiring explicit approval for that item. /// /// - `collection`: The identifier of the collection. /// - `maybe_item`: The optional item of the collection that the delegated account has an diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 37fbde39..23989220 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2342,13 +2342,6 @@ fn cancel_approval_works_with_admin() { account(2), default_item_config() )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 50, - account(1), - default_item_config() - )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), @@ -2370,24 +2363,20 @@ fn cancel_approval_works_with_admin() { Error::::NotDelegate ); + // delegate approval conflicts. assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), - 0, - Some(50), - account(3), - None - )); - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(2)), 0, None, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(50), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), Error::::DelegateApprovalConflict ); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert_ok!(Nfts::cancel_approval( RuntimeOrigin::signed(account(2)), 0, @@ -2521,13 +2510,6 @@ fn clear_all_collection_approvals_works() { 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)), From fe924ee36d59f221c97d61ebb7f17886b1a776be Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:48:40 +0700 Subject: [PATCH 40/99] chore: check bad witness --- pallets/nfts/src/features/approvals.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 31dbad42..7b00e0c2 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -302,6 +302,7 @@ impl, I: 'static> Pallet { // Iterate and remove each collection approval, return the deposited fund back to the // `origin`. for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { + ensure!(removed_approvals < witness_approvals, Error::::BadWitness); T::Currency::unreserve(&origin, deposit); removed_approvals.saturating_inc(); } From fa360a8ee29f2432a629bacbbf8dd579ddd320f5 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:48:55 +0700 Subject: [PATCH 41/99] fix: test --- pallets/nfts/src/tests.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 23989220..08a771ed 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2329,7 +2329,7 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2511,6 +2511,14 @@ fn clear_all_collection_approvals_works() { 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, @@ -2527,11 +2535,6 @@ fn clear_all_collection_approvals_works() { )); assert_eq!(Balances::free_balance(&account(1)), 98); - assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, None, Some(1)), - Error::::BadWitness - ); - assert_ok!(Nfts::clear_all_transfer_approvals( RuntimeOrigin::signed(account(1)), 0, From 8d5155b70f96b1f49efcca70ebf1298052c82aa8 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:13:42 +0700 Subject: [PATCH 42/99] chore: resolve review comments (#398) --- pallets/nfts/src/benchmarking.rs | 10 +- pallets/nfts/src/features/approvals.rs | 93 +++++++++++-------- .../src/features/create_delete_collection.rs | 3 +- .../nfts/src/features/create_delete_item.rs | 10 +- pallets/nfts/src/features/transfer.rs | 10 +- pallets/nfts/src/lib.rs | 56 +++++------ pallets/nfts/src/tests.rs | 40 ++++---- pallets/nfts/src/weights.rs | 1 - runtime/devnet/src/config/assets.rs | 3 +- runtime/testnet/src/config/assets.rs | 3 +- 10 files changed, 117 insertions(+), 112 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 85a4d48d..a08687f9 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -595,13 +595,13 @@ benchmarks_instance_pallet! { 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(); let maybe_item = if i == 0 { None } else { - let (item, ..) = mint_item::(0); Some(item) }; }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, Some(deadline)) @@ -613,6 +613,7 @@ benchmarks_instance_pallet! { 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(); @@ -620,7 +621,6 @@ benchmarks_instance_pallet! { let maybe_item = if i == 0 { None } else { - let (item, ..) = mint_item::(0); Some(item) }; Nfts::::approve_transfer(origin, collection, maybe_item, delegate_lookup.clone(), Some(deadline))?; @@ -634,19 +634,19 @@ benchmarks_instance_pallet! { let n in 0 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); let (maybe_item, witness_approvals) = if i == 0 { for i in 0 .. n { approve_collection::(i); } - (None, Some(n)) + (None, n) } else { - 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))?; - (Some(item), None) + (Some(item), 1) }; }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, witness_approvals) verify { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 7b00e0c2..15d75488 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -122,8 +122,8 @@ impl, I: 'static> Pallet { } } - // Cannot revoke approval for a specific collection item if the delegate already has - // permission to transfer all items owned by the origin in the collection. + // Cannot revoke approval for a specific collection item if the delegate has + // permission to transfer all collection items owned by the origin. ensure!( !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), Error::::DelegateApprovalConflict @@ -155,14 +155,19 @@ impl, I: 'static> Pallet { /// performed. /// - `collection`: The collection ID containing the item. /// - `item`: The item ID for which transfer approvals will be cleared. + /// - `witness_approvals`: Information on the collection approvals cleared. This must be + /// correct. pub(crate) fn do_clear_all_transfer_approvals( maybe_check_origin: Option, collection: T::CollectionId, item: T::ItemId, + witness_approvals: u32, ) -> DispatchResult { let mut details = Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; + ensure!(details.approvals.len() as u32 == witness_approvals, Error::::BadWitness); + if let Some(check_origin) = maybe_check_origin { ensure!( CollectionApprovals::::iter_prefix((collection, &check_origin)) @@ -186,9 +191,9 @@ impl, I: 'static> Pallet { Ok(()) } - /// Approves the transfer of items in the collection that owned by the origin to a delegate. + /// Approves the transfer of all collection items owned by the origin to a delegate. /// - /// This function is used to approve the transfer of items in the `collection` that owned by the + /// This function is used to approve the transfer of items in the `collection` owned by the /// `origin` to a `delegate`. The `delegate` is the account that will be allowed to take control /// of items in the collection. Optionally, a `deadline` can be specified to set a time limit /// for the approval. The `deadline` is expressed in block numbers and is added to the current @@ -201,7 +206,7 @@ impl, I: 'static> Pallet { /// - `origin`: The account grants permission to approve the transfer. /// - `collection`: The identifier of the collection. /// - `delegate`: The account that will be allowed to take control of items in the collection - /// that owned by the `origin`. + /// owned by the `origin`. /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. pub(crate) fn do_approve_collection_transfer( @@ -214,6 +219,9 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); + let collection_items = + Self::collection_items(collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_items > 0, Error::::CollectionEmpty); let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -252,23 +260,23 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the transfer of items in the collection that owned by the origin to a delegate. + /// Cancels the transfer of all collection items owned by the origin to a delegate. /// /// This function is used to cancel the approval for the transfer of items in the `collection` - /// that owned by the `origin` to a `delegate`. After canceling the approval, the function + /// owned by the `origin` to a `delegate`. After canceling the approval, the function /// returns the `origin` back the deposited fund and emits the `ApprovalCancelled` event. /// /// - `origin`: The account grants permission to cancel the transfer. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that was previously allowed to take control of items in the - /// collection that owned by the origin. + /// - `delegate`: The account that had permission to manage collection items owned by the + /// `account`. pub(crate) fn do_cancel_collection_approval( origin: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { let (_, deposit) = CollectionApprovals::::take((&collection, &origin, &delegate)) - .ok_or(Error::::UnknownCollection)?; + .ok_or(Error::::Unapproved)?; T::Currency::unreserve(&origin, deposit); @@ -299,25 +307,30 @@ impl, I: 'static> Pallet { witness_approvals: u32, ) -> DispatchResult { let mut removed_approvals: u32 = 0; - // Iterate and remove each collection approval, return the deposited fund back to the + let mut deposits: BalanceOf = Zero::zero(); + // Iterate and remove each collection approval, returning the deposited funds back to the // `origin`. for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { ensure!(removed_approvals < witness_approvals, Error::::BadWitness); - T::Currency::unreserve(&origin, deposit); removed_approvals.saturating_inc(); + deposits = deposits.saturating_add(deposit); } - ensure!(removed_approvals == witness_approvals, Error::::BadWitness); + ensure!( + removed_approvals > 0 && removed_approvals == witness_approvals, + Error::::BadWitness + ); + T::Currency::unreserve(&origin, deposits); Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); Ok(()) } - /// Checks whether the `delegate` is approved to transfer items in the `collection` that owned + /// Checks whether the `delegate` is approved to transfer items in the `collection` owned /// by the `account`. /// /// - `collection`: The identifier of the collection. /// - `account`: The account that granted the permission for `delegate` to transfer items. - /// - `delegate`: The account that was previously allowed to take control of items in the - /// `collection` that owned by the `account`. + /// - `delegate`: The account that had permission to manage collection items owned by the + /// `account`. fn check_collection_approval( collection: &T::CollectionId, account: &T::AccountId, @@ -333,43 +346,45 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` is approved by the `account` to transfer items that owned by + /// Checks whether the `delegate` is approved by the `account` to transfer items owned by /// the `account` or a specific item in the collection. If the `delegate` has - /// an approval to transfer items in the collection that owned by the `account`, they can + /// an approval to transfer items in the collection owned by the `account`, they can /// transfer every item without requiring explicit approval for that item. /// /// - `collection`: The identifier of the collection. /// - `maybe_item`: The optional item of the collection that the delegated account has an /// approval to transfer. If not provided, an approval to transfer items in the collection - /// that owned by the `account` will be checked. + /// owned by the `account` will be checked. /// - `account`: The account that granted the permission for `delegate` to transfer items in the /// `collection` or the owner of the specified collection item. - /// - `delegate`: The account that was previously allowed to take control of items in the - /// collection that owned by the `account` or the specified collection item. + /// - `delegate`: The account that had permission to manage collection items owned by the + /// `account` or the specified collection item. pub fn check_approval( collection: &T::CollectionId, maybe_item: &Option, account: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { - // Check if a `delegate` has a permission to transfer items in the collection that owned by + // Check if a `delegate` has permission to transfer items in the collection owned by // the `owner`. - let error = match Self::check_collection_approval(collection, account, delegate) { - Ok(()) => return Ok(()), - Err(error) => error, - }; - // Check if a `delegate` has a permission to transfer the collection item. - if let Some(item) = maybe_item { - let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - - let maybe_deadline = - details.approvals.get(delegate).ok_or(Error::::NoPermission)?; - if let Some(deadline) = maybe_deadline { - let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *deadline, Error::::ApprovalExpired); - } - return Ok(()); - }; - Err(error) + match Self::check_collection_approval(collection, account, delegate) { + Ok(()) => Ok(()), + Err(error) => { + // Check if a `delegate` has permission to transfer the collection item. + if let Some(item) = maybe_item { + let details = + Item::::get(collection, item).ok_or(Error::::UnknownItem)?; + + let maybe_deadline = + details.approvals.get(delegate).ok_or(Error::::NoPermission)?; + if let Some(deadline) = maybe_deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *deadline, Error::::ApprovalExpired); + } + return Ok(()); + }; + Err(error) + }, + } } } diff --git a/pallets/nfts/src/features/create_delete_collection.rs b/pallets/nfts/src/features/create_delete_collection.rs index c749a212..4a8bed33 100644 --- a/pallets/nfts/src/features/create_delete_collection.rs +++ b/pallets/nfts/src/features/create_delete_collection.rs @@ -96,8 +96,7 @@ impl, I: 'static> Pallet { /// ([`NoPermission`](crate::Error::NoPermission)). /// - If the collection is not empty (contains items) /// ([`CollectionNotEmpty`](crate::Error::CollectionNotEmpty)). - /// - If there are collection approvals (contains permissions to transfer items in the - /// collection granted by accounts). + /// - If there are collection approvals /// ([`CollectionApprovalsExist`](crate::Error::CollectionApprovalsExist)). /// - If the `witness` does not match the actual collection details /// ([`BadWitness`](crate::Error::BadWitness)). diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 2694aa6d..0e51759c 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -264,12 +264,10 @@ impl, I: 'static> Pallet { PendingSwapOf::::remove(collection, item); ItemAttributesApprovalsOf::::remove(collection, item); - let balance = AccountBalance::::get(collection, &owner) - .checked_sub(&One::one()) - .ok_or(ArithmeticError::Overflow)?; - if balance == Zero::zero() { - AccountBalance::::remove(collection, &owner); - } else { + let balance = AccountBalance::::take(collection, &owner) + .checked_sub(1) + .ok_or(ArithmeticError::Underflow)?; + if balance > 0 { AccountBalance::::insert(collection, &owner, balance); } diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 2671e7c9..5dac9ffb 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -91,12 +91,10 @@ impl, I: 'static> Pallet { balance.saturating_inc(); }); // Update account balance of the owner. - let balance = AccountBalance::::get(collection, &details.owner) - .checked_sub(&One::one()) - .ok_or(ArithmeticError::Overflow)?; - if balance == Zero::zero() { - AccountBalance::::remove(collection, &details.owner); - } else { + let balance = AccountBalance::::take(collection, &details.owner) + .checked_sub(1) + .ok_or(ArithmeticError::Underflow)?; + if balance > 0 { AccountBalance::::insert(collection, &details.owner, balance); } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index db8b1b53..af556ddd 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::traits::{ use frame_system::Config as SystemConfig; pub use pallet::*; use sp_runtime::{ - traits::{CheckedSub, IdentifyAccount, One, Saturating, StaticLookup, Verify, Zero}, + traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; pub use types::*; @@ -151,15 +151,7 @@ pub mod pallet { type CollectionId: Member + Parameter + MaxEncodedLen + Copy + Incrementable; /// The type used to identify a unique item within a collection. - type ItemId: Member - + Parameter - + MaxEncodedLen - + Copy - + Default - + One - + Zero - + CheckedSub - + Saturating; + type ItemId: Member + Parameter + MaxEncodedLen + Copy; /// The currency mechanism, used for paying for reserves. type Currency: ReservableCurrency; @@ -184,6 +176,10 @@ pub mod pallet { type CollectionDeposit: Get>; /// The basic amount of funds that must be reserved for collection approvals. + /// + /// This is held for an additional storage item whose value size is + /// `sizeof((Option, Balance))` bytes and whose key size is + /// `sizeof((CollectionId, AccountId, AccountId))` bytes. #[pallet::constant] type CollectionApprovalDeposit: Get>; @@ -418,7 +414,7 @@ pub mod pallet { pub type CollectionConfigOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; - /// Number of collection items that accounts own. + /// Number of collection items owned by an account. #[pallet::storage] pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< _, @@ -426,7 +422,7 @@ pub mod pallet { T::CollectionId, Blake2_128Concat, T::AccountId, - T::ItemId, + u32, ValueQuery, >; @@ -435,12 +431,9 @@ pub mod pallet { pub type CollectionApprovals, I: 'static = ()> = StorageNMap< _, ( - // Collection ID. NMapKey, - // Collection Account Id. - NMapKey, - // Delegate Id. - NMapKey, + NMapKey, // owner + NMapKey, // delegate ), (Option>, DepositBalanceOf), >; @@ -732,6 +725,8 @@ pub mod pallet { MaxAttributesLimitReached, /// The provided namespace isn't supported in this call. WrongNamespace, + /// The collection has no items. + CollectionEmpty, /// Can't delete non-empty collections. CollectionNotEmpty, /// The witness data should be provided. @@ -1330,8 +1325,8 @@ pub mod pallet { /// /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `maybe_item`: The optional item to be approved for delegated transfer. If not - /// provided, items in the collection that owned by the `origin` will be approved for - /// delegated transfer. + /// provided, all collection items owned by the `origin` will be approved for delegated + /// transfer. /// - `delegate`: The account to delegate permission to transfer the item. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire @@ -1384,8 +1379,8 @@ pub mod pallet { /// Arguments: /// - `collection`: The collection of the item of whose approval will be cancelled. /// - `maybe_item`: The optional item of the collection of whose approval will be cancelled. - /// If not provided, approval to transfer items in the collection that owned by `origin` - /// will be cancelled. + /// If not provided, approval to transfer items in the collection owned by `origin` will + /// be cancelled. /// - `delegate`: The account that is going to loose their approval. /// /// Emits `ApprovalCancelled` on success. @@ -1433,17 +1428,12 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(17)] - #[pallet::weight( - T::WeightInfo::clear_all_transfer_approvals( - maybe_item.is_some() as u32, - T::ApprovalsLimit::get() - ) - )] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals(maybe_item.is_some() as u32, *witness_approvals))] pub fn clear_all_transfer_approvals( origin: OriginFor, collection: T::CollectionId, maybe_item: Option, - witness_approvals: Option, + witness_approvals: u32, ) -> DispatchResultWithPostInfo { let weight = match maybe_item { Some(item) => { @@ -1451,12 +1441,16 @@ pub mod pallet { T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { ensure_signed(origin).map(Some).map_err(DispatchError::from) })?; - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; - T::WeightInfo::clear_all_transfer_approvals(1, 0) + Self::do_clear_all_transfer_approvals( + maybe_check_origin, + collection, + item, + witness_approvals, + )?; + T::WeightInfo::clear_all_transfer_approvals(1, T::ApprovalsLimit::get()) }, None => { let origin = ensure_signed(origin)?; - let witness_approvals = witness_approvals.unwrap_or_default(); Self::do_clear_all_collection_approvals(origin, collection, witness_approvals)?; T::WeightInfo::clear_all_transfer_approvals(0, witness_approvals) }, diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 08a771ed..72b36e87 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -662,15 +662,6 @@ fn transfer_owner_should_work() { assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); assert_eq!(System::consumers(&account(2)), 1); - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(1)), - 0, - None, - account(3), - None - )); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3),)); - assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2))); assert_eq!(System::consumers(&account(2)), 1); // one consumer is added due to deposit repatriation @@ -2080,7 +2071,7 @@ fn cancel_approval_collection_works() { assert_eq!(Balances::reserved_balance(&account(2)), 1); assert_noop!( Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), - Error::::UnknownCollection + Error::::Unapproved ); assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); @@ -2210,6 +2201,13 @@ fn approve_transfer_collection_works() { account(1), default_collection_config() )); + + // throws error `Error::CollectionEmpty`. + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, None, account(3), None), + Error::::CollectionEmpty + ); + assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, @@ -2217,6 +2215,13 @@ fn approve_transfer_collection_works() { account(2), default_item_config() )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 1, + 42, + account(2), + default_item_config() + )); // throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( @@ -2229,10 +2234,10 @@ fn approve_transfer_collection_works() { Error::::ItemsNonTransferable ); - // throws error `Error::NoConfig`. + // throws error `Error::UnknownCollection`. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), - Error::::NoConfig + Error::::UnknownCollection ); assert_ok!(Nfts::approve_transfer( @@ -2466,12 +2471,7 @@ fn clear_all_transfer_approvals_works() { )); assert_noop!( - Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(account(3)), - 0, - Some(42), - None - ), + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, Some(42), 2), Error::::NoPermission ); @@ -2479,7 +2479,7 @@ fn clear_all_transfer_approvals_works() { RuntimeOrigin::signed(account(2)), 0, Some(42), - None + 2 )); assert!(events().contains(&Event::::AllApprovalsCancelled { @@ -2539,7 +2539,7 @@ fn clear_all_collection_approvals_works() { RuntimeOrigin::signed(account(1)), 0, None, - Some(2) + 2 )); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index f9d8b331..4acfbd13 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -1513,4 +1513,3 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } - diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 3e5f11b4..cceda7e6 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,7 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 0); + /// Key = 68 bytes (4+32+32), Value = 32 bytes (16+16) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index 3e5f11b4..cceda7e6 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,7 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 0); + /// Key = 68 bytes (4+32+32), Value = 32 bytes (16+16) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); From 9f6e159ee0cb2e00c38f389af38e641a2f55f1b0 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:23:00 +0700 Subject: [PATCH 43/99] fix: comments --- pallets/nfts/src/features/approvals.rs | 20 ++++++++++---------- pallets/nfts/src/features/transfer.rs | 2 +- runtime/devnet/src/config/assets.rs | 2 +- runtime/testnet/src/config/assets.rs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 15d75488..caeb2f25 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -123,7 +123,7 @@ impl, I: 'static> Pallet { } // Cannot revoke approval for a specific collection item if the delegate has - // permission to transfer all collection items owned by the origin. + // permission to transfer collection items owned by the origin. ensure!( !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), Error::::DelegateApprovalConflict @@ -268,7 +268,7 @@ impl, I: 'static> Pallet { /// /// - `origin`: The account grants permission to cancel the transfer. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that had permission to manage collection items owned by the + /// - `delegate`: The account that had permission to transfer collection items owned by the /// `account`. pub(crate) fn do_cancel_collection_approval( origin: T::AccountId, @@ -292,10 +292,10 @@ impl, I: 'static> Pallet { /// Clears all collection approvals. /// - /// This function is used to clear all approvals to transfer items in the `collection` that - /// owned by the `origin` to a `delegate`. After clearing all approvals, the function returns - /// the `origin` back the deposited fund of each collection approval and emits the - /// `AllApprovalsCancelled` event. + /// This function is used to clear all approvals to transfer collection items owned by the + /// `origin` to a `delegate`. After clearing all approvals, the function returns the `origin` + /// back the deposited fund of each collection approval and emits the `AllApprovalsCancelled` + /// event. /// /// - `origin`: The account grants permission to clear the transfer. /// - `collection`: The collection ID containing the item. @@ -329,7 +329,7 @@ impl, I: 'static> Pallet { /// /// - `collection`: The identifier of the collection. /// - `account`: The account that granted the permission for `delegate` to transfer items. - /// - `delegate`: The account that had permission to manage collection items owned by the + /// - `delegate`: The account that had permission to transfer collection items owned by the /// `account`. fn check_collection_approval( collection: &T::CollectionId, @@ -353,11 +353,11 @@ impl, I: 'static> Pallet { /// /// - `collection`: The identifier of the collection. /// - `maybe_item`: The optional item of the collection that the delegated account has an - /// approval to transfer. If not provided, an approval to transfer items in the collection - /// owned by the `account` will be checked. + /// approval to transfer. If not provided, an approval to transfer collection items owned by + /// the `account` will be checked. /// - `account`: The account that granted the permission for `delegate` to transfer items in the /// `collection` or the owner of the specified collection item. - /// - `delegate`: The account that had permission to manage collection items owned by the + /// - `delegate`: The account that had permission to transfer collection items owned by the /// `account` or the specified collection item. pub fn check_approval( collection: &T::CollectionId, diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 5dac9ffb..9d1157fa 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -223,7 +223,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/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index cceda7e6..45ecdcd3 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 68 bytes (4+32+32), Value = 32 bytes (16+16) + /// Key = 32 bytes (16+16), Value = 68 bytes (4+32+32) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index cceda7e6..45ecdcd3 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 68 bytes (4+32+32), Value = 32 bytes (16+16) + /// Key = 32 bytes (16+16), Value = 68 bytes (4+32+32) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); From 924d2d3089443017090f58dbc9985d285cc98267 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:58:58 +0700 Subject: [PATCH 44/99] chore: update weights --- pallets/nfts/src/weights.rs | 44 ++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 4acfbd13..70eebc66 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -540,16 +540,18 @@ 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`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `192 + i * (145 ±0)` + // Measured: `360` // Estimated: `3602 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(24_983_673, 3602) - .saturating_add(T::DbWeight::get().reads(2_u64)) + Weight::from_parts(26_897_959, 3602) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } @@ -560,10 +562,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `322 + i * (23 ±0)` + // Measured: `359` // Estimated: `3602 + i * (2163 ±0)` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(22_891_836, 3602) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(22_612_244, 3602) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -577,12 +579,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1770` + // Measured: `1860` // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(289_694_442, 55842) - // Standard Error: 62_848 - .saturating_add(Weight::from_parts(21_298, 0).saturating_mul(n.into())) + Weight::from_parts(94_579_140, 55842) + // Standard Error: 24_413 + .saturating_add(Weight::from_parts(46_655, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(20_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) @@ -1259,16 +1261,18 @@ 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`) + /// Storage: `Nfts::Collection` (r:1 w:0) + /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 1]`. fn approve_transfer(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `192 + i * (145 ±0)` + // Measured: `360` // Estimated: `3602 + i * (2163 ±0)` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(24_983_673, 3602) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + Weight::from_parts(26_897_959, 3602) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2163).saturating_mul(i.into())) } @@ -1279,10 +1283,10 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1]`. fn cancel_approval(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `322 + i * (23 ±0)` + // Measured: `359` // Estimated: `3602 + i * (2163 ±0)` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(22_891_836, 3602) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(22_612_244, 3602) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1296,12 +1300,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 20]`. fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1770` + // Measured: `1860` // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(289_694_442, 55842) - // Standard Error: 62_848 - .saturating_add(Weight::from_parts(21_298, 0).saturating_mul(n.into())) + Weight::from_parts(94_579_140, 55842) + // Standard Error: 24_413 + .saturating_add(Weight::from_parts(46_655, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(20_u64)) .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) From a9c201464f0a5131b49731296728915b0f8f693c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:21:14 +0700 Subject: [PATCH 45/99] chore: comments & tests --- pallets/nfts/src/features/approvals.rs | 12 +++--------- pallets/nfts/src/lib.rs | 23 ++++++++++------------- pallets/nfts/src/tests.rs | 22 +++++++++++++++------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index caeb2f25..02e32c38 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -155,19 +155,14 @@ impl, I: 'static> Pallet { /// performed. /// - `collection`: The collection ID containing the item. /// - `item`: The item ID for which transfer approvals will be cleared. - /// - `witness_approvals`: Information on the collection approvals cleared. This must be - /// correct. pub(crate) fn do_clear_all_transfer_approvals( maybe_check_origin: Option, collection: T::CollectionId, item: T::ItemId, - witness_approvals: u32, ) -> DispatchResult { let mut details = Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; - ensure!(details.approvals.len() as u32 == witness_approvals, Error::::BadWitness); - if let Some(check_origin) = maybe_check_origin { ensure!( CollectionApprovals::::iter_prefix((collection, &check_origin)) @@ -201,7 +196,8 @@ impl, I: 'static> Pallet { /// transfer, the function emits the `TransferApproved` event. /// /// This function reserves the required deposit from the `origin` account. If an approval - /// already exists, the new amount is added to such existing approval. + /// already exists, the deposit amount is incremented, and the approval's existing deadline is + /// overridden. /// /// - `origin`: The account grants permission to approve the transfer. /// - `collection`: The identifier of the collection. @@ -219,9 +215,7 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - let collection_items = - Self::collection_items(collection).ok_or(Error::::UnknownCollection)?; - ensure!(collection_items > 0, Error::::CollectionEmpty); + ensure!(AccountBalance::::get(collection, &origin) > 0, Error::::NoItemOwned); let collection_config = Self::get_collection_config(&collection)?; ensure!( diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index af556ddd..5407f90e 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -641,7 +641,7 @@ pub mod pallet { pub enum Error { /// The signing account has no permission to do the operation. NoPermission, - /// The given item ID is unknown. + /// The given collection ID is unknown. UnknownCollection, /// The item ID has already been used for an item. AlreadyExists, @@ -725,12 +725,12 @@ pub mod pallet { MaxAttributesLimitReached, /// The provided namespace isn't supported in this call. WrongNamespace, - /// The collection has no items. - CollectionEmpty, /// Can't delete non-empty collections. CollectionNotEmpty, /// The witness data should be provided. WitnessRequired, + /// The account owns zero item in the collection. + NoItemOwned, /// The collection has existing approvals. CollectionApprovalsExist, /// Collection and item approval conflicts. @@ -1320,8 +1320,8 @@ pub mod pallet { /// 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` if the `item` is provided. If not, the sender must have sufficient funds to grant - /// a collection approval. + /// `maybe_item` if the `maybe_item` is provided. If not, the sender must have sufficient + /// funds to grant a collection approval. /// /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `maybe_item`: The optional item to be approved for delegated transfer. If not @@ -1374,7 +1374,8 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item` if the `item` is provided; + /// - `Signed` with the signer being the Owner of the `maybe_item` if the `maybe_item` is + /// provided; /// /// Arguments: /// - `collection`: The collection of the item of whose approval will be cancelled. @@ -1414,7 +1415,8 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `item` if the `item` is provided; + /// - `Signed` with the signer being the Owner of the `maybe_item` if the `maybe_item` is + /// provided; /// /// Arguments: /// - `collection`: The collection of the item of whose approvals will be cleared. @@ -1441,12 +1443,7 @@ pub mod pallet { T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { ensure_signed(origin).map(Some).map_err(DispatchError::from) })?; - Self::do_clear_all_transfer_approvals( - maybe_check_origin, - collection, - item, - witness_approvals, - )?; + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; T::WeightInfo::clear_all_transfer_approvals(1, T::ApprovalsLimit::get()) }, None => { diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 72b36e87..bd6cec97 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -309,6 +309,7 @@ fn destroy_with_bad_witness_should_not_work() { fn destroy_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( RuntimeOrigin::signed(account(1)), account(1), @@ -318,7 +319,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(1)), + RuntimeOrigin::signed(account(2)), 0, None, account(3), @@ -345,7 +346,7 @@ fn destroy_should_work() { ), Error::::CollectionApprovalsExist ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, None, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, @@ -2202,10 +2203,10 @@ fn approve_transfer_collection_works() { default_collection_config() )); - // throws error `Error::CollectionEmpty`. + // approve collection without items, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, None, account(3), None), - Error::::CollectionEmpty + Error::::NoItemOwned ); assert_ok!(Nfts::force_mint( @@ -2222,6 +2223,13 @@ fn approve_transfer_collection_works() { account(2), default_item_config() )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 43, + account(3), + default_item_config() + )); // throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( @@ -2234,10 +2242,10 @@ fn approve_transfer_collection_works() { Error::::ItemsNonTransferable ); - // throws error `Error::UnknownCollection`. + // approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), - Error::::UnknownCollection + Error::::NoItemOwned ); assert_ok!(Nfts::approve_transfer( @@ -2515,7 +2523,7 @@ fn clear_all_collection_approvals_works() { RuntimeOrigin::signed(account(1)), 0, 42, - account(2), + account(1), default_item_config() )); From 4404716e827f9e9a4f49aaabd3496cd3b8fb20db Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 02:29:08 +0700 Subject: [PATCH 46/99] refactor: force origin --- pallets/nfts/src/benchmarking.rs | 94 +++++---- pallets/nfts/src/lib.rs | 315 +++++++++++++++++++++---------- pallets/nfts/src/tests.rs | 191 +++++++++---------- pallets/nfts/src/weights.rs | 140 ++++++++------ 4 files changed, 444 insertions(+), 296 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index a08687f9..9d9c5738 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -63,9 +63,10 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account } fn approve_collection, I: 'static>( + collection: T::CollectionId, index: u32, ) -> (T::AccountId, AccountIdLookupOf) { - let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; + let caller = Collection::::get(collection).unwrap().owner; if caller != whitelisted_caller() { whitelist_account!(caller); } @@ -73,10 +74,9 @@ fn approve_collection, I: 'static>( let delegate: T::AccountId = account("delegate", index, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let deadline = BlockNumberFor::::max_value(); - assert_ok!(Nfts::::approve_transfer( + assert_ok!(Nfts::::approve_collection_transfer( SystemOrigin::Signed(caller.clone()).into(), - T::Helper::collection(0), - None, + collection, delegate_lookup.clone(), Some(deadline), )); @@ -592,65 +592,77 @@ 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(); - let maybe_item = if i == 0 { - None - } else { - Some(item) - }; - }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, delegate_lookup, Some(deadline)) + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) verify { - assert_last_event::(Event::TransferApproved { collection, item: maybe_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 { - let i in 0 .. 1; + approve_collection_transfer { + let (collection, caller, _) = create_collection::(); + 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, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + cancel_approval { 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(); - 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) + Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: maybe_item, owner: caller, delegate }.into()); + assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); } - clear_all_transfer_approvals { - let i in 0 .. 1; - let n in 0 .. T::ApprovalsLimit::get(); + cancel_collection_approval { + let (collection, caller, _) = create_collection::(); + 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_collection_transfer(origin, collection, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); + } + clear_all_transfer_approvals { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); - let (maybe_item, witness_approvals) = if i == 0 { - for i in 0 .. n { - approve_collection::(i); - } - (None, n) - } else { - 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))?; - (Some(item), 1) - }; - }: _(SystemOrigin::Signed(caller.clone()), collection, maybe_item, witness_approvals) + 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, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::AllApprovalsCancelled {collection, item: Some(item), owner: caller}.into()); + } + + clear_all_collection_approvals { + let n in 1 .. T::ApprovalsLimit::get() + 1; + + let (collection, caller, _) = create_collection::(); + mint_item::(0); + for i in 0 .. n { + approve_collection::(collection, i); + } + }: _(SystemOrigin::Signed(caller.clone()), collection, n) verify { - assert_last_event::(Event::AllApprovalsCancelled {collection, item: maybe_item, owner: caller}.into()); + assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } set_accept_ownership { diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 5407f90e..daeb2f07 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1320,13 +1320,10 @@ pub mod pallet { /// 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 - /// `maybe_item` if the `maybe_item` is provided. If not, the sender must have sufficient - /// funds to grant a collection approval. + /// `item`. /// /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `maybe_item`: The optional item to be approved for delegated transfer. If not - /// provided, all collection items owned by the `origin` will be approved for delegated - /// transfer. + /// - `item`: The item to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer the item. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire @@ -1335,124 +1332,242 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::approve_transfer(maybe_item.is_some() as u32))] + #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> 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)?; - match maybe_item { - Some(item) => { - let maybe_check_origin = - T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { - ensure_signed(origin).map(Some).map_err(DispatchError::from) - })?; - Self::do_approve_transfer( - maybe_check_origin, - collection, - item, - delegate, - maybe_deadline, - ) - }, - None => { - let origin = ensure_signed(origin)?; - Self::do_approve_collection_transfer( - origin, - collection, - delegate, - maybe_deadline, - ) - }, - } + Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) + } + + /// Approve collection items owned by the origin to be transferred by a delegated + /// third-party account. This function reserves the required deposit + /// `CollectionApprovalDeposit` from the `origin` account. + /// + /// Origin must be Signed. + /// + /// - `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 collection items owned by + /// the origin. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(16)] + #[pallet::weight(T::WeightInfo::approve_collection_transfer())] + pub fn approve_collection_transfer( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + maybe_deadline: Option>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_collection_transfer(origin, collection, delegate, maybe_deadline) + } + + /// Force-approve collection items owned by the origin to be transferred by a delegated + /// third-party account. This function reserves the required deposit + /// `CollectionApprovalDeposit` from the `origin` account. + /// + /// Origin must be the `ForceOrigin`. + /// + /// - `approve_as`: The account granting approval for delegated transfer. + /// - `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 collection items owned by + /// the origin. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire. + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::approve_collection_transfer())] + pub fn force_approve_collection_transfer( + origin: OriginFor, + approve_as: AccountIdLookupOf, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + maybe_deadline: Option>, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + let account = T::Lookup::lookup(approve_as)?; + Self::do_approve_collection_transfer(account, collection, delegate, maybe_deadline) } /// 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 `maybe_item` if the `maybe_item` is - /// provided; + /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: - /// - `collection`: The collection of the item of whose approval will be cancelled. - /// - `maybe_item`: The optional item of the collection of whose approval will be cancelled. - /// If not provided, approval to transfer items in the collection owned by `origin` will - /// be cancelled. + /// - `collection`: The collection 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(16)] - #[pallet::weight(T::WeightInfo::cancel_approval(maybe_item.is_some() as u32))] + #[pallet::call_index(18)] + #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, + item: T::ItemId, 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)?; - match maybe_item { - Some(item) => { - let maybe_check_origin = - T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { - ensure_signed(origin).map(Some).map_err(DispatchError::from) - })?; - Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) - }, - None => { - let origin = ensure_signed(origin)?; - Self::do_cancel_collection_approval(origin, collection, delegate) - }, - } + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) + } + + /// Cancel one of the collection approvals. + /// + /// Origin must be Signed. + /// + /// Arguments: + /// - `collection`: The collection 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(19)] + #[pallet::weight(T::WeightInfo::cancel_collection_approval())] + pub fn cancel_collection_approval( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_collection_approval(origin, collection, delegate) + } + + /// Force-cancel one of the collection approvals. + /// + /// Origin must be `ForceOrigin`. + /// + /// Arguments: + /// - `cancel_as`: The account cancelling approval for delegated transfer. + /// - `collection`: 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(20)] + #[pallet::weight(T::WeightInfo::cancel_collection_approval())] + pub fn force_cancel_collection_approval( + origin: OriginFor, + cancel_as: AccountIdLookupOf, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + let account = T::Lookup::lookup(cancel_as)?; + Self::do_cancel_collection_approval(account, collection, delegate) } /// Cancel all the approvals of a specific item. /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Owner of the `maybe_item` if the `maybe_item` is - /// provided; + /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: /// - `collection`: The collection of the item of whose approvals will be cleared. - /// - `maybe_item`: The item of the collection of whose approvals will be cleared. The - /// optional item of the collection of whose approval will be cleared. If not provided, - /// all approvals to transfer items within collection. + /// - `item`: The item of the collection of whose approvals will be cleared. + /// + /// Emits `AllApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(21)] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + pub fn clear_all_transfer_approvals( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; + Ok(()) + } + + /// Cancel all the collection approvals. + /// + /// Origin must be Signed. + /// + /// Arguments: + /// - `collection`: The collection whose approvals will be cleared. /// - `witness_approvals`: Information on the collection approvals cleared. This must be /// correct. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals(maybe_item.is_some() as u32, *witness_approvals))] - pub fn clear_all_transfer_approvals( + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + pub fn clear_all_collection_approvals( origin: OriginFor, collection: T::CollectionId, - maybe_item: Option, witness_approvals: u32, - ) -> DispatchResultWithPostInfo { - let weight = match maybe_item { - Some(item) => { - let maybe_check_origin = - T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { - ensure_signed(origin).map(Some).map_err(DispatchError::from) - })?; - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; - T::WeightInfo::clear_all_transfer_approvals(1, T::ApprovalsLimit::get()) - }, - None => { - let origin = ensure_signed(origin)?; - Self::do_clear_all_collection_approvals(origin, collection, witness_approvals)?; - T::WeightInfo::clear_all_transfer_approvals(0, witness_approvals) - }, - }; - Ok(Some(weight).into()) + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_clear_all_collection_approvals(origin, collection, witness_approvals)?; + Ok(()) + } + + /// Cancel all the collection approvals. + /// + /// Origin must be `ForceOrigin`. + /// + /// Arguments: + /// - `collection`: The collection whose approvals will be cleared. + /// - `clear_as`: The account clearing all collection approvals. + /// - `witness_approvals`: Information on the collection approvals cleared. This must be + /// correct. + /// + /// Emits `AllApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + pub fn force_clear_collection_approvals( + origin: OriginFor, + clear_as: AccountIdLookupOf, + collection: T::CollectionId, + witness_approvals: u32, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let account = T::Lookup::lookup(clear_as)?; + Self::do_clear_all_collection_approvals(account, collection, witness_approvals)?; + Ok(()) } /// Disallows changing the metadata or attributes of the item. @@ -1472,7 +1587,7 @@ pub mod pallet { /// Emits `ItemPropertiesLocked`. /// /// Weight: `O(1)` - #[pallet::call_index(18)] + #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::lock_item_properties())] pub fn lock_item_properties( origin: OriginFor, @@ -1515,7 +1630,7 @@ pub mod pallet { /// Emits `AttributeSet`. /// /// Weight: `O(1)` - #[pallet::call_index(19)] + #[pallet::call_index(25)] #[pallet::weight(T::WeightInfo::set_attribute())] pub fn set_attribute( origin: OriginFor, @@ -1551,7 +1666,7 @@ pub mod pallet { /// Emits `AttributeSet`. /// /// Weight: `O(1)` - #[pallet::call_index(20)] + #[pallet::call_index(26)] #[pallet::weight(T::WeightInfo::force_set_attribute())] pub fn force_set_attribute( origin: OriginFor, @@ -1581,7 +1696,7 @@ pub mod pallet { /// Emits `AttributeCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(21)] + #[pallet::call_index(27)] #[pallet::weight(T::WeightInfo::clear_attribute())] pub fn clear_attribute( origin: OriginFor, @@ -1605,7 +1720,7 @@ pub mod pallet { /// - `delegate`: The account to delegate permission to change attributes of the item. /// /// Emits `ItemAttributesApprovalAdded` on success. - #[pallet::call_index(22)] + #[pallet::call_index(28)] #[pallet::weight(T::WeightInfo::approve_item_attributes())] pub fn approve_item_attributes( origin: OriginFor, @@ -1628,7 +1743,7 @@ pub mod pallet { /// - `delegate`: The previously approved account to remove. /// /// Emits `ItemAttributesApprovalRemoved` on success. - #[pallet::call_index(23)] + #[pallet::call_index(29)] #[pallet::weight(T::WeightInfo::cancel_item_attributes_approval( witness.account_attributes ))] @@ -1660,7 +1775,7 @@ pub mod pallet { /// Emits `ItemMetadataSet`. /// /// Weight: `O(1)` - #[pallet::call_index(24)] + #[pallet::call_index(30)] #[pallet::weight(T::WeightInfo::set_metadata())] pub fn set_metadata( origin: OriginFor, @@ -1687,7 +1802,7 @@ pub mod pallet { /// Emits `ItemMetadataCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(25)] + #[pallet::call_index(31)] #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata( origin: OriginFor, @@ -1715,7 +1830,7 @@ pub mod pallet { /// Emits `CollectionMetadataSet`. /// /// Weight: `O(1)` - #[pallet::call_index(26)] + #[pallet::call_index(32)] #[pallet::weight(T::WeightInfo::set_collection_metadata())] pub fn set_collection_metadata( origin: OriginFor, @@ -1740,7 +1855,7 @@ pub mod pallet { /// Emits `CollectionMetadataCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(27)] + #[pallet::call_index(33)] #[pallet::weight(T::WeightInfo::clear_collection_metadata())] pub fn clear_collection_metadata( origin: OriginFor, @@ -1762,7 +1877,7 @@ pub mod pallet { /// ownership transferal. /// /// Emits `OwnershipAcceptanceChanged`. - #[pallet::call_index(28)] + #[pallet::call_index(34)] #[pallet::weight(T::WeightInfo::set_accept_ownership())] pub fn set_accept_ownership( origin: OriginFor, @@ -1781,7 +1896,7 @@ pub mod pallet { /// - `max_supply`: The maximum number of items a collection could have. /// /// Emits `CollectionMaxSupplySet` event when successful. - #[pallet::call_index(29)] + #[pallet::call_index(35)] #[pallet::weight(T::WeightInfo::set_collection_max_supply())] pub fn set_collection_max_supply( origin: OriginFor, @@ -1803,7 +1918,7 @@ pub mod pallet { /// - `mint_settings`: The new mint settings. /// /// Emits `CollectionMintSettingsUpdated` event when successful. - #[pallet::call_index(30)] + #[pallet::call_index(36)] #[pallet::weight(T::WeightInfo::update_mint_settings())] pub fn update_mint_settings( origin: OriginFor, @@ -1827,7 +1942,7 @@ pub mod pallet { /// /// Emits `ItemPriceSet` on success if the price is not `None`. /// Emits `ItemPriceRemoved` on success if the price is `None`. - #[pallet::call_index(31)] + #[pallet::call_index(37)] #[pallet::weight(T::WeightInfo::set_price())] pub fn set_price( origin: OriginFor, @@ -1850,7 +1965,7 @@ pub mod pallet { /// - `bid_price`: The price the sender is willing to pay. /// /// Emits `ItemBought` on success. - #[pallet::call_index(32)] + #[pallet::call_index(38)] #[pallet::weight(T::WeightInfo::buy_item())] pub fn buy_item( origin: OriginFor, @@ -1869,7 +1984,7 @@ pub mod pallet { /// - `tips`: Tips array. /// /// Emits `TipSent` on every tip transfer. - #[pallet::call_index(33)] + #[pallet::call_index(39)] #[pallet::weight(T::WeightInfo::pay_tips(tips.len() as u32))] pub fn pay_tips( origin: OriginFor, @@ -1895,7 +2010,7 @@ pub mod pallet { /// after which the swap will expire. /// /// Emits `SwapCreated` on success. - #[pallet::call_index(34)] + #[pallet::call_index(40)] #[pallet::weight(T::WeightInfo::create_swap())] pub fn create_swap( origin: OriginFor, @@ -1927,7 +2042,7 @@ pub mod pallet { /// - `item`: The item an owner wants to give. /// /// Emits `SwapCancelled` on success. - #[pallet::call_index(35)] + #[pallet::call_index(41)] #[pallet::weight(T::WeightInfo::cancel_swap())] pub fn cancel_swap( origin: OriginFor, @@ -1950,7 +2065,7 @@ pub mod pallet { /// - `witness_price`: A price that was previously agreed on. /// /// Emits `SwapClaimed` on success. - #[pallet::call_index(36)] + #[pallet::call_index(42)] #[pallet::weight(T::WeightInfo::claim_swap())] pub fn claim_swap( origin: OriginFor, @@ -1984,7 +2099,7 @@ pub mod pallet { /// Emits `Issued` on success. /// Emits `AttributeSet` if the attributes were provided. /// Emits `ItemMetadataSet` if the metadata was not empty. - #[pallet::call_index(37)] + #[pallet::call_index(43)] #[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))] pub fn mint_pre_signed( origin: OriginFor, @@ -2010,7 +2125,7 @@ pub mod pallet { /// Emits `AttributeSet` for each provided attribute. /// Emits `ItemAttributesApprovalAdded` if the approval wasn't set before. /// Emits `PreSignedAttributesSet` on success. - #[pallet::call_index(38)] + #[pallet::call_index(44)] #[pallet::weight(T::WeightInfo::set_attributes_pre_signed(data.attributes.len() as u32))] pub fn set_attributes_pre_signed( origin: OriginFor, diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index bd6cec97..bbe78c28 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -318,10 +318,9 @@ 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( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); @@ -346,7 +345,11 @@ fn destroy_should_work() { ), Error::::CollectionApprovalsExist ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(account(2)), + 0, + account(3) + )); assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, @@ -523,7 +526,7 @@ fn transfer_should_work() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), 0, - Some(42), + 42, account(2), None )); @@ -1818,7 +1821,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); @@ -1832,7 +1835,7 @@ fn approval_lifecycle_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(2), None )); @@ -1860,7 +1863,7 @@ fn approval_lifecycle_works() { Nfts::approve_transfer( RuntimeOrigin::signed(account(1)), collection_id, - Some(1), + 1, account(2), None ), @@ -1886,10 +1889,9 @@ fn check_approval_works() { default_item_config() )); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); @@ -1910,7 +1912,7 @@ fn check_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); @@ -1927,17 +1929,16 @@ fn check_approval_works() { // Test collection approvals with deadline. let deadline = 10; - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), Some(deadline) )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(11) )); @@ -1979,35 +1980,30 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); @@ -2024,23 +2020,18 @@ fn cancel_approval_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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, - Some(42), - account(3) - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); assert_eq!(approvals(0, 69), vec![]); }); } @@ -2062,20 +2053,23 @@ fn cancel_approval_collection_works() { default_item_config() )); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); assert_eq!(Balances::reserved_balance(&account(2)), 1); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, None, account(3)), + Nfts::cancel_collection_approval(RuntimeOrigin::signed(account(2)), 1, account(3)), Error::::Unapproved ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(account(2)), + 0, + account(3) + )); assert_eq!(Balances::reserved_balance(&account(2)), 0); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, @@ -2113,21 +2107,21 @@ fn approving_multiple_accounts_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(5), Some(2) )); @@ -2168,20 +2162,14 @@ fn approvals_limit_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(i), None )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - account(14), - None - ), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), Error::::ReachedApprovalLimit ); }); @@ -2205,7 +2193,12 @@ fn approve_transfer_collection_works() { // approve collection without items, throws error `Error::NoItemOwned`. assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, None, account(3), None), + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(account(2)), + 0, + account(3), + None + ), Error::::NoItemOwned ); @@ -2238,39 +2231,46 @@ fn approve_transfer_collection_works() { CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 1, None, account(3), None), + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(account(2)), + 1, + account(3), + None + ), Error::::ItemsNonTransferable ); // approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 2, None, account(3), None), + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(account(2)), + 2, + account(3), + None + ), Error::::NoItemOwned ); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); assert_eq!(Balances::reserved_balance(&account(2)), 1); // must not update the total collection approvals. - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); assert_eq!(Balances::reserved_balance(&account(2)), 1); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(3)), 0, - None, account(4), None )); @@ -2310,7 +2310,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), Some(2) )); @@ -2329,7 +2329,7 @@ fn approval_deadline_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(4)), 0, - Some(42), + 42, account(6), Some(4) )); @@ -2359,45 +2359,43 @@ fn cancel_approval_works_with_admin() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); // delegate approval conflicts. - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - None, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::DelegateApprovalConflict ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, None, account(3))); - - assert_ok!(Nfts::cancel_approval( + assert_ok!(Nfts::cancel_collection_approval( RuntimeOrigin::signed(account(2)), 0, - Some(42), account(3) )); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2422,26 +2420,26 @@ fn cancel_approval_works_with_force() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(43), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, Some(42), account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2466,29 +2464,24 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(3), None )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), 0, - Some(42), + 42, account(4), None )); assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, Some(42), 2), + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), Error::::NoPermission ); - assert_ok!(Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(account(2)), - 0, - Some(42), - 2 - )); + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, @@ -2527,28 +2520,30 @@ fn clear_all_collection_approvals_works() { default_item_config() )); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(1)), 0, - None, account(3), None )); - assert_ok!(Nfts::approve_transfer( + assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(1)), 0, - None, account(4), None )); assert_eq!(Balances::free_balance(&account(1)), 98); - - assert_ok!(Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(account(1)), - 0, - None, - 2 - )); + // witness data is zero + assert_noop!( + Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 0), + Error::::BadWitness + ); + // incorrect witness data + assert_noop!( + Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 1), + Error::::BadWitness + ); + assert_ok!(Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 2)); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, item: None, @@ -3584,7 +3579,7 @@ fn pallet_level_feature_flags_should_work() { Nfts::approve_transfer( RuntimeOrigin::signed(user_id.clone()), collection_id, - Some(item_id), + item_id, account(2), None ), diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 70eebc66..f3de6987 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -59,9 +59,11 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; - fn approve_transfer(i: u32, ) -> Weight; - fn cancel_approval(i: u32, ) -> Weight; - fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight; + fn approve_transfer() -> Weight; + fn approve_collection_transfer() -> Weight; + fn cancel_approval() -> Weight; + fn cancel_collection_approval() -> Weight; + fn clear_all_transfer_approvals() -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -540,54 +542,66 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - fn approve_transfer(i: u32, ) -> Weight { + fn approve_collection_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `360` - // Estimated: `3602 + i * (2163 ±0)` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(26_897_959, 3602) + // Measured: `450` + // Estimated: `3602` + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(28_000_000, 3602) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - fn cancel_approval(i: u32, ) -> Weight { + fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602 + i * (2163 ±0)` + // Measured: `345` + // Estimated: `4326` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(22_612_244, 3602) + Weight::from_parts(16_000_000, 4326) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - /// The range of component `n` is `[0, 20]`. - fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { + fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `1860` - // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` + // Measured: `345` + // Estimated: `4326` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(94_579_140, 55842) - // Standard Error: 24_413 - .saturating_add(Weight::from_parts(46_655, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(21_u64)) - .saturating_add(T::DbWeight::get().writes(20_u64)) - .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) + Weight::from_parts(16_000_000, 4326) + .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`) @@ -1261,54 +1275,66 @@ 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`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, 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::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - fn approve_transfer(i: u32, ) -> Weight { + fn approve_collection_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `360` - // Estimated: `3602 + i * (2163 ±0)` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(26_897_959, 3602) + // Measured: `450` + // Estimated: `3602` + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(28_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - fn cancel_approval(i: u32, ) -> Weight { + fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602 + i * (2163 ±0)` + // Measured: `345` + // Estimated: `4326` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(22_612_244, 3602) + Weight::from_parts(16_000_000, 4326) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_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`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `i` is `[0, 1]`. - /// The range of component `n` is `[0, 20]`. - fn clear_all_transfer_approvals(i: u32, n: u32, ) -> Weight { + fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `1860` - // Estimated: `55842 + i * (4325 ±496_172_781_796_926)` + // Measured: `345` + // Estimated: `4326` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(94_579_140, 55842) - // Standard Error: 24_413 - .saturating_add(Weight::from_parts(46_655, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(21_u64)) - .saturating_add(RocksDbWeight::get().writes(20_u64)) - .saturating_add(Weight::from_parts(0, 4325).saturating_mul(i.into())) + Weight::from_parts(16_000_000, 4326) + .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`) From 0f1d960e0efb73f7026b612fdb2f017c35ccfbcd Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:22:05 +0700 Subject: [PATCH 47/99] chore: update weights --- pallets/nfts/src/benchmarking.rs | 40 ++++++++ pallets/nfts/src/lib.rs | 21 ++-- pallets/nfts/src/weights.rs | 160 +++++++++++++++++++++++++++---- 3 files changed, 189 insertions(+), 32 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 9d9c5738..222eddcb 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -613,6 +613,18 @@ benchmarks_instance_pallet! { assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); } + force_approve_collection_transfer { + let (collection, caller, _) = create_collection::(); + mint_item::(0); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let delegate: T::AccountId = account("delegate", 0, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + }: _(SystemOrigin::Root, caller_lookup, collection, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + cancel_approval { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -639,6 +651,20 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); } + force_cancel_collection_approval { + let (collection, caller, _) = create_collection::(); + mint_item::(0); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + 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_collection_transfer(origin, collection, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Root, caller_lookup, collection, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); + } + clear_all_transfer_approvals { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -665,6 +691,20 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } + force_clear_all_collection_approvals { + let n in 1 .. T::ApprovalsLimit::get() + 1; + + let (collection, caller, _) = create_collection::(); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + mint_item::(0); + for i in 0 .. n { + approve_collection::(collection, i); + } + }: _(SystemOrigin::Root, caller_lookup, collection, n) + verify { + assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); + } + set_accept_ownership { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index daeb2f07..d37de72a 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1400,7 +1400,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::approve_collection_transfer())] + #[pallet::weight(T::WeightInfo::force_approve_collection_transfer())] pub fn force_approve_collection_transfer( origin: OriginFor, approve_as: AccountIdLookupOf, @@ -1479,7 +1479,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(20)] - #[pallet::weight(T::WeightInfo::cancel_collection_approval())] + #[pallet::weight(T::WeightInfo::force_cancel_collection_approval())] pub fn force_cancel_collection_approval( origin: OriginFor, cancel_as: AccountIdLookupOf, @@ -1515,8 +1515,7 @@ pub mod pallet { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)?; - Ok(()) + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) } /// Cancel all the collection approvals. @@ -1532,18 +1531,17 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(22)] - #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + #[pallet::weight(T::WeightInfo::clear_all_collection_approvals(*witness_approvals))] pub fn clear_all_collection_approvals( origin: OriginFor, collection: T::CollectionId, witness_approvals: u32, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::do_clear_all_collection_approvals(origin, collection, witness_approvals)?; - Ok(()) + Self::do_clear_all_collection_approvals(origin, collection, witness_approvals) } - /// Cancel all the collection approvals. + /// Force-cancel all the collection approvals. /// /// Origin must be `ForceOrigin`. /// @@ -1557,8 +1555,8 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(23)] - #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] - pub fn force_clear_collection_approvals( + #[pallet::weight(T::WeightInfo::force_clear_all_collection_approvals(*witness_approvals))] + pub fn force_clear_all_collection_approvals( origin: OriginFor, clear_as: AccountIdLookupOf, collection: T::CollectionId, @@ -1566,8 +1564,7 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let account = T::Lookup::lookup(clear_as)?; - Self::do_clear_all_collection_approvals(account, collection, witness_approvals)?; - Ok(()) + Self::do_clear_all_collection_approvals(account, collection, witness_approvals) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index f3de6987..22d85490 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -61,9 +61,13 @@ pub trait WeightInfo { fn clear_collection_metadata() -> Weight; fn approve_transfer() -> Weight; fn approve_collection_transfer() -> Weight; + fn force_approve_collection_transfer() -> Weight; fn cancel_approval() -> Weight; fn cancel_collection_approval() -> Weight; + fn force_cancel_collection_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; + fn clear_all_collection_approvals(n: u32, ) -> Weight; + fn force_clear_all_collection_approvals(n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -546,8 +550,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `337` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -561,8 +565,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `450` // Estimated: `3602` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(28_000_000, 3602) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(30_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `450` + // Estimated: `3602` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -574,8 +593,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(36_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -585,8 +604,19 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `359` // Estimated: `3602` - // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 3602) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3602) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -598,11 +628,43 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(21_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 21]`. + fn clear_all_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(16_630_042, 3602) + // Standard Error: 121_416 + .saturating_add(Weight::from_parts(3_823_189, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 21]`. + fn force_clear_all_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(13_455_783, 3602) + // Standard Error: 146_830 + .saturating_add(Weight::from_parts(4_223_404, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { @@ -1279,8 +1341,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `337` // Estimated: `4326` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1294,8 +1356,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `450` // Estimated: `3602` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(28_000_000, 3602) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(30_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `450` + // Estimated: `3602` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1307,8 +1384,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(36_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1318,8 +1395,19 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `359` // Estimated: `3602` - // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 3602) + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 17_000_000 picoseconds. + Weight::from_parts(18_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1331,11 +1419,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 4326) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(21_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 21]`. + fn clear_all_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(16_630_042, 3602) + // Standard Error: 121_416 + .saturating_add(Weight::from_parts(3_823_189, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 21]`. + fn force_clear_all_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(13_455_783, 3602) + // Standard Error: 146_830 + .saturating_add(Weight::from_parts(4_223_404, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { From e1226d6ad7fefc773303221783ff015f5127e61e Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:41:59 +0700 Subject: [PATCH 48/99] chore: comments --- pallets/nfts/src/benchmarking.rs | 3 +-- pallets/nfts/src/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 222eddcb..7dd0b143 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -657,9 +657,8 @@ benchmarks_instance_pallet! { let caller_lookup = T::Lookup::unlookup(caller.clone()); 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_collection_transfer(origin, collection, delegate_lookup.clone(), Some(deadline))?; + Nfts::::approve_collection_transfer(SystemOrigin::Signed(caller.clone()).into(), collection, delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Root, caller_lookup, collection, delegate_lookup) verify { assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index d37de72a..1f47ad4c 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1384,7 +1384,7 @@ pub mod pallet { /// Force-approve collection items owned by the origin to be transferred by a delegated /// third-party account. This function reserves the required deposit - /// `CollectionApprovalDeposit` from the `origin` account. + /// `CollectionApprovalDeposit` from the `approve_as` account. /// /// Origin must be the `ForceOrigin`. /// @@ -1421,7 +1421,7 @@ pub mod pallet { /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: - /// - `collection`: The collection the item of whose approval will be cancelled. + /// - `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. /// @@ -1466,7 +1466,7 @@ pub mod pallet { Self::do_cancel_collection_approval(origin, collection, delegate) } - /// Force-cancel one of the collection approvals. + /// Force-cancel one of the collection approvals granted by `cancel_as` account. /// /// Origin must be `ForceOrigin`. /// @@ -1541,7 +1541,7 @@ pub mod pallet { Self::do_clear_all_collection_approvals(origin, collection, witness_approvals) } - /// Force-cancel all the collection approvals. + /// Force-cancel all the collection approvals granted by `clear_as` account. /// /// Origin must be `ForceOrigin`. /// From 67f422a84865ddf832abb14e0df370576b70daf9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:03:34 +0700 Subject: [PATCH 49/99] chore: add integrity test --- pallets/nfts/src/lib.rs | 11 +++++++++++ pallets/nfts/src/tests.rs | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 1f47ad4c..9647be32 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -737,6 +737,17 @@ pub mod pallet { DelegateApprovalConflict, } + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + #[cfg(any(feature = "std", test))] + fn integrity_test() { + assert!( + size_of::<>::ItemId>() == size_of::(), + "ItemId must be bounded by u32 type." + ); + } + } + #[pallet::call] impl, I: 'static> Pallet { /// Issue a new collection of non-fungible items from a public origin. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index bbe78c28..f58d3919 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2037,7 +2037,7 @@ fn cancel_approval_works() { } #[test] -fn cancel_approval_collection_works() { +fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( @@ -2176,7 +2176,7 @@ fn approvals_limit_works() { } #[test] -fn approve_transfer_collection_works() { +fn approve_collection_transfer_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&account(2), 100); Balances::make_free_balance_be(&account(3), 100); From 60122d9dd2adbcda62ceae322deede2af4b397ef Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:47:07 +0700 Subject: [PATCH 50/99] chore: update comment --- pallets/nfts/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 9647be32..e30770e2 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1403,7 +1403,7 @@ pub mod pallet { /// - `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 collection items owned by - /// the origin. + /// the `approve_as`. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire. /// From 7d9c48f2faa8be54fba4f7f198449d642ed72817 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:51:42 +0700 Subject: [PATCH 51/99] chore: update comments Co-authored-by: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> --- pallets/nfts/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index e30770e2..2593da98 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -175,11 +175,10 @@ pub mod pallet { #[pallet::constant] type CollectionDeposit: Get>; - /// The basic amount of funds that must be reserved for collection approvals. + /// The basic amount of funds that must be reserved for a collection approval. /// - /// This is held for an additional storage item whose value size is - /// `sizeof((Option, Balance))` bytes and whose key size is - /// `sizeof((CollectionId, AccountId, AccountId))` bytes. + /// Key: `sizeof((CollectionId, AccountId, AccountId))` bytes. + /// Value: `sizeof((Option, Balance))` bytes. #[pallet::constant] type CollectionApprovalDeposit: Get>; @@ -426,7 +425,7 @@ pub mod pallet { ValueQuery, >; - /// Permission for a delegate to transfer all owner's items within a collection. + /// Permission for a delegate to transfer all owner's collection items. #[pallet::storage] pub type CollectionApprovals, I: 'static = ()> = StorageNMap< _, @@ -729,7 +728,7 @@ pub mod pallet { CollectionNotEmpty, /// The witness data should be provided. WitnessRequired, - /// The account owns zero item in the collection. + /// The account owns zero items in the collection. NoItemOwned, /// The collection has existing approvals. CollectionApprovalsExist, @@ -1477,7 +1476,7 @@ pub mod pallet { Self::do_cancel_collection_approval(origin, collection, delegate) } - /// Force-cancel one of the collection approvals granted by `cancel_as` account. + /// Force-cancel a collection approval granted by `cancel_as` account. /// /// Origin must be `ForceOrigin`. /// From e1b2b62026992e09d5244099f03f21ae451472bf Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:53:43 +0700 Subject: [PATCH 52/99] chore: update comments Co-authored-by: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> --- pallets/nfts/src/features/approvals.rs | 67 ++++++++++---------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 02e32c38..6d5627dc 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -123,7 +123,7 @@ impl, I: 'static> Pallet { } // Cannot revoke approval for a specific collection item if the delegate has - // permission to transfer collection items owned by the origin. + // permission to transfer all collection items owned by the origin. ensure!( !CollectionApprovals::::contains_key((collection, &details.owner, &delegate)), Error::::DelegateApprovalConflict @@ -186,23 +186,21 @@ impl, I: 'static> Pallet { Ok(()) } - /// Approves the transfer of all collection items owned by the origin to a delegate. + /// Approves the transfer of all collection items of `owner` to a delegate. /// - /// This function is used to approve the transfer of items in the `collection` owned by the - /// `origin` to a `delegate`. The `delegate` is the account that will be allowed to take control - /// of items in the collection. Optionally, a `deadline` can be specified to set a time limit + /// This function is used to approve the transfer of all collection items of `owner` to a `delegate`. The `delegate` account will be allowed to take control + /// of the items. Optionally, a `deadline` can be specified to set a time limit /// for the approval. The `deadline` is expressed in block numbers and is added to the current /// block number to determine the absolute deadline for the approval. After approving the /// transfer, the function emits the `TransferApproved` event. /// - /// This function reserves the required deposit from the `origin` account. If an approval + /// This function reserves the required deposit from the `owner` account. If an approval /// already exists, the deposit amount is incremented, and the approval's existing deadline is /// overridden. /// - /// - `origin`: The account grants permission to approve the transfer. + /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that will be allowed to take control of items in the collection - /// owned by the `origin`. + /// - `delegate`: The account that will be allowed to take control of the collection items. /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. pub(crate) fn do_approve_collection_transfer( @@ -254,16 +252,13 @@ impl, I: 'static> Pallet { Ok(()) } - /// Cancels the transfer of all collection items owned by the origin to a delegate. + /// Cancels the transfer of all `collection` items of `owner` to a `delegate`. /// - /// This function is used to cancel the approval for the transfer of items in the `collection` - /// owned by the `origin` to a `delegate`. After canceling the approval, the function - /// returns the `origin` back the deposited fund and emits the `ApprovalCancelled` event. + /// This function is used to cancel the approval for the transfer of the collection items of `owner` to a `delegate`. After canceling the approval, the deposit is returned to the `owner` account and the `ApprovalCancelled` event is emitted. /// - /// - `origin`: The account grants permission to cancel the transfer. + /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that had permission to transfer collection items owned by the - /// `account`. + /// - `delegate`: The account that had permission to transfer collection items. pub(crate) fn do_cancel_collection_approval( origin: T::AccountId, collection: T::CollectionId, @@ -286,13 +281,11 @@ impl, I: 'static> Pallet { /// Clears all collection approvals. /// - /// This function is used to clear all approvals to transfer collection items owned by the - /// `origin` to a `delegate`. After clearing all approvals, the function returns the `origin` - /// back the deposited fund of each collection approval and emits the `AllApprovalsCancelled` - /// event. + /// This function is used to clear all approvals for the collection items of `owner`. After clearing all approvals, the deposit of each collection approval is returned to the `owner` account and the `AllApprovalsCancelled` + /// event is emitted. /// - /// - `origin`: The account grants permission to clear the transfer. - /// - `collection`: The collection ID containing the item. + /// - `owner`: The owner of the collection items. + /// - `collection`: The collection ID containing the item. /// - `witness_approvals`: Information on the collection approvals cleared. This must be /// correct. pub(crate) fn do_clear_all_collection_approvals( @@ -302,8 +295,7 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); - // Iterate and remove each collection approval, returning the deposited funds back to the - // `origin`. + // Iterate and remove each collection approval, returning the deposit back to the `owner`. for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { ensure!(removed_approvals < witness_approvals, Error::::BadWitness); removed_approvals.saturating_inc(); @@ -318,13 +310,11 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` is approved to transfer items in the `collection` owned - /// by the `account`. + /// Checks whether the `delegate` is approved to transfer collection items of `owner`. /// /// - `collection`: The identifier of the collection. - /// - `account`: The account that granted the permission for `delegate` to transfer items. - /// - `delegate`: The account that had permission to transfer collection items owned by the - /// `account`. + /// - `owner`: The owner of the collection items. + /// - `delegate`: The account to check for approval to transfer collection items of `owner`. fn check_collection_approval( collection: &T::CollectionId, account: &T::AccountId, @@ -340,31 +330,24 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` is approved by the `account` to transfer items owned by - /// the `account` or a specific item in the collection. If the `delegate` has - /// an approval to transfer items in the collection owned by the `account`, they can - /// transfer every item without requiring explicit approval for that item. + /// Checks whether the `delegate` is approved by `owner` to transfer its collection item(s). If the `delegate` is approved for all `owner`'s collection items it can transfer every item without requiring explicit approval for an item. /// /// - `collection`: The identifier of the collection. /// - `maybe_item`: The optional item of the collection that the delegated account has an - /// approval to transfer. If not provided, an approval to transfer collection items owned by - /// the `account` will be checked. - /// - `account`: The account that granted the permission for `delegate` to transfer items in the - /// `collection` or the owner of the specified collection item. - /// - `delegate`: The account that had permission to transfer collection items owned by the - /// `account` or the specified collection item. + /// approval to transfer. If not provided, an approval to transfer all `owner`'s collection items will be checked. + /// - `owner`: The owner of the specified collection item. + /// - `delegate`: The account to check for approval to transfer collection item(s) of owner. pub fn check_approval( collection: &T::CollectionId, maybe_item: &Option, account: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { - // Check if a `delegate` has permission to transfer items in the collection owned by - // the `owner`. + // Check if `delegate` has permission to transfer `owner`'s collection items. match Self::check_collection_approval(collection, account, delegate) { Ok(()) => Ok(()), Err(error) => { - // Check if a `delegate` has permission to transfer the collection item. + // Check if a `delegate` has permission to transfer the given collection item. if let Some(item) = maybe_item { let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; From 0656b4e0b1758bb86c22c11b8a494c63b2812c91 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 4 Dec 2024 20:20:49 +0700 Subject: [PATCH 53/99] chore: resolve comments --- pallets/nfts/src/features/approvals.rs | 57 ++++++++------ pallets/nfts/src/lib.rs | 105 +++++++++++++------------ pallets/nfts/src/tests.rs | 18 ++--- 3 files changed, 94 insertions(+), 86 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 6d5627dc..73e67e76 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -188,11 +188,12 @@ impl, I: 'static> Pallet { /// Approves the transfer of all collection items of `owner` to a delegate. /// - /// This function is used to approve the transfer of all collection items of `owner` to a `delegate`. The `delegate` account will be allowed to take control - /// of the items. Optionally, a `deadline` can be specified to set a time limit - /// for the approval. The `deadline` is expressed in block numbers and is added to the current - /// block number to determine the absolute deadline for the approval. After approving the - /// transfer, the function emits the `TransferApproved` event. + /// This function is used to approve the transfer of all collection items of `owner` to a + /// `delegate`. The `delegate` account will be allowed to take control of the items. + /// Optionally, a `deadline` can be specified to set a time limit for the approval. The + /// `deadline` is expressed in block numbers and is added to the current block number to + /// determine the absolute deadline for the approval. After approving the transfer, the + /// function emits the `TransferApproved` event. /// /// This function reserves the required deposit from the `owner` account. If an approval /// already exists, the deposit amount is incremented, and the approval's existing deadline is @@ -254,7 +255,9 @@ impl, I: 'static> Pallet { /// Cancels the transfer of all `collection` items of `owner` to a `delegate`. /// - /// This function is used to cancel the approval for the transfer of the collection items of `owner` to a `delegate`. After canceling the approval, the deposit is returned to the `owner` account and the `ApprovalCancelled` event is emitted. + /// This function is used to cancel the approval for the transfer of the collection items of + /// `owner` to a `delegate`. After canceling the approval, the deposit is returned to the + /// `owner` account and the `ApprovalCancelled` event is emitted. /// /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. @@ -281,11 +284,12 @@ impl, I: 'static> Pallet { /// Clears all collection approvals. /// - /// This function is used to clear all approvals for the collection items of `owner`. After clearing all approvals, the deposit of each collection approval is returned to the `owner` account and the `AllApprovalsCancelled` - /// event is emitted. + /// This function is used to clear all approvals for the collection items of `owner`. After + /// clearing all approvals, the deposit of each collection approval is returned to the `owner` + /// account and the `AllApprovalsCancelled` event is emitted. /// - /// - `owner`: The owner of the collection items. - /// - `collection`: The collection ID containing the item. + /// - `owner`: The owner of the collection items. + /// - `collection`: The collection ID containing the item. /// - `witness_approvals`: Information on the collection approvals cleared. This must be /// correct. pub(crate) fn do_clear_all_collection_approvals( @@ -293,6 +297,10 @@ impl, I: 'static> Pallet { collection: T::CollectionId, witness_approvals: u32, ) -> DispatchResult { + ensure!( + witness_approvals > 0 && witness_approvals <= T::ApprovalsLimit::get(), + Error::::BadWitness + ); let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. @@ -301,10 +309,7 @@ impl, I: 'static> Pallet { removed_approvals.saturating_inc(); deposits = deposits.saturating_add(deposit); } - ensure!( - removed_approvals > 0 && removed_approvals == witness_approvals, - Error::::BadWitness - ); + ensure!(removed_approvals == witness_approvals, Error::::BadWitness); T::Currency::unreserve(&origin, deposits); Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); Ok(()) @@ -317,11 +322,11 @@ impl, I: 'static> Pallet { /// - `delegate`: The account to check for approval to transfer collection items of `owner`. fn check_collection_approval( collection: &T::CollectionId, - account: &T::AccountId, + owner: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { let (maybe_deadline, _) = - CollectionApprovals::::get((&collection, &account, &delegate)) + CollectionApprovals::::get((&collection, &owner, &delegate)) .ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { let block_number = frame_system::Pallet::::block_number(); @@ -330,28 +335,28 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` is approved by `owner` to transfer its collection item(s). If the `delegate` is approved for all `owner`'s collection items it can transfer every item without requiring explicit approval for an item. + /// Checks whether the `delegate` is approved by `owner` to transfer its collection item(s). If + /// the `delegate` is approved for all `owner`'s collection items it can transfer every item + /// without requiring explicit approval for an item. /// /// - `collection`: The identifier of the collection. - /// - `maybe_item`: The optional item of the collection that the delegated account has an - /// approval to transfer. If not provided, an approval to transfer all `owner`'s collection items will be checked. + /// - `maybe_details`: The optional collection item details that the delegated account has an + /// approval to transfer. If not provided, an approval to transfer all `owner`'s collection + /// items will be checked. /// - `owner`: The owner of the specified collection item. /// - `delegate`: The account to check for approval to transfer collection item(s) of owner. pub fn check_approval( collection: &T::CollectionId, - maybe_item: &Option, - account: &T::AccountId, + maybe_details: &Option>, + owner: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { // Check if `delegate` has permission to transfer `owner`'s collection items. - match Self::check_collection_approval(collection, account, delegate) { + match Self::check_collection_approval(collection, owner, delegate) { Ok(()) => Ok(()), Err(error) => { // Check if a `delegate` has permission to transfer the given collection item. - if let Some(item) = maybe_item { - let details = - Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - + if let Some(details) = maybe_details { let maybe_deadline = details.approvals.get(delegate).ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 2593da98..2578e095 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1087,7 +1087,12 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_approval(&collection, &Some(item), &details.owner, &origin)?; + Self::check_approval( + &collection, + &Some(details.clone()), + &details.owner, + &origin, + )?; } Ok(()) }) @@ -1379,7 +1384,7 @@ pub mod pallet { /// Emits `TransferApproved` on success. /// /// Weight: `O(1)` - #[pallet::call_index(16)] + #[pallet::call_index(39)] #[pallet::weight(T::WeightInfo::approve_collection_transfer())] pub fn approve_collection_transfer( origin: OriginFor, @@ -1394,34 +1399,34 @@ pub mod pallet { /// Force-approve collection items owned by the origin to be transferred by a delegated /// third-party account. This function reserves the required deposit - /// `CollectionApprovalDeposit` from the `approve_as` account. + /// `CollectionApprovalDeposit` from the `owner` account. /// /// Origin must be the `ForceOrigin`. /// - /// - `approve_as`: The account granting approval for delegated transfer. + /// - `owner`: The account granting approval for delegated transfer. /// - `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 collection items owned by - /// the `approve_as`. + /// the `owner`. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the /// number of blocks after which the approval will expire. /// /// Emits `TransferApproved` on success. /// /// Weight: `O(1)` - #[pallet::call_index(17)] + #[pallet::call_index(40)] #[pallet::weight(T::WeightInfo::force_approve_collection_transfer())] pub fn force_approve_collection_transfer( origin: OriginFor, - approve_as: AccountIdLookupOf, + owner: AccountIdLookupOf, collection: T::CollectionId, delegate: AccountIdLookupOf, maybe_deadline: Option>, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let delegate = T::Lookup::lookup(delegate)?; - let account = T::Lookup::lookup(approve_as)?; - Self::do_approve_collection_transfer(account, collection, delegate, maybe_deadline) + let owner = T::Lookup::lookup(owner)?; + Self::do_approve_collection_transfer(owner, collection, delegate, maybe_deadline) } /// Cancel one of the transfer approvals for a specific item. @@ -1438,7 +1443,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(18)] + #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, @@ -1453,7 +1458,7 @@ pub mod pallet { Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) } - /// Cancel one of the collection approvals. + /// Cancel a collection approval. /// /// Origin must be Signed. /// @@ -1464,7 +1469,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(19)] + #[pallet::call_index(41)] #[pallet::weight(T::WeightInfo::cancel_collection_approval())] pub fn cancel_collection_approval( origin: OriginFor, @@ -1476,30 +1481,30 @@ pub mod pallet { Self::do_cancel_collection_approval(origin, collection, delegate) } - /// Force-cancel a collection approval granted by `cancel_as` account. + /// Force-cancel a collection approval granted by `owner` account. /// /// Origin must be `ForceOrigin`. /// /// Arguments: - /// - `cancel_as`: The account cancelling approval for delegated transfer. + /// - `owner`: The account cancelling approval for delegated transfer. /// - `collection`: 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(20)] + #[pallet::call_index(42)] #[pallet::weight(T::WeightInfo::force_cancel_collection_approval())] pub fn force_cancel_collection_approval( origin: OriginFor, - cancel_as: AccountIdLookupOf, + owner: AccountIdLookupOf, collection: T::CollectionId, delegate: AccountIdLookupOf, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let delegate = T::Lookup::lookup(delegate)?; - let account = T::Lookup::lookup(cancel_as)?; - Self::do_cancel_collection_approval(account, collection, delegate) + let owner = T::Lookup::lookup(owner)?; + Self::do_cancel_collection_approval(owner, collection, delegate) } /// Cancel all the approvals of a specific item. @@ -1515,7 +1520,7 @@ pub mod pallet { /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(21)] + #[pallet::call_index(17)] #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] pub fn clear_all_transfer_approvals( origin: OriginFor, @@ -1534,13 +1539,12 @@ pub mod pallet { /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. - /// - `witness_approvals`: Information on the collection approvals cleared. This must be - /// correct. + /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(22)] + #[pallet::call_index(43)] #[pallet::weight(T::WeightInfo::clear_all_collection_approvals(*witness_approvals))] pub fn clear_all_collection_approvals( origin: OriginFor, @@ -1551,30 +1555,29 @@ pub mod pallet { Self::do_clear_all_collection_approvals(origin, collection, witness_approvals) } - /// Force-cancel all the collection approvals granted by `clear_as` account. + /// Force-cancel all the collection approvals granted by `owner` account. /// /// Origin must be `ForceOrigin`. /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. - /// - `clear_as`: The account clearing all collection approvals. - /// - `witness_approvals`: Information on the collection approvals cleared. This must be - /// correct. + /// - `owner`: The account clearing all collection approvals. + /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(23)] + #[pallet::call_index(44)] #[pallet::weight(T::WeightInfo::force_clear_all_collection_approvals(*witness_approvals))] pub fn force_clear_all_collection_approvals( origin: OriginFor, - clear_as: AccountIdLookupOf, + owner: AccountIdLookupOf, collection: T::CollectionId, witness_approvals: u32, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; - let account = T::Lookup::lookup(clear_as)?; - Self::do_clear_all_collection_approvals(account, collection, witness_approvals) + let owner = T::Lookup::lookup(owner)?; + Self::do_clear_all_collection_approvals(owner, collection, witness_approvals) } /// Disallows changing the metadata or attributes of the item. @@ -1594,7 +1597,7 @@ pub mod pallet { /// Emits `ItemPropertiesLocked`. /// /// Weight: `O(1)` - #[pallet::call_index(24)] + #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::lock_item_properties())] pub fn lock_item_properties( origin: OriginFor, @@ -1637,7 +1640,7 @@ pub mod pallet { /// Emits `AttributeSet`. /// /// Weight: `O(1)` - #[pallet::call_index(25)] + #[pallet::call_index(19)] #[pallet::weight(T::WeightInfo::set_attribute())] pub fn set_attribute( origin: OriginFor, @@ -1673,7 +1676,7 @@ pub mod pallet { /// Emits `AttributeSet`. /// /// Weight: `O(1)` - #[pallet::call_index(26)] + #[pallet::call_index(20)] #[pallet::weight(T::WeightInfo::force_set_attribute())] pub fn force_set_attribute( origin: OriginFor, @@ -1703,7 +1706,7 @@ pub mod pallet { /// Emits `AttributeCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(27)] + #[pallet::call_index(21)] #[pallet::weight(T::WeightInfo::clear_attribute())] pub fn clear_attribute( origin: OriginFor, @@ -1727,7 +1730,7 @@ pub mod pallet { /// - `delegate`: The account to delegate permission to change attributes of the item. /// /// Emits `ItemAttributesApprovalAdded` on success. - #[pallet::call_index(28)] + #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::approve_item_attributes())] pub fn approve_item_attributes( origin: OriginFor, @@ -1750,7 +1753,7 @@ pub mod pallet { /// - `delegate`: The previously approved account to remove. /// /// Emits `ItemAttributesApprovalRemoved` on success. - #[pallet::call_index(29)] + #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::cancel_item_attributes_approval( witness.account_attributes ))] @@ -1782,7 +1785,7 @@ pub mod pallet { /// Emits `ItemMetadataSet`. /// /// Weight: `O(1)` - #[pallet::call_index(30)] + #[pallet::call_index(24)] #[pallet::weight(T::WeightInfo::set_metadata())] pub fn set_metadata( origin: OriginFor, @@ -1809,7 +1812,7 @@ pub mod pallet { /// Emits `ItemMetadataCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(31)] + #[pallet::call_index(25)] #[pallet::weight(T::WeightInfo::clear_metadata())] pub fn clear_metadata( origin: OriginFor, @@ -1837,7 +1840,7 @@ pub mod pallet { /// Emits `CollectionMetadataSet`. /// /// Weight: `O(1)` - #[pallet::call_index(32)] + #[pallet::call_index(26)] #[pallet::weight(T::WeightInfo::set_collection_metadata())] pub fn set_collection_metadata( origin: OriginFor, @@ -1862,7 +1865,7 @@ pub mod pallet { /// Emits `CollectionMetadataCleared`. /// /// Weight: `O(1)` - #[pallet::call_index(33)] + #[pallet::call_index(27)] #[pallet::weight(T::WeightInfo::clear_collection_metadata())] pub fn clear_collection_metadata( origin: OriginFor, @@ -1884,7 +1887,7 @@ pub mod pallet { /// ownership transferal. /// /// Emits `OwnershipAcceptanceChanged`. - #[pallet::call_index(34)] + #[pallet::call_index(28)] #[pallet::weight(T::WeightInfo::set_accept_ownership())] pub fn set_accept_ownership( origin: OriginFor, @@ -1903,7 +1906,7 @@ pub mod pallet { /// - `max_supply`: The maximum number of items a collection could have. /// /// Emits `CollectionMaxSupplySet` event when successful. - #[pallet::call_index(35)] + #[pallet::call_index(29)] #[pallet::weight(T::WeightInfo::set_collection_max_supply())] pub fn set_collection_max_supply( origin: OriginFor, @@ -1925,7 +1928,7 @@ pub mod pallet { /// - `mint_settings`: The new mint settings. /// /// Emits `CollectionMintSettingsUpdated` event when successful. - #[pallet::call_index(36)] + #[pallet::call_index(30)] #[pallet::weight(T::WeightInfo::update_mint_settings())] pub fn update_mint_settings( origin: OriginFor, @@ -1949,7 +1952,7 @@ pub mod pallet { /// /// Emits `ItemPriceSet` on success if the price is not `None`. /// Emits `ItemPriceRemoved` on success if the price is `None`. - #[pallet::call_index(37)] + #[pallet::call_index(31)] #[pallet::weight(T::WeightInfo::set_price())] pub fn set_price( origin: OriginFor, @@ -1972,7 +1975,7 @@ pub mod pallet { /// - `bid_price`: The price the sender is willing to pay. /// /// Emits `ItemBought` on success. - #[pallet::call_index(38)] + #[pallet::call_index(32)] #[pallet::weight(T::WeightInfo::buy_item())] pub fn buy_item( origin: OriginFor, @@ -1991,7 +1994,7 @@ pub mod pallet { /// - `tips`: Tips array. /// /// Emits `TipSent` on every tip transfer. - #[pallet::call_index(39)] + #[pallet::call_index(33)] #[pallet::weight(T::WeightInfo::pay_tips(tips.len() as u32))] pub fn pay_tips( origin: OriginFor, @@ -2017,7 +2020,7 @@ pub mod pallet { /// after which the swap will expire. /// /// Emits `SwapCreated` on success. - #[pallet::call_index(40)] + #[pallet::call_index(34)] #[pallet::weight(T::WeightInfo::create_swap())] pub fn create_swap( origin: OriginFor, @@ -2049,7 +2052,7 @@ pub mod pallet { /// - `item`: The item an owner wants to give. /// /// Emits `SwapCancelled` on success. - #[pallet::call_index(41)] + #[pallet::call_index(35)] #[pallet::weight(T::WeightInfo::cancel_swap())] pub fn cancel_swap( origin: OriginFor, @@ -2072,7 +2075,7 @@ pub mod pallet { /// - `witness_price`: A price that was previously agreed on. /// /// Emits `SwapClaimed` on success. - #[pallet::call_index(42)] + #[pallet::call_index(36)] #[pallet::weight(T::WeightInfo::claim_swap())] pub fn claim_swap( origin: OriginFor, @@ -2106,7 +2109,7 @@ pub mod pallet { /// Emits `Issued` on success. /// Emits `AttributeSet` if the attributes were provided. /// Emits `ItemMetadataSet` if the metadata was not empty. - #[pallet::call_index(43)] + #[pallet::call_index(37)] #[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))] pub fn mint_pre_signed( origin: OriginFor, @@ -2132,7 +2135,7 @@ pub mod pallet { /// Emits `AttributeSet` for each provided attribute. /// Emits `ItemAttributesApprovalAdded` if the approval wasn't set before. /// Emits `PreSignedAttributesSet` on success. - #[pallet::call_index(44)] + #[pallet::call_index(38)] #[pallet::weight(T::WeightInfo::set_attributes_pre_signed(data.attributes.len() as u32))] pub fn set_attributes_pre_signed( origin: OriginFor, diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index f58d3919..7c798e63 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1902,11 +1902,11 @@ fn check_approval_works() { Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&1, &Some(43), &account(2), &account(3)), - Error::::UnknownItem + Nfts::check_approval(&1, &Item::::get(0, 43), &account(2), &account(3)), + Error::::NoPermission ); assert_ok!(Nfts::check_approval(&0, &None, &account(2), &account(3))); - assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); // Test collection item approvals without deadline. assert_ok!(Nfts::approve_transfer( @@ -1918,14 +1918,14 @@ fn check_approval_works() { )); assert_noop!( - Nfts::check_approval(&0, &Some(43), &account(2), &account(4)), - Error::::UnknownItem + Nfts::check_approval(&0, &Item::::get(0, 43), &account(2), &account(4)), + Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&0, &Some(42), &account(2), &account(4)), + Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(4)), Error::::NoPermission ); - assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); // Test collection approvals with deadline. let deadline = 10; @@ -1948,14 +1948,14 @@ fn check_approval_works() { Nfts::check_approval(&0, &None, &account(2), &account(3)), Error::::ApprovalExpired ); - assert_ok!(Nfts::check_approval(&0, &Some(42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); System::set_block_number(14); assert_noop!( Nfts::check_approval(&0, &None, &account(2), &account(3)), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval(&0, &Some(42), &account(2), &account(3)), + Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3)), Error::::ApprovalExpired ); }); From 92d98ecdf6600411f59f7b96cf19cfce2ffe29cb Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:56:50 +0700 Subject: [PATCH 54/99] chore: add variables to tests --- pallets/nfts/src/features/approvals.rs | 28 +- pallets/nfts/src/lib.rs | 41 +- pallets/nfts/src/tests.rs | 582 ++++++++++++++++--------- 3 files changed, 401 insertions(+), 250 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 73e67e76..f6f01a2c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -290,29 +290,25 @@ impl, I: 'static> Pallet { /// /// - `owner`: The owner of the collection items. /// - `collection`: The collection ID containing the item. - /// - `witness_approvals`: Information on the collection approvals cleared. This must be - /// correct. pub(crate) fn do_clear_all_collection_approvals( origin: T::AccountId, collection: T::CollectionId, - witness_approvals: u32, - ) -> DispatchResult { - ensure!( - witness_approvals > 0 && witness_approvals <= T::ApprovalsLimit::get(), - Error::::BadWitness - ); + ) -> Result { let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. - for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { - ensure!(removed_approvals < witness_approvals, Error::::BadWitness); + for (i, (_, (_, deposit))) in + CollectionApprovals::::drain_prefix((collection, &origin)).enumerate() + { removed_approvals.saturating_inc(); deposits = deposits.saturating_add(deposit); + if i + 1 >= (T::ApprovalsLimit::get() as usize) { + break + }; } - ensure!(removed_approvals == witness_approvals, Error::::BadWitness); T::Currency::unreserve(&origin, deposits); Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); - Ok(()) + Ok(removed_approvals) } /// Checks whether the `delegate` is approved to transfer collection items of `owner`. @@ -340,14 +336,14 @@ impl, I: 'static> Pallet { /// without requiring explicit approval for an item. /// /// - `collection`: The identifier of the collection. - /// - `maybe_details`: The optional collection item details that the delegated account has an + /// - `maybe_item`: The optional item of the collection that the delegated account has an /// approval to transfer. If not provided, an approval to transfer all `owner`'s collection /// items will be checked. /// - `owner`: The owner of the specified collection item. /// - `delegate`: The account to check for approval to transfer collection item(s) of owner. pub fn check_approval( collection: &T::CollectionId, - maybe_details: &Option>, + maybe_item: &Option, owner: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { @@ -356,7 +352,9 @@ impl, I: 'static> Pallet { Ok(()) => Ok(()), Err(error) => { // Check if a `delegate` has permission to transfer the given collection item. - if let Some(details) = maybe_details { + if let Some(item) = maybe_item { + let details = + Item::::get(collection, item).ok_or(Error::::UnknownItem)?; let maybe_deadline = details.approvals.get(delegate).ok_or(Error::::NoPermission)?; if let Some(deadline) = maybe_deadline { diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 2578e095..d6af107e 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1087,12 +1087,7 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_approval( - &collection, - &Some(details.clone()), - &details.owner, - &origin, - )?; + Self::check_approval(&collection, &Some(item), &details.owner, &origin)?; } Ok(()) }) @@ -1533,51 +1528,57 @@ pub mod pallet { Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) } - /// Cancel all the collection approvals. + /// Cancel collection approvals. + /// + /// Due to weight restrictions, this function may need to be called multiple times to fully + /// cancel all collection approvals. It will cancel `ApprovalsLimit` approvals at a time. /// /// Origin must be Signed. /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. - /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_all_collection_approvals(*witness_approvals))] - pub fn clear_all_collection_approvals( + #[pallet::weight(T::WeightInfo::clear_all_collection_approvals(T::ApprovalsLimit::get()))] + pub fn clear_collection_approvals( origin: OriginFor, collection: T::CollectionId, - witness_approvals: u32, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; - Self::do_clear_all_collection_approvals(origin, collection, witness_approvals) + let removed_approvals = Self::do_clear_all_collection_approvals(origin, collection)?; + Ok(Some(T::WeightInfo::clear_all_collection_approvals(removed_approvals)).into()) } - /// Force-cancel all the collection approvals granted by `owner` account. + /// Force-cancel collection approvals granted by `owner` account. + /// + /// Due to weight restrictions, this function may need to be called multiple times to fully + /// cancel all collection approvals. It will cancel `ApprovalsLimit` approvals at a time. /// /// Origin must be `ForceOrigin`. /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. /// - `owner`: The account clearing all collection approvals. - /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_all_collection_approvals(*witness_approvals))] - pub fn force_clear_all_collection_approvals( + #[pallet::weight(T::WeightInfo::force_clear_all_collection_approvals( + T::ApprovalsLimit::get() + ))] + pub fn force_clear_collection_approvals( origin: OriginFor, owner: AccountIdLookupOf, collection: T::CollectionId, - witness_approvals: u32, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - Self::do_clear_all_collection_approvals(owner, collection, witness_approvals) + let removed_approvals = Self::do_clear_all_collection_approvals(owner, collection)?; + Ok(Some(T::WeightInfo::force_clear_all_collection_approvals(removed_approvals)).into()) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 7c798e63..e30f6512 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -157,25 +157,44 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { + let collection_owner_1 = account(1); + let collection_owner_2 = account(2); + let mint_to = account(1); + assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner_1.clone(), default_collection_config() )); - 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_eq!(collections(), vec![(collection_owner_1.clone(), 0)]); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(collection_owner_1.clone()), + 0, + 42, + mint_to.clone(), + None + )); + assert_eq!(AccountBalance::::get(0, mint_to.clone()), 1); + assert_eq!(items(), vec![(mint_to.clone(), 0, 42)]); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(2), + collection_owner_2.clone(), default_collection_config() )); - 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)]); + assert_eq!( + collections(), + vec![(collection_owner_1.clone(), 0), (collection_owner_2.clone(), 1)] + ); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(collection_owner_2.clone()), + 1, + 69, + mint_to.clone(), + None + )); + assert_eq!(AccountBalance::::get(1, collection_owner_1.clone()), 1); + assert_eq!(items(), vec![(mint_to.clone(), 0, 42), (mint_to.clone(), 1, 69)]); }); } @@ -308,58 +327,77 @@ fn destroy_with_bad_witness_should_not_work() { #[test] fn destroy_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); - Balances::make_free_balance_be(&account(2), 100); + let collection_id = 0; + let item_id = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&collection_owner, 100); + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(account(1)), - account(1), + RuntimeOrigin::signed(collection_owner.clone()), + collection_owner.clone(), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); - assert_eq!(AccountBalance::::get(0, account(2)), 1); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + None + )); + assert_eq!(AccountBalance::::get(0, item_owner.clone()), 1); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), None )); assert_noop!( Nfts::destroy( - RuntimeOrigin::signed(account(1)), - 0, + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, Nfts::get_destroy_witness(&0).unwrap() ), Error::::CollectionNotEmpty ); - assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42)); - assert_eq!(Collection::::get(0).unwrap().item_configs, 1); - assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); - assert!(ItemConfigOf::::contains_key(0, 42)); + assert_ok!(Nfts::lock_item_transfer( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id + )); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id)); + assert_eq!(Collection::::get(collection_id).unwrap().item_configs, 1); + assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 1); + assert!(ItemConfigOf::::contains_key(collection_id, item_id)); assert_noop!( Nfts::destroy( - RuntimeOrigin::signed(account(1)), - 0, - Nfts::get_destroy_witness(&0).unwrap() + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() ), Error::::CollectionApprovalsExist ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() )); assert_ok!(Nfts::destroy( - RuntimeOrigin::signed(account(1)), - 0, - Nfts::get_destroy_witness(&0).unwrap() + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() )); - assert_eq!(AccountBalance::::get(0, account(1)), 0); - assert_eq!(AccountBalance::::contains_key(0, account(5)), false); - assert_eq!(CollectionApprovals::::iter_prefix((0,)).count(), 0); - assert!(!ItemConfigOf::::contains_key(0, 42)); - assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); + assert_eq!(AccountBalance::::get(collection_id, collection_owner.clone()), 0); + assert_eq!( + AccountBalance::::contains_key(collection_id, collection_owner.clone()), + false + ); + assert_eq!(CollectionApprovals::::iter_prefix((collection_id,)).count(), 0); + assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); + assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 0); }); } @@ -1754,52 +1792,59 @@ fn force_update_collection_should_work() { #[test] fn burn_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); + let collection_id = 0; + let item_id_1 = 42; + let item_id_2 = 69; + let collection_owner = account(1); + let (admin_1, admin_2, admin_3) = (account(2), account(3), account(4)); + let item_owner = account(5); + + Balances::make_free_balance_be(&collection_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), collection_config_with_all_settings_enabled() )); assert_ok!(Nfts::set_team( - RuntimeOrigin::signed(account(1)), - 0, - Some(account(2)), - Some(account(3)), - Some(account(4)), + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Some(admin_1.clone()), + Some(admin_2.clone()), + Some(admin_3.clone()), )); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42), + Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1), Error::::UnknownItem ); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(5), + RuntimeOrigin::signed(admin_1.clone()), + collection_id, + item_id_1, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(2)), - 0, - 69, - account(5), + RuntimeOrigin::signed(admin_1.clone()), + collection_id, + item_id_2, + item_owner.clone(), default_item_config() )); - assert_eq!(AccountBalance::::get(0, account(5)), 2); - assert_eq!(Balances::reserved_balance(account(1)), 2); + assert_eq!(AccountBalance::::get(collection_id, item_owner.clone()), 2); + assert_eq!(Balances::reserved_balance(collection_owner.clone()), 2); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), + Nfts::burn(RuntimeOrigin::signed(account(0)), collection_id, item_id_1), 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!(AccountBalance::::contains_key(0, account(5)), false); - assert_eq!(Balances::reserved_balance(account(1)), 0); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1)); + assert_eq!(AccountBalance::::get(0, item_owner.clone()), 1); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_2)); + assert_eq!(AccountBalance::::get(0, item_owner.clone()), 0); + assert_eq!(AccountBalance::::contains_key(collection_id, item_owner.clone()), false); + assert_eq!(Balances::reserved_balance(collection_owner.clone()), 0); }); } @@ -1875,87 +1920,118 @@ fn approval_lifecycle_works() { #[test] fn check_approval_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); + let collection_id = 0; + let item_id = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner.clone(), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(2), + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), None )); // Test collection approvals without deadline. assert_noop!( - Nfts::check_approval(&1, &None, &account(2), &account(3)), + Nfts::check_approval(&1, &None, &item_owner.clone(), &delegate.clone()), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&1, &Item::::get(0, 43), &account(2), &account(3)), - Error::::NoPermission + Nfts::check_approval(&1, &Some(43), &item_owner.clone(), &delegate.clone()), + Error::::UnknownItem ); - assert_ok!(Nfts::check_approval(&0, &None, &account(2), &account(3))); - assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval( + &collection_id, + &None, + &item_owner.clone(), + &delegate.clone() + )); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner.clone(), + &delegate.clone() + )); // Test collection item approvals without deadline. assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), None )); assert_noop!( - Nfts::check_approval(&0, &Item::::get(0, 43), &account(2), &account(4)), - Error::::NoPermission + Nfts::check_approval(&collection_id, &Some(43), &item_owner.clone(), &account(4)), + Error::::UnknownItem ); assert_noop!( - Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(4)), + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner.clone(), &account(4)), Error::::NoPermission ); - assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner.clone(), + &delegate.clone() + )); // Test collection approvals with deadline. let deadline = 10; assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), 0, - account(3), + delegate.clone(), Some(deadline) )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), + collection_id, + item_id, + delegate.clone(), Some(11) )); System::set_block_number(12); // The item approval deadline has passed, but the collection approval remains valid. assert_noop!( - Nfts::check_approval(&0, &None, &account(2), &account(3)), + Nfts::check_approval(&collection_id, &None, &item_owner.clone(), &delegate.clone()), Error::::ApprovalExpired ); - assert_ok!(Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3))); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner.clone(), + &delegate.clone() + )); System::set_block_number(14); assert_noop!( - Nfts::check_approval(&0, &None, &account(2), &account(3)), + Nfts::check_approval(&collection_id, &None, &item_owner.clone(), &delegate.clone()), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval(&0, &Item::::get(0, 42), &account(2), &account(3)), + Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner.clone(), + &delegate.clone() + ), Error::::ApprovalExpired ); }); @@ -1964,46 +2040,70 @@ fn check_approval_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, 42, - account(2), + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), 0, 42, - account(3), + delegate.clone(), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + 1, + 42, + delegate.clone() + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + 0, + 43, + delegate.clone() + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(delegate.clone()), 0, 42, delegate.clone()), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(item_owner.clone()), 0, 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(item_owner.clone()), + 0, + 42, + delegate.clone() + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + 0, + 42, + delegate.clone() + ), Error::::NotDelegate ); @@ -2013,25 +2113,30 @@ fn cancel_approval_works() { RuntimeOrigin::signed(account(1)), 0, 69, - account(2), + item_owner.clone(), default_item_config() )); // approval expires after 2 blocks. assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), 0, 42, - account(3), + delegate.clone(), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, delegate.clone()), 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, + 42, + delegate.clone() + )); assert_eq!(approvals(0, 69), vec![]); }); } @@ -2039,48 +2144,59 @@ fn cancel_approval_works() { #[test] fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, 42, - account(2), + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), 0, - account(3), + delegate.clone(), None )); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(Balances::reserved_balance(&item_owner), 1); assert_noop!( - Nfts::cancel_collection_approval(RuntimeOrigin::signed(account(2)), 1, account(3)), + Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + 1, + delegate.clone() + ), Error::::Unapproved ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), 0, - account(3) + delegate.clone() )); - assert_eq!(Balances::reserved_balance(&account(2)), 0); + assert_eq!(Balances::reserved_balance(&item_owner.clone()), 0); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, item: None, - owner: account(2), - delegate: account(3) + owner: item_owner.clone(), + delegate: delegate.clone() })); - assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), None); + assert_eq!( + CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + None + ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), + Nfts::transfer(RuntimeOrigin::signed(delegate.clone()), 0, 42, account(4)), Error::::NoPermission ); }); @@ -2178,62 +2294,61 @@ fn approvals_limit_works() { #[test] fn approve_collection_transfer_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); - Balances::make_free_balance_be(&account(3), 100); + let (collection, locked_collection) = (0, 1); + let item = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&delegate, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); // approve collection without items, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection, + delegate.clone(), None ), Error::::NoItemOwned ); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(2), + RuntimeOrigin::signed(collection_owner.clone()), + collection, + item, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - 1, - 42, - account(2), - default_item_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 43, - account(3), + locked_collection, + item, + item_owner.clone(), default_item_config() )); // throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( RuntimeOrigin::signed(account(1)), - 1, + locked_collection, CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); assert_noop!( Nfts::approve_collection_transfer( RuntimeOrigin::signed(account(2)), - 1, + locked_collection, account(3), None ), @@ -2243,47 +2358,48 @@ fn approve_collection_transfer_works() { // approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), 2, - account(3), + delegate.clone(), None ), Error::::NoItemOwned ); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection, + delegate.clone(), None )); assert_eq!(Balances::reserved_balance(&account(2)), 1); - // must not update the total collection approvals. + // must not update the total reserved funds. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection, + delegate.clone(), None )); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(3)), - 0, - account(4), - None - )); - assert_eq!(Balances::reserved_balance(&account(2)), 1); assert!(events().contains(&Event::::TransferApproved { collection: 0, item: None, - owner: account(2), - delegate: account(3), + owner: item_owner.clone(), + delegate: delegate.clone(), deadline: None })); - assert_eq!(CollectionApprovals::::get((0, account(2), account(3))), Some((None, 1))); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); + assert_eq!( + CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + Some((None, 1)) + ); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(delegate.clone()), + collection, + item, + account(4) + )); }); } @@ -2342,60 +2458,96 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); + let collection_id = 0; + let item_id = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - 0, - 42, - account(2), + collection_id, + item_id, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + 1, + item_id, + account(1) + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + 43, + account(1) + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + account(4) + ), Error::::NotDelegate ); // delegate approval conflicts. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + ), Error::::DelegateApprovalConflict ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() )); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + account(5) + ), Error::::NotDelegate ); }); @@ -2503,61 +2655,61 @@ fn clear_all_transfer_approvals_works() { } #[test] -fn clear_all_collection_approvals_works() { +fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); + let collection_owner = account(1); + let delegate_1 = account(3); + let delegate_2 = account(4); + + Balances::make_free_balance_be(&collection_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); - assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, 42, - account(1), + collection_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), 0, - account(3), + delegate_1.clone(), None )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), 0, - account(4), + delegate_2.clone(), None )); - assert_eq!(Balances::free_balance(&account(1)), 98); - // witness data is zero - assert_noop!( - Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 0), - Error::::BadWitness - ); - // incorrect witness data - assert_noop!( - Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 1), - Error::::BadWitness - ); - assert_ok!(Nfts::clear_all_collection_approvals(RuntimeOrigin::signed(account(1)), 0, 2)); + assert_eq!(Balances::free_balance(&collection_owner.clone()), 98); + + // should refund approvals. + assert_ok!(Nfts::clear_collection_approvals( + RuntimeOrigin::signed(collection_owner.clone()), + 0 + )); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, item: None, - owner: account(1), + owner: collection_owner.clone(), })); - assert_eq!(Balances::free_balance(&account(1)), 100); - assert_eq!(CollectionApprovals::::iter_prefix((0, account(1))).count(), 0); + assert_eq!(Balances::free_balance(&collection_owner.clone()), 100); + assert!(CollectionApprovals::::iter_prefix((0, collection_owner.clone())) + .count() + .is_zero()); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), + Nfts::transfer(RuntimeOrigin::signed(delegate_1.clone()), 0, 42, account(5)), Error::::NoPermission ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), + Nfts::transfer(RuntimeOrigin::signed(delegate_2.clone()), 0, 42, account(5)), Error::::NoPermission ); }); From b40d585b9f248c671c0127dd40011ce74d0e757c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:47:46 +0700 Subject: [PATCH 55/99] fix: tests --- pallets/nfts/src/benchmarking.rs | 14 +- pallets/nfts/src/features/approvals.rs | 11 +- pallets/nfts/src/lib.rs | 14 +- pallets/nfts/src/tests.rs | 680 +++++++++++++++++-------- pallets/nfts/src/weights.rs | 108 ++-- 5 files changed, 548 insertions(+), 279 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 7dd0b143..c908990a 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -677,29 +677,27 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AllApprovalsCancelled {collection, item: Some(item), owner: caller}.into()); } - clear_all_collection_approvals { - let n in 1 .. T::ApprovalsLimit::get() + 1; - + clear_collection_approvals { + let n in 0 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); mint_item::(0); for i in 0 .. n { approve_collection::(collection, i); } - }: _(SystemOrigin::Signed(caller.clone()), collection, n) + }: _(SystemOrigin::Signed(caller.clone()), collection) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } - force_clear_all_collection_approvals { - let n in 1 .. T::ApprovalsLimit::get() + 1; - + force_clear_collection_approvals { + let n in 0 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); let caller_lookup = T::Lookup::unlookup(caller.clone()); mint_item::(0); for i in 0 .. n { approve_collection::(collection, i); } - }: _(SystemOrigin::Root, caller_lookup, collection, n) + }: _(SystemOrigin::Root, caller_lookup, collection) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index f6f01a2c..b2d1badf 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -282,15 +282,16 @@ impl, I: 'static> Pallet { Ok(()) } - /// Clears all collection approvals. + /// Clears collection approvals. /// - /// This function is used to clear all approvals for the collection items of `owner`. After - /// clearing all approvals, the deposit of each collection approval is returned to the `owner` - /// account and the `AllApprovalsCancelled` event is emitted. + /// This function is used to clear up to `ApprovalsLimit` collection approvals for the + /// collection items of `owner`. After clearing collection approvals, the deposit of each + /// collection approval is returned to the `owner` account and the `AllApprovalsCancelled` + /// event is emitted. /// /// - `owner`: The owner of the collection items. /// - `collection`: The collection ID containing the item. - pub(crate) fn do_clear_all_collection_approvals( + pub(crate) fn do_clear_collection_approvals( origin: T::AccountId, collection: T::CollectionId, ) -> Result { diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index d6af107e..77dd60e5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1542,14 +1542,14 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_all_collection_approvals(T::ApprovalsLimit::get()))] + #[pallet::weight(T::WeightInfo::clear_collection_approvals(T::ApprovalsLimit::get()))] pub fn clear_collection_approvals( origin: OriginFor, collection: T::CollectionId, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; - let removed_approvals = Self::do_clear_all_collection_approvals(origin, collection)?; - Ok(Some(T::WeightInfo::clear_all_collection_approvals(removed_approvals)).into()) + let removed_approvals = Self::do_clear_collection_approvals(origin, collection)?; + Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) } /// Force-cancel collection approvals granted by `owner` account. @@ -1567,9 +1567,7 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_all_collection_approvals( - T::ApprovalsLimit::get() - ))] + #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(T::ApprovalsLimit::get()))] pub fn force_clear_collection_approvals( origin: OriginFor, owner: AccountIdLookupOf, @@ -1577,8 +1575,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - let removed_approvals = Self::do_clear_all_collection_approvals(owner, collection)?; - Ok(Some(T::WeightInfo::force_clear_all_collection_approvals(removed_approvals)).into()) + let removed_approvals = Self::do_clear_collection_approvals(owner, collection)?; + Ok(Some(T::WeightInfo::force_clear_collection_approvals(removed_approvals)).into()) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index e30f6512..ca6e5d9c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -32,9 +32,10 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; -use crate::{mock::*, Event, SystemConfig, *}; +use crate::{mock::*, Event, SystemConfig, WeightInfo as WeightInfoTrait, *}; type AccountIdOf = ::AccountId; +type WeightInfo = ::WeightInfo; fn account(id: u8) -> AccountIdOf { [id; 32].into() @@ -157,146 +158,184 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - let collection_owner_1 = account(1); - let collection_owner_2 = account(2); - let mint_to = account(1); + let (collection_id_1, collection_id_2) = (0, 1); + let (item_id_1, item_id_2) = (42, 69); + let owner_1 = account(1); + let owner_2 = account(2); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner_1.clone(), + owner_1.clone(), default_collection_config() )); - assert_eq!(collections(), vec![(collection_owner_1.clone(), 0)]); + assert_eq!(collections(), vec![(owner_1.clone(), collection_id_1)]); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(collection_owner_1.clone()), - 0, - 42, - mint_to.clone(), + RuntimeOrigin::signed(owner_1.clone()), + collection_id_1, + item_id_1, + owner_1.clone(), None )); - assert_eq!(AccountBalance::::get(0, mint_to.clone()), 1); - assert_eq!(items(), vec![(mint_to.clone(), 0, 42)]); + assert_eq!(AccountBalance::::get(collection_id_1, owner_1.clone()), 1); + assert_eq!(items(), vec![(owner_1.clone(), collection_id_1, item_id_1)]); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner_2.clone(), + owner_2.clone(), default_collection_config() )); assert_eq!( collections(), - vec![(collection_owner_1.clone(), 0), (collection_owner_2.clone(), 1)] + vec![(owner_1.clone(), collection_id_1), (owner_2.clone(), collection_id_2)] ); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(collection_owner_2.clone()), - 1, - 69, - mint_to.clone(), + RuntimeOrigin::signed(owner_2), + collection_id_2, + item_id_2, + owner_1.clone(), None )); - assert_eq!(AccountBalance::::get(1, collection_owner_1.clone()), 1); - assert_eq!(items(), vec![(mint_to.clone(), 0, 42), (mint_to.clone(), 1, 69)]); + assert_eq!(AccountBalance::::get(collection_id_2, owner_1.clone()), 1); + assert_eq!( + items(), + vec![ + (owner_1.clone(), collection_id_1, item_id_1), + (owner_1, collection_id_2, item_id_2) + ] + ); }); } #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); + let collection_id = 0; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(account(1)), - account(1), + RuntimeOrigin::signed(owner.clone()), + owner.clone(), collection_config_with_all_settings_enabled() )); - assert_eq!(Balances::reserved_balance(&account(1)), 2); - assert_eq!(collections(), vec![(account(1), 0)]); + assert_eq!(Balances::reserved_balance(&owner), 2); + assert_eq!(collections(), vec![(owner.clone(), 0)]); assert_ok!(Nfts::set_collection_metadata( - RuntimeOrigin::signed(account(1)), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, bvec![0, 0] )); - assert_eq!(Balances::reserved_balance(&account(1)), 5); + assert_eq!(Balances::reserved_balance(&owner), 5); assert!(CollectionMetadataOf::::contains_key(0)); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, 42, account(10), default_item_config() )); - assert_eq!(AccountBalance::::get(0, account(10)), 1); - assert_eq!(Balances::reserved_balance(&account(1)), 6); + assert_eq!(AccountBalance::::get(collection_id, account(10)), 1); + assert_eq!(Balances::reserved_balance(&owner), 6); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, 69, 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); - assert_eq!(Collection::::get(0).unwrap().item_configs, 3); - - 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(&owner), 7); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 70, + owner.clone(), + None + )); + assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 1); + assert_eq!( + items(), + vec![ + (owner.clone(), collection_id, 70), + (account(10), collection_id, 42), + (account(20), collection_id, 69) + ] + ); + assert_eq!(Collection::::get(collection_id).unwrap().items, 3); + assert_eq!(Collection::::get(collection_id).unwrap().item_metadatas, 0); + assert_eq!(Collection::::get(collection_id).unwrap().item_configs, 3); + + assert_eq!(Balances::reserved_balance(&owner), 8); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 70, + account(2) + )); + assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); + assert_eq!(AccountBalance::::get(collection_id, account(2)), 1); + assert_eq!(Balances::reserved_balance(&owner), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); - assert_eq!(Balances::reserved_balance(&account(1)), 11); + assert_ok!(Nfts::set_metadata( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 42, + bvec![42, 42] + )); + assert_eq!(Balances::reserved_balance(&owner), 11); assert!(ItemMetadataOf::::contains_key(0, 42)); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); - assert_eq!(Balances::reserved_balance(&account(1)), 14); - assert!(ItemMetadataOf::::contains_key(0, 69)); - assert!(ItemConfigOf::::contains_key(0, 69)); + assert_ok!(Nfts::set_metadata( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 69, + bvec![69, 69] + )); + assert_eq!(Balances::reserved_balance(&owner), 14); + assert!(ItemMetadataOf::::contains_key(collection_id, 69)); + assert!(ItemConfigOf::::contains_key(collection_id, 69)); let w = Nfts::get_destroy_witness(&0).unwrap(); assert_eq!(w.item_metadatas, 2); assert_eq!(w.item_configs, 3); assert_noop!( - Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), + Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w), Error::::CollectionNotEmpty ); - assert_eq!(AccountBalance::::get(0, account(1)), 0); + assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(account(1)), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, Some(69), AttributeNamespace::CollectionOwner, bvec![0], 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(10)), collection_id, 42)); + assert_eq!(AccountBalance::::get(collection_id, 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)); + assert_eq!(AccountBalance::::get(collection_id, account(10)), 0); + assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); assert_eq!(w.attributes, 1); 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)); - assert!(!CollectionConfigOf::::contains_key(0)); - assert!(!Item::::contains_key(0, 42)); - assert!(!Item::::contains_key(0, 69)); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w)); + assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); + assert_eq!(Balances::reserved_balance(&owner), 0); + + assert!(!Collection::::contains_key(collection_id)); + assert!(!CollectionConfigOf::::contains_key(collection_id)); + assert!(!Item::::contains_key(collection_id, 42)); + assert!(!Item::::contains_key(collection_id, 69)); assert!(!CollectionMetadataOf::::contains_key(0)); - assert!(!ItemMetadataOf::::contains_key(0, 42)); - assert!(!ItemMetadataOf::::contains_key(0, 69)); - assert!(!ItemConfigOf::::contains_key(0, 69)); - assert_eq!(attributes(0), vec![]); + assert!(!ItemMetadataOf::::contains_key(collection_id, 42)); + assert!(!ItemMetadataOf::::contains_key(collection_id, 69)); + assert!(!ItemConfigOf::::contains_key(collection_id, 69)); + assert_eq!(attributes(collection_id), vec![]); assert_eq!(collections(), vec![]); assert_eq!(items(), vec![]); }); @@ -381,9 +420,9 @@ fn destroy_should_work() { Error::::CollectionApprovalsExist ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), + RuntimeOrigin::signed(item_owner), collection_id, - delegate.clone() + delegate )); assert_ok!(Nfts::destroy( RuntimeOrigin::signed(collection_owner.clone()), @@ -391,10 +430,7 @@ fn destroy_should_work() { Nfts::get_destroy_witness(&collection_id).unwrap() )); assert_eq!(AccountBalance::::get(collection_id, collection_owner.clone()), 0); - assert_eq!( - AccountBalance::::contains_key(collection_id, collection_owner.clone()), - false - ); + assert!(!AccountBalance::::contains_key(collection_id, collection_owner)); assert_eq!(CollectionApprovals::::iter_prefix((collection_id,)).count(), 0); assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 0); @@ -569,7 +605,6 @@ 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 @@ -1796,7 +1831,7 @@ fn burn_works() { let item_id_1 = 42; let item_id_2 = 69; let collection_owner = account(1); - let (admin_1, admin_2, admin_3) = (account(2), account(3), account(4)); + let admin_1 = account(2); let item_owner = account(5); Balances::make_free_balance_be(&collection_owner, 100); @@ -1809,8 +1844,8 @@ fn burn_works() { RuntimeOrigin::signed(collection_owner.clone()), collection_id, Some(admin_1.clone()), - Some(admin_2.clone()), - Some(admin_3.clone()), + Some(account(2)), + Some(account(3)), )); assert_noop!( @@ -1840,11 +1875,10 @@ fn burn_works() { Error::::NoPermission ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1)); - assert_eq!(AccountBalance::::get(0, item_owner.clone()), 1); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_2)); - assert_eq!(AccountBalance::::get(0, item_owner.clone()), 0); - assert_eq!(AccountBalance::::contains_key(collection_id, item_owner.clone()), false); - assert_eq!(Balances::reserved_balance(collection_owner.clone()), 0); + assert_eq!(AccountBalance::::get(collection_id, item_owner.clone()), 0); + assert_eq!(AccountBalance::::contains_key(collection_id, item_owner), false); + assert_eq!(Balances::reserved_balance(collection_owner), 0); }); } @@ -1926,7 +1960,7 @@ fn check_approval_works() { let item_owner = account(2); let delegate = account(3); - Balances::make_free_balance_be(&item_owner.clone(), 100); + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), collection_owner.clone(), @@ -1949,23 +1983,18 @@ fn check_approval_works() { // Test collection approvals without deadline. assert_noop!( - Nfts::check_approval(&1, &None, &item_owner.clone(), &delegate.clone()), + Nfts::check_approval(&1, &None, &item_owner, &delegate.clone()), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&1, &Some(43), &item_owner.clone(), &delegate.clone()), + Nfts::check_approval(&1, &Some(43), &item_owner, &delegate.clone()), Error::::UnknownItem ); - assert_ok!(Nfts::check_approval( - &collection_id, - &None, - &item_owner.clone(), - &delegate.clone() - )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone())); assert_ok!(Nfts::check_approval( &collection_id, &Some(item_id), - &item_owner.clone(), + &item_owner, &delegate.clone() )); @@ -1979,17 +2008,17 @@ fn check_approval_works() { )); assert_noop!( - Nfts::check_approval(&collection_id, &Some(43), &item_owner.clone(), &account(4)), + Nfts::check_approval(&collection_id, &Some(43), &item_owner, &account(4)), Error::::UnknownItem ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner.clone(), &account(4)), + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &account(4)), Error::::NoPermission ); assert_ok!(Nfts::check_approval( &collection_id, &Some(item_id), - &item_owner.clone(), + &item_owner, &delegate.clone() )); @@ -2001,37 +2030,33 @@ fn check_approval_works() { delegate.clone(), Some(deadline) )); + // Test collection item approvals with deadline. assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(2)), collection_id, item_id, delegate.clone(), - Some(11) + Some(deadline + 1) )); - System::set_block_number(12); + System::set_block_number(deadline + 2); // The item approval deadline has passed, but the collection approval remains valid. assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner.clone(), &delegate.clone()), + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone()), Error::::ApprovalExpired ); assert_ok!(Nfts::check_approval( &collection_id, &Some(item_id), - &item_owner.clone(), + &item_owner, &delegate.clone() )); - System::set_block_number(14); + System::set_block_number(deadline + 4); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner.clone(), &delegate.clone()), + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone()), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner.clone(), - &delegate.clone() - ), + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate.clone()), Error::::ApprovalExpired ); }); @@ -2040,70 +2065,46 @@ fn check_approval_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - let collection_owner = account(1); - let item_owner = account(2); - let delegate = account(3); - assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, 42, - item_owner.clone(), + account(2), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), + RuntimeOrigin::signed(account(2)), 0, 42, - delegate.clone(), + account(3), None )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 1, - 42, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 0, - 43, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(delegate.clone()), 0, 42, delegate.clone()), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(item_owner.clone()), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 0, - 42, - delegate.clone() - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 0, - 42, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); @@ -2113,30 +2114,25 @@ fn cancel_approval_works() { RuntimeOrigin::signed(account(1)), 0, 69, - item_owner.clone(), + account(2), default_item_config() )); // approval expires after 2 blocks. assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), + RuntimeOrigin::signed(account(2)), 0, 42, - delegate.clone(), + account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, delegate.clone()), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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, - delegate.clone() - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); assert_eq!(approvals(0, 69), vec![]); }); } @@ -2144,31 +2140,34 @@ fn cancel_approval_works() { #[test] fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { - let collection_owner = account(1); + let collection_id = 0; + let item_id = 42; let item_owner = account(2); let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - 0, - 42, + collection_id, + item_id, item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), - 0, + collection_id, delegate.clone(), None )); assert_eq!(Balances::reserved_balance(&item_owner), 1); + + // Cancel an unapproved delegate. assert_noop!( Nfts::cancel_collection_approval( RuntimeOrigin::signed(item_owner.clone()), @@ -2178,25 +2177,93 @@ fn cancel_collection_approval_works() { Error::::Unapproved ); + // Successfully cancel a collection approval. assert_ok!(Nfts::cancel_collection_approval( RuntimeOrigin::signed(item_owner.clone()), - 0, + collection_id, delegate.clone() )); - assert_eq!(Balances::reserved_balance(&item_owner.clone()), 0); + assert_eq!(Balances::reserved_balance(&item_owner), 0); assert!(events().contains(&Event::::ApprovalCancelled { - collection: 0, + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone() + })); + assert_eq!( + CollectionApprovals::::get((collection_id, item_owner, delegate.clone())), + None + ); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(delegate), collection_id, item_id, account(4)), + Error::::NoPermission + ); + }); +} + +#[test] +fn force_cancel_collection_approvals_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let item_id = 42; + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_eq!(Balances::reserved_balance(&item_owner), 1); + + // Cancel an unapproved delegate. + assert_noop!( + Nfts::force_cancel_collection_approval( + RuntimeOrigin::root(), + item_owner.clone(), + 1, + delegate.clone() + ), + Error::::Unapproved + ); + + // Successfully cancel a collection approval. + assert_ok!(Nfts::force_cancel_collection_approval( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + delegate.clone() + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, item: None, owner: item_owner.clone(), delegate: delegate.clone() })); assert_eq!( - CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + CollectionApprovals::::get((collection_id, item_owner, delegate.clone())), None ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate.clone()), 0, 42, account(4)), + Nfts::transfer(RuntimeOrigin::signed(delegate), collection_id, item_id, account(4)), Error::::NoPermission ); }); @@ -2313,7 +2380,7 @@ fn approve_collection_transfer_works() { default_collection_config() )); - // approve collection without items, throws error `Error::NoItemOwned`. + // Approve collection without items, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -2332,22 +2399,22 @@ fn approve_collection_transfer_works() { default_item_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), locked_collection, item, item_owner.clone(), default_item_config() )); - // throws error `Error::ItemsNonTransferable`. + // Throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner), locked_collection, CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); assert_noop!( Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(item_owner.clone()), locked_collection, account(3), None @@ -2355,7 +2422,7 @@ fn approve_collection_transfer_works() { Error::::ItemsNonTransferable ); - // approve unknown collection, throws error `Error::NoItemOwned`. + // Approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -2366,15 +2433,31 @@ fn approve_collection_transfer_works() { Error::::NoItemOwned ); + // Test with deadline. + let deadline = 10; assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection, delegate.clone(), - None + Some(deadline) + )); + assert_ok!(Nfts::check_approval(&collection, &None, &item_owner, &delegate)); + System::set_block_number(deadline + 2); + assert_noop!( + Nfts::check_approval(&collection, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + + // Approve delegate of an existing expired approval to transfer. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection, + delegate.clone(), + Some(deadline) )); assert_eq!(Balances::reserved_balance(&account(2)), 1); - // must not update the total reserved funds. + // Approve same delegate again not updating the total reserved funds. assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection, @@ -2391,15 +2474,139 @@ fn approve_collection_transfer_works() { deadline: None })); assert_eq!( - CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + CollectionApprovals::::get((0, item_owner, delegate.clone())), Some((None, 1)) ); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(delegate.clone()), + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); + }); +} + +#[test] +fn force_approve_collection_transfer_work() { + new_test_ext().execute_with(|| { + let (collection, locked_collection) = (0, 1); + let item = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&delegate, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + + // Approve collection without items, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), collection, item, - account(4) + item_owner.clone(), + default_item_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), + locked_collection, + item, + item_owner.clone(), + default_item_config() + )); + + // Throws error `Error::ItemsNonTransferable`. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner), + locked_collection, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + locked_collection, + account(3), + None + ), + Error::::ItemsNonTransferable + ); + + // Approve unknown collection, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + 2, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + + // Test with deadline. + let deadline = 10; + assert_ok!(Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection, + delegate.clone(), + Some(deadline) + )); + assert_ok!(Nfts::check_approval(&collection, &None, &item_owner, &delegate)); + System::set_block_number(deadline + 2); + assert_noop!( + Nfts::check_approval(&collection, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + + // Approve delegate of an existing expired approval to transfer. + assert_ok!(Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection, + delegate.clone(), + Some(deadline) + )); + assert_eq!(Balances::reserved_balance(&account(2)), 1); + + // Approve same delegate again not updating the total reserved funds. + assert_ok!(Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection, + delegate.clone(), + None )); + assert_eq!(Balances::reserved_balance(&item_owner), 1); + + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline: None + })); + assert_eq!( + CollectionApprovals::::get((0, item_owner, delegate.clone())), + Some((None, 1)) + ); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); }); } @@ -2657,66 +2864,133 @@ fn clear_all_transfer_approvals_works() { #[test] fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { - let collection_owner = account(1); + let collection_id = 0; + let item_id = 42; + let owner = account(1); let delegate_1 = account(3); let delegate_2 = account(4); + let balance = 100; - Balances::make_free_balance_be(&collection_owner, 100); + Balances::make_free_balance_be(&owner, balance); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - 0, - 42, - collection_owner.clone(), + collection_id, + item_id, + owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(collection_owner.clone()), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, delegate_1.clone(), None )); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(collection_owner.clone()), - 0, + RuntimeOrigin::signed(owner.clone()), + collection_id, delegate_2.clone(), None )); - assert_eq!(Balances::free_balance(&collection_owner.clone()), 98); + assert_eq!(Balances::free_balance(&owner), balance - 2); - // should refund approvals. - assert_ok!(Nfts::clear_collection_approvals( - RuntimeOrigin::signed(collection_owner.clone()), - 0 + // Should refund approvals and return a correct weight. + assert_eq!( + Nfts::clear_collection_approvals(RuntimeOrigin::signed(owner.clone()), collection_id), + Ok(Some(WeightInfo::clear_collection_approvals(2)).into()) + ); + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); + assert_eq!(Balances::free_balance(&owner), balance); + assert!(CollectionApprovals::::iter_prefix((0, owner)).count().is_zero()); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(delegate_2), collection_id, item_id, account(5)), + Error::::NoPermission + ); + }); +} + +#[test] +fn force_clear_collection_approvals_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let item_id = 42; + let owner = account(1); + let delegate_1 = account(3); + let delegate_2 = account(4); + let balance = 100; + + Balances::make_free_balance_be(&owner, balance); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate_1.clone(), + None + )); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate_2.clone(), + None )); + assert_eq!(Balances::free_balance(&owner), balance - 2); + + // Should refund approvals and return a correct weight. + assert_eq!( + Nfts::force_clear_collection_approvals( + RuntimeOrigin::root(), + owner.clone(), + collection_id + ), + Ok(Some(WeightInfo::force_clear_collection_approvals(2)).into()) + ); assert!(events().contains(&Event::::AllApprovalsCancelled { - collection: 0, + collection: collection_id, item: None, - owner: collection_owner.clone(), + owner: owner.clone(), })); - assert_eq!(Balances::free_balance(&collection_owner.clone()), 100); - assert!(CollectionApprovals::::iter_prefix((0, collection_owner.clone())) - .count() - .is_zero()); + assert_eq!(Balances::free_balance(&owner), balance); + assert!(CollectionApprovals::::iter_prefix((0, owner)).count().is_zero()); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_1.clone()), 0, 42, account(5)), + Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), Error::::NoPermission ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_2.clone()), 0, 42, account(5)), + Nfts::transfer(RuntimeOrigin::signed(delegate_2), collection_id, item_id, account(5)), Error::::NoPermission ); }); } #[test] -fn total_supply_should_works() { +fn collection_item_works() { new_test_ext().execute_with(|| { let collection_id = 0; let user_id = account(1); @@ -3449,8 +3723,6 @@ 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, diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 22d85490..9dd04044 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -66,8 +66,8 @@ pub trait WeightInfo { fn cancel_collection_approval() -> Weight; fn force_cancel_collection_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; - fn clear_all_collection_approvals(n: u32, ) -> Weight; - fn force_clear_all_collection_approvals(n: u32, ) -> Weight; + fn clear_collection_approvals(n: u32, ) -> Weight; + fn force_clear_collection_approvals(n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -565,8 +565,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `450` // Estimated: `3602` - // Minimum execution time: 22_000_000 picoseconds. - Weight::from_parts(30_000_000, 3602) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3602) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -581,7 +581,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `450` // Estimated: `3602` // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(22_000_000, 3602) + Weight::from_parts(21_000_000, 3602) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -593,8 +593,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(36_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -604,8 +604,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `359` // Estimated: `3602` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -616,7 +616,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `359` // Estimated: `3602` // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) + Weight::from_parts(17_000_000, 3602) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -628,38 +628,38 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(21_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 21]`. - fn clear_all_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 20]`. + fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + n * (75 ±0)` + // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(16_630_042, 3602) - // Standard Error: 121_416 - .saturating_add(Weight::from_parts(3_823_189, 0).saturating_mul(n.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(14_440_852, 3602) + // Standard Error: 22_164 + .saturating_add(Weight::from_parts(3_380_372, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) } - /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 21]`. - fn force_clear_all_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 20]`. + fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + n * (75 ±0)` + // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(13_455_783, 3602) - // Standard Error: 146_830 - .saturating_add(Weight::from_parts(4_223_404, 0).saturating_mul(n.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(14_472_321, 3602) + // Standard Error: 21_742 + .saturating_add(Weight::from_parts(3_333_999, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1356,8 +1356,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `450` // Estimated: `3602` - // Minimum execution time: 22_000_000 picoseconds. - Weight::from_parts(30_000_000, 3602) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1372,7 +1372,7 @@ impl WeightInfo for () { // Measured: `450` // Estimated: `3602` // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(22_000_000, 3602) + Weight::from_parts(21_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1384,8 +1384,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(36_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1395,8 +1395,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `359` // Estimated: `3602` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1407,7 +1407,7 @@ impl WeightInfo for () { // Measured: `359` // Estimated: `3602` // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) + Weight::from_parts(17_000_000, 3602) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1419,38 +1419,38 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(21_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 21]`. - fn clear_all_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 20]`. + fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + n * (75 ±0)` + // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(16_630_042, 3602) - // Standard Error: 121_416 - .saturating_add(Weight::from_parts(3_823_189, 0).saturating_mul(n.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(14_440_852, 3602) + // Standard Error: 22_164 + .saturating_add(Weight::from_parts(3_380_372, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) } - /// Storage: `Nfts::CollectionApprovals` (r:22 w:21) + /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 21]`. - fn force_clear_all_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 20]`. + fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + n * (75 ±0)` + // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(13_455_783, 3602) - // Standard Error: 146_830 - .saturating_add(Weight::from_parts(4_223_404, 0).saturating_mul(n.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(14_472_321, 3602) + // Standard Error: 21_742 + .saturating_add(Weight::from_parts(3_333_999, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) From 86fcfa3793317612cfd19c90d796476dad50f35c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:49:10 +0700 Subject: [PATCH 56/99] refactor: check_approval test --- pallets/nfts/src/tests.rs | 178 ++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 102 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index ca6e5d9c..a0be7ed2 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -20,11 +20,13 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, + dispatch::DispatchResult, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, }, }; +use frame_system::pallet_prelude::BlockNumberFor; use pallet_balances::Error as BalancesError; use sp_core::{bounded::BoundedVec, Pair}; use sp_runtime::{ @@ -176,7 +178,7 @@ fn basic_minting_should_work() { owner_1.clone(), None )); - assert_eq!(AccountBalance::::get(collection_id_1, owner_1.clone()), 1); + assert_eq!(AccountBalance::::get(collection_id_1, &owner_1), 1); assert_eq!(items(), vec![(owner_1.clone(), collection_id_1, item_id_1)]); assert_ok!(Nfts::force_create( @@ -195,7 +197,7 @@ fn basic_minting_should_work() { owner_1.clone(), None )); - assert_eq!(AccountBalance::::get(collection_id_2, owner_1.clone()), 1); + assert_eq!(AccountBalance::::get(collection_id_2, &owner_1), 1); assert_eq!( items(), vec![ @@ -254,7 +256,7 @@ fn lifecycle_should_work() { owner.clone(), None )); - assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 1); + assert_eq!(AccountBalance::::get(collection_id, &owner), 1); assert_eq!( items(), vec![ @@ -274,7 +276,7 @@ fn lifecycle_should_work() { 70, account(2) )); - assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); + assert_eq!(AccountBalance::::get(collection_id, &owner), 0); assert_eq!(AccountBalance::::get(collection_id, account(2)), 1); assert_eq!(Balances::reserved_balance(&owner), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -303,7 +305,7 @@ fn lifecycle_should_work() { Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w), Error::::CollectionNotEmpty ); - assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); + assert_eq!(AccountBalance::::get(collection_id, &owner), 0); assert_ok!(Nfts::set_attribute( RuntimeOrigin::signed(owner.clone()), @@ -324,7 +326,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w)); - assert_eq!(AccountBalance::::get(collection_id, owner.clone()), 0); + assert_eq!(AccountBalance::::get(collection_id, &owner), 0); assert_eq!(Balances::reserved_balance(&owner), 0); assert!(!Collection::::contains_key(collection_id)); @@ -387,7 +389,7 @@ fn destroy_should_work() { item_owner.clone(), None )); - assert_eq!(AccountBalance::::get(0, item_owner.clone()), 1); + assert_eq!(AccountBalance::::get(0, &item_owner), 1); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -429,8 +431,8 @@ fn destroy_should_work() { collection_id, Nfts::get_destroy_witness(&collection_id).unwrap() )); - assert_eq!(AccountBalance::::get(collection_id, collection_owner.clone()), 0); - assert!(!AccountBalance::::contains_key(collection_id, collection_owner)); + assert_eq!(AccountBalance::::get(collection_id, &collection_owner), 0); + assert!(!AccountBalance::::contains_key(collection_id, &collection_owner)); assert_eq!(CollectionApprovals::::iter_prefix((collection_id,)).count(), 0); assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 0); @@ -1831,7 +1833,7 @@ fn burn_works() { let item_id_1 = 42; let item_id_2 = 69; let collection_owner = account(1); - let admin_1 = account(2); + let admin = account(2); let item_owner = account(5); Balances::make_free_balance_be(&collection_owner, 100); @@ -1843,7 +1845,7 @@ fn burn_works() { assert_ok!(Nfts::set_team( RuntimeOrigin::signed(collection_owner.clone()), collection_id, - Some(admin_1.clone()), + Some(admin.clone()), Some(account(2)), Some(account(3)), )); @@ -1854,20 +1856,20 @@ fn burn_works() { ); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(admin_1.clone()), + RuntimeOrigin::signed(admin.clone()), collection_id, item_id_1, item_owner.clone(), default_item_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(admin_1.clone()), + RuntimeOrigin::signed(admin), collection_id, item_id_2, item_owner.clone(), default_item_config() )); - assert_eq!(AccountBalance::::get(collection_id, item_owner.clone()), 2); + assert_eq!(AccountBalance::::get(collection_id, &item_owner), 2); assert_eq!(Balances::reserved_balance(collection_owner.clone()), 2); assert_noop!( @@ -1876,8 +1878,8 @@ fn burn_works() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1)); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_2)); - assert_eq!(AccountBalance::::get(collection_id, item_owner.clone()), 0); - assert_eq!(AccountBalance::::contains_key(collection_id, item_owner), false); + assert_eq!(AccountBalance::::get(collection_id, &item_owner), 0); + assert_eq!(AccountBalance::::contains_key(collection_id, &item_owner), false); assert_eq!(Balances::reserved_balance(collection_owner), 0); }); } @@ -1974,91 +1976,63 @@ fn check_approval_works() { default_item_config() )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - - // Test collection approvals without deadline. - assert_noop!( - Nfts::check_approval(&1, &None, &item_owner, &delegate.clone()), - Error::::NoPermission - ); - assert_noop!( - Nfts::check_approval(&1, &Some(43), &item_owner, &delegate.clone()), - Error::::UnknownItem - ); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone())); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate.clone() - )); - - // Test collection item approvals without deadline. - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - None - )); + let deadline = 10; + let error = Err(Error::::ApprovalExpired.into()); + for case in Vec::<( + // Deadline of the collection and item approval. + (Option>, Option>), + // Check results when collection or item approval deadline has padded. + (DispatchResult, DispatchResult), + // Check results when both collection and item approval deadline has passed. + (DispatchResult, DispatchResult), + )>::from(vec![ + // No deadline set for both collection and item approval. + ((None, None), (Ok(()), Ok(())), (Ok(()), Ok(()))), + // Set deadline for both. Collection approval expires first. + ((Some(deadline), Some(deadline + 1)), (error, Ok(())), (error, error)), + // Set deadline for both. Item approval expires first. + ((Some(deadline + 1), Some(deadline)), (Ok(()), Ok(())), (error, error)), + ]) { + System::set_block_number(0); + let (collection_deadline, item_deadline) = case.0; + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + collection_deadline + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + item_deadline + )); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(43), &item_owner, &account(4)), - Error::::UnknownItem - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &account(4)), - Error::::NoPermission - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate.clone() - )); + // Collection or item approval deadline has padded. + System::set_block_number(deadline + 1); + let (collection_result, item_result) = case.1; + assert_eq!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + collection_result + ); + assert_eq!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + item_result + ); - // Test collection approvals with deadline. - let deadline = 10; - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - delegate.clone(), - Some(deadline) - )); - // Test collection item approvals with deadline. - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - collection_id, - item_id, - delegate.clone(), - Some(deadline + 1) - )); - System::set_block_number(deadline + 2); - // The item approval deadline has passed, but the collection approval remains valid. - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone()), - Error::::ApprovalExpired - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate.clone() - )); - System::set_block_number(deadline + 4); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate.clone()), - Error::::ApprovalExpired - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate.clone()), - Error::::ApprovalExpired - ); + // Both collection and item approval deadline has passed. + System::set_block_number(deadline + 2); + let (collection_result, item_result) = case.2; + assert_eq!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + collection_result + ); + assert_eq!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + item_result + ); + } }); } @@ -3355,7 +3329,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), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -3813,8 +3787,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), 2); + assert_eq!(AccountBalance::::get(collection_id, &user_2), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); From 62cd8fa5466f035ff244b469f069af84ae4cc47e Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:53:38 +0700 Subject: [PATCH 57/99] refactor: benchmarking code --- pallets/nfts/src/benchmarking.rs | 41 ++++++++++++++------------------ 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index c908990a..5f4a9c5c 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -62,27 +62,6 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account (caller, caller_lookup) } -fn approve_collection, I: 'static>( - collection: T::CollectionId, - index: u32, -) -> (T::AccountId, AccountIdLookupOf) { - let caller = Collection::::get(collection).unwrap().owner; - if caller != whitelisted_caller() { - whitelist_account!(caller); - } - let caller_lookup = T::Lookup::unlookup(caller.clone()); - let delegate: T::AccountId = account("delegate", index, SEED); - let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); - assert_ok!(Nfts::::approve_collection_transfer( - SystemOrigin::Signed(caller.clone()).into(), - collection, - delegate_lookup.clone(), - Some(deadline), - )); - (caller, caller_lookup) -} - fn mint_item, I: 'static>( index: u16, ) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { @@ -682,7 +661,15 @@ benchmarks_instance_pallet! { let (collection, caller, _) = create_collection::(); mint_item::(0); for i in 0 .. n { - approve_collection::(collection, i); + let delegate: T::AccountId = account("delegate", i, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + Nfts::::approve_collection_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + delegate_lookup.clone(), + Some(deadline), + )?; } }: _(SystemOrigin::Signed(caller.clone()), collection) verify { @@ -695,7 +682,15 @@ benchmarks_instance_pallet! { let caller_lookup = T::Lookup::unlookup(caller.clone()); mint_item::(0); for i in 0 .. n { - approve_collection::(collection, i); + let delegate: T::AccountId = account("delegate", i, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + Nfts::::approve_collection_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + delegate_lookup.clone(), + Some(deadline), + )?; } }: _(SystemOrigin::Root, caller_lookup, collection) verify { From 2acb01b6e4b5f6dbbb696d3b98ab2d450e3f342a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:22:26 +0700 Subject: [PATCH 58/99] fix: tests --- pallets/nfts/src/tests.rs | 84 ++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index a0be7ed2..fb43ad0b 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -222,7 +222,7 @@ fn lifecycle_should_work() { collection_config_with_all_settings_enabled() )); assert_eq!(Balances::reserved_balance(&owner), 2); - assert_eq!(collections(), vec![(owner.clone(), 0)]); + assert_eq!(collections(), vec![(owner.clone(), collection_id)]); assert_ok!(Nfts::set_collection_metadata( RuntimeOrigin::signed(owner.clone()), collection_id, @@ -288,7 +288,7 @@ fn lifecycle_should_work() { bvec![42, 42] )); assert_eq!(Balances::reserved_balance(&owner), 11); - assert!(ItemMetadataOf::::contains_key(0, 42)); + assert!(ItemMetadataOf::::contains_key(collection_id, 42)); assert_ok!(Nfts::set_metadata( RuntimeOrigin::signed(owner.clone()), collection_id, @@ -302,7 +302,7 @@ fn lifecycle_should_work() { assert_eq!(w.item_metadatas, 2); assert_eq!(w.item_configs, 3); assert_noop!( - Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w), + Nfts::destroy(RuntimeOrigin::signed(owner.clone()), collection_id, w), Error::::CollectionNotEmpty ); assert_eq!(AccountBalance::::get(collection_id, &owner), 0); @@ -317,15 +317,15 @@ fn lifecycle_should_work() { )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), collection_id, 42)); assert_eq!(AccountBalance::::get(collection_id, account(10)), 0); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), collection_id, 69)); assert_eq!(AccountBalance::::get(collection_id, account(10)), 0); assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 70)); - let w = Nfts::get_destroy_witness(&0).unwrap(); + let w = Nfts::get_destroy_witness(&collection_id).unwrap(); assert_eq!(w.attributes, 1); assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); - assert_ok!(Nfts::destroy(RuntimeOrigin::signed(owner.clone()), 0, w)); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(owner.clone()), collection_id, w)); assert_eq!(AccountBalance::::get(collection_id, &owner), 0); assert_eq!(Balances::reserved_balance(&owner), 0); @@ -333,7 +333,7 @@ fn lifecycle_should_work() { assert!(!CollectionConfigOf::::contains_key(collection_id)); assert!(!Item::::contains_key(collection_id, 42)); assert!(!Item::::contains_key(collection_id, 69)); - assert!(!CollectionMetadataOf::::contains_key(0)); + assert!(!CollectionMetadataOf::::contains_key(collection_id)); assert!(!ItemMetadataOf::::contains_key(collection_id, 42)); assert!(!ItemMetadataOf::::contains_key(collection_id, 69)); assert!(!ItemConfigOf::::contains_key(collection_id, 69)); @@ -389,7 +389,7 @@ fn destroy_should_work() { item_owner.clone(), None )); - assert_eq!(AccountBalance::::get(0, &item_owner), 1); + assert_eq!(AccountBalance::::get(collection_id, &item_owner), 1); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -400,7 +400,7 @@ fn destroy_should_work() { Nfts::destroy( RuntimeOrigin::signed(collection_owner.clone()), collection_id, - Nfts::get_destroy_witness(&0).unwrap() + Nfts::get_destroy_witness(&collection_id).unwrap() ), Error::::CollectionNotEmpty ); @@ -1981,7 +1981,7 @@ fn check_approval_works() { for case in Vec::<( // Deadline of the collection and item approval. (Option>, Option>), - // Check results when collection or item approval deadline has padded. + // Check results when collection or item approval deadline has passed. (DispatchResult, DispatchResult), // Check results when both collection and item approval deadline has passed. (DispatchResult, DispatchResult), @@ -2009,7 +2009,7 @@ fn check_approval_works() { item_deadline )); - // Collection or item approval deadline has padded. + // Collection or item approval deadline has passed. System::set_block_number(deadline + 1); let (collection_result, item_result) = case.1; assert_eq!( @@ -2116,17 +2116,18 @@ fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { let collection_id = 0; let item_id = 42; + let collection_owner = account(1); let item_owner = account(2); let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner), collection_id, item_id, item_owner.clone(), @@ -2181,17 +2182,18 @@ fn force_cancel_collection_approvals_work() { new_test_ext().execute_with(|| { let collection_id = 0; let item_id = 42; + let collection_owner = account(1); let item_owner = account(2); let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner), collection_id, item_id, item_owner.clone(), @@ -2407,7 +2409,7 @@ fn approve_collection_transfer_works() { Error::::NoItemOwned ); - // Test with deadline. + // Approval expires after `deadline`. let deadline = 10; assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -2430,6 +2432,18 @@ fn approve_collection_transfer_works() { Some(deadline) )); assert_eq!(Balances::reserved_balance(&account(2)), 1); + let now = System::block_number(); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline: Some(now + deadline) + })); + assert_eq!( + CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + Some((Some(now + deadline), 1)) + ); // Approve same delegate again not updating the total reserved funds. assert_ok!(Nfts::approve_collection_transfer( @@ -2440,23 +2454,12 @@ fn approve_collection_transfer_works() { )); assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline: None - })); - assert_eq!( - CollectionApprovals::::get((0, item_owner, delegate.clone())), - Some((None, 1)) - ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); }); } #[test] -fn force_approve_collection_transfer_work() { +fn force_approve_collection_transfer_works() { new_test_ext().execute_with(|| { let (collection, locked_collection) = (0, 1); let item = 42; @@ -2533,7 +2536,7 @@ fn force_approve_collection_transfer_work() { Error::::NoItemOwned ); - // Test with deadline. + // Approval expires after `deadline`. let deadline = 10; assert_ok!(Nfts::force_approve_collection_transfer( RuntimeOrigin::root(), @@ -2558,6 +2561,18 @@ fn force_approve_collection_transfer_work() { Some(deadline) )); assert_eq!(Balances::reserved_balance(&account(2)), 1); + let now = System::block_number(); + assert!(events().contains(&Event::::TransferApproved { + collection: 0, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline: Some(now + deadline) + })); + assert_eq!( + CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), + Some((Some(now + deadline), 1)) + ); // Approve same delegate again not updating the total reserved funds. assert_ok!(Nfts::force_approve_collection_transfer( @@ -2569,17 +2584,6 @@ fn force_approve_collection_transfer_work() { )); assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline: None - })); - assert_eq!( - CollectionApprovals::::get((0, item_owner, delegate.clone())), - Some((None, 1)) - ); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); }); } From ba33b7ca032a518fdd84a1499ac8b6e482d44092 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:47:32 +0700 Subject: [PATCH 59/99] chore: revert clear_collection_approvals --- pallets/nfts/src/benchmarking.rs | 26 ++++++------- pallets/nfts/src/features/approvals.rs | 26 ++++++------- pallets/nfts/src/lib.rs | 30 +++++++-------- pallets/nfts/src/tests.rs | 53 +++++++++++++++++++++----- pallets/nfts/src/weights.rs | 52 ++++++++++++------------- 5 files changed, 109 insertions(+), 78 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 5f4a9c5c..b1da4c49 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -75,7 +75,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(), @@ -656,43 +656,39 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AllApprovalsCancelled {collection, item: Some(item), owner: caller}.into()); } - clear_collection_approvals { - let n in 0 .. T::ApprovalsLimit::get(); + clear_collection_approvals_limit { + let n in 1 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); mint_item::(0); for i in 0 .. n { let delegate: T::AccountId = account("delegate", i, SEED); - let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); Nfts::::approve_collection_transfer( SystemOrigin::Signed(caller.clone()).into(), collection, - delegate_lookup.clone(), - Some(deadline), + T::Lookup::unlookup(delegate), + Some(BlockNumberFor::::max_value()), )?; } - }: _(SystemOrigin::Signed(caller.clone()), collection) + }: _(SystemOrigin::Signed(caller.clone()), collection, n) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } - force_clear_collection_approvals { - let n in 0 .. T::ApprovalsLimit::get(); + force_clear_collection_approvals_limit { + let n in 1 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); let caller_lookup = T::Lookup::unlookup(caller.clone()); mint_item::(0); for i in 0 .. n { let delegate: T::AccountId = account("delegate", i, SEED); - let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); Nfts::::approve_collection_transfer( SystemOrigin::Signed(caller.clone()).into(), collection, - delegate_lookup.clone(), - Some(deadline), + T::Lookup::unlookup(delegate), + Some(BlockNumberFor::::max_value()), )?; } - }: _(SystemOrigin::Root, caller_lookup, collection) + }: _(SystemOrigin::Root, caller_lookup, collection, n) verify { assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index b2d1badf..2bca9989 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -284,32 +284,32 @@ impl, I: 'static> Pallet { /// Clears collection approvals. /// - /// This function is used to clear up to `ApprovalsLimit` collection approvals for the - /// collection items of `owner`. After clearing collection approvals, the deposit of each - /// collection approval is returned to the `owner` account and the `AllApprovalsCancelled` - /// event is emitted. + /// This function is used to clear `witness_approvals` collection approvals for the + /// collection items of `owner`. After clearing all approvals, the deposit of each collection + /// approval is returned to the `owner` account and the `AllApprovalsCancelled` event is + /// emitted. /// /// - `owner`: The owner of the collection items. /// - `collection`: The collection ID containing the item. - pub(crate) fn do_clear_collection_approvals( + /// - `witness_approvals`: The amount of collection approvals that will be cleared. + pub(crate) fn do_clear_collection_approvals_limit( origin: T::AccountId, collection: T::CollectionId, - ) -> Result { + witness_approvals: u32, + ) -> DispatchResult { + ensure!(witness_approvals > 0, Error::::BadWitness); let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. - for (i, (_, (_, deposit))) in - CollectionApprovals::::drain_prefix((collection, &origin)).enumerate() - { + for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { + ensure!(removed_approvals < witness_approvals, Error::::BadWitness); removed_approvals.saturating_inc(); deposits = deposits.saturating_add(deposit); - if i + 1 >= (T::ApprovalsLimit::get() as usize) { - break - }; } + ensure!(removed_approvals == witness_approvals, Error::::BadWitness); T::Currency::unreserve(&origin, deposits); Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); - Ok(removed_approvals) + Ok(()) } /// Checks whether the `delegate` is approved to transfer collection items of `owner`. diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 77dd60e5..5061766b 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1400,7 +1400,6 @@ pub mod pallet { /// /// - `owner`: The account granting approval for delegated transfer. /// - `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 collection items owned by /// the `owner`. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the @@ -1537,46 +1536,47 @@ pub mod pallet { /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. + /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_collection_approvals(T::ApprovalsLimit::get()))] - pub fn clear_collection_approvals( + #[pallet::weight(T::WeightInfo::clear_collection_approvals_limit(*witness_approvals))] + pub fn clear_collection_approvals_limit( origin: OriginFor, collection: T::CollectionId, - ) -> DispatchResultWithPostInfo { + witness_approvals: u32, + ) -> DispatchResult { let origin = ensure_signed(origin)?; - let removed_approvals = Self::do_clear_collection_approvals(origin, collection)?; - Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) + Self::do_clear_collection_approvals_limit(origin, collection, witness_approvals)?; + Ok(()) } /// Force-cancel collection approvals granted by `owner` account. /// - /// Due to weight restrictions, this function may need to be called multiple times to fully - /// cancel all collection approvals. It will cancel `ApprovalsLimit` approvals at a time. - /// /// Origin must be `ForceOrigin`. /// /// Arguments: - /// - `collection`: The collection whose approvals will be cleared. /// - `owner`: The account clearing all collection approvals. + /// - `collection`: The collection whose approvals will be cleared. + /// - `witness_approvals`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(T::ApprovalsLimit::get()))] - pub fn force_clear_collection_approvals( + #[pallet::weight(T::WeightInfo::force_clear_collection_approvals_limit(*witness_approvals))] + pub fn force_clear_collection_approvals_limit( origin: OriginFor, owner: AccountIdLookupOf, collection: T::CollectionId, - ) -> DispatchResultWithPostInfo { + witness_approvals: u32, + ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - let removed_approvals = Self::do_clear_collection_approvals(owner, collection)?; - Ok(Some(T::WeightInfo::force_clear_collection_approvals(removed_approvals)).into()) + Self::do_clear_collection_approvals_limit(owner, collection, witness_approvals)?; + Ok(()) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index fb43ad0b..361ceb7b 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2877,11 +2877,29 @@ fn clear_collection_approvals_works() { )); assert_eq!(Balances::free_balance(&owner), balance - 2); - // Should refund approvals and return a correct weight. - assert_eq!( - Nfts::clear_collection_approvals(RuntimeOrigin::signed(owner.clone()), collection_id), - Ok(Some(WeightInfo::clear_collection_approvals(2)).into()) + // Throws error `BadWitness` for zero witness data. + assert_noop!( + Nfts::clear_collection_approvals_limit( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 0 + ), + Error::::BadWitness + ); + // Throws error `BadWitness` for invalid witness data. + assert_noop!( + Nfts::clear_collection_approvals_limit( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 1 + ), + Error::::BadWitness ); + assert_ok!(Nfts::clear_collection_approvals_limit( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 2 + )); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: collection_id, item: None, @@ -2939,15 +2957,32 @@ fn force_clear_collection_approvals_work() { )); assert_eq!(Balances::free_balance(&owner), balance - 2); - // Should refund approvals and return a correct weight. - assert_eq!( - Nfts::force_clear_collection_approvals( + // Throws error `BadWitness` for zero witness data. + assert_noop!( + Nfts::force_clear_collection_approvals_limit( + RuntimeOrigin::root(), + owner.clone(), + collection_id, + 0 + ), + Error::::BadWitness + ); + // Throws error `BadWitness` for invalid witness data. + assert_noop!( + Nfts::force_clear_collection_approvals_limit( RuntimeOrigin::root(), owner.clone(), - collection_id + collection_id, + 1 ), - Ok(Some(WeightInfo::force_clear_collection_approvals(2)).into()) + Error::::BadWitness ); + assert_ok!(Nfts::force_clear_collection_approvals_limit( + RuntimeOrigin::root(), + owner.clone(), + collection_id, + 2 + )); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: collection_id, item: None, diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 9dd04044..096d8fa9 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -66,8 +66,8 @@ pub trait WeightInfo { fn cancel_collection_approval() -> Weight; fn force_cancel_collection_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; - fn clear_collection_approvals(n: u32, ) -> Weight; - fn force_clear_collection_approvals(n: u32, ) -> Weight; + fn clear_collection_approvals_limit(n: u32, ) -> Weight; + fn force_clear_collection_approvals_limit(n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -635,15 +635,15 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 20]`. - fn clear_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[1, 20]`. + fn clear_collection_approvals_limit(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(14_440_852, 3602) - // Standard Error: 22_164 - .saturating_add(Weight::from_parts(3_380_372, 0).saturating_mul(n.into())) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(16_365_393, 3602) + // Standard Error: 5_564 + .saturating_add(Weight::from_parts(3_008_044, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -651,15 +651,15 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 20]`. - fn force_clear_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[1, 20]`. + fn force_clear_collection_approvals_limit(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(14_472_321, 3602) - // Standard Error: 21_742 - .saturating_add(Weight::from_parts(3_333_999, 0).saturating_mul(n.into())) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(16_193_192, 3602) + // Standard Error: 5_637 + .saturating_add(Weight::from_parts(3_029_821, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1426,15 +1426,15 @@ impl WeightInfo for () { } /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 20]`. - fn clear_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[1, 20]`. + fn clear_collection_approvals_limit(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(14_440_852, 3602) - // Standard Error: 22_164 - .saturating_add(Weight::from_parts(3_380_372, 0).saturating_mul(n.into())) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(16_365_393, 3602) + // Standard Error: 5_564 + .saturating_add(Weight::from_parts(3_008_044, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1442,15 +1442,15 @@ impl WeightInfo for () { } /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[0, 20]`. - fn force_clear_collection_approvals(n: u32, ) -> Weight { + /// The range of component `n` is `[1, 20]`. + fn force_clear_collection_approvals_limit(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(14_472_321, 3602) - // Standard Error: 21_742 - .saturating_add(Weight::from_parts(3_333_999, 0).saturating_mul(n.into())) + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(16_193_192, 3602) + // Standard Error: 5_637 + .saturating_add(Weight::from_parts(3_029_821, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) From 824978d415bff5d1cd9250c774fc50d2e7162c8b Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:30:53 +0700 Subject: [PATCH 60/99] docs: pallet-nfts (#399) Co-authored-by: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> --- pallets/nfts/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index 93ccf294..d9bd726a 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -51,7 +51,9 @@ The NFTs pallet in Substrate is designed to make the following possible: * `transfer`: Send an item to a new owner. * `redeposit`: Update the deposit amount of an item, potentially freeing funds. * `approve_transfer`: Name a delegate who may authorize a transfer. +* `approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the account. * `cancel_approval`: Revert the effects of a previous `approve_transfer`. +* `cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. * `approve_item_attributes`: Name a delegate who may change item's attributes within a namespace. * `cancel_item_attributes_approval`: Revert the effects of a previous `approve_item_attributes`. * `set_price`: Set the price for an item. @@ -70,6 +72,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `lock_item_transfer`: Prevent an individual item from being transferred. * `unlock_item_transfer`: Revert the effects of a previous `lock_item_transfer`. * `clear_all_transfer_approvals`: Clears all transfer approvals set by calling the `approve_transfer`. +* `clear_all_collection_approvals`: Clears all collection approvals set by calling the `approve_collection_transfer`. * `lock_collection`: Prevent all items within a collection from being transferred (making them all `soul bound`). * `lock_item_properties`: Lock item's metadata or attributes. * `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items @@ -95,6 +98,9 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_collection_owner`: Change collection's owner. * `force_collection_config`: Change collection's config. * `force_set_attribute`: Set an attribute. +* `force_approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the specified account. +* `force_cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. +* `force_clear_all_collection_approvals`: Clears all collection approvals set by calling the `approve_collection_transfer`. Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and its associated variants for documentation on each function. From 9b42bb711f36119683e96a5f3215abbd5628a8bb Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:49:40 +0700 Subject: [PATCH 61/99] refactor: approve_collection deposit --- pallets/nfts/src/features/approvals.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 2bca9989..98d84f47 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -228,11 +228,8 @@ impl, I: 'static> Pallet { (&collection, &origin, &delegate), |maybe_approval| -> DispatchResult { let deposit_required = T::CollectionApprovalDeposit::get(); - let mut current_deposit = match maybe_approval.take() { - Some((_, deposit)) => deposit, - None => Zero::zero(), - }; - + let mut current_deposit = + maybe_approval.take().map(|(_, deposit)| deposit).unwrap_or_default(); if current_deposit < deposit_required { T::Currency::reserve(&origin, deposit_required - current_deposit)?; current_deposit = deposit_required; From f68a28e09274938777c126d3f6d72778ed864d2d Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:14:00 +0700 Subject: [PATCH 62/99] chore: resolve review comments --- pallets/nfts/src/features/approvals.rs | 42 ++++----- pallets/nfts/src/lib.rs | 23 +++-- pallets/nfts/src/tests.rs | 113 +++++++++++++++++-------- 3 files changed, 107 insertions(+), 71 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 98d84f47..811ba1ba 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -205,7 +205,7 @@ impl, I: 'static> Pallet { /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. pub(crate) fn do_approve_collection_transfer( - origin: T::AccountId, + owner: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, maybe_deadline: Option>, @@ -214,7 +214,7 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - ensure!(AccountBalance::::get(collection, &origin) > 0, Error::::NoItemOwned); + ensure!(AccountBalance::::get(collection, &owner) > 0, Error::::NoItemOwned); let collection_config = Self::get_collection_config(&collection)?; ensure!( @@ -225,13 +225,13 @@ impl, I: 'static> Pallet { let deadline = maybe_deadline.map(|d| d.saturating_add(now)); CollectionApprovals::::try_mutate_exists( - (&collection, &origin, &delegate), + (&collection, &owner, &delegate), |maybe_approval| -> DispatchResult { let deposit_required = T::CollectionApprovalDeposit::get(); let mut current_deposit = maybe_approval.take().map(|(_, deposit)| deposit).unwrap_or_default(); if current_deposit < deposit_required { - T::Currency::reserve(&origin, deposit_required - current_deposit)?; + T::Currency::reserve(&owner, deposit_required - current_deposit)?; current_deposit = deposit_required; } *maybe_approval = Some((deadline, current_deposit)); @@ -242,7 +242,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::TransferApproved { collection, item: None, - owner: origin, + owner, delegate, deadline, }); @@ -260,52 +260,46 @@ impl, I: 'static> Pallet { /// - `collection`: The identifier of the collection. /// - `delegate`: The account that had permission to transfer collection items. pub(crate) fn do_cancel_collection_approval( - origin: T::AccountId, + owner: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, ) -> DispatchResult { - let (_, deposit) = CollectionApprovals::::take((&collection, &origin, &delegate)) + let (_, deposit) = CollectionApprovals::::take((&collection, &owner, &delegate)) .ok_or(Error::::Unapproved)?; - T::Currency::unreserve(&origin, deposit); + T::Currency::unreserve(&owner, deposit); - Self::deposit_event(Event::ApprovalCancelled { - collection, - owner: origin, - item: None, - delegate, - }); + Self::deposit_event(Event::ApprovalCancelled { collection, owner, item: None, delegate }); Ok(()) } /// Clears collection approvals. /// - /// This function is used to clear `witness_approvals` collection approvals for the + /// This function is used to clear `limit` collection approvals for the /// collection items of `owner`. After clearing all approvals, the deposit of each collection /// approval is returned to the `owner` account and the `AllApprovalsCancelled` event is /// emitted. /// /// - `owner`: The owner of the collection items. /// - `collection`: The collection ID containing the item. - /// - `witness_approvals`: The amount of collection approvals that will be cleared. + /// - `limit`: The amount of collection approvals that will be cleared. pub(crate) fn do_clear_collection_approvals_limit( - origin: T::AccountId, + owner: T::AccountId, collection: T::CollectionId, - witness_approvals: u32, + limit: u32, ) -> DispatchResult { - ensure!(witness_approvals > 0, Error::::BadWitness); + ensure!(limit > 0, Error::::BadWitness); let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. - for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &origin)) { - ensure!(removed_approvals < witness_approvals, Error::::BadWitness); + for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &owner)) { + ensure!(removed_approvals < limit, Error::::BadWitness); removed_approvals.saturating_inc(); deposits = deposits.saturating_add(deposit); } - ensure!(removed_approvals == witness_approvals, Error::::BadWitness); - T::Currency::unreserve(&origin, deposits); - Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner: origin }); + T::Currency::unreserve(&owner, deposits); + Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner }); Ok(()) } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 5061766b..0009b2b5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1527,55 +1527,52 @@ pub mod pallet { Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) } - /// Cancel collection approvals. - /// - /// Due to weight restrictions, this function may need to be called multiple times to fully - /// cancel all collection approvals. It will cancel `ApprovalsLimit` approvals at a time. + /// Cancel collection approvals, up to a specified limit. /// /// Origin must be Signed. /// /// Arguments: /// - `collection`: The collection whose approvals will be cleared. - /// - `witness_approvals`: The amount of collection approvals that will be cleared. + /// - `limit`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_collection_approvals_limit(*witness_approvals))] + #[pallet::weight(T::WeightInfo::clear_collection_approvals_limit(*limit))] pub fn clear_collection_approvals_limit( origin: OriginFor, collection: T::CollectionId, - witness_approvals: u32, + limit: u32, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::do_clear_collection_approvals_limit(origin, collection, witness_approvals)?; + Self::do_clear_collection_approvals_limit(origin, collection, limit)?; Ok(()) } - /// Force-cancel collection approvals granted by `owner` account. + /// Force-cancel collection approvals granted by `owner` account, up to a specified limit. /// /// Origin must be `ForceOrigin`. /// /// Arguments: /// - `owner`: The account clearing all collection approvals. /// - `collection`: The collection whose approvals will be cleared. - /// - `witness_approvals`: The amount of collection approvals that will be cleared. + /// - `limit`: The amount of collection approvals that will be cleared. /// /// Emits `AllApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_collection_approvals_limit(*witness_approvals))] + #[pallet::weight(T::WeightInfo::force_clear_collection_approvals_limit(*limit))] pub fn force_clear_collection_approvals_limit( origin: OriginFor, owner: AccountIdLookupOf, collection: T::CollectionId, - witness_approvals: u32, + limit: u32, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - Self::do_clear_collection_approvals_limit(owner, collection, witness_approvals)?; + Self::do_clear_collection_approvals_limit(owner, collection, limit)?; Ok(()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 361ceb7b..27088a0c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -34,10 +34,9 @@ use sp_runtime::{ MultiSignature, MultiSigner, }; -use crate::{mock::*, Event, SystemConfig, WeightInfo as WeightInfoTrait, *}; +use crate::{mock::*, Event, SystemConfig, *}; type AccountIdOf = ::AccountId; -type WeightInfo = ::WeightInfo; fn account(id: u8) -> AccountIdOf { [id; 32].into() @@ -1954,7 +1953,7 @@ fn approval_lifecycle_works() { } #[test] -fn check_approval_works() { +fn check_approval_without_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let item_id = 42; @@ -1976,61 +1975,107 @@ fn check_approval_works() { default_item_config() )); - let deadline = 10; - let error = Err(Error::::ApprovalExpired.into()); - for case in Vec::<( - // Deadline of the collection and item approval. - (Option>, Option>), - // Check results when collection or item approval deadline has passed. - (DispatchResult, DispatchResult), - // Check results when both collection and item approval deadline has passed. - (DispatchResult, DispatchResult), - )>::from(vec![ - // No deadline set for both collection and item approval. - ((None, None), (Ok(()), Ok(())), (Ok(()), Ok(()))), - // Set deadline for both. Collection approval expires first. - ((Some(deadline), Some(deadline + 1)), (error, Ok(())), (error, error)), - // Set deadline for both. Item approval expires first. - ((Some(deadline + 1), Some(deadline)), (Ok(()), Ok(())), (error, error)), - ]) { + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + // Has only item approval. + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + // Has both collection and item approval. + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + }); +} + +#[test] +fn check_approval_with_deadline_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let item_id = 42; + let collection_owner = account(1); + let item_owner = account(2); + let delegate = account(3); + + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + + let deadline: BlockNumberFor = 10; + for case in [ + // Collection approval expires first. + (deadline, deadline + 1, Err(Error::::ApprovalExpired.into()), Ok(())), + // Item approval expires first. + (deadline + 1, deadline, Ok(()), Ok(())), + ] { System::set_block_number(0); - let (collection_deadline, item_deadline) = case.0; assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, delegate.clone(), - collection_deadline + Some(case.0) )); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id, delegate.clone(), - item_deadline + Some(case.1) + )); + + // Block 0: Initially, all approvals should be valid + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate )); - // Collection or item approval deadline has passed. + // Move past the deadline by 1 block. System::set_block_number(deadline + 1); - let (collection_result, item_result) = case.1; - assert_eq!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - collection_result - ); + + // Block 1: Collection or item approval deadline has passed. + assert_eq!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), case.2); assert_eq!( Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - item_result + case.3 ); - // Both collection and item approval deadline has passed. + // Move past the deadline by 2 block. System::set_block_number(deadline + 2); - let (collection_result, item_result) = case.2; + + // Block 2: Both collection and item approval expires. assert_eq!( Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - collection_result + Err(Error::::ApprovalExpired.into()) ); assert_eq!( Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - item_result + Err(Error::::ApprovalExpired.into()) ); } }); From 1da978dd477461a0de2a1a7785fbc76e608175f9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:51:25 +0700 Subject: [PATCH 63/99] refactor: clear_collection_approvals --- pallets/nfts/src/features/approvals.rs | 11 +++- pallets/nfts/src/lib.rs | 4 +- pallets/nfts/src/tests.rs | 85 ++++++++++++++------------ 3 files changed, 56 insertions(+), 44 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 811ba1ba..293c1257 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -289,15 +289,20 @@ impl, I: 'static> Pallet { collection: T::CollectionId, limit: u32, ) -> DispatchResult { - ensure!(limit > 0, Error::::BadWitness); + if limit == 0 { + return Ok(()); + } let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &owner)) { - ensure!(removed_approvals < limit, Error::::BadWitness); - removed_approvals.saturating_inc(); deposits = deposits.saturating_add(deposit); + removed_approvals.saturating_inc(); + if removed_approvals == limit { + break; + } } + T::Currency::unreserve(&owner, deposits); Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner }); Ok(()) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 0009b2b5..44cb6de5 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -741,8 +741,8 @@ pub mod pallet { #[cfg(any(feature = "std", test))] fn integrity_test() { assert!( - size_of::<>::ItemId>() == size_of::(), - "ItemId must be bounded by u32 type." + size_of::<>::ItemId>() <= size_of::(), + "ItemId must fit within the size of a u32." ); } } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 27088a0c..4a48cc7a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -20,7 +20,6 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, - dispatch::DispatchResult, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, @@ -2920,26 +2919,30 @@ fn clear_collection_approvals_works() { delegate_2.clone(), None )); + // Remove zero collection approvals, no event emitted. + assert_ok!(Nfts::clear_collection_approvals_limit( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 0 + )); assert_eq!(Balances::free_balance(&owner), balance - 2); + assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); + assert!(!events().contains(&Event::::AllApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); - // Throws error `BadWitness` for zero witness data. - assert_noop!( - Nfts::clear_collection_approvals_limit( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 0 - ), - Error::::BadWitness - ); - // Throws error `BadWitness` for invalid witness data. - assert_noop!( - Nfts::clear_collection_approvals_limit( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 1 - ), - Error::::BadWitness - ); + // Partially removes collection approvals. + assert_ok!(Nfts::clear_collection_approvals_limit( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 1 + )); + assert_eq!(Balances::free_balance(&owner), balance - 1); + assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); + + // Successfully remove all collection approvals. assert_ok!(Nfts::clear_collection_approvals_limit( RuntimeOrigin::signed(owner.clone()), collection_id, @@ -3000,28 +3003,32 @@ fn force_clear_collection_approvals_work() { delegate_2.clone(), None )); + // Remove zero collection approvals, no event emitted. + assert_ok!(Nfts::force_clear_collection_approvals_limit( + RuntimeOrigin::root(), + owner.clone(), + collection_id, + 0 + )); assert_eq!(Balances::free_balance(&owner), balance - 2); + assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); + assert!(!events().contains(&Event::::AllApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); - // Throws error `BadWitness` for zero witness data. - assert_noop!( - Nfts::force_clear_collection_approvals_limit( - RuntimeOrigin::root(), - owner.clone(), - collection_id, - 0 - ), - Error::::BadWitness - ); - // Throws error `BadWitness` for invalid witness data. - assert_noop!( - Nfts::force_clear_collection_approvals_limit( - RuntimeOrigin::root(), - owner.clone(), - collection_id, - 1 - ), - Error::::BadWitness - ); + // Partially removes collection approvals. + assert_ok!(Nfts::force_clear_collection_approvals_limit( + RuntimeOrigin::root(), + owner.clone(), + collection_id, + 1 + )); + assert_eq!(Balances::free_balance(&owner), balance - 1); + assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); + + // Successfully remove all collection approvals. assert_ok!(Nfts::force_clear_collection_approvals_limit( RuntimeOrigin::root(), owner.clone(), From 5b639f7f6935cc0eb9ae0445468a6ee86155b834 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:03:18 +0700 Subject: [PATCH 64/99] fix: comments --- pallets/nfts/src/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4a48cc7a..ee25a3f1 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2057,17 +2057,17 @@ fn check_approval_with_deadline_works() { // Move past the deadline by 1 block. System::set_block_number(deadline + 1); - // Block 1: Collection or item approval deadline has passed. + // (deadline + 1): Collection or item approval deadline has passed. assert_eq!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), case.2); assert_eq!( Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), case.3 ); - // Move past the deadline by 2 block. + // Move past the deadline by 2 blocks. System::set_block_number(deadline + 2); - // Block 2: Both collection and item approval expires. + // (deadline + 2): Both collection and item approval expires. assert_eq!( Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), Err(Error::::ApprovalExpired.into()) From 1afd4ba58f03734b8069b3fab19038656a0a8f52 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:03:44 +0700 Subject: [PATCH 65/99] fix: comment --- 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 ee25a3f1..a4953678 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2045,7 +2045,7 @@ fn check_approval_with_deadline_works() { Some(case.1) )); - // Block 0: Initially, all approvals should be valid + // Initially, all approvals should be valid. assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); assert_ok!(Nfts::check_approval( &collection_id, From 672ceaea8592e249eed544d3c8eae390113c5c98 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:11:14 +0700 Subject: [PATCH 66/99] refactor: transfer_should_workd --- pallets/nfts/src/tests.rs | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index a4953678..d0bc5edc 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -245,7 +245,7 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(AccountBalance::::get(0, account(20)), 1); + assert_eq!(AccountBalance::::get(collection_id, account(20)), 1); assert_eq!(Balances::reserved_balance(&owner), 7); assert_ok!(Nfts::mint( RuntimeOrigin::signed(owner.clone()), @@ -576,57 +576,70 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { + let collection_id = 0; + let item_id = 42; + let owner = account(1); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - 0, - 42, + collection_id, + item_id, account(2), default_item_config() )); - 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_ok!(Nfts::transfer( + RuntimeOrigin::signed(account(2)), + collection_id, + item_id, + account(3) + )); + assert_eq!(AccountBalance::::get(collection_id, account(2)), 0); + assert_eq!(AccountBalance::::get(collection_id, account(3)), 1); + assert_eq!(items(), vec![(account(3), collection_id, item_id)]); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::transfer(RuntimeOrigin::signed(account(2)), collection_id, item_id, account(4)), Error::::NoPermission ); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), - 0, - 42, + collection_id, + item_id, account(2), None )); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - assert_eq!(AccountBalance::::get(0, account(3)), 0); - assert_eq!(AccountBalance::::get(0, account(4)), 1); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(account(2)), + collection_id, + item_id, + account(4) + )); + assert_eq!(AccountBalance::::get(collection_id, account(3)), 0); + assert_eq!(AccountBalance::::get(collection_id, account(4)), 1); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + owner.clone(), collection_config_from_disabled_settings( CollectionSetting::TransferableItems | CollectionSetting::DepositRequired ) )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 1, + RuntimeOrigin::signed(owner.clone()), + collection_id, 1, account(42), default_item_config() )); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(1)), collection_id, 42, account(3)), + Nfts::transfer(RuntimeOrigin::signed(owner), collection_id, item_id, account(3)), Error::::ItemsNonTransferable ); }); From c62dd834593addf3e8d30fc6d45181739ead60a2 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:14:31 +0700 Subject: [PATCH 67/99] Revert "refactor: transfer_should_workd" This reverts commit 672ceaea8592e249eed544d3c8eae390113c5c98. --- pallets/nfts/src/tests.rs | 49 ++++++++++++++------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index d0bc5edc..a4953678 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -245,7 +245,7 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(AccountBalance::::get(collection_id, account(20)), 1); + assert_eq!(AccountBalance::::get(0, account(20)), 1); assert_eq!(Balances::reserved_balance(&owner), 7); assert_ok!(Nfts::mint( RuntimeOrigin::signed(owner.clone()), @@ -576,70 +576,57 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - let collection_id = 0; - let item_id = 42; - let owner = account(1); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), - collection_id, - item_id, + 0, + 42, account(2), default_item_config() )); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(account(2)), - collection_id, - item_id, - account(3) - )); - assert_eq!(AccountBalance::::get(collection_id, account(2)), 0); - assert_eq!(AccountBalance::::get(collection_id, account(3)), 1); - assert_eq!(items(), vec![(account(3), collection_id, item_id)]); + 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)), collection_id, item_id, account(4)), + Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NoPermission ); assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(account(3)), - collection_id, - item_id, + 0, + 42, account(2), None )); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(account(2)), - collection_id, - item_id, - account(4) - )); - assert_eq!(AccountBalance::::get(collection_id, account(3)), 0); - assert_eq!(AccountBalance::::get(collection_id, account(4)), 1); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); + 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( RuntimeOrigin::root(), - owner.clone(), + account(1), collection_config_from_disabled_settings( CollectionSetting::TransferableItems | CollectionSetting::DepositRequired ) )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 1, 1, account(42), default_item_config() )); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(owner), collection_id, item_id, account(3)), + Nfts::transfer(RuntimeOrigin::signed(account(1)), collection_id, 42, account(3)), Error::::ItemsNonTransferable ); }); From c76f66b6e34a5d2a83eb912db63e2218397fdac8 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:48:26 +0700 Subject: [PATCH 68/99] chore: comments --- pallets/nfts/src/features/approvals.rs | 38 ++++++++++++-------------- pallets/nfts/src/lib.rs | 3 +- pallets/nfts/src/tests.rs | 4 +-- pallets/nfts/src/weights.rs | 2 +- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 293c1257..8acce9d8 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -195,9 +195,9 @@ impl, I: 'static> Pallet { /// determine the absolute deadline for the approval. After approving the transfer, the /// function emits the `TransferApproved` event. /// - /// This function reserves the required deposit from the `owner` account. If an approval - /// already exists, the deposit amount is incremented, and the approval's existing deadline is - /// overridden. + /// This function reserves the necessary deposit from the owner account. If an approval already + /// exists, additional funds are reserved only if the updated deposit exceeds the currently + /// reserved amount. The existing approval's deadline is also updated. /// /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. @@ -345,23 +345,21 @@ impl, I: 'static> Pallet { delegate: &T::AccountId, ) -> DispatchResult { // Check if `delegate` has permission to transfer `owner`'s collection items. - match Self::check_collection_approval(collection, owner, delegate) { - Ok(()) => Ok(()), - Err(error) => { - // Check if a `delegate` has permission to transfer the given collection item. - if let Some(item) = maybe_item { - let details = - Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - let maybe_deadline = - details.approvals.get(delegate).ok_or(Error::::NoPermission)?; - if let Some(deadline) = maybe_deadline { - let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *deadline, Error::::ApprovalExpired); - } - return Ok(()); - }; - Err(error) - }, + if let Err(error) = Self::check_collection_approval(collection, owner, delegate) { + // Check if a `delegate` has permission to transfer the given collection item. + if let Some(item) = maybe_item { + let details = + Item::::get(collection, item).ok_or(Error::::UnknownItem)?; + let maybe_deadline = + details.approvals.get(delegate).ok_or(Error::::NoPermission)?; + if let Some(deadline) = maybe_deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *deadline, Error::::ApprovalExpired); + } + return Ok(()); + }; + return Err(error); } + Ok(()) } } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 44cb6de5..80dae5e2 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -1370,7 +1370,6 @@ pub mod pallet { /// Origin must be Signed. /// /// - `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 collection items owned by /// the origin. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the @@ -1392,7 +1391,7 @@ pub mod pallet { Self::do_approve_collection_transfer(origin, collection, delegate, maybe_deadline) } - /// Force-approve collection items owned by the origin to be transferred by a delegated + /// Force-approve collection items owned by the `owner` to be transferred by a delegated /// third-party account. This function reserves the required deposit /// `CollectionApprovalDeposit` from the `owner` account. /// diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index a4953678..2006f73a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -3061,7 +3061,7 @@ fn collection_item_works() { let user_id = account(1); let total_items = 10; - // no collection. + // No collection. assert_eq!(Nfts::collection_items(collection_id), None); assert_ok!(Nfts::force_create( @@ -3070,7 +3070,7 @@ fn collection_item_works() { default_collection_config() )); - // mint items and validate the total supply. + // Mint items and validate the total supply. (0..total_items).into_iter().for_each(|i| { assert_ok!(Nfts::force_mint( RuntimeOrigin::root(), diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 096d8fa9..2f178d2b 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-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-06, 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` From 8f1c56d28a1554c6a63d716970ee947d6ba27cae Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:29:28 +0700 Subject: [PATCH 69/99] chore: resolve review comments --- pallets/nfts/README.md | 2 +- pallets/nfts/src/benchmarking.rs | 8 ++-- pallets/nfts/src/features/approvals.rs | 55 +++++++++++++------------- pallets/nfts/src/lib.rs | 47 ++++++++++++---------- pallets/nfts/src/tests.rs | 32 ++++++++++----- pallets/nfts/src/weights.rs | 12 +++--- runtime/devnet/src/config/assets.rs | 4 +- runtime/testnet/src/config/assets.rs | 4 +- 8 files changed, 91 insertions(+), 73 deletions(-) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index d9bd726a..d4c02d23 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -100,7 +100,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_set_attribute`: Set an attribute. * `force_approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the specified account. * `force_cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. -* `force_clear_all_collection_approvals`: Clears all collection approvals set by calling the `approve_collection_transfer`. +* `force_clear_all_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer calls` for the collection. Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and its associated variants for documentation on each function. diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index b1da4c49..07762273 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -656,7 +656,7 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AllApprovalsCancelled {collection, item: Some(item), owner: caller}.into()); } - clear_collection_approvals_limit { + clear_collection_approvals { let n in 1 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); mint_item::(0); @@ -671,10 +671,10 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Signed(caller.clone()), collection, n) verify { - assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller}.into()); } - force_clear_collection_approvals_limit { + force_clear_collection_approvals { let n in 1 .. T::ApprovalsLimit::get(); let (collection, caller, _) = create_collection::(); let caller_lookup = T::Lookup::unlookup(caller.clone()); @@ -690,7 +690,7 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Root, caller_lookup, collection, n) verify { - assert_last_event::(Event::AllApprovalsCancelled {collection, item: None, owner: caller}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller}.into()); } set_accept_ownership { diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 8acce9d8..3e8ccd7c 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -153,7 +153,7 @@ impl, I: 'static> Pallet { /// - `maybe_check_origin`: The optional account that is required to be the owner of the item, /// granting permission to clear all transfer approvals. If `None`, no permission check is /// performed. - /// - `collection`: The collection ID containing the item. + /// - `collection`: The identifier of the collection. /// - `item`: The item ID for which transfer approvals will be cleared. pub(crate) fn do_clear_all_transfer_approvals( maybe_check_origin: Option, @@ -188,9 +188,9 @@ impl, I: 'static> Pallet { /// Approves the transfer of all collection items of `owner` to a delegate. /// - /// This function is used to approve the transfer of all collection items of `owner` to a - /// `delegate`. The `delegate` account will be allowed to take control of the items. - /// Optionally, a `deadline` can be specified to set a time limit for the approval. The + /// This function is used to approve the transfer of all (current and future) collection items + /// of `owner` to a `delegate`. The `delegate` account will be allowed to take control of the + /// items. Optionally, a `deadline` can be specified to set a time limit for the approval. The /// `deadline` is expressed in block numbers and is added to the current block number to /// determine the absolute deadline for the approval. After approving the transfer, the /// function emits the `TransferApproved` event. @@ -228,13 +228,12 @@ impl, I: 'static> Pallet { (&collection, &owner, &delegate), |maybe_approval| -> DispatchResult { let deposit_required = T::CollectionApprovalDeposit::get(); - let mut current_deposit = + let current_deposit = maybe_approval.take().map(|(_, deposit)| deposit).unwrap_or_default(); if current_deposit < deposit_required { T::Currency::reserve(&owner, deposit_required - current_deposit)?; - current_deposit = deposit_required; } - *maybe_approval = Some((deadline, current_deposit)); + *maybe_approval = Some((deadline, deposit_required)); Ok(()) }, )?; @@ -274,17 +273,17 @@ impl, I: 'static> Pallet { Ok(()) } - /// Clears collection approvals. + /// Clears all collection approvals. /// /// This function is used to clear `limit` collection approvals for the /// collection items of `owner`. After clearing all approvals, the deposit of each collection - /// approval is returned to the `owner` account and the `AllApprovalsCancelled` event is + /// approval is returned to the `owner` account and the `ApprovalsCancelled` event is /// emitted. /// /// - `owner`: The owner of the collection items. - /// - `collection`: The collection ID containing the item. + /// - `collection`: The identifier of the collection. /// - `limit`: The amount of collection approvals that will be cleared. - pub(crate) fn do_clear_collection_approvals_limit( + pub(crate) fn do_clear_collection_approvals( owner: T::AccountId, collection: T::CollectionId, limit: u32, @@ -304,7 +303,7 @@ impl, I: 'static> Pallet { } T::Currency::unreserve(&owner, deposits); - Self::deposit_event(Event::AllApprovalsCancelled { collection, item: None, owner }); + Self::deposit_event(Event::ApprovalsCancelled { collection, item: None, owner }); Ok(()) } @@ -345,21 +344,21 @@ impl, I: 'static> Pallet { delegate: &T::AccountId, ) -> DispatchResult { // Check if `delegate` has permission to transfer `owner`'s collection items. - if let Err(error) = Self::check_collection_approval(collection, owner, delegate) { - // Check if a `delegate` has permission to transfer the given collection item. - if let Some(item) = maybe_item { - let details = - Item::::get(collection, item).ok_or(Error::::UnknownItem)?; - let maybe_deadline = - details.approvals.get(delegate).ok_or(Error::::NoPermission)?; - if let Some(deadline) = maybe_deadline { - let block_number = frame_system::Pallet::::block_number(); - ensure!(block_number <= *deadline, Error::::ApprovalExpired); - } - return Ok(()); - }; - return Err(error); - } - Ok(()) + let Err(error) = Self::check_collection_approval(collection, owner, delegate) else { + return Ok(()); + }; + + // Check if a `delegate` has permission to transfer the given collection item. + if let Some(item) = maybe_item { + let details = Item::::get(collection, item).ok_or(Error::::UnknownItem)?; + let maybe_deadline = + details.approvals.get(delegate).ok_or(Error::::NoPermission)?; + if let Some(deadline) = maybe_deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *deadline, Error::::ApprovalExpired); + } + return Ok(()); + }; + Err(error) } } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 80dae5e2..9f7254ed 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -176,9 +176,8 @@ pub mod pallet { type CollectionDeposit: Get>; /// The basic amount of funds that must be reserved for a collection approval. - /// - /// Key: `sizeof((CollectionId, AccountId, AccountId))` bytes. - /// Value: `sizeof((Option, Balance))` bytes. + // Key: `sizeof((CollectionId, AccountId, AccountId))` bytes. + // Value: `sizeof((Option, Balance))` bytes. #[pallet::constant] type CollectionApprovalDeposit: Get>; @@ -501,14 +500,20 @@ pub mod pallet { delegate: T::AccountId, deadline: Option>, }, - /// An approval for a `delegate` account to transfer the `item` of an item - /// `collection` was cancelled by its `owner`. + /// An approval for a `delegate` account to transfer a specific `item` in a `collection` or + /// all collection items owned by the `owner` has been cancelled by the owner. ApprovalCancelled { collection: T::CollectionId, item: Option, owner: T::AccountId, delegate: T::AccountId, }, + /// Multiple approvals of a collection or item were cancelled. + ApprovalsCancelled { + collection: T::CollectionId, + item: Option, + owner: T::AccountId, + }, /// All approvals of a collection or item were cancelled. AllApprovalsCancelled { collection: T::CollectionId, @@ -740,9 +745,10 @@ pub mod pallet { impl, I: 'static> Hooks> for Pallet { #[cfg(any(feature = "std", test))] fn integrity_test() { + use core::any::TypeId; assert!( - size_of::<>::ItemId>() <= size_of::(), - "ItemId must fit within the size of a u32." + TypeId::of::<>::ItemId>() != TypeId::of::() && + TypeId::of::<>::ItemId>() != TypeId::of::() ); } } @@ -1431,7 +1437,7 @@ pub mod pallet { /// 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. + /// - `delegate`: The account that is going to lose their approval. /// /// Emits `ApprovalCancelled` on success. /// @@ -1457,7 +1463,7 @@ pub mod pallet { /// /// Arguments: /// - `collection`: The collection whose approval will be cancelled. - /// - `delegate`: The account that is going to loose their approval. + /// - `delegate`: The account that is going to lose their approval. /// /// Emits `ApprovalCancelled` on success. /// @@ -1481,7 +1487,7 @@ pub mod pallet { /// Arguments: /// - `owner`: The account cancelling approval for delegated transfer. /// - `collection`: The collection of whose approval will be cancelled. - /// - `delegate`: The account that is going to loose their approval. + /// - `delegate`: The account that is going to lose their approval. /// /// Emits `ApprovalCancelled` on success. /// @@ -1526,7 +1532,7 @@ pub mod pallet { Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) } - /// Cancel collection approvals, up to a specified limit. + /// Cancel all collection approvals, up to a specified limit. /// /// Origin must be Signed. /// @@ -1534,22 +1540,23 @@ pub mod pallet { /// - `collection`: The collection whose approvals will be cleared. /// - `limit`: The amount of collection approvals that will be cleared. /// - /// Emits `AllApprovalsCancelled` on success. + /// Emits `ApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_collection_approvals_limit(*limit))] - pub fn clear_collection_approvals_limit( + #[pallet::weight(T::WeightInfo::clear_collection_approvals(*limit))] + pub fn clear_collection_approvals( origin: OriginFor, collection: T::CollectionId, limit: u32, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::do_clear_collection_approvals_limit(origin, collection, limit)?; + Self::do_clear_collection_approvals(origin, collection, limit)?; Ok(()) } - /// Force-cancel collection approvals granted by `owner` account, up to a specified limit. + /// Force-cancel all collection approvals granted by `owner` account, up to a specified + /// limit. /// /// Origin must be `ForceOrigin`. /// @@ -1558,12 +1565,12 @@ pub mod pallet { /// - `collection`: The collection whose approvals will be cleared. /// - `limit`: The amount of collection approvals that will be cleared. /// - /// Emits `AllApprovalsCancelled` on success. + /// Emits `ApprovalsCancelled` on success. /// /// Weight: `O(1)` #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_collection_approvals_limit(*limit))] - pub fn force_clear_collection_approvals_limit( + #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(*limit))] + pub fn force_clear_collection_approvals( origin: OriginFor, owner: AccountIdLookupOf, collection: T::CollectionId, @@ -1571,7 +1578,7 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; - Self::do_clear_collection_approvals_limit(owner, collection, limit)?; + Self::do_clear_collection_approvals(owner, collection, limit)?; Ok(()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 2006f73a..86a99dfe 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -20,10 +20,12 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, + pallet_prelude::MaxEncodedLen, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, }, + Blake2_128Concat, StorageHasher, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_balances::Error as BalancesError; @@ -2920,21 +2922,21 @@ fn clear_collection_approvals_works() { None )); // Remove zero collection approvals, no event emitted. - assert_ok!(Nfts::clear_collection_approvals_limit( + assert_ok!(Nfts::clear_collection_approvals( RuntimeOrigin::signed(owner.clone()), collection_id, 0 )); assert_eq!(Balances::free_balance(&owner), balance - 2); assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); - assert!(!events().contains(&Event::::AllApprovalsCancelled { + assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, owner: owner.clone(), })); // Partially removes collection approvals. - assert_ok!(Nfts::clear_collection_approvals_limit( + assert_ok!(Nfts::clear_collection_approvals( RuntimeOrigin::signed(owner.clone()), collection_id, 1 @@ -2943,12 +2945,12 @@ fn clear_collection_approvals_works() { assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); // Successfully remove all collection approvals. - assert_ok!(Nfts::clear_collection_approvals_limit( + assert_ok!(Nfts::clear_collection_approvals( RuntimeOrigin::signed(owner.clone()), collection_id, 2 )); - assert!(events().contains(&Event::::AllApprovalsCancelled { + assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, owner: owner.clone(), @@ -3004,7 +3006,7 @@ fn force_clear_collection_approvals_work() { None )); // Remove zero collection approvals, no event emitted. - assert_ok!(Nfts::force_clear_collection_approvals_limit( + assert_ok!(Nfts::force_clear_collection_approvals( RuntimeOrigin::root(), owner.clone(), collection_id, @@ -3012,14 +3014,14 @@ fn force_clear_collection_approvals_work() { )); assert_eq!(Balances::free_balance(&owner), balance - 2); assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); - assert!(!events().contains(&Event::::AllApprovalsCancelled { + assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, owner: owner.clone(), })); // Partially removes collection approvals. - assert_ok!(Nfts::force_clear_collection_approvals_limit( + assert_ok!(Nfts::force_clear_collection_approvals( RuntimeOrigin::root(), owner.clone(), collection_id, @@ -3029,13 +3031,13 @@ fn force_clear_collection_approvals_work() { assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); // Successfully remove all collection approvals. - assert_ok!(Nfts::force_clear_collection_approvals_limit( + assert_ok!(Nfts::force_clear_collection_approvals( RuntimeOrigin::root(), owner.clone(), collection_id, 2 )); - assert!(events().contains(&Event::::AllApprovalsCancelled { + assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, owner: owner.clone(), @@ -4775,3 +4777,13 @@ fn clear_collection_metadata_works() { assert_eq!(Balances::reserved_balance(&account(1)), 10); }); } + +#[test] +fn ensure_collection_approval_bytes() { + let key = Blake2_128Concat::max_len::<::CollectionId>() + + Blake2_128Concat::max_len::() + + Blake2_128Concat::max_len::(); + let value = Option::>::max_encoded_len() + .saturating_add(BalanceOf::::max_encoded_len()); + assert_eq!(key + value, 133); +} diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 2f178d2b..91faa0ae 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -66,8 +66,8 @@ pub trait WeightInfo { fn cancel_collection_approval() -> Weight; fn force_cancel_collection_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; - fn clear_collection_approvals_limit(n: u32, ) -> Weight; - fn force_clear_collection_approvals_limit(n: u32, ) -> Weight; + fn clear_collection_approvals(n: u32, ) -> Weight; + fn force_clear_collection_approvals(n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -636,7 +636,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 20]`. - fn clear_collection_approvals_limit(n: u32, ) -> Weight { + fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` @@ -652,7 +652,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 20]`. - fn force_clear_collection_approvals_limit(n: u32, ) -> Weight { + fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` @@ -1427,7 +1427,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 20]`. - fn clear_collection_approvals_limit(n: u32, ) -> Weight { + fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` @@ -1443,7 +1443,7 @@ impl WeightInfo for () { /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 20]`. - fn force_clear_collection_approvals_limit(n: u32, ) -> Weight { + fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `348 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 45ecdcd3..f55b7169 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,8 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 32 bytes (16+16), Value = 68 bytes (4+32+32) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); + /// Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index 45ecdcd3..f55b7169 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,8 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 32 bytes (16+16), Value = 68 bytes (4+32+32) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 100); + /// Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); From 627a0e63cffcb91df472bd841e4e212c6b0ba021 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:26:37 +0700 Subject: [PATCH 70/99] chore: update README --- pallets/nfts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index d4c02d23..1056388a 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -100,7 +100,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_set_attribute`: Set an attribute. * `force_approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the specified account. * `force_cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. -* `force_clear_all_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer calls` for the collection. +* `force_clear_all_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer` calls for the collection. Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and its associated variants for documentation on each function. From 4535a52495fe0d25074e63f6019abc94b0f684f9 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:33:37 +0700 Subject: [PATCH 71/99] chore: comments --- pallets/nfts/src/features/approvals.rs | 2 ++ pallets/nfts/src/tests.rs | 38 ++++++++++++++++++-------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 3e8ccd7c..26cd89d5 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -164,6 +164,8 @@ impl, I: 'static> Pallet { Item::::get(collection, item).ok_or(Error::::UnknownCollection)?; if let Some(check_origin) = maybe_check_origin { + // Cannot revoke approvals for individual items when there are existing approvals to + // transfer all items in the collection owned by the origin. ensure!( CollectionApprovals::::iter_prefix((collection, &check_origin)) .take(1) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 86a99dfe..27e0aa90 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -247,7 +247,7 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(AccountBalance::::get(0, account(20)), 1); + assert_eq!(AccountBalance::::get(collection_id, account(20)), 1); assert_eq!(Balances::reserved_balance(&owner), 7); assert_ok!(Nfts::mint( RuntimeOrigin::signed(owner.clone()), @@ -2438,7 +2438,7 @@ fn approve_collection_transfer_works() { Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), locked_collection, - account(3), + delegate.clone(), None ), Error::::ItemsNonTransferable @@ -2477,7 +2477,7 @@ fn approve_collection_transfer_works() { delegate.clone(), Some(deadline) )); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(Balances::reserved_balance(&item_owner), 1); let now = System::block_number(); assert!(events().contains(&Event::::TransferApproved { collection: 0, @@ -2564,7 +2564,7 @@ fn force_approve_collection_transfer_works() { RuntimeOrigin::root(), item_owner.clone(), locked_collection, - account(3), + delegate.clone(), None ), Error::::ItemsNonTransferable @@ -2606,7 +2606,7 @@ fn force_approve_collection_transfer_works() { delegate.clone(), Some(deadline) )); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(Balances::reserved_balance(&item_owner), 1); let now = System::block_number(); assert!(events().contains(&Event::::TransferApproved { collection: 0, @@ -2928,7 +2928,10 @@ fn clear_collection_approvals_works() { 0 )); assert_eq!(Balances::free_balance(&owner), balance - 2); - assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 2 + ); assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, @@ -2942,7 +2945,10 @@ fn clear_collection_approvals_works() { 1 )); assert_eq!(Balances::free_balance(&owner), balance - 1); - assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 1 + ); // Successfully remove all collection approvals. assert_ok!(Nfts::clear_collection_approvals( @@ -2956,7 +2962,9 @@ fn clear_collection_approvals_works() { owner: owner.clone(), })); assert_eq!(Balances::free_balance(&owner), balance); - assert!(CollectionApprovals::::iter_prefix((0, owner)).count().is_zero()); + assert!(CollectionApprovals::::iter_prefix((collection_id, owner)) + .count() + .is_zero()); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), @@ -3013,7 +3021,10 @@ fn force_clear_collection_approvals_work() { 0 )); assert_eq!(Balances::free_balance(&owner), balance - 2); - assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 2); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 2 + ); assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, @@ -3028,7 +3039,10 @@ fn force_clear_collection_approvals_work() { 1 )); assert_eq!(Balances::free_balance(&owner), balance - 1); - assert_eq!(CollectionApprovals::::iter_prefix((0, owner.clone())).count(), 1); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 1 + ); // Successfully remove all collection approvals. assert_ok!(Nfts::force_clear_collection_approvals( @@ -3043,7 +3057,9 @@ fn force_clear_collection_approvals_work() { owner: owner.clone(), })); assert_eq!(Balances::free_balance(&owner), balance); - assert!(CollectionApprovals::::iter_prefix((0, owner)).count().is_zero()); + assert!(CollectionApprovals::::iter_prefix((collection_id, owner)) + .count() + .is_zero()); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), From 6eb8928f26361a291f87a5c9d5ef4b6611b4aa40 Mon Sep 17 00:00:00 2001 From: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> Date: Wed, 11 Dec 2024 05:11:09 +0100 Subject: [PATCH 72/99] refactor: test check_approval (#403) --- pallets/nfts/src/tests.rs | 173 ++++++++++++++++++++++++++++---------- 1 file changed, 128 insertions(+), 45 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 27e0aa90..4584a3bb 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1954,20 +1954,33 @@ fn approval_lifecycle_works() { } #[test] -fn check_approval_without_deadline_works() { +fn check_approval_works_without_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; - let item_id = 42; let collection_owner = account(1); + let item_id = 42; let item_owner = account(2); let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); + // TODO: we should return a clear error for smart contracts. + // assert_noop!(Nfts::check_collection_approval(&collection_id, &None, &delegate), + // Error::::UnknownCollection); assert_noop!(Nfts::check_collection_approval(& + // collection_id, &Some(item_owner), &delegate), Error::::UnknownCollection); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), collection_owner.clone(), default_collection_config() )); + // Item doesn't exist. + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::UnknownItem + ); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(collection_owner.clone()), collection_id, @@ -1975,7 +1988,63 @@ fn check_approval_without_deadline_works() { item_owner.clone(), default_item_config() )); - + // No approval. + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + // Approve collection without deadline. + { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + } + // Approve item without deadline. + { + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + )); + } + // Approve collection and item without deadline. assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -1983,20 +2052,12 @@ fn check_approval_without_deadline_works() { delegate.clone(), None )); - // Has only item approval. - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, delegate.clone(), None )); - // Has both collection and item approval. assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); }); @@ -2006,8 +2067,8 @@ fn check_approval_without_deadline_works() { fn check_approval_with_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; - let item_id = 42; let collection_owner = account(1); + let item_id = 42; let item_owner = account(2); let delegate = account(3); @@ -2024,61 +2085,83 @@ fn check_approval_with_deadline_works() { item_owner.clone(), default_item_config() )); - - let deadline: BlockNumberFor = 10; - for case in [ - // Collection approval expires first. - (deadline, deadline + 1, Err(Error::::ApprovalExpired.into()), Ok(())), - // Item approval expires first. - (deadline + 1, deadline, Ok(()), Ok(())), - ] { - System::set_block_number(0); + // Approve collection with deadline. + { + let deadline: BlockNumberFor = 10; assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, delegate.clone(), - Some(case.0) + Some(deadline), + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), )); + } + // Approve item with deadline. + { + let deadline: BlockNumberFor = 20; assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id, delegate.clone(), - Some(case.1) + Some(deadline), )); - - // Initially, all approvals should be valid. - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); assert_ok!(Nfts::check_approval( &collection_id, &Some(item_id), &item_owner, &delegate )); - - // Move past the deadline by 1 block. - System::set_block_number(deadline + 1); - - // (deadline + 1): Collection or item approval deadline has passed. - assert_eq!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), case.2); - assert_eq!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - case.3 - ); - - // Move past the deadline by 2 blocks. - System::set_block_number(deadline + 2); - - // (deadline + 2): Both collection and item approval expires. - assert_eq!( + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Err(Error::::ApprovalExpired.into()) + Error::::NoPermission ); - assert_eq!( + assert_noop!( Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Err(Error::::ApprovalExpired.into()) + Error::::ApprovalExpired ); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + )); } + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); }); } From 25e58d3e181a06436e9d9ec3111ba60781b3baa5 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Thu, 12 Dec 2024 00:03:49 +0700 Subject: [PATCH 73/99] chore: resolve feedback comments (#404) --- pallets/nfts/README.md | 2 +- pallets/nfts/src/features/approvals.rs | 6 +- pallets/nfts/src/lib.rs | 33 +- pallets/nfts/src/tests.rs | 1118 ++++++++++++------------ 4 files changed, 606 insertions(+), 553 deletions(-) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index 1056388a..a1825221 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -72,7 +72,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `lock_item_transfer`: Prevent an individual item from being transferred. * `unlock_item_transfer`: Revert the effects of a previous `lock_item_transfer`. * `clear_all_transfer_approvals`: Clears all transfer approvals set by calling the `approve_transfer`. -* `clear_all_collection_approvals`: Clears all collection approvals set by calling the `approve_collection_transfer`. +* `clear_collection_approvals`: Clears collection approvals set by calling the `approve_collection_transfer`. * `lock_collection`: Prevent all items within a collection from being transferred (making them all `soul bound`). * `lock_item_properties`: Lock item's metadata or attributes. * `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 26cd89d5..4c580421 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -289,9 +289,9 @@ impl, I: 'static> Pallet { owner: T::AccountId, collection: T::CollectionId, limit: u32, - ) -> DispatchResult { + ) -> Result { if limit == 0 { - return Ok(()); + return Ok(0); } let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); @@ -306,7 +306,7 @@ impl, I: 'static> Pallet { T::Currency::unreserve(&owner, deposits); Self::deposit_event(Event::ApprovalsCancelled { collection, item: None, owner }); - Ok(()) + Ok(removed_approvals) } /// Checks whether the `delegate` is approved to transfer collection items of `owner`. diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 9f7254ed..705ae52b 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -56,9 +56,12 @@ use alloc::{boxed::Box, vec, vec::Vec}; use core::cmp::Ordering; use codec::{Decode, Encode}; -use frame_support::traits::{ - tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, - ReservableCurrency, +use frame_support::{ + dispatch::WithPostDispatchInfo, + traits::{ + tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, + ReservableCurrency, + }, }; use frame_system::Config as SystemConfig; pub use pallet::*; @@ -1403,7 +1406,7 @@ pub mod pallet { /// /// Origin must be the `ForceOrigin`. /// - /// - `owner`: The account granting approval for delegated transfer. + /// - `owner`: The owner of the collection items to be force-approved by the `origin`. /// - `collection`: The collection of the item to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer collection items owned by /// the `owner`. @@ -1485,7 +1488,7 @@ pub mod pallet { /// Origin must be `ForceOrigin`. /// /// Arguments: - /// - `owner`: The account cancelling approval for delegated transfer. + /// - `owner`: The owner of the approval to be force-cancelled by the `origin`. /// - `collection`: The collection of whose approval will be cancelled. /// - `delegate`: The account that is going to lose their approval. /// @@ -1549,10 +1552,11 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, limit: u32, - ) -> DispatchResult { - let origin = ensure_signed(origin)?; - Self::do_clear_collection_approvals(origin, collection, limit)?; - Ok(()) + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin) + .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; + let removed_approvals = Self::do_clear_collection_approvals(origin, collection, limit)?; + Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) } /// Force-cancel all collection approvals granted by `owner` account, up to a specified @@ -1561,7 +1565,7 @@ pub mod pallet { /// Origin must be `ForceOrigin`. /// /// Arguments: - /// - `owner`: The account clearing all collection approvals. + /// - `owner`: The owner of the approvals to be force-cancelled by the `origin`. /// - `collection`: The collection whose approvals will be cleared. /// - `limit`: The amount of collection approvals that will be cleared. /// @@ -1575,11 +1579,12 @@ pub mod pallet { owner: AccountIdLookupOf, collection: T::CollectionId, limit: u32, - ) -> DispatchResult { - T::ForceOrigin::ensure_origin(origin)?; + ) -> DispatchResultWithPostInfo { + T::ForceOrigin::ensure_origin(origin) + .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; let owner = T::Lookup::lookup(owner)?; - Self::do_clear_collection_approvals(owner, collection, limit)?; - Ok(()) + let removed_approvals = Self::do_clear_collection_approvals(owner, collection, limit)?; + Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) } /// Disallows changing the metadata or attributes of the item. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 4584a3bb..1b3de023 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -20,6 +20,7 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, + dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}, pallet_prelude::MaxEncodedLen, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, @@ -32,17 +33,28 @@ use pallet_balances::Error as BalancesError; use sp_core::{bounded::BoundedVec, Pair}; use sp_runtime::{ traits::{Dispatchable, IdentifyAccount}, - MultiSignature, MultiSigner, + DispatchError::BadOrigin, + DispatchResult, MultiSignature, MultiSigner, }; use crate::{mock::*, Event, SystemConfig, *}; +type CollectionId = ::CollectionId; type AccountIdOf = ::AccountId; +type WeightOf = ::WeightInfo; fn account(id: u8) -> AccountIdOf { [id; 32].into() } +fn root() -> RuntimeOrigin { + RuntimeOrigin::root() +} + +fn none() -> RuntimeOrigin { + RuntimeOrigin::none() +} + fn items() -> Vec<(AccountIdOf, u32, u32)> { let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); r.sort(); @@ -150,6 +162,49 @@ fn item_config_from_disabled_settings(settings: BitFlags) -> ItemCo ItemConfig { settings: ItemSettings::from_disabled(settings) } } +fn clear_collection_approvals( + origin: RuntimeOrigin, + maybe_owner: Option, + collection: CollectionId, + limit: u32, +) -> DispatchResultWithPostInfo { + match maybe_owner { + Some(owner) => Nfts::force_clear_collection_approvals(origin, owner, collection, limit), + None => Nfts::clear_collection_approvals(origin, collection, limit), + } +} + +fn approve_collection_transfer( + origin: RuntimeOrigin, + maybe_owner: Option, + collection: CollectionId, + delegate: AccountIdOf, + maybe_deadline: Option>, +) -> DispatchResult { + match maybe_owner { + Some(owner) => Nfts::force_approve_collection_transfer( + origin, + owner, + collection, + delegate, + maybe_deadline, + ), + None => Nfts::approve_collection_transfer(origin, collection, delegate, maybe_deadline), + } +} + +fn cancel_collection_approval( + origin: RuntimeOrigin, + maybe_owner: Option, + collection: CollectionId, + delegate: AccountIdOf, +) -> DispatchResult { + match maybe_owner { + Some(owner) => Nfts::force_cancel_collection_approval(origin, owner, collection, delegate), + None => Nfts::cancel_collection_approval(origin, collection, delegate), + } +} + #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { @@ -229,7 +284,7 @@ fn lifecycle_should_work() { bvec![0, 0] )); assert_eq!(Balances::reserved_balance(&owner), 5); - assert!(CollectionMetadataOf::::contains_key(0)); + assert!(CollectionMetadataOf::::contains_key(collection_id)); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(owner.clone()), @@ -369,10 +424,10 @@ fn destroy_with_bad_witness_should_not_work() { fn destroy_should_work() { new_test_ext().execute_with(|| { let collection_id = 0; - let item_id = 42; let collection_owner = account(1); - let item_owner = account(2); let delegate = account(3); + let item_id = 42; + let item_owner = account(2); Balances::make_free_balance_be(&collection_owner, 100); Balances::make_free_balance_be(&item_owner, 100); @@ -389,7 +444,6 @@ fn destroy_should_work() { item_owner.clone(), None )); - assert_eq!(AccountBalance::::get(collection_id, &item_owner), 1); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -431,9 +485,6 @@ fn destroy_should_work() { collection_id, Nfts::get_destroy_witness(&collection_id).unwrap() )); - assert_eq!(AccountBalance::::get(collection_id, &collection_owner), 0); - assert!(!AccountBalance::::contains_key(collection_id, &collection_owner)); - assert_eq!(CollectionApprovals::::iter_prefix((collection_id,)).count(), 0); assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 0); }); @@ -1829,11 +1880,11 @@ fn force_update_collection_should_work() { #[test] fn burn_works() { new_test_ext().execute_with(|| { + let admin = account(2); let collection_id = 0; + let collection_owner = account(1); let item_id_1 = 42; let item_id_2 = 69; - let collection_owner = account(1); - let admin = account(2); let item_owner = account(5); Balances::make_free_balance_be(&collection_owner, 100); @@ -1846,8 +1897,8 @@ fn burn_works() { RuntimeOrigin::signed(collection_owner.clone()), collection_id, Some(admin.clone()), - Some(account(2)), Some(account(3)), + Some(account(4)), )); assert_noop!( @@ -1878,8 +1929,7 @@ fn burn_works() { ); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1)); assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_2)); - assert_eq!(AccountBalance::::get(collection_id, &item_owner), 0); - assert_eq!(AccountBalance::::contains_key(collection_id, &item_owner), false); + assert!(!AccountBalance::::contains_key(collection_id, &item_owner)); assert_eq!(Balances::reserved_balance(collection_owner), 0); }); } @@ -1920,6 +1970,13 @@ fn approval_lifecycle_works() { account(2), None )); + assert!(events().contains(&Event::TransferApproved { + collection: 0, + item: Some(42), + owner: account(4), + delegate: account(2), + deadline: None + })); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(2))); // ensure we can't buy an item when the collection has a NonTransferableItems flag @@ -1958,9 +2015,9 @@ fn check_approval_works_without_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); + let delegate = account(3); let item_id = 42; let item_owner = account(2); - let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); // TODO: we should return a clear error for smart contracts. @@ -2068,9 +2125,9 @@ fn check_approval_with_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); + let delegate = account(3); let item_id = 42; let item_owner = account(2); - let delegate = account(3); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( @@ -2168,152 +2225,188 @@ fn check_approval_with_deadline_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { + let collection_owner = account(1); + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(2), + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + 1, + item_id, + delegate.clone() + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + 43, + delegate.clone() + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Nfts::cancel_approval( + RuntimeOrigin::signed(delegate.clone()), + collection_id, + item_id, + delegate.clone() + ), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + account(4) + ), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection + // approval. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), - Error::::NotDelegate + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + ), + Error::::DelegateApprovalConflict ); - - let current_block = 1; - System::set_block_number(current_block); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 69, - account(2), - default_item_config() + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() )); - // approval expires after 2 blocks. - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), - Some(2) + + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() )); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, + item: Some(item_id), + owner: item_owner.clone(), + delegate: delegate.clone() + })); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3)), - Error::::NoPermission + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + ), + Error::::NotDelegate ); - 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_eq!(approvals(0, 69), vec![]); - }); -} - -#[test] -fn cancel_collection_approval_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let item_id = 42; - let collection_owner = account(1); - let item_owner = account(2); - let delegate = account(3); - - Balances::make_free_balance_be(&item_owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); + let current_block = 1; + System::set_block_number(current_block); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner), + RuntimeOrigin::signed(collection_owner.clone()), collection_id, - item_id, + 69, item_owner.clone(), default_item_config() )); - - assert_ok!(Nfts::approve_collection_transfer( + // approval expires after 2 blocks. + assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, + item_id, delegate.clone(), - None + Some(2) )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - - // Cancel an unapproved delegate. assert_noop!( - Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - 1, + Nfts::cancel_approval( + RuntimeOrigin::signed(account(5)), + collection_id, + item_id, delegate.clone() ), - Error::::Unapproved + Error::::NoPermission ); - // Successfully cancel a collection approval. - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), + 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)), collection_id, + item_id, delegate.clone() )); - assert_eq!(Balances::reserved_balance(&item_owner), 0); assert!(events().contains(&Event::::ApprovalCancelled { collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone() + item: Some(item_id), + owner: item_owner, + delegate })); - assert_eq!( - CollectionApprovals::::get((collection_id, item_owner, delegate.clone())), - None - ); - - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate), collection_id, item_id, account(4)), - Error::::NoPermission - ); + assert_eq!(approvals(collection_id, 69), vec![]); }); } #[test] -fn force_cancel_collection_approvals_work() { +fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { let collection_id = 0; - let item_id = 42; let collection_owner = account(1); - let item_owner = account(2); let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + // Origin checks for the `cancel_collection_approval`. + for origin in [root(), none()] { + assert_noop!( + Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), + BadOrigin + ); + } + // Origin checks for the `force_cancel_collection_approval`. + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_cancel_collection_approval( + origin, + item_owner.clone(), + collection_id, + delegate.clone() + ), + BadOrigin + ); + } Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( @@ -2329,48 +2422,58 @@ fn force_cancel_collection_approvals_work() { default_item_config() )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); + for (origin, maybe_owner) in + [(RuntimeOrigin::signed(item_owner.clone()), None), (root(), Some(item_owner.clone()))] + { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_eq!(Balances::reserved_balance(&item_owner), 1); - // Cancel an unapproved delegate. - assert_noop!( - Nfts::force_cancel_collection_approval( - RuntimeOrigin::root(), + // Cancel an unapproved delegate. + assert_noop!( + cancel_collection_approval( + origin.clone(), + maybe_owner.clone(), + 1, + delegate.clone() + ), + Error::::Unapproved + ); + + // Successfully cancel a collection approval. + assert_ok!(cancel_collection_approval( + origin.clone(), + maybe_owner.clone(), + collection_id, + delegate.clone() + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone() + })); + assert!(!CollectionApprovals::::contains_key(( + collection_id, item_owner.clone(), - 1, delegate.clone() - ), - Error::::Unapproved - ); - - // Successfully cancel a collection approval. - assert_ok!(Nfts::force_cancel_collection_approval( - RuntimeOrigin::root(), - item_owner.clone(), - collection_id, - delegate.clone() - )); - assert_eq!(Balances::reserved_balance(&item_owner), 0); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone() - })); - assert_eq!( - CollectionApprovals::::get((collection_id, item_owner, delegate.clone())), - None - ); + ))); - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate), collection_id, item_id, account(4)), - Error::::NoPermission - ); + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(delegate.clone()), + collection_id, + item_id, + account(4) + ), + Error::::NoPermission + ); + } }); } @@ -2413,20 +2516,36 @@ fn approving_multiple_accounts_works() { account(5), Some(2) )); + assert_eq!( + events().last_chunk::<3>(), + Some(&[ + Event::TransferApproved { + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(3), + deadline: None + }, + Event::TransferApproved { + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(4), + deadline: None + }, + Event::TransferApproved { + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(5), + deadline: Some(current_block + 2) + } + ]) + ); assert_eq!( approvals(0, 42), vec![(account(3), None), (account(4), None), (account(5), Some(current_block + 2))] ); - - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(6))); - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(7)), - Error::::NoPermission - ); - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(5)), 0, 42, account(8)), - Error::::NoPermission - ); }); } @@ -2466,138 +2585,47 @@ fn approvals_limit_works() { #[test] fn approve_collection_transfer_works() { new_test_ext().execute_with(|| { - let (collection, locked_collection) = (0, 1); - let item = 42; + let (collection_id, locked_collection_id) = (0, 1); let collection_owner = account(1); - let item_owner = account(2); let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + // Origin checks for the `approve_collection_transfer`. + for origin in [root(), none()] { + assert_noop!( + Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), + BadOrigin + ); + } + // Origin checks for the `force_approve_collection_transfer`. + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_approve_collection_transfer( + origin, + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + BadOrigin + ); + } Balances::make_free_balance_be(&item_owner, 100); Balances::make_free_balance_be(&delegate, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - - // Approve collection without items, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection, - item, - item_owner.clone(), - default_item_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - locked_collection, - item, - item_owner.clone(), - default_item_config() - )); - - // Throws error `Error::ItemsNonTransferable`. - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(collection_owner), - locked_collection, - CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) - )); - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - locked_collection, - delegate.clone(), - None - ), - Error::::ItemsNonTransferable - ); // Approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), - 2, + collection_id, delegate.clone(), None ), Error::::NoItemOwned ); - // Approval expires after `deadline`. - let deadline = 10; - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection, - delegate.clone(), - Some(deadline) - )); - assert_ok!(Nfts::check_approval(&collection, &None, &item_owner, &delegate)); - System::set_block_number(deadline + 2); - assert_noop!( - Nfts::check_approval(&collection, &None, &item_owner, &delegate), - Error::::ApprovalExpired - ); - - // Approve delegate of an existing expired approval to transfer. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection, - delegate.clone(), - Some(deadline) - )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - let now = System::block_number(); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline: Some(now + deadline) - })); - assert_eq!( - CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), - Some((Some(now + deadline), 1)) - ); - - // Approve same delegate again not updating the total reserved funds. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection, - delegate.clone(), - None - )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); - }); -} - -#[test] -fn force_approve_collection_transfer_works() { - new_test_ext().execute_with(|| { - let (collection, locked_collection) = (0, 1); - let item = 42; - let collection_owner = account(1); - let item_owner = account(2); - let delegate = account(3); - - Balances::make_free_balance_be(&item_owner, 100); - Balances::make_free_balance_be(&delegate, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), collection_owner.clone(), @@ -2611,10 +2639,9 @@ fn force_approve_collection_transfer_works() { // Approve collection without items, throws error `Error::NoItemOwned`. assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection, + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, delegate.clone(), None ), @@ -2623,97 +2650,84 @@ fn force_approve_collection_transfer_works() { assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(collection_owner.clone()), - collection, - item, + collection_id, + item_id, item_owner.clone(), default_item_config() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(collection_owner.clone()), - locked_collection, - item, + locked_collection_id, + item_id, item_owner.clone(), default_item_config() )); - // Throws error `Error::ItemsNonTransferable`. - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(collection_owner), - locked_collection, - CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) - )); - assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - locked_collection, + for (origin, maybe_item_owner) in + [(RuntimeOrigin::signed(item_owner.clone()), None), (root(), Some(item_owner.clone()))] + { + // Throws error `Error::ItemsNonTransferable`. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner.clone()), + locked_collection_id, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + approve_collection_transfer( + origin.clone(), + maybe_item_owner.clone(), + locked_collection_id, + delegate.clone(), + None + ), + Error::::ItemsNonTransferable + ); + + // Approve unknown collection, throws error `Error::NoItemOwned`. + assert_noop!( + approve_collection_transfer( + origin.clone(), + maybe_item_owner.clone(), + 2, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + + assert_ok!(approve_collection_transfer( + origin.clone(), + maybe_item_owner.clone(), + collection_id, delegate.clone(), None - ), - Error::::ItemsNonTransferable - ); - - // Approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - 2, + )); + assert!(events().contains(&Event::::TransferApproved { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline: None, + })); + assert_eq!(Balances::reserved_balance(&item_owner), 1); + + // Approve same delegate again not updating the total reserved funds. + assert_ok!(approve_collection_transfer( + origin.clone(), + maybe_item_owner.clone(), + collection_id, delegate.clone(), None - ), - Error::::NoItemOwned - ); - - // Approval expires after `deadline`. - let deadline = 10; - assert_ok!(Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection, - delegate.clone(), - Some(deadline) - )); - assert_ok!(Nfts::check_approval(&collection, &None, &item_owner, &delegate)); - System::set_block_number(deadline + 2); - assert_noop!( - Nfts::check_approval(&collection, &None, &item_owner, &delegate), - Error::::ApprovalExpired - ); - - // Approve delegate of an existing expired approval to transfer. - assert_ok!(Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection, - delegate.clone(), - Some(deadline) - )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - let now = System::block_number(); - assert!(events().contains(&Event::::TransferApproved { - collection: 0, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline: Some(now + deadline) - })); - assert_eq!( - CollectionApprovals::::get((0, item_owner.clone(), delegate.clone())), - Some((Some(now + deadline), 1)) - ); - - // Approve same delegate again not updating the total reserved funds. - assert_ok!(Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection, - delegate.clone(), - None - )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); + )); + assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(delegate), collection, item, account(4))); + // Clean up. + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + } }); } @@ -2772,11 +2786,11 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - let collection_id = 0; + let delegate = account(3); let item_id = 42; - let collection_owner = account(1); let item_owner = account(2); - let delegate = account(3); + let collection_id = 0; + let collection_owner = account(1); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( @@ -2827,7 +2841,8 @@ fn cancel_approval_works_with_admin() { Error::::NotDelegate ); - // delegate approval conflicts. + // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection + // approval. assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -2855,9 +2870,16 @@ fn cancel_approval_works_with_admin() { item_id, delegate.clone() )); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, + item: Some(item_id), + owner: item_owner.clone(), + delegate + })); + assert_noop!( Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), + RuntimeOrigin::signed(item_owner), collection_id, item_id, account(5) @@ -2870,184 +2892,185 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { + let collection_owner = account(1); + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - account(1), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 42, - account(2), + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(3), + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, item_id, collection_owner.clone()), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), + Nfts::cancel_approval( + RuntimeOrigin::root(), + collection_id, + 43, + collection_owner.clone() + ), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), collection_id, item_id, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); - assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), - Error::::NotDelegate - ); - }); -} - -#[test] -fn clear_all_transfer_approvals_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, - 42, - account(3), - None - )); - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(account(2)), - 0, - 42, - account(4), + // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection + // approval. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), None )); - assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), - Error::::NoPermission + Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + ), + Error::::DelegateApprovalConflict ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); - assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); - - assert!(events().contains(&Event::::AllApprovalsCancelled { - collection: 0, - item: Some(42), - owner: account(2), + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::root(), + collection_id, + item_id, + delegate.clone() + )); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, + item: Some(item_id), + owner: item_owner, + delegate })); - assert_eq!(approvals(0, 42), vec![]); - assert_eq!(CollectionApprovals::::iter_prefix((0, account(2))).count(), 0); - - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), - Error::::NoPermission - ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), - Error::::NoPermission + Nfts::cancel_approval(RuntimeOrigin::root(), collection_id, item_id, collection_owner), + Error::::NotDelegate ); }); } #[test] -fn clear_collection_approvals_works() { +fn clear_all_transfer_approvals_works() { new_test_ext().execute_with(|| { let collection_id = 0; - let item_id = 42; - let owner = account(1); + let collection_owner = account(1); let delegate_1 = account(3); let delegate_2 = account(4); - let balance = 100; + let item_id = 42; + let item_owner = account(2); - Balances::make_free_balance_be(&owner, balance); + Balances::make_free_balance_be(&collection_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - owner.clone(), + collection_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + 43, + collection_owner.clone(), + default_item_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), collection_id, item_id, - owner.clone(), + item_owner.clone(), default_item_config() )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), collection_id, + item_id, delegate_1.clone(), None )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), collection_id, + item_id, delegate_2.clone(), None )); - // Remove zero collection approvals, no event emitted. - assert_ok!(Nfts::clear_collection_approvals( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 0 - )); - assert_eq!(Balances::free_balance(&owner), balance - 2); - assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 2 + + assert_noop!( + Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(delegate_1.clone()), + collection_id, + item_id + ), + Error::::NoPermission ); - assert!(!events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - item: None, - owner: owner.clone(), - })); - // Partially removes collection approvals. - assert_ok!(Nfts::clear_collection_approvals( - RuntimeOrigin::signed(owner.clone()), + // Throws `DelegateApprovalConflict` if there are existing collection approvals. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(collection_owner.clone()), collection_id, - 1 + delegate_1.clone(), + None )); - assert_eq!(Balances::free_balance(&owner), balance - 1); - assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 1 + assert_noop!( + Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id + ), + Error::::DelegateApprovalConflict ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + delegate_1.clone() + )); - // Successfully remove all collection approvals. - assert_ok!(Nfts::clear_collection_approvals( - RuntimeOrigin::signed(owner.clone()), + assert_ok!(Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(item_owner.clone()), collection_id, - 2 + item_id )); - assert!(events().contains(&Event::::ApprovalsCancelled { + + assert!(events().contains(&Event::::AllApprovalsCancelled { collection: collection_id, - item: None, - owner: owner.clone(), + item: Some(item_id), + owner: item_owner.clone(), })); - assert_eq!(Balances::free_balance(&owner), balance); - assert!(CollectionApprovals::::iter_prefix((collection_id, owner)) - .count() - .is_zero()); + assert_eq!(approvals(collection_id, item_id), vec![]); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, item_owner.clone())).count(), + 0 + ); assert_noop!( Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), @@ -3061,16 +3084,30 @@ fn clear_collection_approvals_works() { } #[test] -fn force_clear_collection_approvals_work() { +fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { + let balance = 100; let collection_id = 0; - let item_id = 42; - let owner = account(1); let delegate_1 = account(3); let delegate_2 = account(4); - let balance = 100; + let item_id = 42; + let owner = account(1); + + // Origin checks for the `clear_collection_approvals`. + for origin in [root(), none()] { + assert_noop!( + Nfts::clear_collection_approvals(origin, collection_id, 0), + BadOrigin.with_weight(WeightOf::::clear_collection_approvals(0)) + ); + } + // Origin checks for the `force_clear_collection_approvals`. + for origin in [RuntimeOrigin::signed(owner.clone()), none()] { + assert_noop!( + Nfts::force_clear_collection_approvals(origin, owner.clone(), collection_id, 0), + BadOrigin.with_weight(WeightOf::::clear_collection_approvals(0)) + ); + } - Balances::make_free_balance_be(&owner, balance); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), owner.clone(), @@ -3084,74 +3121,85 @@ fn force_clear_collection_approvals_work() { default_item_config() )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate_1.clone(), - None - )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate_2.clone(), - None - )); - // Remove zero collection approvals, no event emitted. - assert_ok!(Nfts::force_clear_collection_approvals( - RuntimeOrigin::root(), - owner.clone(), - collection_id, - 0 - )); - assert_eq!(Balances::free_balance(&owner), balance - 2); - assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 2 - ); - assert!(!events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - item: None, - owner: owner.clone(), - })); + for (origin, maybe_owner) in + [(root(), Some(owner.clone())), (RuntimeOrigin::signed(owner.clone()), None)] + { + Balances::make_free_balance_be(&owner, balance); - // Partially removes collection approvals. - assert_ok!(Nfts::force_clear_collection_approvals( - RuntimeOrigin::root(), - owner.clone(), - collection_id, - 1 - )); - assert_eq!(Balances::free_balance(&owner), balance - 1); - assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 1 - ); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate_1.clone(), + None + )); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate_2.clone(), + None + )); + // Removes zero collection approval. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 0), + Ok(Some(WeightOf::::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&owner), balance - 2); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 2 + ); + assert!(!events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); + + // Partially removes collection approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), + Ok(Some(WeightOf::::clear_collection_approvals(1)).into()) + ); + assert_eq!(Balances::free_balance(&owner), balance - 1); + assert_eq!( + CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), + 1 + ); - // Successfully remove all collection approvals. - assert_ok!(Nfts::force_clear_collection_approvals( - RuntimeOrigin::root(), - owner.clone(), - collection_id, - 2 - )); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - item: None, - owner: owner.clone(), - })); - assert_eq!(Balances::free_balance(&owner), balance); - assert!(CollectionApprovals::::iter_prefix((collection_id, owner)) - .count() - .is_zero()); + // Successfully removes all collection approvals. Only charges post-dispatch weight for + // the removed approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::::clear_collection_approvals(1)).into()) + ); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); + assert_eq!(Balances::free_balance(&owner), balance); + assert!(CollectionApprovals::::iter_prefix((collection_id, owner.clone())) + .count() + .is_zero()); - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), - Error::::NoPermission - ); - assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_2), collection_id, item_id, account(5)), - Error::::NoPermission - ); + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(delegate_1.clone()), + collection_id, + item_id, + account(5) + ), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(delegate_2.clone()), + collection_id, + item_id, + account(5) + ), + Error::::NoPermission + ); + } }); } @@ -3159,8 +3207,8 @@ fn force_clear_collection_approvals_work() { fn collection_item_works() { new_test_ext().execute_with(|| { let collection_id = 0; - let user_id = account(1); let total_items = 10; + let user_id = account(1); // No collection. assert_eq!(Nfts::collection_items(collection_id), None); From ca27938a1dfc4ae76389e7f3270ceb660539fb74 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 12 Dec 2024 00:09:39 +0700 Subject: [PATCH 74/99] chore: fix comment --- pallets/nfts/src/tests.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 1b3de023..a8fb136f 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -1970,13 +1970,6 @@ fn approval_lifecycle_works() { account(2), None )); - assert!(events().contains(&Event::TransferApproved { - collection: 0, - item: Some(42), - owner: account(4), - delegate: account(2), - deadline: None - })); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(2))); // ensure we can't buy an item when the collection has a NonTransferableItems flag @@ -2422,9 +2415,12 @@ fn cancel_collection_approval_works() { default_item_config() )); - for (origin, maybe_owner) in - [(RuntimeOrigin::signed(item_owner.clone()), None), (root(), Some(item_owner.clone()))] - { + for (origin, maybe_owner) in [ + // Parameters for `cancel_collection_approval`. + (RuntimeOrigin::signed(item_owner.clone()), None), + // Parameters for `force_cancel_collection_approval`. + (root(), Some(item_owner.clone())), + ] { assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -2663,9 +2659,12 @@ fn approve_collection_transfer_works() { default_item_config() )); - for (origin, maybe_item_owner) in - [(RuntimeOrigin::signed(item_owner.clone()), None), (root(), Some(item_owner.clone()))] - { + for (origin, maybe_item_owner) in [ + // Parameters for `approve_collection_transfer`. + (RuntimeOrigin::signed(item_owner.clone()), None), + // Parameters for `force_approve_collection_transfer`. + (root(), Some(item_owner.clone())), + ] { // Throws error `Error::ItemsNonTransferable`. assert_ok!(Nfts::lock_collection( RuntimeOrigin::signed(collection_owner.clone()), @@ -3121,9 +3120,12 @@ fn clear_collection_approvals_works() { default_item_config() )); - for (origin, maybe_owner) in - [(root(), Some(owner.clone())), (RuntimeOrigin::signed(owner.clone()), None)] - { + for (origin, maybe_owner) in [ + // Parameters for `clear_collection_approvals`. + (root(), Some(owner.clone())), + // Parameters for `force_clear_collection_approvals`. + (RuntimeOrigin::signed(owner.clone()), None), + ] { Balances::make_free_balance_be(&owner, balance); assert_ok!(Nfts::approve_collection_transfer( From fafb988685a030ff9fc5065049baeb0d516850b1 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:06:10 +0700 Subject: [PATCH 75/99] chore: update weight and test --- pallets/nfts/src/benchmarking.rs | 4 +-- pallets/nfts/src/features/approvals.rs | 6 ++-- pallets/nfts/src/tests.rs | 49 ++++++++++++++++++------- pallets/nfts/src/weights.rs | 50 +++++++++++++------------- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 07762273..047c08ca 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -657,7 +657,7 @@ benchmarks_instance_pallet! { } clear_collection_approvals { - let n in 1 .. T::ApprovalsLimit::get(); + let n in 1 .. 1_000; let (collection, caller, _) = create_collection::(); mint_item::(0); for i in 0 .. n { @@ -675,7 +675,7 @@ benchmarks_instance_pallet! { } force_clear_collection_approvals { - let n in 1 .. T::ApprovalsLimit::get(); + let n in 1 .. 1_000; let (collection, caller, _) = create_collection::(); let caller_lookup = T::Lookup::unlookup(caller.clone()); mint_item::(0); diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 4c580421..8a740f39 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -304,8 +304,10 @@ impl, I: 'static> Pallet { } } - T::Currency::unreserve(&owner, deposits); - Self::deposit_event(Event::ApprovalsCancelled { collection, item: None, owner }); + if removed_approvals > 0 { + T::Currency::unreserve(&owner, deposits); + Self::deposit_event(Event::ApprovalsCancelled { collection, item: None, owner }); + } Ok(removed_approvals) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index a8fb136f..938f7981 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2004,7 +2004,7 @@ fn approval_lifecycle_works() { } #[test] -fn check_approval_works_without_deadline_works() { +fn check_approval_without_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); @@ -2622,6 +2622,18 @@ fn approve_collection_transfer_works() { Error::::NoItemOwned ); + // Force-approve unknown collection, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_create( RuntimeOrigin::root(), collection_owner.clone(), @@ -2644,6 +2656,18 @@ fn approve_collection_transfer_works() { Error::::NoItemOwned ); + // Force-approve collection without items, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(collection_owner.clone()), collection_id, @@ -2682,18 +2706,6 @@ fn approve_collection_transfer_works() { Error::::ItemsNonTransferable ); - // Approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - approve_collection_transfer( - origin.clone(), - maybe_item_owner.clone(), - 2, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - assert_ok!(approve_collection_transfer( origin.clone(), maybe_item_owner.clone(), @@ -3183,6 +3195,17 @@ fn clear_collection_approvals_works() { .count() .is_zero()); + // Emitting no event if zero approvals removed. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::::clear_collection_approvals(0)).into()) + ); + assert!(!events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + item: None, + owner: owner.clone(), + })); + assert_noop!( Nfts::transfer( RuntimeOrigin::signed(delegate_1.clone()), diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 91faa0ae..6e291bfc 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-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-12, 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` @@ -633,33 +633,33 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 20]`. + /// The range of component `n` is `[1, 1000]`. fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + n * (75 ±0)` + // Measured: `327 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(16_365_393, 3602) - // Standard Error: 5_564 - .saturating_add(Weight::from_parts(3_008_044, 0).saturating_mul(n.into())) + Weight::from_parts(18_000_000, 3602) + // Standard Error: 7_954 + .saturating_add(Weight::from_parts(3_625_558, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) } - /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 20]`. + /// The range of component `n` is `[1, 1000]`. fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + n * (75 ±0)` + // Measured: `327 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(16_193_192, 3602) - // Standard Error: 5_637 - .saturating_add(Weight::from_parts(3_029_821, 0).saturating_mul(n.into())) + Weight::from_parts(18_000_000, 3602) + // Standard Error: 5_861 + .saturating_add(Weight::from_parts(3_576_220, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1424,33 +1424,33 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 20]`. + /// The range of component `n` is `[1, 1000]`. fn clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + n * (75 ±0)` + // Measured: `327 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(16_365_393, 3602) - // Standard Error: 5_564 - .saturating_add(Weight::from_parts(3_008_044, 0).saturating_mul(n.into())) + Weight::from_parts(18_000_000, 3602) + // Standard Error: 7_954 + .saturating_add(Weight::from_parts(3_625_558, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) } - /// Storage: `Nfts::CollectionApprovals` (r:21 w:20) + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 20]`. + /// The range of component `n` is `[1, 1000]`. fn force_clear_collection_approvals(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + n * (75 ±0)` + // Measured: `327 + n * (75 ±0)` // Estimated: `3602 + n * (2612 ±0)` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(16_193_192, 3602) - // Standard Error: 5_637 - .saturating_add(Weight::from_parts(3_029_821, 0).saturating_mul(n.into())) + Weight::from_parts(18_000_000, 3602) + // Standard Error: 5_861 + .saturating_add(Weight::from_parts(3_576_220, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) From e88b6add24090252ed03cf71d8d3f0f418187e31 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:04:58 +0700 Subject: [PATCH 76/99] chore: remove TODO --- pallets/nfts/src/tests.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 938f7981..3c224eea 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2013,10 +2013,6 @@ fn check_approval_without_deadline_works() { let item_owner = account(2); Balances::make_free_balance_be(&item_owner, 100); - // TODO: we should return a clear error for smart contracts. - // assert_noop!(Nfts::check_collection_approval(&collection_id, &None, &delegate), - // Error::::UnknownCollection); assert_noop!(Nfts::check_collection_approval(& - // collection_id, &Some(item_owner), &delegate), Error::::UnknownCollection); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), collection_owner.clone(), From abc54e8d222d53cdfae22798f9aaab4000c65fca Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:33:33 +0700 Subject: [PATCH 77/99] chore: resolve comments --- pallets/nfts/README.md | 2 +- pallets/nfts/src/benchmarking.rs | 11 ++++------- pallets/nfts/src/common_functions.rs | 10 ++++++++++ pallets/nfts/src/tests.rs | 4 ++-- runtime/devnet/src/config/assets.rs | 2 +- runtime/testnet/src/config/assets.rs | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index a1825221..93ed18cf 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -100,7 +100,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_set_attribute`: Set an attribute. * `force_approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the specified account. * `force_cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. -* `force_clear_all_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer` calls for the collection. +* `force_clear_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer` calls for the collection. Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and its associated variants for documentation on each function. diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 047c08ca..bc7caa6c 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -75,7 +75,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(), @@ -593,9 +593,8 @@ benchmarks_instance_pallet! { } force_approve_collection_transfer { - let (collection, caller, _) = create_collection::(); + let (collection, caller, caller_lookup) = create_collection::(); mint_item::(0); - let caller_lookup = T::Lookup::unlookup(caller.clone()); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let deadline = BlockNumberFor::::max_value(); @@ -631,9 +630,8 @@ benchmarks_instance_pallet! { } force_cancel_collection_approval { - let (collection, caller, _) = create_collection::(); + let (collection, caller, caller_lookup) = create_collection::(); mint_item::(0); - let caller_lookup = T::Lookup::unlookup(caller.clone()); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let deadline = BlockNumberFor::::max_value(); @@ -676,8 +674,7 @@ benchmarks_instance_pallet! { force_clear_collection_approvals { let n in 1 .. 1_000; - let (collection, caller, _) = create_collection::(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + let (collection, caller, caller_lookup) = create_collection::(); mint_item::(0); for i in 0 .. n { let delegate: T::AccountId = account("delegate", i, SEED); diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 1aa151c3..38f6cfc8 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -25,21 +25,31 @@ use crate::*; impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. + /// + /// - `collection`: The identifier of the collection. + /// - `item`: The identifier of the collection item. pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option { Item::::get(collection, item).map(|i| i.owner) } /// Get the owner of the collection, if the collection exists. + /// + /// - `collection`: The identifier of the collection. pub fn collection_owner(collection: T::CollectionId) -> Option { Collection::::get(collection).map(|i| i.owner) } /// Get the total number of items in the collection, if the collection exists. + /// + /// - `collection`: The identifier of the collection. pub fn collection_items(collection: T::CollectionId) -> Option { Collection::::get(collection).map(|i| i.items) } /// Get the metadata of the collection item. + /// + /// - `collection`: The identifier of the collection. + /// - `item`: The identifier of the collection item. pub fn item_metadata( collection: T::CollectionId, item: T::ItemId, diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 3c224eea..494c2b25 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -39,9 +39,9 @@ use sp_runtime::{ use crate::{mock::*, Event, SystemConfig, *}; -type CollectionId = ::CollectionId; +type CollectionId = ::CollectionId; type AccountIdOf = ::AccountId; -type WeightOf = ::WeightInfo; +type WeightOf = ::WeightInfo; fn account(id: u8) -> AccountIdOf { [id; 32].into() diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index f55b7169..0ff2a0cf 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) + // Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index f55b7169..0ff2a0cf 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,7 +30,7 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - /// Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) + // Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); From 6ef9b32a63664c245c7bea5467997102fc1b5778 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:55:31 +0700 Subject: [PATCH 78/99] chore: verify benchmarks with storage checks --- pallets/nfts/src/benchmarking.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index bc7caa6c..b70fcb0e 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -669,7 +669,8 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Signed(caller.clone()), collection, n) verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone()}.into()); + assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); } force_clear_collection_approvals { @@ -687,7 +688,8 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Root, caller_lookup, collection, n) verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone()}.into()); + assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); } set_accept_ownership { From 0076a3b06fbe291d0cff3e25f372d1a9220c2848 Mon Sep 17 00:00:00 2001 From: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:46:34 +0100 Subject: [PATCH 79/99] refactor: tests (#405) Co-authored-by: Tin Chung <56880684+chungquantin@users.noreply.github.com> --- pallets/nfts/src/tests.rs | 420 ++++++++++++++++++-------------------- 1 file changed, 198 insertions(+), 222 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 494c2b25..ac16c456 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -39,9 +39,11 @@ use sp_runtime::{ use crate::{mock::*, Event, SystemConfig, *}; -type CollectionId = ::CollectionId; type AccountIdOf = ::AccountId; -type WeightOf = ::WeightInfo; +type CollectionApprovals = crate::CollectionApprovals; +type CollectionApprovalDeposit = ::CollectionApprovalDeposit; +type CollectionId = ::CollectionId; +type WeightOf = ::WeightInfo; fn account(id: u8) -> AccountIdOf { [id; 32].into() @@ -164,44 +166,51 @@ fn item_config_from_disabled_settings(settings: BitFlags) -> ItemCo fn clear_collection_approvals( origin: RuntimeOrigin, - maybe_owner: Option, + maybe_owner: Option<&AccountId>, collection: CollectionId, limit: u32, ) -> DispatchResultWithPostInfo { match maybe_owner { - Some(owner) => Nfts::force_clear_collection_approvals(origin, owner, collection, limit), + Some(owner) => + Nfts::force_clear_collection_approvals(origin, owner.clone(), collection, limit), None => Nfts::clear_collection_approvals(origin, collection, limit), } } fn approve_collection_transfer( origin: RuntimeOrigin, - maybe_owner: Option, + maybe_owner: Option<&AccountId>, collection: CollectionId, - delegate: AccountIdOf, + delegate: &AccountId, maybe_deadline: Option>, ) -> DispatchResult { match maybe_owner { Some(owner) => Nfts::force_approve_collection_transfer( origin, - owner, + owner.clone(), collection, - delegate, + delegate.clone(), maybe_deadline, ), - None => Nfts::approve_collection_transfer(origin, collection, delegate, maybe_deadline), + None => + Nfts::approve_collection_transfer(origin, collection, delegate.clone(), maybe_deadline), } } fn cancel_collection_approval( origin: RuntimeOrigin, - maybe_owner: Option, + maybe_owner: Option<&AccountId>, collection: CollectionId, - delegate: AccountIdOf, + delegate: &AccountId, ) -> DispatchResult { match maybe_owner { - Some(owner) => Nfts::force_cancel_collection_approval(origin, owner, collection, delegate), - None => Nfts::cancel_collection_approval(origin, collection, delegate), + Some(owner) => Nfts::force_cancel_collection_approval( + origin, + owner.clone(), + collection, + delegate.clone(), + ), + None => Nfts::cancel_collection_approval(origin, collection, delegate.clone()), } } @@ -2415,7 +2424,7 @@ fn cancel_collection_approval_works() { // Parameters for `cancel_collection_approval`. (RuntimeOrigin::signed(item_owner.clone()), None), // Parameters for `force_cancel_collection_approval`. - (root(), Some(item_owner.clone())), + (root(), Some(&item_owner)), ] { assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -2423,15 +2432,18 @@ fn cancel_collection_approval_works() { delegate.clone(), None )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - + // Cancel an approval for a non existing collection. + assert_noop!( + cancel_collection_approval(origin.clone(), maybe_owner, 1, &delegate), + Error::::Unapproved + ); // Cancel an unapproved delegate. assert_noop!( cancel_collection_approval( origin.clone(), - maybe_owner.clone(), - 1, - delegate.clone() + maybe_owner, + collection_id, + &account(69), ), Error::::Unapproved ); @@ -2439,31 +2451,20 @@ fn cancel_collection_approval_works() { // Successfully cancel a collection approval. assert_ok!(cancel_collection_approval( origin.clone(), - maybe_owner.clone(), + maybe_owner, collection_id, - delegate.clone() + &delegate )); assert_eq!(Balances::reserved_balance(&item_owner), 0); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone() - })); - assert!(!CollectionApprovals::::contains_key(( - collection_id, - item_owner.clone(), - delegate.clone() - ))); - - assert_noop!( - Nfts::transfer( - RuntimeOrigin::signed(delegate.clone()), - collection_id, - item_id, - account(4) - ), - Error::::NoPermission + assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); + System::assert_last_event( + Event::::ApprovalCancelled { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + } + .into(), ); } }); @@ -2577,8 +2578,9 @@ fn approvals_limit_works() { #[test] fn approve_collection_transfer_works() { new_test_ext().execute_with(|| { - let (collection_id, locked_collection_id) = (0, 1); + let mut collection_id = 0; let collection_owner = account(1); + let deadline: BlockNumberFor = 20; let delegate = account(3); let item_id = 42; let item_owner = account(2); @@ -2604,136 +2606,120 @@ fn approve_collection_transfer_works() { ); } + // Provide balance to accounts. Balances::make_free_balance_be(&item_owner, 100); Balances::make_free_balance_be(&delegate, 100); - // Approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - - // Force-approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - - // Approve collection without items, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - - // Force-approve collection without items, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - locked_collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - for (origin, maybe_item_owner) in [ // Parameters for `approve_collection_transfer`. (RuntimeOrigin::signed(item_owner.clone()), None), // Parameters for `force_approve_collection_transfer`. - (root(), Some(item_owner.clone())), + (root(), Some(&item_owner)), ] { - // Throws error `Error::ItemsNonTransferable`. - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(collection_owner.clone()), - locked_collection_id, - CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) - )); + // Approve unknown collection, throws error `Error::NoItemOwned`. assert_noop!( approve_collection_transfer( origin.clone(), - maybe_item_owner.clone(), - locked_collection_id, - delegate.clone(), + maybe_item_owner, + collection_id, + &delegate, None ), - Error::::ItemsNonTransferable + Error::::NoItemOwned ); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); - assert_ok!(approve_collection_transfer( - origin.clone(), - maybe_item_owner.clone(), + // Approve collection without items, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), collection_id, - delegate.clone(), - None + item_id, + item_owner.clone(), + default_item_config() )); - assert!(events().contains(&Event::::TransferApproved { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline: None, - })); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - // Approve same delegate again not updating the total reserved funds. - assert_ok!(approve_collection_transfer( - origin.clone(), - maybe_item_owner.clone(), + // Approving a collection to a delegate with: + // 1. no deadline. + // 2. no deadline, again. + // 3. deadline. + // 3. equal deadline. + // 4. larger deadline. + // 5. smaller deadline. + // 6. no deadline, again. + // + // This tests all cases of approving the same delegate. + for deadline in [ + None, + None, + Some(deadline), + Some(deadline), + Some(deadline * 2), + Some(deadline), + None, + ] { + assert_ok!(approve_collection_transfer( + origin.clone(), + maybe_item_owner, + collection_id, + &delegate, + deadline, + )); + let deadline = deadline.map(|d| d + 1); + System::assert_last_event( + Event::::TransferApproved { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline, + } + .into(), + ); + assert_eq!(Balances::reserved_balance(&item_owner), 1); + assert_eq!( + CollectionApprovals::get((collection_id, &item_owner, &delegate)), + Some((deadline, CollectionApprovalDeposit::get())) + ); + } + + // Set collection settings to non transferable, throws error + // `Error::ItemsNonTransferable`. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner.clone()), collection_id, - delegate.clone(), - None + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); - assert_eq!(Balances::reserved_balance(&item_owner), 1); + assert_noop!( + approve_collection_transfer( + origin.clone(), + maybe_item_owner, + collection_id, + &delegate, + None + ), + Error::::ItemsNonTransferable + ); - // Clean up. + // To reset reserved balance. assert_ok!(Nfts::cancel_collection_approval( RuntimeOrigin::signed(item_owner.clone()), collection_id, delegate.clone() )); + collection_id.saturating_inc(); } }); } @@ -2806,7 +2792,7 @@ fn cancel_approval_works_with_admin() { default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), collection_id, item_id, item_owner.clone(), @@ -2825,7 +2811,7 @@ fn cancel_approval_works_with_admin() { RuntimeOrigin::signed(item_owner.clone()), 1, item_id, - account(1) + collection_owner.clone() ), Error::::UnknownItem ); @@ -2834,7 +2820,7 @@ fn cancel_approval_works_with_admin() { RuntimeOrigin::signed(item_owner.clone()), collection_id, 43, - account(1) + collection_owner.clone() ), Error::::UnknownItem ); @@ -3075,7 +3061,7 @@ fn clear_all_transfer_approvals_works() { })); assert_eq!(approvals(collection_id, item_id), vec![]); assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, item_owner.clone())).count(), + CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), 0 ); @@ -3095,131 +3081,121 @@ fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { let balance = 100; let collection_id = 0; - let delegate_1 = account(3); - let delegate_2 = account(4); let item_id = 42; - let owner = account(1); + let item_owner = account(1); + let delegates = 10..20; // Origin checks for the `clear_collection_approvals`. for origin in [root(), none()] { assert_noop!( Nfts::clear_collection_approvals(origin, collection_id, 0), - BadOrigin.with_weight(WeightOf::::clear_collection_approvals(0)) + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) ); } // Origin checks for the `force_clear_collection_approvals`. - for origin in [RuntimeOrigin::signed(owner.clone()), none()] { + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { assert_noop!( - Nfts::force_clear_collection_approvals(origin, owner.clone(), collection_id, 0), - BadOrigin.with_weight(WeightOf::::clear_collection_approvals(0)) + Nfts::force_clear_collection_approvals( + origin, + item_owner.clone(), + collection_id, + 0 + ), + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) ); } assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - owner.clone(), + item_owner.clone(), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id, - owner.clone(), + item_owner.clone(), default_item_config() )); + Balances::make_free_balance_be(&item_owner, balance); for (origin, maybe_owner) in [ // Parameters for `clear_collection_approvals`. - (root(), Some(owner.clone())), + (root(), Some(&item_owner)), // Parameters for `force_clear_collection_approvals`. - (RuntimeOrigin::signed(owner.clone()), None), + (RuntimeOrigin::signed(item_owner.clone()), None), ] { - Balances::make_free_balance_be(&owner, balance); + // Approve delegates. + let mut approvals = 0u64; + for i in delegates.clone() { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + account(i), + None + )); + approvals.saturating_inc(); + } - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate_1.clone(), - None - )); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate_2.clone(), - None - )); - // Removes zero collection approval. + // Remove zero collection approvals. assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 0), - Ok(Some(WeightOf::::clear_collection_approvals(0)).into()) + clear_collection_approvals(origin.clone(), maybe_owner, collection_id, 0), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) ); - assert_eq!(Balances::free_balance(&owner), balance - 2); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals); assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 2 + CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), + approvals as usize ); assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, - owner: owner.clone(), + owner: item_owner.clone(), })); - // Partially removes collection approvals. + // Partially remove collection approvals. assert_eq!( clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), - Ok(Some(WeightOf::::clear_collection_approvals(1)).into()) + Ok(Some(WeightOf::clear_collection_approvals(1)).into()) ); - assert_eq!(Balances::free_balance(&owner), balance - 1); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals + 1); assert_eq!( - CollectionApprovals::::iter_prefix((collection_id, owner.clone())).count(), - 1 - ); - - // Successfully removes all collection approvals. Only charges post-dispatch weight for - // the removed approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::::clear_collection_approvals(1)).into()) + CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), + approvals as usize - 1 ); assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, - owner: owner.clone(), + owner: item_owner.clone(), })); - assert_eq!(Balances::free_balance(&owner), balance); - assert!(CollectionApprovals::::iter_prefix((collection_id, owner.clone())) - .count() - .is_zero()); - // Emitting no event if zero approvals removed. + // Successfully remove all collection approvals. Only charges post-dispatch weight for + // the removed approvals. assert_eq!( clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::::clear_collection_approvals(0)).into()) + Ok(Some(WeightOf::clear_collection_approvals(9)).into()) ); - assert!(!events().contains(&Event::::ApprovalsCancelled { + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) + .count() + .is_zero()); + assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, item: None, - owner: owner.clone(), + owner: item_owner.clone(), })); - - assert_noop!( - Nfts::transfer( - RuntimeOrigin::signed(delegate_1.clone()), - collection_id, - item_id, - account(5) - ), - Error::::NoPermission - ); - assert_noop!( - Nfts::transfer( - RuntimeOrigin::signed(delegate_2.clone()), - collection_id, - item_id, - account(5) - ), - Error::::NoPermission - ); + // Ensure delegates are not able to transfer. + for i in delegates.clone() { + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(account(i)), + collection_id, + item_id, + account(5) + ), + Error::::NoPermission + ); + } } }); } From 4cd8dd51b29a8ca299bfd6a8199a5316533b8980 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:55:47 +0700 Subject: [PATCH 80/99] chore: revert formatting --- pallets/nfts/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index b70fcb0e..9881f2ed 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -75,7 +75,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(), From 2ea60c0e9d65e71f15b6653a108889bc4bb10a1c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 16 Dec 2024 08:32:49 +0700 Subject: [PATCH 81/99] chore: revert unnecessary change --- pallets/nfts/src/tests.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index ac16c456..1d195913 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2539,6 +2539,16 @@ fn approving_multiple_accounts_works() { approvals(0, 42), vec![(account(3), None), (account(4), None), (account(5), Some(current_block + 2))] ); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(6))); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(7)), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(5)), 0, 42, account(8)), + Error::::NoPermission + ); }); } From 829b433ccf2730516f3d834e2cd749a9979b5c38 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:05:12 +0700 Subject: [PATCH 82/99] refactor: dispatchables & events --- pallets/nfts/src/lib.rs | 356 ++++++++++++++++++++-------------------- 1 file changed, 178 insertions(+), 178 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 705ae52b..13bc1995 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -415,6 +415,18 @@ pub mod pallet { pub type CollectionConfigOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; + /// Config of an item. + #[pallet::storage] + pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemConfig, + OptionQuery, + >; + /// Number of collection items owned by an account. #[pallet::storage] pub type AccountBalance, I: 'static = ()> = StorageDoubleMap< @@ -439,18 +451,6 @@ pub mod pallet { (Option>, DepositBalanceOf), >; - /// Config of an item. - #[pallet::storage] - pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< - _, - Blake2_128Concat, - T::CollectionId, - Blake2_128Concat, - T::ItemId, - ItemConfig, - OptionQuery, - >; - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] #[allow(missing_docs)] @@ -511,12 +511,6 @@ pub mod pallet { owner: T::AccountId, delegate: T::AccountId, }, - /// Multiple approvals of a collection or item were cancelled. - ApprovalsCancelled { - collection: T::CollectionId, - item: Option, - owner: T::AccountId, - }, /// All approvals of a collection or item were cancelled. AllApprovalsCancelled { collection: T::CollectionId, @@ -642,6 +636,12 @@ pub mod pallet { attribute: PalletAttributes, value: BoundedVec, }, + /// Multiple approvals of a collection or item were cancelled. + ApprovalsCancelled { + collection: T::CollectionId, + item: Option, + owner: T::AccountId, + }, } #[pallet::error] @@ -1372,65 +1372,6 @@ pub mod pallet { ) } - /// Approve collection items owned by the origin to be transferred by a delegated - /// third-party account. This function reserves the required deposit - /// `CollectionApprovalDeposit` from the `origin` account. - /// - /// Origin must be Signed. - /// - /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `delegate`: The account to delegate permission to transfer collection items owned by - /// the origin. - /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the - /// number of blocks after which the approval will expire - /// - /// Emits `TransferApproved` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(39)] - #[pallet::weight(T::WeightInfo::approve_collection_transfer())] - pub fn approve_collection_transfer( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - maybe_deadline: Option>, - ) -> DispatchResult { - let origin = ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_collection_transfer(origin, collection, delegate, maybe_deadline) - } - - /// Force-approve collection items owned by the `owner` to be transferred by a delegated - /// third-party account. This function reserves the required deposit - /// `CollectionApprovalDeposit` from the `owner` account. - /// - /// Origin must be the `ForceOrigin`. - /// - /// - `owner`: The owner of the collection items to be force-approved by the `origin`. - /// - `collection`: The collection of the item to be approved for delegated transfer. - /// - `delegate`: The account to delegate permission to transfer collection items owned by - /// the `owner`. - /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the - /// number of blocks after which the approval will expire. - /// - /// Emits `TransferApproved` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(40)] - #[pallet::weight(T::WeightInfo::force_approve_collection_transfer())] - pub fn force_approve_collection_transfer( - origin: OriginFor, - owner: AccountIdLookupOf, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - maybe_deadline: Option>, - ) -> DispatchResult { - T::ForceOrigin::ensure_origin(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - let owner = T::Lookup::lookup(owner)?; - Self::do_approve_collection_transfer(owner, collection, delegate, maybe_deadline) - } - /// Cancel one of the transfer approvals for a specific item. /// /// Origin must be either: @@ -1460,55 +1401,6 @@ pub mod pallet { Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) } - /// Cancel a collection approval. - /// - /// Origin must be Signed. - /// - /// Arguments: - /// - `collection`: The collection whose approval will be cancelled. - /// - `delegate`: The account that is going to lose their approval. - /// - /// Emits `ApprovalCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(41)] - #[pallet::weight(T::WeightInfo::cancel_collection_approval())] - pub fn cancel_collection_approval( - origin: OriginFor, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - let origin = ensure_signed(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - Self::do_cancel_collection_approval(origin, collection, delegate) - } - - /// Force-cancel a collection approval granted by `owner` account. - /// - /// Origin must be `ForceOrigin`. - /// - /// Arguments: - /// - `owner`: The owner of the approval to be force-cancelled by the `origin`. - /// - `collection`: The collection of whose approval will be cancelled. - /// - `delegate`: The account that is going to lose their approval. - /// - /// Emits `ApprovalCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(42)] - #[pallet::weight(T::WeightInfo::force_cancel_collection_approval())] - pub fn force_cancel_collection_approval( - origin: OriginFor, - owner: AccountIdLookupOf, - collection: T::CollectionId, - delegate: AccountIdLookupOf, - ) -> DispatchResult { - T::ForceOrigin::ensure_origin(origin)?; - let delegate = T::Lookup::lookup(delegate)?; - let owner = T::Lookup::lookup(owner)?; - Self::do_cancel_collection_approval(owner, collection, delegate) - } - /// Cancel all the approvals of a specific item. /// /// Origin must be either: @@ -1535,58 +1427,6 @@ pub mod pallet { Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) } - /// Cancel all collection approvals, up to a specified limit. - /// - /// Origin must be Signed. - /// - /// Arguments: - /// - `collection`: The collection whose approvals will be cleared. - /// - `limit`: The amount of collection approvals that will be cleared. - /// - /// Emits `ApprovalsCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(43)] - #[pallet::weight(T::WeightInfo::clear_collection_approvals(*limit))] - pub fn clear_collection_approvals( - origin: OriginFor, - collection: T::CollectionId, - limit: u32, - ) -> DispatchResultWithPostInfo { - let origin = ensure_signed(origin) - .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; - let removed_approvals = Self::do_clear_collection_approvals(origin, collection, limit)?; - Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) - } - - /// Force-cancel all collection approvals granted by `owner` account, up to a specified - /// limit. - /// - /// Origin must be `ForceOrigin`. - /// - /// Arguments: - /// - `owner`: The owner of the approvals to be force-cancelled by the `origin`. - /// - `collection`: The collection whose approvals will be cleared. - /// - `limit`: The amount of collection approvals that will be cleared. - /// - /// Emits `ApprovalsCancelled` on success. - /// - /// Weight: `O(1)` - #[pallet::call_index(44)] - #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(*limit))] - pub fn force_clear_collection_approvals( - origin: OriginFor, - owner: AccountIdLookupOf, - collection: T::CollectionId, - limit: u32, - ) -> DispatchResultWithPostInfo { - T::ForceOrigin::ensure_origin(origin) - .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; - let owner = T::Lookup::lookup(owner)?; - let removed_approvals = Self::do_clear_collection_approvals(owner, collection, limit)?; - Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) - } - /// Disallows changing the metadata or attributes of the item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin @@ -2154,6 +1994,166 @@ pub mod pallet { Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } + + /// Approve collection items owned by the origin to be transferred by a delegated + /// third-party account. This function reserves the required deposit + /// `CollectionApprovalDeposit` from the `origin` account. + /// + /// Origin must be Signed. + /// + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer collection items owned by + /// the origin. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(39)] + #[pallet::weight(T::WeightInfo::approve_collection_transfer())] + pub fn approve_collection_transfer( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + maybe_deadline: Option>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_collection_transfer(origin, collection, delegate, maybe_deadline) + } + + /// Force-approve collection items owned by the `owner` to be transferred by a delegated + /// third-party account. This function reserves the required deposit + /// `CollectionApprovalDeposit` from the `owner` account. + /// + /// Origin must be the `ForceOrigin`. + /// + /// - `owner`: The owner of the collection items to be force-approved by the `origin`. + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer collection items owned by + /// the `owner`. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire. + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(40)] + #[pallet::weight(T::WeightInfo::force_approve_collection_transfer())] + pub fn force_approve_collection_transfer( + origin: OriginFor, + owner: AccountIdLookupOf, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + maybe_deadline: Option>, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + let owner = T::Lookup::lookup(owner)?; + Self::do_approve_collection_transfer(owner, collection, delegate, maybe_deadline) + } + + /// Cancel a collection approval. + /// + /// Origin must be Signed. + /// + /// Arguments: + /// - `collection`: The collection whose approval will be cancelled. + /// - `delegate`: The account that is going to lose their approval. + /// + /// Emits `ApprovalCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(41)] + #[pallet::weight(T::WeightInfo::cancel_collection_approval())] + pub fn cancel_collection_approval( + origin: OriginFor, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_collection_approval(origin, collection, delegate) + } + + /// Force-cancel a collection approval granted by `owner` account. + /// + /// Origin must be `ForceOrigin`. + /// + /// Arguments: + /// - `owner`: The owner of the approval to be force-cancelled by the `origin`. + /// - `collection`: The collection of whose approval will be cancelled. + /// - `delegate`: The account that is going to lose their approval. + /// + /// Emits `ApprovalCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(42)] + #[pallet::weight(T::WeightInfo::force_cancel_collection_approval())] + pub fn force_cancel_collection_approval( + origin: OriginFor, + owner: AccountIdLookupOf, + collection: T::CollectionId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + let owner = T::Lookup::lookup(owner)?; + Self::do_cancel_collection_approval(owner, collection, delegate) + } + + /// Cancel all collection approvals, up to a specified limit. + /// + /// Origin must be Signed. + /// + /// Arguments: + /// - `collection`: The collection whose approvals will be cleared. + /// - `limit`: The amount of collection approvals that will be cleared. + /// + /// Emits `ApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(43)] + #[pallet::weight(T::WeightInfo::clear_collection_approvals(*limit))] + pub fn clear_collection_approvals( + origin: OriginFor, + collection: T::CollectionId, + limit: u32, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin) + .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; + let removed_approvals = Self::do_clear_collection_approvals(origin, collection, limit)?; + Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) + } + + /// Force-cancel all collection approvals granted by `owner` account, up to a specified + /// limit. + /// + /// Origin must be `ForceOrigin`. + /// + /// Arguments: + /// - `owner`: The owner of the approvals to be force-cancelled by the `origin`. + /// - `collection`: The collection whose approvals will be cleared. + /// - `limit`: The amount of collection approvals that will be cleared. + /// + /// Emits `ApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(44)] + #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(*limit))] + pub fn force_clear_collection_approvals( + origin: OriginFor, + owner: AccountIdLookupOf, + collection: T::CollectionId, + limit: u32, + ) -> DispatchResultWithPostInfo { + T::ForceOrigin::ensure_origin(origin) + .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; + let owner = T::Lookup::lookup(owner)?; + let removed_approvals = Self::do_clear_collection_approvals(owner, collection, limit)?; + Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) + } } } From 9af5e24ea774b8cf122629bb511b7db6c10201c7 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:38:49 +0700 Subject: [PATCH 83/99] chore: add new field in ApprovalsCancelled and refactored events --- pallets/nfts/src/benchmarking.rs | 4 ++-- pallets/nfts/src/features/approvals.rs | 7 ++++++- pallets/nfts/src/lib.rs | 1 + pallets/nfts/src/tests.rs | 9 ++++++--- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index 9881f2ed..ba111276 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -669,7 +669,7 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Signed(caller.clone()), collection, n) verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone()}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone(), approvals: n}.into()); assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); } @@ -688,7 +688,7 @@ benchmarks_instance_pallet! { } }: _(SystemOrigin::Root, caller_lookup, collection, n) verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone()}.into()); + assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone(), approvals: n}.into()); assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 8a740f39..f591a90e 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -306,7 +306,12 @@ impl, I: 'static> Pallet { if removed_approvals > 0 { T::Currency::unreserve(&owner, deposits); - Self::deposit_event(Event::ApprovalsCancelled { collection, item: None, owner }); + Self::deposit_event(Event::ApprovalsCancelled { + collection, + item: None, + owner, + approvals: removed_approvals, + }); } Ok(removed_approvals) } diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 13bc1995..4707f05e 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -641,6 +641,7 @@ pub mod pallet { collection: T::CollectionId, item: Option, owner: T::AccountId, + approvals: u32, }, } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 1d195913..9372d0d3 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -3136,7 +3136,7 @@ fn clear_collection_approvals_works() { (RuntimeOrigin::signed(item_owner.clone()), None), ] { // Approve delegates. - let mut approvals = 0u64; + let mut approvals = 0u32; for i in delegates.clone() { assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -3152,7 +3152,7 @@ fn clear_collection_approvals_works() { clear_collection_approvals(origin.clone(), maybe_owner, collection_id, 0), Ok(Some(WeightOf::clear_collection_approvals(0)).into()) ); - assert_eq!(Balances::free_balance(&item_owner), balance - approvals); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); assert_eq!( CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), approvals as usize @@ -3161,6 +3161,7 @@ fn clear_collection_approvals_works() { collection: collection_id, item: None, owner: item_owner.clone(), + approvals })); // Partially remove collection approvals. @@ -3168,7 +3169,7 @@ fn clear_collection_approvals_works() { clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), Ok(Some(WeightOf::clear_collection_approvals(1)).into()) ); - assert_eq!(Balances::free_balance(&item_owner), balance - approvals + 1); + assert_eq!(Balances::free_balance(&item_owner), balance - (approvals as u64) + 1); assert_eq!( CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), approvals as usize - 1 @@ -3177,6 +3178,7 @@ fn clear_collection_approvals_works() { collection: collection_id, item: None, owner: item_owner.clone(), + approvals: 1 })); // Successfully remove all collection approvals. Only charges post-dispatch weight for @@ -3193,6 +3195,7 @@ fn clear_collection_approvals_works() { collection: collection_id, item: None, owner: item_owner.clone(), + approvals: approvals - 1 })); // Ensure delegates are not able to transfer. for i in delegates.clone() { From 87aa08e0b1f5aa6670b6b2fe1f007612dfe44441 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:43:55 +0700 Subject: [PATCH 84/99] chore: comments --- pallets/nfts/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 4707f05e..bea1b098 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -2002,7 +2002,7 @@ pub mod pallet { /// /// Origin must be Signed. /// - /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `collection`: The collection of the items to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer collection items owned by /// the origin. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the @@ -2031,7 +2031,7 @@ pub mod pallet { /// Origin must be the `ForceOrigin`. /// /// - `owner`: The owner of the collection items to be force-approved by the `origin`. - /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `collection`: The collection of the items to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer collection items owned by /// the `owner`. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the @@ -2084,7 +2084,7 @@ pub mod pallet { /// /// Arguments: /// - `owner`: The owner of the approval to be force-cancelled by the `origin`. - /// - `collection`: The collection of whose approval will be cancelled. + /// - `collection`: The collection whose approval will be cancelled. /// - `delegate`: The account that is going to lose their approval. /// /// Emits `ApprovalCancelled` on success. From c1b46c1ff8254f0c16a7756610291f14e9ea37ed Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:20:51 +0700 Subject: [PATCH 85/99] chore: remove zero collection approvals --- pallets/nfts/src/features/approvals.rs | 16 +++++++--------- pallets/nfts/src/tests.rs | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index f591a90e..b6867f0d 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -304,15 +304,13 @@ impl, I: 'static> Pallet { } } - if removed_approvals > 0 { - T::Currency::unreserve(&owner, deposits); - Self::deposit_event(Event::ApprovalsCancelled { - collection, - item: None, - owner, - approvals: removed_approvals, - }); - } + T::Currency::unreserve(&owner, deposits); + Self::deposit_event(Event::ApprovalsCancelled { + collection, + item: None, + owner, + approvals: removed_approvals, + }); Ok(removed_approvals) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 9372d0d3..0ff60dc0 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -3197,6 +3197,20 @@ fn clear_collection_approvals_works() { owner: item_owner.clone(), approvals: approvals - 1 })); + + // Remove zero collection approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + item: None, + owner: item_owner.clone(), + approvals: 0 + })); + // Ensure delegates are not able to transfer. for i in delegates.clone() { assert_noop!( From 11d60a137449a86da563d25dacf6a3b4c527fe6b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:07:10 +0700 Subject: [PATCH 86/99] chore: resolve comments --- pallets/nfts/README.md | 6 +- pallets/nfts/src/benchmarking.rs | 172 +++++++++++------------ pallets/nfts/src/features/approvals.rs | 22 ++- pallets/nfts/src/features/atomic_swap.rs | 3 +- pallets/nfts/src/features/transfer.rs | 12 +- pallets/nfts/src/lib.rs | 37 ++--- pallets/nfts/src/tests.rs | 6 +- 7 files changed, 122 insertions(+), 136 deletions(-) diff --git a/pallets/nfts/README.md b/pallets/nfts/README.md index 93ed18cf..dcd03628 100644 --- a/pallets/nfts/README.md +++ b/pallets/nfts/README.md @@ -53,7 +53,7 @@ The NFTs pallet in Substrate is designed to make the following possible: * `approve_transfer`: Name a delegate who may authorize a transfer. * `approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the account. * `cancel_approval`: Revert the effects of a previous `approve_transfer`. -* `cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. +* `cancel_collection_approval`: Revert the effects of a previous `approve_collection_transfer`. * `approve_item_attributes`: Name a delegate who may change item's attributes within a namespace. * `cancel_item_attributes_approval`: Revert the effects of a previous `approve_item_attributes`. * `set_price`: Set the price for an item. @@ -99,8 +99,8 @@ The NFTs pallet in Substrate is designed to make the following possible: * `force_collection_config`: Change collection's config. * `force_set_attribute`: Set an attribute. * `force_approve_collection_transfer`: Name a delegate who may authorize a transfer of all collection items owned by the specified account. -* `force_cancel_collection_transfer`: Revert the effects of a previous `approve_collection_transfer`. -* `force_clear_collection_approvals`: Reverts the effects of all previous `approve_collection_transfer` calls for the collection. +* `force_cancel_collection_approval`: Revert the effects of a previous `approve_collection_transfer`. +* `force_clear_collection_approvals`: Revert the effects of all previous `approve_collection_transfer` calls for the collection. Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum and its associated variants for documentation on each function. diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index ba111276..bfe961e8 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -581,28 +581,6 @@ benchmarks_instance_pallet! { assert_last_event::(Event::TransferApproved { collection, item: Some(item), owner: caller, delegate, deadline: Some(deadline) }.into()); } - approve_collection_transfer { - let (collection, caller, _) = create_collection::(); - 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, delegate_lookup, Some(deadline)) - verify { - assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); - } - - force_approve_collection_transfer { - let (collection, caller, caller_lookup) = create_collection::(); - 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::Root, caller_lookup, collection, delegate_lookup, Some(deadline)) - verify { - assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); - } - cancel_approval { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -616,31 +594,6 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ApprovalCancelled { collection, item: Some(item), owner: caller, delegate }.into()); } - cancel_collection_approval { - let (collection, caller, _) = create_collection::(); - 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_collection_transfer(origin, collection, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Signed(caller.clone()), collection, delegate_lookup) - verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); - } - - force_cancel_collection_approval { - let (collection, caller, caller_lookup) = create_collection::(); - mint_item::(0); - let delegate: T::AccountId = account("delegate", 0, SEED); - let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); - Nfts::::approve_collection_transfer(SystemOrigin::Signed(caller.clone()).into(), collection, delegate_lookup.clone(), Some(deadline))?; - }: _(SystemOrigin::Root, caller_lookup, collection, delegate_lookup) - verify { - assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); - } - clear_all_transfer_approvals { let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); @@ -651,45 +604,7 @@ benchmarks_instance_pallet! { Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { - assert_last_event::(Event::AllApprovalsCancelled {collection, item: Some(item), owner: caller}.into()); - } - - clear_collection_approvals { - let n in 1 .. 1_000; - let (collection, caller, _) = create_collection::(); - mint_item::(0); - for i in 0 .. n { - let delegate: T::AccountId = account("delegate", i, SEED); - Nfts::::approve_collection_transfer( - SystemOrigin::Signed(caller.clone()).into(), - collection, - T::Lookup::unlookup(delegate), - Some(BlockNumberFor::::max_value()), - )?; - } - }: _(SystemOrigin::Signed(caller.clone()), collection, n) - verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone(), approvals: n}.into()); - assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); - } - - force_clear_collection_approvals { - let n in 1 .. 1_000; - let (collection, caller, caller_lookup) = create_collection::(); - mint_item::(0); - for i in 0 .. n { - let delegate: T::AccountId = account("delegate", i, SEED); - Nfts::::approve_collection_transfer( - SystemOrigin::Signed(caller.clone()).into(), - collection, - T::Lookup::unlookup(delegate), - Some(BlockNumberFor::::max_value()), - )?; - } - }: _(SystemOrigin::Root, caller_lookup, collection, n) - verify { - assert_last_event::(Event::ApprovalsCancelled {collection, item: None, owner: caller.clone(), approvals: n}.into()); - assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); + assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); } set_accept_ownership { @@ -961,5 +876,90 @@ benchmarks_instance_pallet! { ); } + approve_collection_transfer { + let (collection, caller, _) = create_collection::(); + 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, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + + force_approve_collection_transfer { + let (collection, caller, caller_lookup) = create_collection::(); + 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::Root, caller_lookup, collection, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item: None, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + + cancel_collection_approval { + let (collection, caller, _) = create_collection::(); + 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_collection_transfer(origin, collection, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); + } + + force_cancel_collection_approval { + let (collection, caller, caller_lookup) = create_collection::(); + mint_item::(0); + let delegate: T::AccountId = account("delegate", 0, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + let deadline = BlockNumberFor::::max_value(); + Nfts::::approve_collection_transfer(SystemOrigin::Signed(caller.clone()).into(), collection, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Root, caller_lookup, collection, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item: None, owner: caller, delegate }.into()); + } + + clear_collection_approvals { + let n in 1 .. 1_000; + let (collection, caller, _) = create_collection::(); + mint_item::(0); + for i in 0 .. n { + let delegate: T::AccountId = account("delegate", i, SEED); + Nfts::::approve_collection_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + T::Lookup::unlookup(delegate), + Some(BlockNumberFor::::max_value()), + )?; + } + }: _(SystemOrigin::Signed(caller.clone()), collection, n) + verify { + assert_last_event::(Event::ApprovalsCancelled {collection, owner: caller.clone(), approvals: n}.into()); + assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); + } + + force_clear_collection_approvals { + let n in 1 .. 1_000; + let (collection, caller, caller_lookup) = create_collection::(); + mint_item::(0); + for i in 0 .. n { + let delegate: T::AccountId = account("delegate", i, SEED); + Nfts::::approve_collection_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + T::Lookup::unlookup(delegate), + Some(BlockNumberFor::::max_value()), + )?; + } + }: _(SystemOrigin::Root, caller_lookup, collection, n) + verify { + assert_last_event::(Event::ApprovalsCancelled {collection, owner: caller.clone(), approvals: n}.into()); + assert!(CollectionApprovals::::iter_prefix((collection, caller,)).take(1).next().is_none()); + } + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index b6867f0d..e40fb6e8 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -66,8 +66,8 @@ impl, I: 'static> Pallet { ensure!(check_origin == details.owner, Error::::NoPermission); } - let now = frame_system::Pallet::::block_number(); - let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + let deadline = + maybe_deadline.map(|d| d.saturating_add(frame_system::Pallet::::block_number())); details .approvals @@ -181,7 +181,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::AllApprovalsCancelled { collection, - item: Some(item), + item, owner: details.owner, }); @@ -223,8 +223,8 @@ impl, I: 'static> Pallet { collection_config.is_setting_enabled(CollectionSetting::TransferableItems), Error::::ItemsNonTransferable ); - let now = frame_system::Pallet::::block_number(); - let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + let deadline = + maybe_deadline.map(|d| d.saturating_add(frame_system::Pallet::::block_number())); CollectionApprovals::::try_mutate_exists( (&collection, &owner, &delegate), @@ -278,7 +278,7 @@ impl, I: 'static> Pallet { /// Clears all collection approvals. /// /// This function is used to clear `limit` collection approvals for the - /// collection items of `owner`. After clearing all approvals, the deposit of each collection + /// collection items of `owner`. After clearing the approvals, the deposit of each collection /// approval is returned to the `owner` account and the `ApprovalsCancelled` event is /// emitted. /// @@ -296,18 +296,16 @@ impl, I: 'static> Pallet { let mut removed_approvals: u32 = 0; let mut deposits: BalanceOf = Zero::zero(); // Iterate and remove each collection approval, returning the deposit back to the `owner`. - for (_, (_, deposit)) in CollectionApprovals::::drain_prefix((collection, &owner)) { - deposits = deposits.saturating_add(deposit); + for (_, (_, deposit)) in + CollectionApprovals::::drain_prefix((collection, &owner)).take(limit as usize) + { + deposits.saturating_accrue(deposit); removed_approvals.saturating_inc(); - if removed_approvals == limit { - break; - } } T::Currency::unreserve(&owner, deposits); Self::deposit_event(Event::ApprovalsCancelled { collection, - item: None, owner, approvals: removed_approvals, }); diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 6c15f15a..75945d43 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -77,8 +77,7 @@ impl, I: 'static> Pallet { ), }; - let now = frame_system::Pallet::::block_number(); - let deadline = duration.saturating_add(now); + let deadline = duration.saturating_add(frame_system::Pallet::::block_number()); PendingSwapOf::::insert( offered_collection_id, diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index 9d1157fa..ffe0befe 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -18,7 +18,7 @@ //! This module contains helper methods to perform the transfer functionalities //! of the NFTs pallet. -use frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError}; +use frame_support::pallet_prelude::*; use crate::*; @@ -86,17 +86,17 @@ impl, I: 'static> Pallet { // Perform the transfer with custom details using the provided closure. with_details(&collection_details, &mut details)?; - // Update account balance of the destination account. - AccountBalance::::mutate(collection, &dest, |balance| { - balance.saturating_inc(); - }); // Update account balance of the owner. let balance = AccountBalance::::take(collection, &details.owner) .checked_sub(1) - .ok_or(ArithmeticError::Underflow)?; + .ok_or(Error::::NoItemOwned)?; if balance > 0 { AccountBalance::::insert(collection, &details.owner, balance); } + // Update account balance of the destination account. + AccountBalance::::mutate(collection, &dest, |balance| { + balance.saturating_inc(); + }); // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index bea1b098..2851e826 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -511,12 +511,8 @@ pub mod pallet { owner: T::AccountId, delegate: T::AccountId, }, - /// All approvals of a collection or item were cancelled. - AllApprovalsCancelled { - collection: T::CollectionId, - item: Option, - owner: T::AccountId, - }, + /// All approvals of an item were cancelled. + AllApprovalsCancelled { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, /// A `collection` has had its config changed by the `Force` origin. CollectionConfigChanged { collection: T::CollectionId }, /// New metadata has been set for a `collection`. @@ -636,13 +632,8 @@ pub mod pallet { attribute: PalletAttributes, value: BoundedVec, }, - /// Multiple approvals of a collection or item were cancelled. - ApprovalsCancelled { - collection: T::CollectionId, - item: Option, - owner: T::AccountId, - approvals: u32, - }, + /// Multiple approvals of a collection were cancelled. + ApprovalsCancelled { collection: T::CollectionId, owner: T::AccountId, approvals: u32 }, } #[pallet::error] @@ -1346,7 +1337,7 @@ pub mod pallet { /// - `item`: The item to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer the item. /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the - /// number of blocks after which the approval will expire + /// number of blocks after which the approval will expire. /// /// Emits `TransferApproved` on success. /// @@ -2011,7 +2002,7 @@ pub mod pallet { /// Emits `TransferApproved` on success. /// /// Weight: `O(1)` - #[pallet::call_index(39)] + #[pallet::call_index(50)] #[pallet::weight(T::WeightInfo::approve_collection_transfer())] pub fn approve_collection_transfer( origin: OriginFor, @@ -2040,7 +2031,7 @@ pub mod pallet { /// Emits `TransferApproved` on success. /// /// Weight: `O(1)` - #[pallet::call_index(40)] + #[pallet::call_index(51)] #[pallet::weight(T::WeightInfo::force_approve_collection_transfer())] pub fn force_approve_collection_transfer( origin: OriginFor, @@ -2066,7 +2057,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(41)] + #[pallet::call_index(52)] #[pallet::weight(T::WeightInfo::cancel_collection_approval())] pub fn cancel_collection_approval( origin: OriginFor, @@ -2090,7 +2081,7 @@ pub mod pallet { /// Emits `ApprovalCancelled` on success. /// /// Weight: `O(1)` - #[pallet::call_index(42)] + #[pallet::call_index(53)] #[pallet::weight(T::WeightInfo::force_cancel_collection_approval())] pub fn force_cancel_collection_approval( origin: OriginFor, @@ -2114,8 +2105,9 @@ pub mod pallet { /// /// Emits `ApprovalsCancelled` on success. /// - /// Weight: `O(1)` - #[pallet::call_index(43)] + /// Weight: `O(n)` where: + /// - `n = limit` + #[pallet::call_index(54)] #[pallet::weight(T::WeightInfo::clear_collection_approvals(*limit))] pub fn clear_collection_approvals( origin: OriginFor, @@ -2140,8 +2132,9 @@ pub mod pallet { /// /// Emits `ApprovalsCancelled` on success. /// - /// Weight: `O(1)` - #[pallet::call_index(44)] + /// Weight: `O(n)` where: + /// - `n = limit` + #[pallet::call_index(55)] #[pallet::weight(T::WeightInfo::force_clear_collection_approvals(*limit))] pub fn force_clear_collection_approvals( origin: OriginFor, diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 0ff60dc0..19ace89f 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -3066,7 +3066,7 @@ fn clear_all_transfer_approvals_works() { assert!(events().contains(&Event::::AllApprovalsCancelled { collection: collection_id, - item: Some(item_id), + item: item_id, owner: item_owner.clone(), })); assert_eq!(approvals(collection_id, item_id), vec![]); @@ -3159,7 +3159,6 @@ fn clear_collection_approvals_works() { ); assert!(!events().contains(&Event::::ApprovalsCancelled { collection: collection_id, - item: None, owner: item_owner.clone(), approvals })); @@ -3176,7 +3175,6 @@ fn clear_collection_approvals_works() { ); assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, - item: None, owner: item_owner.clone(), approvals: 1 })); @@ -3193,7 +3191,6 @@ fn clear_collection_approvals_works() { .is_zero()); assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, - item: None, owner: item_owner.clone(), approvals: approvals - 1 })); @@ -3206,7 +3203,6 @@ fn clear_collection_approvals_works() { assert_eq!(Balances::free_balance(&item_owner), balance); assert!(events().contains(&Event::::ApprovalsCancelled { collection: collection_id, - item: None, owner: item_owner.clone(), approvals: 0 })); From 24c0c2d484b98e8d7f199fba502d7d95d3ece8d5 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:32:15 +0700 Subject: [PATCH 87/99] chore: revert test changes --- pallets/nfts/src/tests.rs | 2045 +++++++++++++++++-------------------- 1 file changed, 914 insertions(+), 1131 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 19ace89f..f1c36c69 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -224,184 +224,125 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - let (collection_id_1, collection_id_2) = (0, 1); - let (item_id_1, item_id_2) = (42, 69); - let owner_1 = account(1); - let owner_2 = account(2); - assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - owner_1.clone(), + account(1), default_collection_config() )); - assert_eq!(collections(), vec![(owner_1.clone(), collection_id_1)]); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner_1.clone()), - collection_id_1, - item_id_1, - owner_1.clone(), - None - )); - assert_eq!(AccountBalance::::get(collection_id_1, &owner_1), 1); - assert_eq!(items(), vec![(owner_1.clone(), collection_id_1, item_id_1)]); + 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( RuntimeOrigin::root(), - owner_2.clone(), + account(2), default_collection_config() )); - assert_eq!( - collections(), - vec![(owner_1.clone(), collection_id_1), (owner_2.clone(), collection_id_2)] - ); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner_2), - collection_id_2, - item_id_2, - owner_1.clone(), - None - )); - assert_eq!(AccountBalance::::get(collection_id_2, &owner_1), 1); - assert_eq!( - items(), - vec![ - (owner_1.clone(), collection_id_1, item_id_1), - (owner_1, collection_id_2, item_id_2) - ] - ); + 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)]); }); } #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { - let collection_id = 0; - let owner = account(1); - - Balances::make_free_balance_be(&owner, 100); + Balances::make_free_balance_be(&account(1), 100); Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(owner.clone()), - owner.clone(), + RuntimeOrigin::signed(account(1)), + account(1), collection_config_with_all_settings_enabled() )); - assert_eq!(Balances::reserved_balance(&owner), 2); - assert_eq!(collections(), vec![(owner.clone(), collection_id)]); + assert_eq!(Balances::reserved_balance(&account(1)), 2); + assert_eq!(collections(), vec![(account(1), 0)]); assert_ok!(Nfts::set_collection_metadata( - RuntimeOrigin::signed(owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, bvec![0, 0] )); - assert_eq!(Balances::reserved_balance(&owner), 5); - assert!(CollectionMetadataOf::::contains_key(collection_id)); + assert_eq!(Balances::reserved_balance(&account(1)), 5); + assert!(CollectionMetadataOf::::contains_key(0)); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, 42, account(10), default_item_config() )); - assert_eq!(AccountBalance::::get(collection_id, account(10)), 1); - assert_eq!(Balances::reserved_balance(&owner), 6); + assert_eq!(Balances::reserved_balance(&account(1)), 6); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, 69, account(20), default_item_config() )); - assert_eq!(AccountBalance::::get(collection_id, account(20)), 1); - assert_eq!(Balances::reserved_balance(&owner), 7); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 70, - owner.clone(), - None - )); - assert_eq!(AccountBalance::::get(collection_id, &owner), 1); - assert_eq!( - items(), - vec![ - (owner.clone(), collection_id, 70), - (account(10), collection_id, 42), - (account(20), collection_id, 69) - ] - ); - assert_eq!(Collection::::get(collection_id).unwrap().items, 3); - assert_eq!(Collection::::get(collection_id).unwrap().item_metadatas, 0); - assert_eq!(Collection::::get(collection_id).unwrap().item_configs, 3); - - assert_eq!(Balances::reserved_balance(&owner), 8); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 70, - account(2) - )); - assert_eq!(AccountBalance::::get(collection_id, &owner), 0); - assert_eq!(AccountBalance::::get(collection_id, account(2)), 1); - assert_eq!(Balances::reserved_balance(&owner), 8); + 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); + assert_eq!(Collection::::get(0).unwrap().item_configs, 3); + + 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); - assert_ok!(Nfts::set_metadata( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 42, - bvec![42, 42] - )); - assert_eq!(Balances::reserved_balance(&owner), 11); - assert!(ItemMetadataOf::::contains_key(collection_id, 42)); - assert_ok!(Nfts::set_metadata( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 69, - bvec![69, 69] - )); - assert_eq!(Balances::reserved_balance(&owner), 14); - assert!(ItemMetadataOf::::contains_key(collection_id, 69)); - assert!(ItemConfigOf::::contains_key(collection_id, 69)); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); + assert_eq!(Balances::reserved_balance(&account(1)), 11); + assert!(ItemMetadataOf::::contains_key(0, 42)); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); + assert_eq!(Balances::reserved_balance(&account(1)), 14); + assert!(ItemMetadataOf::::contains_key(0, 69)); + assert!(ItemConfigOf::::contains_key(0, 69)); let w = Nfts::get_destroy_witness(&0).unwrap(); assert_eq!(w.item_metadatas, 2); assert_eq!(w.item_configs, 3); assert_noop!( - Nfts::destroy(RuntimeOrigin::signed(owner.clone()), collection_id, w), + Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), Error::::CollectionNotEmpty ); - assert_eq!(AccountBalance::::get(collection_id, &owner), 0); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, Some(69), AttributeNamespace::CollectionOwner, bvec![0], bvec![0], )); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), collection_id, 42)); - assert_eq!(AccountBalance::::get(collection_id, account(10)), 0); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), collection_id, 69)); - assert_eq!(AccountBalance::::get(collection_id, account(10)), 0); - assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 70)); + 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(20)), 0); + assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); - let w = Nfts::get_destroy_witness(&collection_id).unwrap(); + let w = Nfts::get_destroy_witness(&0).unwrap(); assert_eq!(w.attributes, 1); assert_eq!(w.item_metadatas, 0); assert_eq!(w.item_configs, 0); - assert_ok!(Nfts::destroy(RuntimeOrigin::signed(owner.clone()), collection_id, w)); - assert_eq!(AccountBalance::::get(collection_id, &owner), 0); - assert_eq!(Balances::reserved_balance(&owner), 0); - - assert!(!Collection::::contains_key(collection_id)); - assert!(!CollectionConfigOf::::contains_key(collection_id)); - assert!(!Item::::contains_key(collection_id, 42)); - assert!(!Item::::contains_key(collection_id, 69)); - assert!(!CollectionMetadataOf::::contains_key(collection_id)); - assert!(!ItemMetadataOf::::contains_key(collection_id, 42)); - assert!(!ItemMetadataOf::::contains_key(collection_id, 69)); - assert!(!ItemConfigOf::::contains_key(collection_id, 69)); - assert_eq!(attributes(collection_id), vec![]); + 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)); + assert!(!CollectionConfigOf::::contains_key(0)); + assert!(!Item::::contains_key(0, 42)); + assert!(!Item::::contains_key(0, 69)); + assert!(!CollectionMetadataOf::::contains_key(0)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 69)); + assert!(!ItemConfigOf::::contains_key(0, 69)); + assert_eq!(attributes(0), vec![]); assert_eq!(collections(), vec![]); assert_eq!(items(), vec![]); }); @@ -432,70 +373,54 @@ fn destroy_with_bad_witness_should_not_work() { #[test] fn destroy_should_work() { new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&collection_owner, 100); - Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(collection_owner.clone()), - collection_owner.clone(), + RuntimeOrigin::signed(account(1)), + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - None - )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + account(3), None )); assert_noop!( Nfts::destroy( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Nfts::get_destroy_witness(&collection_id).unwrap() + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() ), Error::::CollectionNotEmpty ); - assert_ok!(Nfts::lock_item_transfer( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id - )); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id)); - assert_eq!(Collection::::get(collection_id).unwrap().item_configs, 1); - assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 1); - assert!(ItemConfigOf::::contains_key(collection_id, item_id)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42)); + assert_eq!(Collection::::get(0).unwrap().item_configs, 1); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); + assert!(ItemConfigOf::::contains_key(0, 42)); assert_noop!( Nfts::destroy( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Nfts::get_destroy_witness(&collection_id).unwrap() + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() ), Error::::CollectionApprovalsExist ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner), - collection_id, - delegate + RuntimeOrigin::signed(account(2)), + 0, + account(3) )); assert_ok!(Nfts::destroy( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Nfts::get_destroy_witness(&collection_id).unwrap() + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() )); - assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); - assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, 0); + assert!(!ItemConfigOf::::contains_key(0, 42)); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); }); } @@ -1889,57 +1814,50 @@ fn force_update_collection_should_work() { #[test] fn burn_works() { new_test_ext().execute_with(|| { - let admin = account(2); - let collection_id = 0; - let collection_owner = account(1); - let item_id_1 = 42; - let item_id_2 = 69; - let item_owner = account(5); - - Balances::make_free_balance_be(&collection_owner, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), collection_config_with_all_settings_enabled() )); assert_ok!(Nfts::set_team( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Some(admin.clone()), + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), Some(account(3)), Some(account(4)), )); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1), + Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42), Error::::UnknownItem ); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(admin.clone()), - collection_id, - item_id_1, - item_owner.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(5), default_item_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(admin), - collection_id, - item_id_2, - item_owner.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 69, + account(5), default_item_config() )); - assert_eq!(AccountBalance::::get(collection_id, &item_owner), 2); - assert_eq!(Balances::reserved_balance(collection_owner.clone()), 2); + assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(0)), collection_id, item_id_1), + Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), Error::::NoPermission ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_1)); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(item_owner.clone()), collection_id, item_id_2)); - assert!(!AccountBalance::::contains_key(collection_id, &item_owner)); - assert_eq!(Balances::reserved_balance(collection_owner), 0); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); + assert!(!AccountBalance::::contains_key(0, &account(5))); + assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -2013,476 +1931,118 @@ fn approval_lifecycle_works() { } #[test] -fn check_approval_without_deadline_works() { +fn cancel_approval_works() { new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); - // Item doesn't exist. + 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, + 42, + account(3), + None + )); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), + Error::::UnknownItem ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - // No approval. assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::NoPermission + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), + Error::::NotDelegate ); - // Approve collection without deadline. - { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() - )); - } - // Approve item without deadline. - { - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - None - )); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - )); - } - // Approve collection and item without deadline. - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - None - )); + + // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection + // approval. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); - }); -} - -#[test] -fn check_approval_with_deadline_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&item_owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - // Approve collection with deadline. - { - let deadline: BlockNumberFor = 10; - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - Some(deadline), - )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - // Expire approval. - System::set_block_number(deadline + System::block_number() + 1); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::ApprovalExpired - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - )); - } - // Approve item with deadline. - { - let deadline: BlockNumberFor = 20; - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - Some(deadline), - )); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - // Expire approval. - System::set_block_number(deadline + System::block_number() + 1); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::ApprovalExpired - ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - )); - } - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::NoPermission - ); - }); -} - -#[test] -fn cancel_approval_works() { - new_test_ext().execute_with(|| { - let collection_owner = account(1); - let collection_id = 0; - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&item_owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + account(3), None )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 1, - item_id, - delegate.clone() - ), - Error::::UnknownItem - ); - assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - 43, - delegate.clone() - ), - Error::::UnknownItem - ); - assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(delegate.clone()), - collection_id, - item_id, - delegate.clone() - ), - Error::::NoPermission - ); - assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - account(4) - ), - Error::::NotDelegate - ); - - // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection - // approval. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::DelegateApprovalConflict ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() + RuntimeOrigin::signed(account(2)), + 0, + account(3) )); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: Some(item_id), - owner: item_owner.clone(), - delegate: delegate.clone() + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(3) })); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); let current_block = 1; System::set_block_number(current_block); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, 69, - item_owner.clone(), + account(2), default_item_config() )); // approval expires after 2 blocks. assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), Some(2) )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(account(5)), - collection_id, - item_id, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 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)), - collection_id, - item_id, - delegate.clone() - )); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: Some(item_id), - owner: item_owner, - delegate - })); - assert_eq!(approvals(collection_id, 69), vec![]); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); + assert_eq!(approvals(0, 69), vec![]); }); } #[test] -fn cancel_collection_approval_works() { +fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - // Origin checks for the `cancel_collection_approval`. - for origin in [root(), none()] { - assert_noop!( - Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), - BadOrigin - ); - } - // Origin checks for the `force_cancel_collection_approval`. - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_cancel_collection_approval( - origin, - item_owner.clone(), - collection_id, - delegate.clone() - ), - BadOrigin - ); - } - - Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - - for (origin, maybe_owner) in [ - // Parameters for `cancel_collection_approval`. - (RuntimeOrigin::signed(item_owner.clone()), None), - // Parameters for `force_cancel_collection_approval`. - (root(), Some(&item_owner)), - ] { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - // Cancel an approval for a non existing collection. - assert_noop!( - cancel_collection_approval(origin.clone(), maybe_owner, 1, &delegate), - Error::::Unapproved - ); - // Cancel an unapproved delegate. - assert_noop!( - cancel_collection_approval( - origin.clone(), - maybe_owner, - collection_id, - &account(69), - ), - Error::::Unapproved - ); - - // Successfully cancel a collection approval. - assert_ok!(cancel_collection_approval( - origin.clone(), - maybe_owner, - collection_id, - &delegate - )); - assert_eq!(Balances::reserved_balance(&item_owner), 0); - assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); - System::assert_last_event( - Event::::ApprovalCancelled { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - } - .into(), - ); - } - }); -} - -#[test] -fn approving_multiple_accounts_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), + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), default_item_config() )); @@ -2585,155 +2145,6 @@ fn approvals_limit_works() { }); } -#[test] -fn approve_collection_transfer_works() { - new_test_ext().execute_with(|| { - let mut collection_id = 0; - let collection_owner = account(1); - let deadline: BlockNumberFor = 20; - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - // Origin checks for the `approve_collection_transfer`. - for origin in [root(), none()] { - assert_noop!( - Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), - BadOrigin - ); - } - // Origin checks for the `force_approve_collection_transfer`. - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_approve_collection_transfer( - origin, - item_owner.clone(), - collection_id, - delegate.clone(), - None - ), - BadOrigin - ); - } - - // Provide balance to accounts. - Balances::make_free_balance_be(&item_owner, 100); - Balances::make_free_balance_be(&delegate, 100); - - for (origin, maybe_item_owner) in [ - // Parameters for `approve_collection_transfer`. - (RuntimeOrigin::signed(item_owner.clone()), None), - // Parameters for `force_approve_collection_transfer`. - (root(), Some(&item_owner)), - ] { - // Approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - approve_collection_transfer( - origin.clone(), - maybe_item_owner, - collection_id, - &delegate, - None - ), - Error::::NoItemOwned - ); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - - // Approve collection without items, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - - // Approving a collection to a delegate with: - // 1. no deadline. - // 2. no deadline, again. - // 3. deadline. - // 3. equal deadline. - // 4. larger deadline. - // 5. smaller deadline. - // 6. no deadline, again. - // - // This tests all cases of approving the same delegate. - for deadline in [ - None, - None, - Some(deadline), - Some(deadline), - Some(deadline * 2), - Some(deadline), - None, - ] { - assert_ok!(approve_collection_transfer( - origin.clone(), - maybe_item_owner, - collection_id, - &delegate, - deadline, - )); - let deadline = deadline.map(|d| d + 1); - System::assert_last_event( - Event::::TransferApproved { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline, - } - .into(), - ); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert_eq!( - CollectionApprovals::get((collection_id, &item_owner, &delegate)), - Some((deadline, CollectionApprovalDeposit::get())) - ); - } - - // Set collection settings to non transferable, throws error - // `Error::ItemsNonTransferable`. - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) - )); - assert_noop!( - approve_collection_transfer( - origin.clone(), - maybe_item_owner, - collection_id, - &delegate, - None - ), - Error::::ItemsNonTransferable - ); - - // To reset reserved balance. - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() - )); - collection_id.saturating_inc(); - } - }); -} - #[test] fn approval_deadline_works() { new_test_ext().execute_with(|| { @@ -2789,104 +2200,68 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - let collection_id = 0; - let collection_owner = account(1); - - Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), None )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - 1, - item_id, - collection_owner.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - 43, - collection_owner.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - account(4) - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection // approval. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + account(3), None )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::DelegateApprovalConflict ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() + RuntimeOrigin::signed(account(2)), + 0, + account(3) )); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: Some(item_id), - owner: item_owner.clone(), - delegate + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(3) })); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner), - collection_id, - item_id, - account(5) - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2895,88 +2270,67 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - let collection_owner = account(1); - let collection_id = 0; - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, item_id, collection_owner.clone()), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::root(), - collection_id, - 43, - collection_owner.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), collection_id, item_id, account(4)), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), Error::::NotDelegate ); // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection // approval. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), + RuntimeOrigin::signed(account(2)), + 0, + account(3), None )); assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - ), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::DelegateApprovalConflict ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() + RuntimeOrigin::signed(account(2)), + 0, + account(3) )); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::root(), - collection_id, - item_id, - delegate.clone() - )); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: Some(item_id), - owner: item_owner, - delegate + collection: 0, + item: Some(42), + owner: account(2), + delegate: account(3) })); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), collection_id, item_id, collection_owner), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -2985,326 +2339,138 @@ fn cancel_approval_works_with_force() { #[test] fn clear_all_transfer_approvals_works() { new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate_1 = account(3); - let delegate_2 = account(4); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&collection_owner, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - collection_owner.clone(), + account(1), default_collection_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, + RuntimeOrigin::signed(account(1)), + 0, 43, - collection_owner.clone(), + account(1), default_item_config() )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id, - item_owner.clone(), + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), default_item_config() )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate_1.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), None )); assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate_2.clone(), + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(4), None )); assert_noop!( - Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(delegate_1.clone()), - collection_id, - item_id - ), + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), Error::::NoPermission ); + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); + // Throws `DelegateApprovalConflict` if there are existing collection approvals. assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - delegate_1.clone(), + RuntimeOrigin::signed(account(1)), + 0, + account(3), None )); assert_noop!( - Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - item_id - ), + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, 42), Error::::DelegateApprovalConflict ); assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - delegate_1.clone() + RuntimeOrigin::signed(account(1)), + 0, + account(3) )); - assert_ok!(Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id - )); + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); assert!(events().contains(&Event::::AllApprovalsCancelled { - collection: collection_id, - item: item_id, - owner: item_owner.clone(), + collection: 0, + item: 42, + owner: account(2), })); - assert_eq!(approvals(collection_id, item_id), vec![]); - assert_eq!( - CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), - 0 - ); + assert_eq!(approvals(0, 42), vec![]); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_1), collection_id, item_id, account(5)), + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), Error::::NoPermission ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(delegate_2), collection_id, item_id, account(5)), + Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), Error::::NoPermission ); }); } #[test] -fn clear_collection_approvals_works() { +fn max_supply_should_work() { new_test_ext().execute_with(|| { - let balance = 100; let collection_id = 0; - let item_id = 42; - let item_owner = account(1); - let delegates = 10..20; - - // Origin checks for the `clear_collection_approvals`. - for origin in [root(), none()] { - assert_noop!( - Nfts::clear_collection_approvals(origin, collection_id, 0), - BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) - ); - } - // Origin checks for the `force_clear_collection_approvals`. - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_clear_collection_approvals( - origin, - item_owner.clone(), - collection_id, - 0 - ), - BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) - ); - } + let user_id = account(1); + let max_supply = 1; + // validate set_collection_max_supply assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - item_owner.clone(), + user_id.clone(), default_collection_config() )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(item_owner.clone()), + assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); + assert!(!events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), collection_id, - item_id, - item_owner.clone(), - default_item_config() + max_supply )); - Balances::make_free_balance_be(&item_owner, balance); - - for (origin, maybe_owner) in [ - // Parameters for `clear_collection_approvals`. - (root(), Some(&item_owner)), - // Parameters for `force_clear_collection_approvals`. - (RuntimeOrigin::signed(item_owner.clone()), None), - ] { - // Approve delegates. - let mut approvals = 0u32; - for i in delegates.clone() { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - account(i), - None - )); - approvals.saturating_inc(); - } + assert_eq!( + CollectionConfigOf::::get(collection_id).unwrap().max_supply, + Some(max_supply) + ); - // Remove zero collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner, collection_id, 0), - Ok(Some(WeightOf::clear_collection_approvals(0)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); - assert_eq!( - CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), - approvals as usize - ); - assert!(!events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals - })); + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); - // Partially remove collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), - Ok(Some(WeightOf::clear_collection_approvals(1)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance - (approvals as u64) + 1); - assert_eq!( - CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), - approvals as usize - 1 - ); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: 1 - })); - - // Successfully remove all collection approvals. Only charges post-dispatch weight for - // the removed approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::clear_collection_approvals(9)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance); - assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) - .count() - .is_zero()); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: approvals - 1 - })); - - // Remove zero collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::clear_collection_approvals(0)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: 0 - })); - - // Ensure delegates are not able to transfer. - for i in delegates.clone() { - assert_noop!( - Nfts::transfer( - RuntimeOrigin::signed(account(i)), - collection_id, - item_id, - account(5) - ), - Error::::NoPermission - ); - } - } - }); -} - -#[test] -fn collection_item_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let total_items = 10; - let user_id = account(1); - - // 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(|| { - let collection_id = 0; - let user_id = account(1); - let max_supply = 1; - - // validate set_collection_max_supply - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - user_id.clone(), - default_collection_config() - )); - assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); - assert!(!events().contains(&Event::::CollectionMaxSupplySet { - collection: collection_id, - max_supply, - })); - - assert_ok!(Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id.clone()), - collection_id, - max_supply - )); - assert_eq!( - CollectionConfigOf::::get(collection_id).unwrap().max_supply, - Some(max_supply) - ); - - assert!(events().contains(&Event::::CollectionMaxSupplySet { - collection: collection_id, - max_supply, - })); - - assert_ok!(Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id.clone()), - collection_id, - max_supply + 1 - )); - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(user_id.clone()), - collection_id, - CollectionSettings::from_disabled(CollectionSetting::UnlockedMaxSupply.into()) - )); - assert_noop!( - Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id.clone()), - collection_id, - max_supply + 2 - ), - Error::::MaxSupplyLocked - ); + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + max_supply + 1 + )); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMaxSupply.into()) + )); + assert_noop!( + Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + max_supply + 2 + ), + Error::::MaxSupplyLocked + ); // validate we can't mint more to max supply assert_ok!(Nfts::mint( @@ -4945,6 +4111,623 @@ fn clear_collection_metadata_works() { }); } +#[test] +fn collection_item_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let total_items = 10; + let user_id = account(1); + + // 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 clear_collection_approvals_works() { + new_test_ext().execute_with(|| { + let balance = 100; + let collection_id = 0; + let item_id = 42; + let item_owner = account(1); + let delegates = 10..20; + + // Origin checks for the `clear_collection_approvals`. + for origin in [root(), none()] { + assert_noop!( + Nfts::clear_collection_approvals(origin, collection_id, 0), + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) + ); + } + // Origin checks for the `force_clear_collection_approvals`. + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_clear_collection_approvals( + origin, + item_owner.clone(), + collection_id, + 0 + ), + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) + ); + } + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + item_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + Balances::make_free_balance_be(&item_owner, balance); + + for (origin, maybe_owner) in [ + // Parameters for `clear_collection_approvals`. + (root(), Some(&item_owner)), + // Parameters for `force_clear_collection_approvals`. + (RuntimeOrigin::signed(item_owner.clone()), None), + ] { + // Approve delegates. + let mut approvals = 0u32; + for i in delegates.clone() { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + account(i), + None + )); + approvals.saturating_inc(); + } + + // Remove zero collection approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner, collection_id, 0), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), + approvals as usize + ); + assert!(!events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals + })); + + // Partially remove collection approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), + Ok(Some(WeightOf::clear_collection_approvals(1)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance - (approvals as u64) + 1); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), + approvals as usize - 1 + ); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals: 1 + })); + + // Successfully remove all collection approvals. Only charges post-dispatch weight for + // the removed approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(9)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) + .count() + .is_zero()); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals: approvals - 1 + })); + + // Remove zero collection approvals. + assert_eq!( + clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals: 0 + })); + + // Ensure delegates are not able to transfer. + for i in delegates.clone() { + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(account(i)), + collection_id, + item_id, + account(5) + ), + Error::::NoPermission + ); + } + } + }); +} + +#[test] +fn approve_collection_transfer_works() { + new_test_ext().execute_with(|| { + let mut collection_id = 0; + let collection_owner = account(1); + let deadline: BlockNumberFor = 20; + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + // Origin checks for the `approve_collection_transfer`. + for origin in [root(), none()] { + assert_noop!( + Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), + BadOrigin + ); + } + // Origin checks for the `force_approve_collection_transfer`. + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_approve_collection_transfer( + origin, + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + BadOrigin + ); + } + + // Provide balance to accounts. + Balances::make_free_balance_be(&item_owner, 100); + Balances::make_free_balance_be(&delegate, 100); + + for (origin, maybe_item_owner) in [ + // Parameters for `approve_collection_transfer`. + (RuntimeOrigin::signed(item_owner.clone()), None), + // Parameters for `force_approve_collection_transfer`. + (root(), Some(&item_owner)), + ] { + // Approve unknown collection, throws error `Error::NoItemOwned`. + assert_noop!( + approve_collection_transfer( + origin.clone(), + maybe_item_owner, + collection_id, + &delegate, + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + + // Approve collection without items, throws error `Error::NoItemOwned`. + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + + // Approving a collection to a delegate with: + // 1. no deadline. + // 2. no deadline, again. + // 3. deadline. + // 3. equal deadline. + // 4. larger deadline. + // 5. smaller deadline. + // 6. no deadline, again. + // + // This tests all cases of approving the same delegate. + for deadline in [ + None, + None, + Some(deadline), + Some(deadline), + Some(deadline * 2), + Some(deadline), + None, + ] { + assert_ok!(approve_collection_transfer( + origin.clone(), + maybe_item_owner, + collection_id, + &delegate, + deadline, + )); + let deadline = deadline.map(|d| d + 1); + System::assert_last_event( + Event::::TransferApproved { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline, + } + .into(), + ); + assert_eq!(Balances::reserved_balance(&item_owner), 1); + assert_eq!( + CollectionApprovals::get((collection_id, &item_owner, &delegate)), + Some((deadline, CollectionApprovalDeposit::get())) + ); + } + + // Set collection settings to non transferable, throws error + // `Error::ItemsNonTransferable`. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + approve_collection_transfer( + origin.clone(), + maybe_item_owner, + collection_id, + &delegate, + None + ), + Error::::ItemsNonTransferable + ); + + // To reset reserved balance. + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + collection_id.saturating_inc(); + } + }); +} + +#[test] +fn cancel_collection_approval_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + // Origin checks for the `cancel_collection_approval`. + for origin in [root(), none()] { + assert_noop!( + Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), + BadOrigin + ); + } + // Origin checks for the `force_cancel_collection_approval`. + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_cancel_collection_approval( + origin, + item_owner.clone(), + collection_id, + delegate.clone() + ), + BadOrigin + ); + } + + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + + for (origin, maybe_owner) in [ + // Parameters for `cancel_collection_approval`. + (RuntimeOrigin::signed(item_owner.clone()), None), + // Parameters for `force_cancel_collection_approval`. + (root(), Some(&item_owner)), + ] { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + // Cancel an approval for a non existing collection. + assert_noop!( + cancel_collection_approval(origin.clone(), maybe_owner, 1, &delegate), + Error::::Unapproved + ); + // Cancel an unapproved delegate. + assert_noop!( + cancel_collection_approval( + origin.clone(), + maybe_owner, + collection_id, + &account(69), + ), + Error::::Unapproved + ); + + // Successfully cancel a collection approval. + assert_ok!(cancel_collection_approval( + origin.clone(), + maybe_owner, + collection_id, + &delegate + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); + System::assert_last_event( + Event::::ApprovalCancelled { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + } + .into(), + ); + } + }); +} + +#[test] +fn check_approval_without_deadline_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + // Item doesn't exist. + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::UnknownItem + ); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + // No approval. + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + // Approve collection without deadline. + { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + } + // Approve item without deadline. + { + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + )); + } + // Approve collection and item without deadline. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + }); +} + +#[test] +fn check_approval_with_deadline_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + // Approve collection with deadline. + { + let deadline: BlockNumberFor = 10; + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + Some(deadline), + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + )); + } + // Approve item with deadline. + { + let deadline: BlockNumberFor = 20; + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + Some(deadline), + )); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::check_approval( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + )); + } + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + }); +} + #[test] fn ensure_collection_approval_bytes() { let key = Blake2_128Concat::max_len::<::CollectionId>() + From cac4bed907a02c448825877ad11e99aaf0bc6ce6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 30 Dec 2024 11:02:18 +0700 Subject: [PATCH 88/99] chore: update tests --- pallets/nfts/src/tests.rs | 557 ++++++++++++++++++++------- runtime/devnet/src/config/assets.rs | 20 +- runtime/testnet/src/config/assets.rs | 20 +- 3 files changed, 460 insertions(+), 137 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index f1c36c69..f7a48b3c 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -21,12 +21,10 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}, - pallet_prelude::MaxEncodedLen, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, }, - Blake2_128Concat, StorageHasher, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_balances::Error as BalancesError; @@ -40,6 +38,7 @@ use sp_runtime::{ use crate::{mock::*, Event, SystemConfig, *}; type AccountIdOf = ::AccountId; +type AccountBalance = crate::AccountBalance; type CollectionApprovals = crate::CollectionApprovals; type CollectionApprovalDeposit = ::CollectionApprovalDeposit; type CollectionId = ::CollectionId; @@ -231,7 +230,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( @@ -241,7 +240,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)]); }); } @@ -281,10 +280,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); @@ -292,8 +291,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!(!AccountBalance::contains_key(0, &account(1))); + assert_eq!(AccountBalance::get(0, account(2)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -321,9 +320,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!(!AccountBalance::contains_key(0, account(10))); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert_eq!(AccountBalance::::get(0, account(20)), 0); + assert!(!AccountBalance::contains_key(0, account(20))); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -331,7 +330,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!(!AccountBalance::contains_key(0, &account(1))); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -374,7 +373,6 @@ fn destroy_with_bad_witness_should_not_work() { fn destroy_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&account(1), 100); - Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( RuntimeOrigin::signed(account(1)), account(1), @@ -382,12 +380,6 @@ fn destroy_should_work() { )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), - None - )); assert_noop!( Nfts::destroy( RuntimeOrigin::signed(account(1)), @@ -401,19 +393,6 @@ fn destroy_should_work() { assert_eq!(Collection::::get(0).unwrap().item_configs, 1); assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); assert!(ItemConfigOf::::contains_key(0, 42)); - assert_noop!( - Nfts::destroy( - RuntimeOrigin::signed(account(1)), - 0, - Nfts::get_destroy_witness(&0).unwrap() - ), - Error::::CollectionApprovalsExist - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) - )); assert_ok!(Nfts::destroy( RuntimeOrigin::signed(account(1)), 0, @@ -433,7 +412,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)]); @@ -499,7 +478,6 @@ 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 @@ -538,7 +516,6 @@ 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), @@ -575,9 +552,8 @@ fn transfer_should_work() { account(2), default_item_config() )); + 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)), @@ -592,8 +568,7 @@ fn transfer_should_work() { None )); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); - 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( @@ -1856,7 +1831,6 @@ fn burn_works() { assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); - assert!(!AccountBalance::::contains_key(0, &account(5))); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -1933,7 +1907,6 @@ fn approval_lifecycle_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -1971,24 +1944,6 @@ fn cancel_approval_works() { Error::::NotDelegate ); - // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection - // approval. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), - None - )); - assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), - Error::::DelegateApprovalConflict - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) - )); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, @@ -2200,7 +2155,6 @@ fn approval_deadline_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2234,24 +2188,6 @@ fn cancel_approval_works_with_admin() { Error::::NotDelegate ); - // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection - // approval. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), - None - )); - assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), - Error::::DelegateApprovalConflict - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) - )); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, @@ -2270,7 +2206,6 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -2304,24 +2239,6 @@ fn cancel_approval_works_with_force() { Error::::NotDelegate ); - // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection - // approval. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(2)), - 0, - account(3), - None - )); - assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), - Error::::DelegateApprovalConflict - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(2)), - 0, - account(3) - )); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert!(events().contains(&Event::::ApprovalCancelled { collection: 0, @@ -2339,19 +2256,11 @@ fn cancel_approval_works_with_force() { #[test] fn clear_all_transfer_approvals_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), default_collection_config() )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), - 0, - 43, - account(1), - default_item_config() - )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, @@ -2382,25 +2291,6 @@ fn clear_all_transfer_approvals_works() { assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); - // Throws `DelegateApprovalConflict` if there are existing collection approvals. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(account(1)), - 0, - account(3), - None - )); - assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(1)), 0, 42), - Error::::DelegateApprovalConflict - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(account(1)), - 0, - account(3) - )); - - assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); - assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, item: 42, @@ -2755,7 +2645,6 @@ fn buy_item_should_work() { item_1, price_1 + 1, )); - assert_eq!(AccountBalance::::get(collection_id, &user_2), 1); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -3213,8 +3102,6 @@ fn claim_swap_should_work() { item_1, Some(price_with_direction.clone()), )); - assert_eq!(AccountBalance::::get(collection_id, &user_1), 2); - assert_eq!(AccountBalance::::get(collection_id, &user_2), 3); // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); @@ -4141,6 +4028,72 @@ fn collection_item_works() { }); } +#[test] +fn clear_all_transfer_approvals_with_conflict_returns_error() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + + // Throws `DelegateApprovalConflict` if there are existing collection approvals. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id + ), + Error::::DelegateApprovalConflict + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate + )); + + assert_ok!(Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id + )); + + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: collection_id, + item: item_id, + owner, + })); + assert_eq!(approvals(collection_id, item_id), vec![]); + }); +} + #[test] fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { @@ -4427,6 +4380,78 @@ fn approve_collection_transfer_works() { }); } +#[test] +fn cancel_approval_with_conflict_returns_error() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + + // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection + // approval. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::cancel_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone() + ), + Error::::DelegateApprovalConflict + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone() + )); + + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone() + )); + assert!(events().contains(&Event::::ApprovalCancelled { + collection: collection_id, + item: Some(item_id), + owner: owner.clone(), + delegate: delegate.clone() + })); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(owner), collection_id, item_id, delegate), + Error::::NotDelegate + ); + }); +} + #[test] fn cancel_collection_approval_works() { new_test_ext().execute_with(|| { @@ -4729,11 +4754,277 @@ fn check_approval_with_deadline_works() { } #[test] -fn ensure_collection_approval_bytes() { - let key = Blake2_128Concat::max_len::<::CollectionId>() + - Blake2_128Concat::max_len::() + - Blake2_128Concat::max_len::(); - let value = Option::>::max_encoded_len() - .saturating_add(BalanceOf::::max_encoded_len()); - assert_eq!(key + value, 133); +fn mint_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let owner = account(1); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 42, + owner.clone(), + None + )); + assert_eq!(AccountBalance::get(collection_id, &owner), 1); + + // Additive. + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 43, + owner.clone(), + None + )); + assert_eq!(AccountBalance::get(collection_id, &owner), 2); + + // Mint with witness data. + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(account(1)), + collection_id, + 44, + account(2), + Some(MintWitness { mint_price: Some(1), ..Default::default() }) + )); + assert_eq!(AccountBalance::get(collection_id, account(2)), 1); + }); +} + +#[test] +fn burn_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 42, + owner.clone(), + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 43, + owner.clone(), + None, + )); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 42)); + assert_eq!(AccountBalance::get(collection_id, &owner), 1); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 43)); + assert!(!AccountBalance::contains_key(collection_id, &owner)); + }); +} + +#[test] +fn transfer_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let dest = account(3); + let item_id = 42; + let owner = account(1); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + dest.clone() + )); + assert!(!AccountBalance::contains_key(collection_id, &owner)); + assert_eq!(AccountBalance::get(collection_id, &dest), 1); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(dest.clone()), + collection_id, + item_id, + owner.clone(), + None + )); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + account(4) + )); + assert!(!AccountBalance::contains_key(collection_id, &dest)); + assert_eq!(AccountBalance::get(collection_id, account(4)), 1); + }); +} + +#[test] +fn claim_swap_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_1 = account(1); + let user_2 = account(2); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let price = 100; + let price_with_direction = + PriceWithDirection { amount: price, direction: PriceDirection::Receive.clone() }; + + Balances::make_free_balance_be(&user_1, 1000); + Balances::make_free_balance_be(&user_2, 1000); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + user_2.clone(), + default_item_config(), + )); + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + 2 + )); + + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction), + )); + assert_eq!(AccountBalance::get(collection_id, &user_1), 1); + assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + }); +} + +#[test] +fn buy_item_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let user_1 = account(1); + let user_2 = account(2); + let collection_id = 0; + let item_1 = 1; + let price_1 = 20; + let initial_balance = 100; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + Some(price_1), + None, + )); + + assert_ok!(Nfts::buy_item( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_1, + price_1 + 1, + )); + assert_eq!(AccountBalance::get(collection_id, &user_1), 0); + assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + }); +} + +#[test] +fn destroy_with_collection_approvals_returns_error() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&collection_owner, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(collection_owner.clone()), + collection_owner.clone(), + collection_config_with_all_settings_enabled() + )); + + CollectionApprovals::set( + (collection_id, item_owner.clone(), delegate.clone()), + Some((None, 0)), + ); + // Throws error `CollectionApprovalsExist`. + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() + ), + Error::::CollectionApprovalsExist + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate + )); + + // Successfully destroy the collection. + assert_ok!(Nfts::destroy( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() + )); + assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); + assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, collection_id); + }); } diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 0ff2a0cf..e46d7dbc 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -30,8 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - // Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); + // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); @@ -123,3 +123,19 @@ impl pallet_assets::Config for Runtime { type StringLimit = AssetsStringLimit; type WeightInfo = pallet_assets::weights::SubstrateWeight; } + +#[cfg(test)] +mod tests { + use frame_support::traits::StorageInfoTrait; + + use super::*; + + #[test] + fn ensure_collection_approval_deposit() { + let max_size = pallet_nfts::CollectionApprovals::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionApprovalDeposit::get()); + } +} diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index 0ff2a0cf..e46d7dbc 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -30,8 +30,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); pub const NftsCollectionDeposit: Balance = 10 * UNIT; - // Key = 116 bytes (4+16+32+16+32+16), Value = 17 bytes (1+8+8) - pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 133); + // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) + pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); pub const NftsItemDeposit: Balance = UNIT / 100; pub const NftsMetadataDepositBase: Balance = deposit(1, 129); pub const NftsAttributeDepositBase: Balance = deposit(1, 0); @@ -123,3 +123,19 @@ impl pallet_assets::Config for Runtime { type StringLimit = AssetsStringLimit; type WeightInfo = pallet_assets::weights::SubstrateWeight; } + +#[cfg(test)] +mod tests { + use frame_support::traits::StorageInfoTrait; + + use super::*; + + #[test] + fn ensure_collection_approval_deposit() { + let max_size = pallet_nfts::CollectionApprovals::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionApprovalDeposit::get()); + } +} From 4b4cd2206b9fbc1596c65fff37a54d1dd029aa1c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 31 Dec 2024 08:43:31 +0700 Subject: [PATCH 89/99] chore: update tests --- pallets/nfts/src/tests.rs | 716 ++++++++++++++++++-------------------- 1 file changed, 340 insertions(+), 376 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index f7a48b3c..e7d7784a 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -230,7 +230,6 @@ 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( @@ -240,7 +239,6 @@ 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)]); }); } @@ -280,10 +278,8 @@ 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); @@ -291,8 +287,6 @@ 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!(!AccountBalance::contains_key(0, &account(1))); - assert_eq!(AccountBalance::get(0, account(2)), 1); assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_eq!(Balances::reserved_balance(&account(2)), 0); @@ -320,9 +314,7 @@ fn lifecycle_should_work() { bvec![0], )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); - assert!(!AccountBalance::contains_key(0, account(10))); assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); - assert!(!AccountBalance::contains_key(0, account(20))); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -330,7 +322,6 @@ 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!(!AccountBalance::contains_key(0, &account(1))); assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); @@ -403,6 +394,52 @@ fn destroy_should_work() { }); } +#[test] +fn destroy_with_collection_approvals_returns_error() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + + Balances::make_free_balance_be(&collection_owner, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(collection_owner.clone()), + collection_owner.clone(), + collection_config_with_all_settings_enabled() + )); + + CollectionApprovals::set( + (collection_id, item_owner.clone(), delegate.clone()), + Some((None, 0)), + ); + // Throws error `CollectionApprovalsExist`. + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() + ), + Error::::CollectionApprovalsExist + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate + )); + + // Successfully destroy the collection. + assert_ok!(Nfts::destroy( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Nfts::get_destroy_witness(&collection_id).unwrap() + )); + assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); + assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, collection_id); + }); +} + #[test] fn mint_should_work() { new_test_ext().execute_with(|| { @@ -412,7 +449,6 @@ 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)]); @@ -537,6 +573,39 @@ fn mint_should_work() { }); } +#[test] +fn mint_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let owner = account(1); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 42, + owner.clone(), + None + )); + assert_eq!(AccountBalance::get(collection_id, &owner), 1); + + // Additive. + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 43, + owner.clone(), + None + )); + assert_eq!(AccountBalance::get(collection_id, &owner), 2); + }); +} + #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { @@ -594,6 +663,37 @@ fn transfer_should_work() { }); } +#[test] +fn transfer_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let dest = account(3); + let item_id = 42; + let owner = account(1); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + dest.clone() + )); + assert!(!AccountBalance::contains_key(collection_id, &owner)); + assert_eq!(AccountBalance::get(collection_id, &dest), 1); + }); +} + #[test] fn locking_transfer_should_work() { new_test_ext().execute_with(|| { @@ -1835,6 +1935,41 @@ fn burn_works() { }); } +#[test] +fn burn_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 42, + owner.clone(), + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + 43, + owner.clone(), + None, + )); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 42)); + assert_eq!(AccountBalance::get(collection_id, &owner), 1); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 43)); + assert!(!AccountBalance::contains_key(collection_id, &owner)); + }); +} + #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { @@ -2309,6 +2444,72 @@ fn clear_all_transfer_approvals_works() { }); } +#[test] +fn clear_all_transfer_approvals_with_conflict_returns_error() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + + // Throws `DelegateApprovalConflict` if there are existing collection approvals. + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id + ), + Error::::DelegateApprovalConflict + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate + )); + + assert_ok!(Nfts::clear_all_transfer_approvals( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id + )); + + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: collection_id, + item: item_id, + owner, + })); + assert_eq!(approvals(collection_id, item_id), vec![]); + }); +} + #[test] fn max_supply_should_work() { new_test_ext().execute_with(|| { @@ -2744,43 +2945,89 @@ fn buy_item_should_work() { } #[test] -fn pay_tips_should_work() { +fn buy_item_should_update_account_balance_works() { new_test_ext().execute_with(|| { let user_1 = account(1); let user_2 = account(2); - let user_3 = account(3); let collection_id = 0; - let item_id = 1; - let tip = 2; + let item_1 = 1; + let price_1 = 20; let initial_balance = 100; Balances::make_free_balance_be(&user_1, initial_balance); Balances::make_free_balance_be(&user_2, initial_balance); - Balances::make_free_balance_be(&user_3, initial_balance); - assert_ok!(Nfts::pay_tips( + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( RuntimeOrigin::signed(user_1.clone()), - bvec![ - ItemTip { - collection: collection_id, - item: item_id, - receiver: user_2.clone(), - amount: tip - }, - ItemTip { - collection: collection_id, - item: item_id, - receiver: user_3.clone(), - amount: tip - }, - ] + collection_id, + item_1, + user_1.clone(), + None )); - assert_eq!(Balances::total_balance(&user_1), initial_balance - tip * 2); - assert_eq!(Balances::total_balance(&user_2), initial_balance + tip); - assert_eq!(Balances::total_balance(&user_3), initial_balance + tip); + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + Some(price_1), + None, + )); - let events = events(); + assert_ok!(Nfts::buy_item( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_1, + price_1 + 1, + )); + assert_eq!(AccountBalance::get(collection_id, &user_1), 0); + assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + }); +} + +#[test] +fn pay_tips_should_work() { + new_test_ext().execute_with(|| { + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); + let collection_id = 0; + let item_id = 1; + let tip = 2; + let initial_balance = 100; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + Balances::make_free_balance_be(&user_3, initial_balance); + + assert_ok!(Nfts::pay_tips( + RuntimeOrigin::signed(user_1.clone()), + bvec![ + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_2.clone(), + amount: tip + }, + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_3.clone(), + amount: tip + }, + ] + )); + + assert_eq!(Balances::total_balance(&user_1), initial_balance - tip * 2); + assert_eq!(Balances::total_balance(&user_2), initial_balance + tip); + assert_eq!(Balances::total_balance(&user_3), initial_balance + tip); + + let events = events(); assert!(events.contains(&Event::::TipSent { collection: collection_id, item: item_id, @@ -3161,6 +3408,65 @@ fn claim_swap_should_work() { }); } +#[test] +fn claim_swap_should_update_account_balance_works() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_1 = account(1); + let user_2 = account(2); + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let price = 100; + let price_with_direction = + PriceWithDirection { amount: price, direction: PriceDirection::Receive.clone() }; + + Balances::make_free_balance_be(&user_1, 1000); + Balances::make_free_balance_be(&user_2, 1000); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + user_2.clone(), + default_item_config(), + )); + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + 2 + )); + + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2.clone()), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction), + )); + assert_eq!(AccountBalance::get(collection_id, &user_1), 1); + assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + }); +} + #[test] fn various_collection_settings() { new_test_ext().execute_with(|| { @@ -4028,72 +4334,6 @@ fn collection_item_works() { }); } -#[test] -fn clear_all_transfer_approvals_with_conflict_returns_error() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let delegate = account(3); - let item_id = 42; - let owner = account(1); - - Balances::make_free_balance_be(&owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id, - owner.clone(), - default_item_config() - )); - - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id, - delegate.clone(), - None - )); - - // Throws `DelegateApprovalConflict` if there are existing collection approvals. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_noop!( - Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id - ), - Error::::DelegateApprovalConflict - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate - )); - - assert_ok!(Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id - )); - - assert!(events().contains(&Event::::AllApprovalsCancelled { - collection: collection_id, - item: item_id, - owner, - })); - assert_eq!(approvals(collection_id, item_id), vec![]); - }); -} - #[test] fn clear_collection_approvals_works() { new_test_ext().execute_with(|| { @@ -4752,279 +4992,3 @@ fn check_approval_with_deadline_works() { ); }); } - -#[test] -fn mint_should_update_account_balance_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let owner = account(1); - - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - owner.clone(), - default_collection_config() - )); - - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 42, - owner.clone(), - None - )); - assert_eq!(AccountBalance::get(collection_id, &owner), 1); - - // Additive. - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 43, - owner.clone(), - None - )); - assert_eq!(AccountBalance::get(collection_id, &owner), 2); - - // Mint with witness data. - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(account(1)), - collection_id, - 44, - account(2), - Some(MintWitness { mint_price: Some(1), ..Default::default() }) - )); - assert_eq!(AccountBalance::get(collection_id, account(2)), 1); - }); -} - -#[test] -fn burn_should_update_account_balance_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let owner = account(1); - - Balances::make_free_balance_be(&owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - owner.clone(), - collection_config_with_all_settings_enabled() - )); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 42, - owner.clone(), - None, - )); - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - 43, - owner.clone(), - None, - )); - - assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 42)); - assert_eq!(AccountBalance::get(collection_id, &owner), 1); - - assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 43)); - assert!(!AccountBalance::contains_key(collection_id, &owner)); - }); -} - -#[test] -fn transfer_should_update_account_balance_works() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let dest = account(3); - let item_id = 42; - let owner = account(1); - - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id, - owner.clone(), - default_item_config() - )); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id, - dest.clone() - )); - assert!(!AccountBalance::contains_key(collection_id, &owner)); - assert_eq!(AccountBalance::get(collection_id, &dest), 1); - - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(dest.clone()), - collection_id, - item_id, - owner.clone(), - None - )); - assert_ok!(Nfts::transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - item_id, - account(4) - )); - assert!(!AccountBalance::contains_key(collection_id, &dest)); - assert_eq!(AccountBalance::get(collection_id, account(4)), 1); - }); -} - -#[test] -fn claim_swap_should_update_account_balance_works() { - new_test_ext().execute_with(|| { - System::set_block_number(1); - let user_1 = account(1); - let user_2 = account(2); - let collection_id = 0; - let item_1 = 1; - let item_2 = 2; - let price = 100; - let price_with_direction = - PriceWithDirection { amount: price, direction: PriceDirection::Receive.clone() }; - - Balances::make_free_balance_be(&user_1, 1000); - Balances::make_free_balance_be(&user_2, 1000); - - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - user_1.clone(), - default_collection_config() - )); - - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_1.clone()), - collection_id, - item_1, - user_1.clone(), - None, - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(user_1.clone()), - collection_id, - item_2, - user_2.clone(), - default_item_config(), - )); - assert_ok!(Nfts::create_swap( - RuntimeOrigin::signed(user_1.clone()), - collection_id, - item_1, - collection_id, - Some(item_2), - Some(price_with_direction.clone()), - 2 - )); - - assert_ok!(Nfts::claim_swap( - RuntimeOrigin::signed(user_2.clone()), - collection_id, - item_2, - collection_id, - item_1, - Some(price_with_direction), - )); - assert_eq!(AccountBalance::get(collection_id, &user_1), 1); - assert_eq!(AccountBalance::get(collection_id, &user_2), 1); - }); -} - -#[test] -fn buy_item_should_update_account_balance_works() { - new_test_ext().execute_with(|| { - let user_1 = account(1); - let user_2 = account(2); - let collection_id = 0; - let item_1 = 1; - let price_1 = 20; - let initial_balance = 100; - - Balances::make_free_balance_be(&user_1, initial_balance); - Balances::make_free_balance_be(&user_2, initial_balance); - - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - user_1.clone(), - default_collection_config() - )); - - assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_1.clone()), - collection_id, - item_1, - user_1.clone(), - None - )); - - assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_1.clone()), - collection_id, - item_1, - Some(price_1), - None, - )); - - assert_ok!(Nfts::buy_item( - RuntimeOrigin::signed(user_2.clone()), - collection_id, - item_1, - price_1 + 1, - )); - assert_eq!(AccountBalance::get(collection_id, &user_1), 0); - assert_eq!(AccountBalance::get(collection_id, &user_2), 1); - }); -} - -#[test] -fn destroy_with_collection_approvals_returns_error() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let collection_owner = account(1); - let delegate = account(3); - let item_id = 42; - let item_owner = account(2); - - Balances::make_free_balance_be(&collection_owner, 100); - assert_ok!(Nfts::create( - RuntimeOrigin::signed(collection_owner.clone()), - collection_owner.clone(), - collection_config_with_all_settings_enabled() - )); - - CollectionApprovals::set( - (collection_id, item_owner.clone(), delegate.clone()), - Some((None, 0)), - ); - // Throws error `CollectionApprovalsExist`. - assert_noop!( - Nfts::destroy( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Nfts::get_destroy_witness(&collection_id).unwrap() - ), - Error::::CollectionApprovalsExist - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate - )); - - // Successfully destroy the collection. - assert_ok!(Nfts::destroy( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Nfts::get_destroy_witness(&collection_id).unwrap() - )); - assert!(!ItemConfigOf::::contains_key(collection_id, item_id)); - assert_eq!(ItemConfigOf::::iter_prefix(collection_id).count() as u32, collection_id); - }); -} From 97450fa84ab0dfc5c676041cedf7f53d64e7016d Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:25:50 +0700 Subject: [PATCH 90/99] chore: apply suggestion --- 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 e7d7784a..22acac80 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -2474,7 +2474,7 @@ fn clear_all_transfer_approvals_with_conflict_returns_error() { None )); - // Throws `DelegateApprovalConflict` if there are existing collection approvals. + // Throws `DelegateApprovalConflict` if collection approvals exists. assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(owner.clone()), collection_id, From 881a04ca5e29261f107ff6ebc0586da4605a2924 Mon Sep 17 00:00:00 2001 From: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:34:55 +0200 Subject: [PATCH 91/99] refactor: tests for collection approval (#419) Co-authored-by: chungquantin <56880684+chungquantin@users.noreply.github.com> --- pallets/nfts/src/tests.rs | 1174 +++++++++++++++++++++---------------- 1 file changed, 684 insertions(+), 490 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 22acac80..5c78450d 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -20,7 +20,7 @@ use enumflags2::BitFlags; use frame_support::{ assert_noop, assert_ok, - dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}, + dispatch::WithPostDispatchInfo, traits::{ tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate}, Currency, Get, @@ -32,7 +32,7 @@ use sp_core::{bounded::BoundedVec, Pair}; use sp_runtime::{ traits::{Dispatchable, IdentifyAccount}, DispatchError::BadOrigin, - DispatchResult, MultiSignature, MultiSigner, + MultiSignature, MultiSigner, }; use crate::{mock::*, Event, SystemConfig, *}; @@ -41,7 +41,6 @@ type AccountIdOf = ::AccountId; type AccountBalance = crate::AccountBalance; type CollectionApprovals = crate::CollectionApprovals; type CollectionApprovalDeposit = ::CollectionApprovalDeposit; -type CollectionId = ::CollectionId; type WeightOf = ::WeightInfo; fn account(id: u8) -> AccountIdOf { @@ -163,56 +162,6 @@ fn item_config_from_disabled_settings(settings: BitFlags) -> ItemCo ItemConfig { settings: ItemSettings::from_disabled(settings) } } -fn clear_collection_approvals( - origin: RuntimeOrigin, - maybe_owner: Option<&AccountId>, - collection: CollectionId, - limit: u32, -) -> DispatchResultWithPostInfo { - match maybe_owner { - Some(owner) => - Nfts::force_clear_collection_approvals(origin, owner.clone(), collection, limit), - None => Nfts::clear_collection_approvals(origin, collection, limit), - } -} - -fn approve_collection_transfer( - origin: RuntimeOrigin, - maybe_owner: Option<&AccountId>, - collection: CollectionId, - delegate: &AccountId, - maybe_deadline: Option>, -) -> DispatchResult { - match maybe_owner { - Some(owner) => Nfts::force_approve_collection_transfer( - origin, - owner.clone(), - collection, - delegate.clone(), - maybe_deadline, - ), - None => - Nfts::approve_collection_transfer(origin, collection, delegate.clone(), maybe_deadline), - } -} - -fn cancel_collection_approval( - origin: RuntimeOrigin, - maybe_owner: Option<&AccountId>, - collection: CollectionId, - delegate: &AccountId, -) -> DispatchResult { - match maybe_owner { - Some(owner) => Nfts::force_cancel_collection_approval( - origin, - owner.clone(), - collection, - delegate.clone(), - ), - None => Nfts::cancel_collection_approval(origin, collection, delegate.clone()), - } -} - #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { @@ -2120,6 +2069,64 @@ fn cancel_approval_works() { }); } +#[test] +fn cancel_approval_ensures_no_active_collection_approval() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let delegate = account(3); + let item_id = 42; + let owner = account(1); + + Balances::make_free_balance_be(&owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + collection_id, + item_id, + owner.clone(), + default_item_config() + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone(), + None + )); + // Delegate has an active collection approval. + assert_noop!( + Nfts::cancel_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + item_id, + delegate.clone() + ), + Error::::DelegateApprovalConflict + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(owner.clone()), + collection_id, + delegate.clone() + )); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(owner), + collection_id, + item_id, + delegate + )); + }); +} + #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { @@ -2445,7 +2452,7 @@ fn clear_all_transfer_approvals_works() { } #[test] -fn clear_all_transfer_approvals_with_conflict_returns_error() { +fn clear_all_transfer_approvals_ensures_no_active_collection_approval() { new_test_ext().execute_with(|| { let collection_id = 0; let delegate = account(3); @@ -2465,7 +2472,6 @@ fn clear_all_transfer_approvals_with_conflict_returns_error() { owner.clone(), default_item_config() )); - assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(owner.clone()), collection_id, @@ -2473,14 +2479,13 @@ fn clear_all_transfer_approvals_with_conflict_returns_error() { delegate.clone(), None )); - - // Throws `DelegateApprovalConflict` if collection approvals exists. assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(owner.clone()), collection_id, delegate.clone(), None )); + // Delegate has an active collection approval. assert_noop!( Nfts::clear_all_transfer_approvals( RuntimeOrigin::signed(owner.clone()), @@ -2494,19 +2499,11 @@ fn clear_all_transfer_approvals_with_conflict_returns_error() { collection_id, delegate )); - assert_ok!(Nfts::clear_all_transfer_approvals( - RuntimeOrigin::signed(owner.clone()), + RuntimeOrigin::signed(owner), collection_id, item_id )); - - assert!(events().contains(&Event::::AllApprovalsCancelled { - collection: collection_id, - item: item_id, - owner, - })); - assert_eq!(approvals(collection_id, item_id), vec![]); }); } @@ -4343,26 +4340,12 @@ fn clear_collection_approvals_works() { let item_owner = account(1); let delegates = 10..20; - // Origin checks for the `clear_collection_approvals`. for origin in [root(), none()] { assert_noop!( Nfts::clear_collection_approvals(origin, collection_id, 0), BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) ); } - // Origin checks for the `force_clear_collection_approvals`. - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_clear_collection_approvals( - origin, - item_owner.clone(), - collection_id, - 0 - ), - BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) - ); - } - assert_ok!(Nfts::force_create( RuntimeOrigin::root(), item_owner.clone(), @@ -4376,318 +4359,473 @@ fn clear_collection_approvals_works() { default_item_config() )); Balances::make_free_balance_be(&item_owner, balance); + // Approve delegates. + let mut approvals = 0u32; + for i in delegates.clone() { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + account(i), + None + )); + approvals.saturating_inc(); + } - for (origin, maybe_owner) in [ - // Parameters for `clear_collection_approvals`. - (root(), Some(&item_owner)), - // Parameters for `force_clear_collection_approvals`. - (RuntimeOrigin::signed(item_owner.clone()), None), - ] { - // Approve delegates. - let mut approvals = 0u32; - for i in delegates.clone() { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - account(i), - None - )); - approvals.saturating_inc(); - } + // Remove zero collection approvals. + assert_eq!( + Nfts::clear_collection_approvals( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + 0 + ), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), + approvals as usize + ); + assert!(!events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals + })); - // Remove zero collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner, collection_id, 0), - Ok(Some(WeightOf::clear_collection_approvals(0)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); - assert_eq!( - CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), - approvals as usize - ); - assert!(!events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals - })); + // Partially remove collection approvals. + let limit = 1; + assert_eq!( + Nfts::clear_collection_approvals( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + limit + ), + Ok(Some(WeightOf::clear_collection_approvals(limit)).into()) + ); + approvals = approvals - limit; + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), + approvals as usize + ); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals: limit + })); - // Partially remove collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 1), - Ok(Some(WeightOf::clear_collection_approvals(1)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance - (approvals as u64) + 1); - assert_eq!( - CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), - approvals as usize - 1 - ); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: 1 - })); + // Successfully remove all collection approvals. Only charges post-dispatch weight for + // the removed approvals. + assert_eq!( + Nfts::clear_collection_approvals( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + 10 + ), + Ok(Some(WeightOf::clear_collection_approvals(approvals)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) + .count() + .is_zero()); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals, + })); - // Successfully remove all collection approvals. Only charges post-dispatch weight for - // the removed approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::clear_collection_approvals(9)).into()) - ); - assert_eq!(Balances::free_balance(&item_owner), balance); - assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) - .count() - .is_zero()); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: approvals - 1 - })); + // Remove collection approvals while there are none. + assert_eq!( + Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner, + approvals: 0 + })); - // Remove zero collection approvals. - assert_eq!( - clear_collection_approvals(origin.clone(), maybe_owner.clone(), collection_id, 10), - Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + // Ensure delegates are not able to transfer. + for i in delegates.clone() { + assert_noop!( + Nfts::transfer( + RuntimeOrigin::signed(account(i)), + collection_id, + item_id, + account(5) + ), + Error::::NoPermission ); - assert_eq!(Balances::free_balance(&item_owner), balance); - assert!(events().contains(&Event::::ApprovalsCancelled { - collection: collection_id, - owner: item_owner.clone(), - approvals: 0 - })); - - // Ensure delegates are not able to transfer. - for i in delegates.clone() { - assert_noop!( - Nfts::transfer( - RuntimeOrigin::signed(account(i)), - collection_id, - item_id, - account(5) - ), - Error::::NoPermission - ); - } } }); } #[test] -fn approve_collection_transfer_works() { +fn force_clear_collection_approvals_works() { new_test_ext().execute_with(|| { - let mut collection_id = 0; - let collection_owner = account(1); - let deadline: BlockNumberFor = 20; - let delegate = account(3); + let balance = 100; + let collection_id = 0; let item_id = 42; - let item_owner = account(2); + let item_owner = account(1); + let delegates = 10..20; - // Origin checks for the `approve_collection_transfer`. - for origin in [root(), none()] { - assert_noop!( - Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), - BadOrigin - ); - } - // Origin checks for the `force_approve_collection_transfer`. for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { assert_noop!( - Nfts::force_approve_collection_transfer( + Nfts::force_clear_collection_approvals( origin, item_owner.clone(), collection_id, - delegate.clone(), - None + 0 ), - BadOrigin + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) ); } - - // Provide balance to accounts. - Balances::make_free_balance_be(&item_owner, 100); - Balances::make_free_balance_be(&delegate, 100); - - for (origin, maybe_item_owner) in [ - // Parameters for `approve_collection_transfer`. - (RuntimeOrigin::signed(item_owner.clone()), None), - // Parameters for `force_approve_collection_transfer`. - (root(), Some(&item_owner)), - ] { - // Approve unknown collection, throws error `Error::NoItemOwned`. - assert_noop!( - approve_collection_transfer( - origin.clone(), - maybe_item_owner, - collection_id, - &delegate, - None - ), - Error::::NoItemOwned - ); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - - // Approve collection without items, throws error `Error::NoItemOwned`. - assert_noop!( - Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - ), - Error::::NoItemOwned - ); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(collection_owner.clone()), + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + item_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + Balances::make_free_balance_be(&item_owner, balance); + // Approve delegates. + let mut approvals = 0u32; + for i in delegates.clone() { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), collection_id, - item_id, - item_owner.clone(), - default_item_config() + account(i), + None )); + approvals.saturating_inc(); + } - // Approving a collection to a delegate with: - // 1. no deadline. - // 2. no deadline, again. - // 3. deadline. - // 3. equal deadline. - // 4. larger deadline. - // 5. smaller deadline. - // 6. no deadline, again. - // - // This tests all cases of approving the same delegate. - for deadline in [ - None, - None, - Some(deadline), - Some(deadline), - Some(deadline * 2), - Some(deadline), - None, - ] { - assert_ok!(approve_collection_transfer( - origin.clone(), - maybe_item_owner, - collection_id, - &delegate, - deadline, - )); - let deadline = deadline.map(|d| d + 1); - System::assert_last_event( - Event::::TransferApproved { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - deadline, - } - .into(), - ); - assert_eq!(Balances::reserved_balance(&item_owner), 1); - assert_eq!( - CollectionApprovals::get((collection_id, &item_owner, &delegate)), - Some((deadline, CollectionApprovalDeposit::get())) - ); - } + // Remove zero collection approvals. + assert_eq!( + Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 0), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, &item_owner)).count(), + approvals as usize + ); + assert!(!events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals + })); - // Set collection settings to non transferable, throws error - // `Error::ItemsNonTransferable`. - assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(collection_owner.clone()), + // Partially remove collection approvals. + let limit = 1; + assert_eq!( + Nfts::force_clear_collection_approvals( + root(), + item_owner.clone(), collection_id, - CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) - )); + limit + ), + Ok(Some(WeightOf::clear_collection_approvals(limit)).into()) + ); + approvals = approvals - limit; + assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); + assert_eq!( + CollectionApprovals::iter_prefix((collection_id, item_owner.clone())).count(), + approvals as usize + ); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals: limit + })); + + // Successfully remove all collection approvals. Only charges post-dispatch weight for + // the removed approvals. + assert_eq!( + Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(approvals)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(CollectionApprovals::iter_prefix((collection_id, item_owner.clone())) + .count() + .is_zero()); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner.clone(), + approvals, + })); + + // Remove collection approvals while there are none. + assert_eq!( + Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Ok(Some(WeightOf::clear_collection_approvals(0)).into()) + ); + assert_eq!(Balances::free_balance(&item_owner), balance); + assert!(events().contains(&Event::::ApprovalsCancelled { + collection: collection_id, + owner: item_owner, + approvals: 0 + })); + + // Ensure delegates are not able to transfer. + for i in delegates.clone() { assert_noop!( - approve_collection_transfer( - origin.clone(), - maybe_item_owner, + Nfts::transfer( + RuntimeOrigin::signed(account(i)), collection_id, - &delegate, - None + item_id, + account(5) ), - Error::::ItemsNonTransferable + Error::::NoPermission ); - - // To reset reserved balance. - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() - )); - collection_id.saturating_inc(); } }); } #[test] -fn cancel_approval_with_conflict_returns_error() { +fn approve_collection_transfer_works() { new_test_ext().execute_with(|| { let collection_id = 0; + let collection_owner = account(1); + let deadline: BlockNumberFor = 20; let delegate = account(3); + let deposit = CollectionApprovalDeposit::get(); let item_id = 42; - let owner = account(1); + let item_owner = account(2); - Balances::make_free_balance_be(&owner, 100); + for origin in [root(), none()] { + assert_noop!( + Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), + BadOrigin + ); + } + // Approve unknown collection. + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - owner.clone(), + root(), + collection_owner.clone(), default_collection_config() )); + // Approve collection without items. + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(collection_owner.clone()), collection_id, item_id, - owner.clone(), + item_owner.clone(), default_item_config() )); + // Approve collection without balance. + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + ), + BalancesError::::InsufficientBalance, + ); - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(owner.clone()), + Balances::make_free_balance_be(&item_owner, 100); + // Approving a collection to a delegate with: + // 1. no deadline. + // 2. no deadline, again. + // 3. deadline. + // 3. equal deadline. + // 4. larger deadline. + // 5. smaller deadline. + // 6. no deadline, again. + // + // This tests all cases of approving the same delegate. + for deadline in + [None, None, Some(deadline), Some(deadline), Some(deadline * 2), Some(deadline), None] + { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + deadline, + )); + let deadline = deadline.map(|d| d + 1); + System::assert_last_event( + Event::::TransferApproved { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline, + } + .into(), + ); + assert_eq!(Balances::reserved_balance(&item_owner), deposit); + assert_eq!( + CollectionApprovals::get((collection_id, &item_owner, &delegate)), + Some((deadline, deposit)) + ); + } + + // Set collection settings to non transferable. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner), collection_id, - item_id, - delegate.clone(), - None + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); + assert_noop!( + Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner), + collection_id, + delegate, + None + ), + Error::::ItemsNonTransferable + ); + }); +} - // Throws `DelegateApprovalConflict`` if the delegate has been granted a collection - // approval. - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(owner.clone()), - collection_id, - delegate.clone(), - None +#[test] +fn force_approve_collection_transfer_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let deadline: BlockNumberFor = 20; + let delegate = account(3); + let deposit = CollectionApprovalDeposit::get(); + let item_id = 42; + let item_owner = account(2); + + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_approve_collection_transfer( + origin, + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + BadOrigin + ); + } + // Approve unknown collection. + assert_noop!( + Nfts::force_approve_collection_transfer( + root(), + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + Error::::NoItemOwned + ); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() )); + // Approve collection without items. assert_noop!( - Nfts::cancel_approval( - RuntimeOrigin::signed(owner.clone()), + Nfts::force_approve_collection_transfer( + root(), + item_owner.clone(), collection_id, - item_id, - delegate.clone() + delegate.clone(), + None ), - Error::::DelegateApprovalConflict + Error::::NoItemOwned ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(owner.clone()), + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner.clone()), collection_id, - delegate.clone() + item_id, + item_owner.clone(), + default_item_config() )); + // Approve collection without balance. + assert_noop!( + Nfts::force_approve_collection_transfer( + root(), + item_owner.clone(), + collection_id, + delegate.clone(), + None + ), + BalancesError::::InsufficientBalance, + ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(owner.clone()), + Balances::make_free_balance_be(&item_owner, 100); + // Approving a collection to a delegate with: + // 1. no deadline. + // 2. no deadline, again. + // 3. deadline. + // 3. equal deadline. + // 4. larger deadline. + // 5. smaller deadline. + // 6. no deadline, again. + // + // This tests all cases of approving the same delegate. + for deadline in + [None, None, Some(deadline), Some(deadline), Some(deadline * 2), Some(deadline), None] + { + assert_ok!(Nfts::force_approve_collection_transfer( + root(), + item_owner.clone(), + collection_id, + delegate.clone(), + deadline, + )); + let deadline = deadline.map(|d| d + 1); + System::assert_last_event( + Event::::TransferApproved { + collection: collection_id, + item: None, + owner: item_owner.clone(), + delegate: delegate.clone(), + deadline, + } + .into(), + ); + assert_eq!(Balances::reserved_balance(&item_owner), deposit); + assert_eq!( + CollectionApprovals::get((collection_id, &item_owner, &delegate)), + Some((deadline, deposit)) + ); + } + + // Set collection settings to non transferable. + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(collection_owner), collection_id, - item_id, - delegate.clone() + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); - assert!(events().contains(&Event::::ApprovalCancelled { - collection: collection_id, - item: Some(item_id), - owner: owner.clone(), - delegate: delegate.clone() - })); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(owner), collection_id, item_id, delegate), - Error::::NotDelegate + Nfts::force_approve_collection_transfer( + root(), + item_owner, + collection_id, + delegate, + None + ), + Error::::ItemsNonTransferable ); }); } @@ -4701,14 +4839,78 @@ fn cancel_collection_approval_works() { let item_id = 42; let item_owner = account(2); - // Origin checks for the `cancel_collection_approval`. for origin in [root(), none()] { assert_noop!( Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), BadOrigin ); } - // Origin checks for the `force_cancel_collection_approval`. + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(collection_owner), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + // Cancel an approval for a non existing collection. + assert_noop!( + Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + ), + Error::::Unapproved + ); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + // Cancel an unapproved delegate. + assert_noop!( + Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + account(69) + ), + Error::::Unapproved + ); + // Successfully cancel a collection approval. + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); + System::assert_last_event( + Event::::ApprovalCancelled { + collection: collection_id, + item: None, + owner: item_owner, + delegate, + } + .into(), + ); + }); +} + +#[test] +fn force_cancel_collection_approval_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let item_id = 42; + let item_owner = account(2); + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { assert_noop!( Nfts::force_cancel_collection_approval( @@ -4720,7 +4922,6 @@ fn cancel_collection_approval_works() { BadOrigin ); } - Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -4734,54 +4935,50 @@ fn cancel_collection_approval_works() { item_owner.clone(), default_item_config() )); - - for (origin, maybe_owner) in [ - // Parameters for `cancel_collection_approval`. - (RuntimeOrigin::signed(item_owner.clone()), None), - // Parameters for `force_cancel_collection_approval`. - (root(), Some(&item_owner)), - ] { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), + // Cancel an approval for a non existing collection. + assert_noop!( + Nfts::force_cancel_collection_approval( + root(), + item_owner.clone(), collection_id, - delegate.clone(), - None - )); - // Cancel an approval for a non existing collection. - assert_noop!( - cancel_collection_approval(origin.clone(), maybe_owner, 1, &delegate), - Error::::Unapproved - ); - // Cancel an unapproved delegate. - assert_noop!( - cancel_collection_approval( - origin.clone(), - maybe_owner, - collection_id, - &account(69), - ), - Error::::Unapproved - ); - - // Successfully cancel a collection approval. - assert_ok!(cancel_collection_approval( - origin.clone(), - maybe_owner, + delegate.clone() + ), + Error::::Unapproved + ); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + // Cancel an unapproved delegate. + assert_noop!( + Nfts::force_cancel_collection_approval( + root(), + item_owner.clone(), collection_id, - &delegate - )); - assert_eq!(Balances::reserved_balance(&item_owner), 0); - assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); - System::assert_last_event( - Event::::ApprovalCancelled { - collection: collection_id, - item: None, - owner: item_owner.clone(), - delegate: delegate.clone(), - } - .into(), - ); - } + account(69) + ), + Error::::Unapproved + ); + // Successfully cancel a collection approval. + assert_ok!(Nfts::force_cancel_collection_approval( + root(), + item_owner.clone(), + collection_id, + delegate.clone() + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); + System::assert_last_event( + Event::::ApprovalCancelled { + collection: collection_id, + item: None, + owner: item_owner, + delegate, + } + .into(), + ); }); } @@ -4825,53 +5022,42 @@ fn check_approval_without_deadline_works() { Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::NoPermission ); + // Approve collection without deadline. - { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone() - )); - } + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone() + )); + // Approve item without deadline. - { - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - None - )); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone() - )); - } + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone() + )); + // Approve collection and item without deadline. assert_ok!(Nfts::approve_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -4913,82 +5099,90 @@ fn check_approval_with_deadline_works() { item_owner.clone(), default_item_config() )); + // Approve collection with deadline. - { - let deadline: BlockNumberFor = 10; - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - Some(deadline), - )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - // Expire approval. - System::set_block_number(deadline + System::block_number() + 1); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::ApprovalExpired - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - )); - } + let deadline: BlockNumberFor = 10; + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + Some(deadline), + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::NoPermission + ); + assert_ok!(Nfts::cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + )); + // Approve item with deadline. - { - let deadline: BlockNumberFor = 20; - assert_ok!(Nfts::approve_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - Some(deadline), - )); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_ok!(Nfts::check_approval( - &collection_id, - &Some(item_id), - &item_owner, - &delegate - )); - // Expire approval. - System::set_block_number(deadline + System::block_number() + 1); - assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), - Error::::NoPermission - ); - assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), - Error::::ApprovalExpired - ); - assert_ok!(Nfts::cancel_approval( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - item_id, - delegate.clone(), - )); - } + let deadline: BlockNumberFor = 20; + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + Some(deadline), + )); assert_noop!( Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + // Expire approval. + System::set_block_number(deadline + System::block_number() + 1); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_ok!(Nfts::cancel_approval( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + )); + + // Approve collection and item with deadline. + let deadline: BlockNumberFor = 30; + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + item_id, + delegate.clone(), + Some(deadline) + )); + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + Some(deadline) + )); + assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + // Expire approvals. + System::set_block_number(deadline + System::block_number() + 1); + assert_noop!( + Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Error::::ApprovalExpired + ); + assert_noop!( + Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Error::::ApprovalExpired + ); }); } From 504d0f0bf10b827abb6467e8e3e18d5401bd3420 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:12:33 +0700 Subject: [PATCH 92/99] feat: allow admin to force cancel approvals --- pallets/nfts/src/features/approvals.rs | 34 +++--- pallets/nfts/src/lib.rs | 61 ++++++++--- pallets/nfts/src/tests.rs | 139 ++++++++++++++++--------- 3 files changed, 154 insertions(+), 80 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index e40fb6e8..cee53666 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -188,7 +188,7 @@ impl, I: 'static> Pallet { Ok(()) } - /// Approves the transfer of all collection items of `owner` to a delegate. + /// Approves the transfer of all collection items of `owner` to a `delegate`. /// /// This function is used to approve the transfer of all (current and future) collection items /// of `owner` to a `delegate`. The `delegate` account will be allowed to take control of the @@ -203,7 +203,7 @@ impl, I: 'static> Pallet { /// /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. - /// - `delegate`: The account that will be allowed to take control of the collection items. + /// - `delegate`: The account that will be approved to take control of the collection items. /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. pub(crate) fn do_approve_collection_transfer( @@ -232,9 +232,7 @@ impl, I: 'static> Pallet { let deposit_required = T::CollectionApprovalDeposit::get(); let current_deposit = maybe_approval.take().map(|(_, deposit)| deposit).unwrap_or_default(); - if current_deposit < deposit_required { - T::Currency::reserve(&owner, deposit_required - current_deposit)?; - } + T::Currency::reserve(&owner, deposit_required - current_deposit)?; *maybe_approval = Some((deadline, deposit_required)); Ok(()) }, @@ -266,7 +264,7 @@ impl, I: 'static> Pallet { delegate: T::AccountId, ) -> DispatchResult { let (_, deposit) = CollectionApprovals::::take((&collection, &owner, &delegate)) - .ok_or(Error::::Unapproved)?; + .ok_or(Error::::NotDelegate)?; T::Currency::unreserve(&owner, deposit); @@ -312,12 +310,12 @@ impl, I: 'static> Pallet { Ok(removed_approvals) } - /// Checks whether the `delegate` is approved to transfer collection items of `owner`. + /// Checks whether the `delegate` has permission to transfer collection items of `owner`. /// /// - `collection`: The identifier of the collection. /// - `owner`: The owner of the collection items. - /// - `delegate`: The account to check for approval to transfer collection items of `owner`. - fn check_collection_approval( + /// - `delegate`: The account to check for permission to transfer collection items of `owner`. + fn check_collection_approval_permission( collection: &T::CollectionId, owner: &T::AccountId, delegate: &T::AccountId, @@ -332,24 +330,26 @@ impl, I: 'static> Pallet { Ok(()) } - /// Checks whether the `delegate` is approved by `owner` to transfer its collection item(s). If - /// the `delegate` is approved for all `owner`'s collection items it can transfer every item - /// without requiring explicit approval for an item. + /// Checks whether the `delegate` has permission to transfer `owner`'s collection item(s). + /// If the `delegate` has permission to transfer all `owner`'s collection items, they can + /// transfer any item without needing explicit approval for each individual item. /// /// - `collection`: The identifier of the collection. - /// - `maybe_item`: The optional item of the collection that the delegated account has an - /// approval to transfer. If not provided, an approval to transfer all `owner`'s collection + /// - `maybe_item`: The optional item of the collection that the delegated account has + /// permission to transfer. If not provided, permission to transfer all `owner`'s collection /// items will be checked. /// - `owner`: The owner of the specified collection item. - /// - `delegate`: The account to check for approval to transfer collection item(s) of owner. - pub fn check_approval( + /// - `delegate`: The account to check for permission to transfer collection item(s) from the + /// owner. + pub fn check_approval_permission( collection: &T::CollectionId, maybe_item: &Option, owner: &T::AccountId, delegate: &T::AccountId, ) -> DispatchResult { // Check if `delegate` has permission to transfer `owner`'s collection items. - let Err(error) = Self::check_collection_approval(collection, owner, delegate) else { + let Err(error) = Self::check_collection_approval_permission(collection, owner, delegate) + else { return Ok(()); }; diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 2851e826..a087f046 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -59,8 +59,8 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::WithPostDispatchInfo, traits::{ - tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, - ReservableCurrency, + nonfungibles_v2::InspectRole, tokens::Locker, BalanceStatus::Reserved, Currency, + EnsureOriginWithArg, Incrementable, ReservableCurrency, }, }; use frame_system::Config as SystemConfig; @@ -448,7 +448,13 @@ pub mod pallet { NMapKey, // owner NMapKey, // delegate ), - (Option>, DepositBalanceOf), + ( + // The optional deadline for the approval. If specified, the approval is valid on or + // before the given block number. + Option>, + // The balance to be deposited. + DepositBalanceOf, + ), >; #[pallet::event] @@ -494,8 +500,9 @@ pub mod pallet { admin: Option, freezer: Option, }, - /// An `item` of a `collection` has been approved by the `owner` for transfer by - /// a `delegate`. + /// A provided `item` of a `collection`, or if no `item` is provided, all items in the + /// `collection` owned by the `owner` have been approved by the `owner` for transfer by a + /// `delegate`. TransferApproved { collection: T::CollectionId, item: Option, @@ -503,8 +510,9 @@ pub mod pallet { delegate: T::AccountId, deadline: Option>, }, - /// An approval for a `delegate` account to transfer a specific `item` in a `collection` or - /// all collection items owned by the `owner` has been cancelled by the owner. + /// An approval for a `delegate` account to transfer a specific `item` in a `collection`, + /// or if no `item` is provided, all collection items owned by the `owner` have been + /// cancelled by the `owner`. ApprovalCancelled { collection: T::CollectionId, item: Option, @@ -658,8 +666,6 @@ pub mod pallet { NotDelegate, /// The delegate turned out to be different to what was expected. WrongDelegate, - /// No approval exists that would allow the transfer. - Unapproved, /// The named owner has not signed ownership acceptance of the collection. Unaccepted, /// The item is locked (non-transferable). @@ -1088,7 +1094,12 @@ pub mod pallet { Self::do_transfer(collection, item, dest, |_, details| { if details.owner != origin { - Self::check_approval(&collection, &Some(item), &details.owner, &origin)?; + Self::check_approval_permission( + &collection, + &Some(item), + &details.owner, + &origin, + )?; } Ok(()) }) @@ -2089,9 +2100,19 @@ pub mod pallet { collection: T::CollectionId, delegate: AccountIdLookupOf, ) -> DispatchResult { - T::ForceOrigin::ensure_origin(origin)?; + 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)?; let owner = T::Lookup::lookup(owner)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!( + Self::is_admin(&collection, &check_origin) || + Self::is_issuer(&collection, &check_origin), + Error::::NoPermission + ); + } Self::do_cancel_collection_approval(owner, collection, delegate) } @@ -2142,9 +2163,23 @@ pub mod pallet { collection: T::CollectionId, limit: u32, ) -> DispatchResultWithPostInfo { - T::ForceOrigin::ensure_origin(origin) - .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; + let maybe_check_origin = + T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { + ensure_signed(origin).map(Some).map_err(|e| { + DispatchError::from(e) + .with_weight(T::WeightInfo::clear_collection_approvals(0)) + }) + })?; let owner = T::Lookup::lookup(owner)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!( + Self::is_admin(&collection, &check_origin) || + Self::is_issuer(&collection, &check_origin), + Error::::NoPermission + .with_weight(T::WeightInfo::clear_collection_approvals(0)) + ); + } let removed_approvals = Self::do_clear_collection_approvals(owner, collection, limit)?; Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 5c78450d..04212223 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4469,17 +4469,19 @@ fn force_clear_collection_approvals_works() { let item_owner = account(1); let delegates = 10..20; - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_clear_collection_approvals( - origin, - item_owner.clone(), - collection_id, - 0 - ), - BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) - ); - } + assert_noop!( + Nfts::force_clear_collection_approvals( + RuntimeOrigin::signed(item_owner.clone()), + item_owner.clone(), + collection_id, + 0 + ), + Error::::NoPermission.with_weight(WeightOf::clear_collection_approvals(0)) + ); + assert_noop!( + Nfts::force_clear_collection_approvals(none(), item_owner.clone(), collection_id, 0), + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) + ); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), item_owner.clone(), @@ -4865,7 +4867,7 @@ fn cancel_collection_approval_works() { collection_id, delegate.clone() ), - Error::::Unapproved + Error::::NotDelegate ); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -4880,7 +4882,7 @@ fn cancel_collection_approval_works() { collection_id, account(69) ), - Error::::Unapproved + Error::::NotDelegate ); // Successfully cancel a collection approval. assert_ok!(Nfts::cancel_collection_approval( @@ -4911,17 +4913,24 @@ fn force_cancel_collection_approval_works() { let item_id = 42; let item_owner = account(2); - for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { - assert_noop!( - Nfts::force_cancel_collection_approval( - origin, - item_owner.clone(), - collection_id, - delegate.clone() - ), - BadOrigin - ); - } + assert_noop!( + Nfts::force_cancel_collection_approval( + RuntimeOrigin::signed(item_owner.clone()), + item_owner.clone(), + collection_id, + delegate.clone() + ), + Error::::NoPermission + ); + assert_noop!( + Nfts::force_cancel_collection_approval( + none(), + item_owner.clone(), + collection_id, + delegate.clone() + ), + BadOrigin + ); Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -4943,7 +4952,7 @@ fn force_cancel_collection_approval_works() { collection_id, delegate.clone() ), - Error::::Unapproved + Error::::NotDelegate ); assert_ok!(Nfts::approve_collection_transfer( RuntimeOrigin::signed(item_owner.clone()), @@ -4959,7 +4968,7 @@ fn force_cancel_collection_approval_works() { collection_id, account(69) ), - Error::::Unapproved + Error::::NotDelegate ); // Successfully cancel a collection approval. assert_ok!(Nfts::force_cancel_collection_approval( @@ -4983,7 +4992,7 @@ fn force_cancel_collection_approval_works() { } #[test] -fn check_approval_without_deadline_works() { +fn check_approval_permission_without_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); @@ -4999,11 +5008,11 @@ fn check_approval_without_deadline_works() { )); // Item doesn't exist. assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::UnknownItem ); assert_ok!(Nfts::force_mint( @@ -5015,11 +5024,11 @@ fn check_approval_without_deadline_works() { )); // No approval. assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::NoPermission ); @@ -5030,8 +5039,13 @@ fn check_approval_without_deadline_works() { delegate.clone(), None )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); assert_ok!(Nfts::cancel_collection_approval( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -5047,10 +5061,15 @@ fn check_approval_without_deadline_works() { None )); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); assert_ok!(Nfts::cancel_approval( RuntimeOrigin::signed(item_owner.clone()), collection_id, @@ -5072,13 +5091,18 @@ fn check_approval_without_deadline_works() { delegate.clone(), None )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); }); } #[test] -fn check_approval_with_deadline_works() { +fn check_approval_permission_with_deadline_works() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); @@ -5108,16 +5132,21 @@ fn check_approval_with_deadline_works() { delegate.clone(), Some(deadline), )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); // Expire approval. System::set_block_number(deadline + System::block_number() + 1); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::NoPermission ); assert_ok!(Nfts::cancel_collection_approval( @@ -5136,18 +5165,23 @@ fn check_approval_with_deadline_works() { Some(deadline), )); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); // Expire approval. System::set_block_number(deadline + System::block_number() + 1); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::NoPermission ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::ApprovalExpired ); assert_ok!(Nfts::cancel_approval( @@ -5172,16 +5206,21 @@ fn check_approval_with_deadline_works() { delegate.clone(), Some(deadline) )); - assert_ok!(Nfts::check_approval(&collection_id, &None, &item_owner, &delegate)); - assert_ok!(Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate)); + assert_ok!(Nfts::check_approval_permission( + &collection_id, + &Some(item_id), + &item_owner, + &delegate + )); // Expire approvals. System::set_block_number(deadline + System::block_number() + 1); assert_noop!( - Nfts::check_approval(&collection_id, &None, &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &None, &item_owner, &delegate), Error::::ApprovalExpired ); assert_noop!( - Nfts::check_approval(&collection_id, &Some(item_id), &item_owner, &delegate), + Nfts::check_approval_permission(&collection_id, &Some(item_id), &item_owner, &delegate), Error::::ApprovalExpired ); }); From 11581434d93665c91e485e971184b0ce7d51eebb Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:13:03 +0700 Subject: [PATCH 93/99] chore: rename destroy test method --- 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 04212223..608677a4 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -344,7 +344,7 @@ fn destroy_should_work() { } #[test] -fn destroy_with_collection_approvals_returns_error() { +fn destroy_ensures_no_active_collection_approval() { new_test_ext().execute_with(|| { let collection_id = 0; let collection_owner = account(1); From 05c16f7772ff8c7f493503f6605560ddaed51ba6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:55:57 +0700 Subject: [PATCH 94/99] feat: allow admin to force cancel approvals --- pallets/nfts/src/features/approvals.rs | 2 +- pallets/nfts/src/tests.rs | 75 ++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index cee53666..c38fe5cd 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -231,7 +231,7 @@ impl, I: 'static> Pallet { |maybe_approval| -> DispatchResult { let deposit_required = T::CollectionApprovalDeposit::get(); let current_deposit = - maybe_approval.take().map(|(_, deposit)| deposit).unwrap_or_default(); + maybe_approval.map(|(_, deposit)| deposit).unwrap_or_default(); T::Currency::reserve(&owner, deposit_required - current_deposit)?; *maybe_approval = Some((deadline, deposit_required)); Ok(()) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 608677a4..288f2e2e 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4904,6 +4904,81 @@ fn cancel_collection_approval_works() { }); } +#[test] +fn cancel_collection_approval_works_with_admin() { + new_test_ext().execute_with(|| { + let admin = account(4); + let collection_id = 0; + let collection_owner = account(1); + let delegate = account(3); + let freezer = account(6); + let issuer = account(5); + let item_id = 42; + let item_owner = account(2); + + for origin in [root(), none()] { + assert_noop!( + Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), + BadOrigin + ); + } + Balances::make_free_balance_be(&item_owner, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + collection_owner.clone(), + default_collection_config() + )); + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(collection_owner.clone()), + collection_id, + Some(issuer.clone()), + Some(admin.clone()), + Some(freezer.clone()) + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(issuer.clone()), + collection_id, + item_id, + item_owner.clone(), + default_item_config() + )); + + // Successfully cancel a collection approval. + for origin in [issuer, admin] { + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_ok!(Nfts::force_cancel_collection_approval( + RuntimeOrigin::signed(origin.clone()), + item_owner.clone(), + collection_id, + delegate.clone() + )); + assert_eq!(Balances::reserved_balance(&item_owner), 0); + assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); + } + + assert_ok!(Nfts::approve_collection_transfer( + RuntimeOrigin::signed(item_owner.clone()), + collection_id, + delegate.clone(), + None + )); + assert_noop!( + Nfts::force_cancel_collection_approval( + RuntimeOrigin::signed(freezer), + item_owner, + collection_id, + delegate + ), + Error::::NoPermission + ); + }); +} + #[test] fn force_cancel_collection_approval_works() { new_test_ext().execute_with(|| { From 68a86c64b4acf0ab795ead59049652d942b60cbf Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:55:35 +0700 Subject: [PATCH 95/99] refactor: force_cancel_collection_approval_works_with_admin --- pallets/nfts/src/tests.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 288f2e2e..9512ae17 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4905,23 +4905,17 @@ fn cancel_collection_approval_works() { } #[test] -fn cancel_collection_approval_works_with_admin() { +fn force_cancel_collection_approval_works_with_admin() { new_test_ext().execute_with(|| { - let admin = account(4); let collection_id = 0; + let item_id = 42; let collection_owner = account(1); + let item_owner = account(2); let delegate = account(3); - let freezer = account(6); + let admin = account(4); let issuer = account(5); - let item_id = 42; - let item_owner = account(2); + let freezer = account(6); - for origin in [root(), none()] { - assert_noop!( - Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), - BadOrigin - ); - } Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), From 1cdad4436b3e66ef45cf2905d0502e881c00f938 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:13:46 +0700 Subject: [PATCH 96/99] feat(nfts): `AccountBalance` deposit (#413) Co-authored-by: Frank Bell Co-authored-by: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com> --- pallets/nfts/src/benchmarking.rs | 6 +- pallets/nfts/src/common_functions.rs | 132 ++- pallets/nfts/src/features/approvals.rs | 7 +- pallets/nfts/src/features/atomic_swap.rs | 13 +- pallets/nfts/src/features/buy_sell.rs | 2 +- .../nfts/src/features/create_delete_item.rs | 41 +- pallets/nfts/src/features/transfer.rs | 23 +- pallets/nfts/src/impl_nonfungibles.rs | 6 +- pallets/nfts/src/lib.rs | 28 +- pallets/nfts/src/mock.rs | 1 + pallets/nfts/src/tests.rs | 281 ++++-- pallets/nfts/src/types.rs | 3 + pallets/nfts/src/weights.rs | 804 +++++++++--------- runtime/devnet/src/config/assets.rs | 12 + runtime/testnet/src/config/assets.rs | 12 + 15 files changed, 842 insertions(+), 529 deletions(-) diff --git a/pallets/nfts/src/benchmarking.rs b/pallets/nfts/src/benchmarking.rs index bfe961e8..33c7dc5c 100644 --- a/pallets/nfts/src/benchmarking.rs +++ b/pallets/nfts/src/benchmarking.rs @@ -274,6 +274,7 @@ benchmarks_instance_pallet! { mint { let (collection, caller, caller_lookup) = create_collection::(); let item = T::Helper::item(0); + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() + T::CollectionDeposit::get() + T::CollectionBalanceDeposit::get()); }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, None) verify { assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); @@ -282,6 +283,7 @@ benchmarks_instance_pallet! { force_mint { let (collection, caller, caller_lookup) = create_collection::(); let item = T::Helper::item(0); + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() + T::CollectionDeposit::get() + T::CollectionBalanceDeposit::get()); }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, default_item_config()) verify { assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); @@ -667,7 +669,7 @@ benchmarks_instance_pallet! { let price = ItemPrice::::from(0u32); let origin = SystemOrigin::Signed(seller.clone()).into(); Nfts::::set_price(origin, collection, item, Some(price), Some(buyer_lookup))?; - T::Currency::make_free_balance_be(&buyer, DepositBalanceOf::::max_value()); + T::Currency::make_free_balance_be(&buyer, T::Currency::minimum_balance() + price + T::CollectionBalanceDeposit::get()); }: _(SystemOrigin::Signed(buyer.clone()), collection, item, price) verify { assert_last_event::(Event::ItemBought { @@ -757,7 +759,7 @@ benchmarks_instance_pallet! { let duration = T::MaxDeadlineDuration::get(); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance() + T::CollectionBalanceDeposit::get()); let origin = SystemOrigin::Signed(caller.clone()); frame_system::Pallet::::set_block_number(One::one()); Nfts::::transfer(origin.clone().into(), collection, item2, target_lookup)?; diff --git a/pallets/nfts/src/common_functions.rs b/pallets/nfts/src/common_functions.rs index 38f6cfc8..f27a9029 100644 --- a/pallets/nfts/src/common_functions.rs +++ b/pallets/nfts/src/common_functions.rs @@ -19,7 +19,7 @@ use alloc::vec::Vec; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError}; use crate::*; @@ -92,6 +92,52 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); } + /// Increment the number of items in the `collection` owned by the `owner`. If no entry exists + /// for the `owner` in `AccountBalance`, create a new record and reserve `deposit_amount` from + /// the `deposit_account`. + pub(crate) fn increment_account_balance( + collection: T::CollectionId, + owner: &T::AccountId, + (deposit_account, deposit_amount): (&T::AccountId, DepositBalanceOf), + ) -> DispatchResult { + AccountBalance::::mutate(collection, owner, |maybe_balance| -> DispatchResult { + match maybe_balance { + None => { + T::Currency::reserve(deposit_account, deposit_amount)?; + *maybe_balance = Some((1, (deposit_account.clone(), deposit_amount))); + }, + Some((balance, _deposit)) => { + balance.saturating_inc(); + }, + } + Ok(()) + }) + } + + /// Decrement the number of `collection` items owned by the `owner`. If the `owner`'s item + /// count reaches zero after the reduction, remove the `AccountBalance` record and unreserve + /// the deposited funds. + pub(crate) fn decrement_account_balance( + collection: T::CollectionId, + owner: &T::AccountId, + ) -> DispatchResult { + AccountBalance::::try_mutate_exists( + collection, + owner, + |maybe_balance| -> DispatchResult { + let (balance, (deposit_account, deposit_amount)) = + maybe_balance.as_mut().ok_or(Error::::NoItemOwned)?; + + *balance = balance.checked_sub(1).ok_or(ArithmeticError::Underflow)?; + if balance.is_zero() { + T::Currency::unreserve(deposit_account, *deposit_amount); + *maybe_balance = None; + } + Ok(()) + }, + ) + } + #[allow(missing_docs)] #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_next_id(id: T::CollectionId) { @@ -105,3 +151,87 @@ impl, I: 'static> Pallet { .expect("Failed to get next collection ID") } } + +#[cfg(test)] +mod tests { + use crate::{mock::*, tests::*, Currency, Error, ReservableCurrency}; + + #[test] + fn increment_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let deposit_account = account(1); + let deposit_amount = balance_deposit(); + let owner = account(2); + assert_noop!( + Nfts::increment_account_balance( + collection_id, + &owner, + (&deposit_account, deposit_amount) + ), + BalancesError::::InsufficientBalance + ); + Balances::make_free_balance_be(&deposit_account, 100); + // Initialize `AccountBalance` and increase the collection item count for the new + // account. + assert_ok!(Nfts::increment_account_balance( + collection_id, + &owner, + (&deposit_account, deposit_amount) + )); + assert_eq!(Balances::reserved_balance(&deposit_account), deposit_amount); + assert_eq!( + AccountBalance::get(collection_id, &owner), + Some((1, (deposit_account.clone(), deposit_amount))) + ); + // Increment the balance of a non-zero balance account. No additional reserves. + assert_ok!(Nfts::increment_account_balance( + collection_id, + &owner, + (&deposit_account, deposit_amount) + )); + assert_eq!(Balances::reserved_balance(&deposit_account), deposit_amount); + assert_eq!( + AccountBalance::get(collection_id, &owner), + Some((2, (deposit_account.clone(), deposit_amount))) + ); + }); + } + + #[test] + fn decrement_account_balance_works() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let balance = 2u32; + let deposit_account = account(1); + let deposit_amount = balance_deposit(); + let owner = account(2); + + Balances::make_free_balance_be(&deposit_account, 100); + // Decrement non-existing `AccountBalance` record. + assert_noop!( + Nfts::decrement_account_balance(collection_id, &deposit_account), + Error::::NoItemOwned + ); + // Set account balance and reserve `DepositBalance`. + AccountBalance::insert( + collection_id, + &owner, + (&balance, (&deposit_account, deposit_amount)), + ); + Balances::reserve(&deposit_account, deposit_amount).expect("should work"); + // Successfully decrement the value of the `AccountBalance` entry. + assert_ok!(Nfts::decrement_account_balance(collection_id, &owner)); + assert_eq!( + AccountBalance::get(collection_id, &owner), + Some((balance - 1, (deposit_account.clone(), deposit_amount))) + ); + assert_eq!(Balances::reserved_balance(&deposit_account), deposit_amount); + // `AccountBalance` record is deleted, and the depositor's funds are unreserved if + // the `AccountBalance` value reaches zero after decrementing. + assert_ok!(Nfts::decrement_account_balance(collection_id, &owner)); + assert_eq!(Balances::reserved_balance(&deposit_account), 0); + assert!(!AccountBalance::contains_key(collection_id, &owner)); + }); + } +} diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index c38fe5cd..218ab569 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -216,7 +216,12 @@ impl, I: 'static> Pallet { Self::is_pallet_feature_enabled(PalletFeature::Approvals), Error::::MethodDisabled ); - ensure!(AccountBalance::::get(collection, &owner) > 0, Error::::NoItemOwned); + ensure!( + AccountBalance::::get(collection, &owner) + .filter(|(balance, _)| !balance.is_zero()) + .is_some(), + Error::::NoItemOwned + ); let collection_config = Self::get_collection_config(&collection)?; ensure!( diff --git a/pallets/nfts/src/features/atomic_swap.rs b/pallets/nfts/src/features/atomic_swap.rs index 75945d43..1ffd6dce 100644 --- a/pallets/nfts/src/features/atomic_swap.rs +++ b/pallets/nfts/src/features/atomic_swap.rs @@ -209,13 +209,20 @@ impl, I: 'static> Pallet { } // This also removes the swap. - Self::do_transfer(send_collection_id, send_item_id, receive_item.owner.clone(), |_, _| { - Ok(()) - })?; + Self::do_transfer( + send_collection_id, + send_item_id, + receive_item.owner.clone(), + Some(&receive_item.owner), + |_, _| Ok(()), + )?; + // Owner of `send_item` is responsible for the deposit if the collection balance + // went to zero due to the previous transfer. Self::do_transfer( receive_collection_id, receive_item_id, send_item.owner.clone(), + Some(&send_item.owner), |_, _| Ok(()), )?; diff --git a/pallets/nfts/src/features/buy_sell.rs b/pallets/nfts/src/features/buy_sell.rs index 476053ee..2b4d2967 100644 --- a/pallets/nfts/src/features/buy_sell.rs +++ b/pallets/nfts/src/features/buy_sell.rs @@ -158,7 +158,7 @@ impl, I: 'static> Pallet { let old_owner = details.owner.clone(); - Self::do_transfer(collection, item, buyer.clone(), |_, _| Ok(()))?; + Self::do_transfer(collection, item, buyer.clone(), Some(&buyer), |_, _| Ok(()))?; Self::deposit_event(Event::ItemBought { collection, diff --git a/pallets/nfts/src/features/create_delete_item.rs b/pallets/nfts/src/features/create_delete_item.rs index 0e51759c..5c687d42 100644 --- a/pallets/nfts/src/features/create_delete_item.rs +++ b/pallets/nfts/src/features/create_delete_item.rs @@ -18,7 +18,7 @@ //! This module contains helper methods to perform functionality associated with minting and burning //! items for the NFTs pallet. -use frame_support::{pallet_prelude::*, sp_runtime::ArithmeticError, traits::ExistenceRequirement}; +use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use crate::*; @@ -68,20 +68,20 @@ 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.is_setting_enabled(CollectionSetting::DepositRequired) { - true => T::ItemDeposit::get(), - false => Zero::zero(), - }; - let deposit_account = match maybe_depositor { - None => collection_details.owner.clone(), - Some(depositor) => depositor, - }; + let deposit_required = + collection_config.is_setting_enabled(CollectionSetting::DepositRequired); + let deposit_account = + maybe_depositor.unwrap_or_else(|| collection_details.owner.clone()); + + let balance_deposit = deposit_required + .then_some(T::CollectionBalanceDeposit::get()) + .unwrap_or_default(); + Self::increment_account_balance( + collection, + &mint_to, + (&deposit_account, balance_deposit), + )?; let item_owner = mint_to.clone(); Account::::insert((&item_owner, &collection, &item), ()); @@ -93,9 +93,11 @@ impl, I: 'static> Pallet { collection_details.item_configs.saturating_inc(); } - T::Currency::reserve(&deposit_account, deposit_amount)?; + let item_deposit = + deposit_required.then_some(T::ItemDeposit::get()).unwrap_or_default(); + T::Currency::reserve(&deposit_account, item_deposit)?; - let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; + let deposit = ItemDeposit { account: deposit_account, amount: item_deposit }; let details = ItemDetails { owner: item_owner, approvals: ApprovalsOf::::default(), @@ -264,12 +266,7 @@ impl, I: 'static> Pallet { PendingSwapOf::::remove(collection, item); ItemAttributesApprovalsOf::::remove(collection, item); - let balance = AccountBalance::::take(collection, &owner) - .checked_sub(1) - .ok_or(ArithmeticError::Underflow)?; - if balance > 0 { - AccountBalance::::insert(collection, &owner, balance); - } + Self::decrement_account_balance(collection, &owner)?; if remove_config { ItemConfigOf::::remove(collection, item); diff --git a/pallets/nfts/src/features/transfer.rs b/pallets/nfts/src/features/transfer.rs index ffe0befe..9f5dc77b 100644 --- a/pallets/nfts/src/features/transfer.rs +++ b/pallets/nfts/src/features/transfer.rs @@ -28,6 +28,8 @@ impl, I: 'static> Pallet { /// - `collection`: The ID of the collection to which the NFT belongs. /// - `item`: The ID of the NFT to transfer. /// - `dest`: The destination account to which the NFT will be transferred. + /// - `depositor`: The account reserving the `CollectionBalanceDeposit` from if `dest` holds no + /// items in the collection. /// - `with_details`: A closure that provides access to the collection and item details, /// allowing customization of the transfer process. /// @@ -48,6 +50,7 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, dest: T::AccountId, + depositor: Option<&T::AccountId>, with_details: impl FnOnce( &CollectionDetailsFor, &mut ItemDetailsFor, @@ -87,16 +90,18 @@ impl, I: 'static> Pallet { with_details(&collection_details, &mut details)?; // Update account balance of the owner. - let balance = AccountBalance::::take(collection, &details.owner) - .checked_sub(1) - .ok_or(Error::::NoItemOwned)?; - if balance > 0 { - AccountBalance::::insert(collection, &details.owner, balance); - } + Self::decrement_account_balance(collection, &details.owner)?; + + let deposit_amount = collection_config + .is_setting_enabled(CollectionSetting::DepositRequired) + .then_some(T::CollectionBalanceDeposit::get()) + .unwrap_or_default(); + // Reserve `CollectionBalanceDeposit` from the depositor if provided. Otherwise, reserve + // from the item's owner. + let deposit_account = depositor.unwrap_or(&details.owner); + // Update account balance of the destination account. - AccountBalance::::mutate(collection, &dest, |balance| { - balance.saturating_inc(); - }); + Self::increment_account_balance(collection, &dest, (deposit_account, deposit_amount))?; // Update account ownership information. Account::::remove((&details.owner, &collection, &item)); diff --git a/pallets/nfts/src/impl_nonfungibles.rs b/pallets/nfts/src/impl_nonfungibles.rs index b014e3ed..e8fa4457 100644 --- a/pallets/nfts/src/impl_nonfungibles.rs +++ b/pallets/nfts/src/impl_nonfungibles.rs @@ -411,7 +411,11 @@ impl, I: 'static> Transfer for Pallet { item: &Self::ItemId, destination: &T::AccountId, ) -> DispatchResult { - Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(())) + // The item's owner pays for the deposit of `AccountBalance` if the `dest` holds no items + // in `collection`. If `dest` paid the deposit, a malicious actor could transfer NFTs to + // reserve involuntary deposits for `dest` . The deposit amount can be accounted for in the + // off chain price of the NFT. + Self::do_transfer(*collection, *item, destination.clone(), None, |_, _| Ok(())) } fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index a087f046..ac9932d7 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -178,12 +178,6 @@ pub mod pallet { #[pallet::constant] type CollectionDeposit: Get>; - /// The basic amount of funds that must be reserved for a collection approval. - // Key: `sizeof((CollectionId, AccountId, AccountId))` bytes. - // Value: `sizeof((Option, Balance))` bytes. - #[pallet::constant] - type CollectionApprovalDeposit: Get>; - /// The basic amount of funds that must be reserved for an item. #[pallet::constant] type ItemDeposit: Get>; @@ -259,6 +253,18 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// The basic amount of funds that must be reserved for a collection approval. + // Key: `sizeof((CollectionId, AccountId, AccountId))` bytes. + // Value: `sizeof((Option, Balance))` bytes. + #[pallet::constant] + type CollectionApprovalDeposit: Get>; + + /// The basic amount of funds that must be reversed for an account's collection balance. + // Key: `sizeof((CollectionId, AccountId))` bytes. + // Value: `sizeof((u32, Some(AccountId, Balance)))` bytes. + #[pallet::constant] + type CollectionBalanceDeposit: Get>; } /// Details of a collection. @@ -435,8 +441,8 @@ pub mod pallet { T::CollectionId, Blake2_128Concat, T::AccountId, - u32, - ValueQuery, + // (Account's collection items, Deposit details). + (u32, AccountDepositOf), >; /// Permission for a delegate to transfer all owner's collection items. @@ -1092,7 +1098,11 @@ pub mod pallet { let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - Self::do_transfer(collection, item, dest, |_, details| { + // The item's owner pays for the deposit of `AccountBalance` if the `dest` holds no + // items in `collection`. A malicious actor could have a deposit reserved from `dest` + // without them knowing about the transfer. The deposit amount can be accounted for + // in the off chain price of the NFT. + Self::do_transfer(collection, item, dest, None, |_, details| { if details.owner != origin { Self::check_approval_permission( &collection, diff --git a/pallets/nfts/src/mock.rs b/pallets/nfts/src/mock.rs index c6e4211e..efd72722 100644 --- a/pallets/nfts/src/mock.rs +++ b/pallets/nfts/src/mock.rs @@ -66,6 +66,7 @@ impl Config for Test { type ApprovalsLimit = ConstU32<10>; type AttributeDepositBase = ConstU64<1>; type CollectionApprovalDeposit = ConstU64<1>; + type CollectionBalanceDeposit = ConstU64<1>; type CollectionDeposit = ConstU64<2>; type CollectionId = u32; type CreateOrigin = AsEnsureOriginWithArg>; diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 9512ae17..0faa4185 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for Nfts pallet. use enumflags2::BitFlags; -use frame_support::{ +pub(crate) use frame_support::{ assert_noop, assert_ok, dispatch::WithPostDispatchInfo, traits::{ @@ -27,7 +27,7 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_balances::Error as BalancesError; +pub(crate) use pallet_balances::Error as BalancesError; use sp_core::{bounded::BoundedVec, Pair}; use sp_runtime::{ traits::{Dispatchable, IdentifyAccount}, @@ -38,19 +38,15 @@ use sp_runtime::{ use crate::{mock::*, Event, SystemConfig, *}; type AccountIdOf = ::AccountId; -type AccountBalance = crate::AccountBalance; +pub(crate) type AccountBalance = crate::AccountBalance; type CollectionApprovals = crate::CollectionApprovals; type CollectionApprovalDeposit = ::CollectionApprovalDeposit; type WeightOf = ::WeightInfo; -fn account(id: u8) -> AccountIdOf { +pub(crate) fn account(id: u8) -> AccountIdOf { [id; 32].into() } -fn root() -> RuntimeOrigin { - RuntimeOrigin::root() -} - fn none() -> RuntimeOrigin { RuntimeOrigin::none() } @@ -162,6 +158,14 @@ fn item_config_from_disabled_settings(settings: BitFlags) -> ItemCo ItemConfig { settings: ItemSettings::from_disabled(settings) } } +pub(crate) fn balance_deposit() -> DepositBalanceOf { + <::CollectionBalanceDeposit>::get() +} + +pub(crate) fn item_deposit() -> DepositBalanceOf { + <::ItemDeposit>::get() +} + #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { @@ -195,6 +199,8 @@ fn basic_minting_should_work() { #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 100); Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( @@ -219,7 +225,7 @@ fn lifecycle_should_work() { account(10), default_item_config() )); - assert_eq!(Balances::reserved_balance(&account(1)), 6); + assert_eq!(Balances::reserved_balance(&account(1)), 6 + balance_deposit); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(account(1)), 0, @@ -227,23 +233,23 @@ fn lifecycle_should_work() { account(20), default_item_config() )); - assert_eq!(Balances::reserved_balance(&account(1)), 7); + assert_eq!(Balances::reserved_balance(&account(1)), 7 + 2 * balance_deposit); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); 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); assert_eq!(Collection::::get(0).unwrap().item_configs, 3); - assert_eq!(Balances::reserved_balance(&account(1)), 8); + assert_eq!(Balances::reserved_balance(&account(1)), 8 + 3 * balance_deposit); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); - assert_eq!(Balances::reserved_balance(&account(1)), 8); + assert_eq!(Balances::reserved_balance(&account(1)), 8 + 3 * balance_deposit); assert_eq!(Balances::reserved_balance(&account(2)), 0); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); - assert_eq!(Balances::reserved_balance(&account(1)), 11); + assert_eq!(Balances::reserved_balance(&account(1)), 11 + 3 * balance_deposit); assert!(ItemMetadataOf::::contains_key(0, 42)); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); - assert_eq!(Balances::reserved_balance(&account(1)), 14); + assert_eq!(Balances::reserved_balance(&account(1)), 14 + 3 * balance_deposit); assert!(ItemMetadataOf::::contains_key(0, 69)); assert!(ItemConfigOf::::contains_key(0, 69)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -525,33 +531,45 @@ fn mint_should_work() { #[test] fn mint_should_update_account_balance_works() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); let collection_id = 0; - let owner = account(1); + let dest = account(1); + let owner = account(2); + Balances::make_free_balance_be(&owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), owner.clone(), - default_collection_config() + collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint( RuntimeOrigin::signed(owner.clone()), collection_id, 42, - owner.clone(), + dest.clone(), None )); - assert_eq!(AccountBalance::get(collection_id, &owner), 1); - - // Additive. + // Minting reserves a deposit because `dest` doesn't have an item in the collection yet and + // thus a storage item has to be created. + assert_eq!( + AccountBalance::get(collection_id, dest.clone()), + Some((1, (owner.clone(), balance_deposit))) + ); + assert_eq!(Balances::reserved_balance(&owner), item_deposit() + balance_deposit); assert_ok!(Nfts::mint( RuntimeOrigin::signed(owner.clone()), collection_id, 43, - owner.clone(), + dest.clone(), None )); - assert_eq!(AccountBalance::get(collection_id, &owner), 2); + // `dest` already has an item in the collection so no extra deposit is reserved. + assert_eq!( + AccountBalance::get(collection_id, &dest), + Some((2, (owner.clone(), balance_deposit))) + ); + assert_eq!(Balances::reserved_balance(&owner), (2 * item_deposit()) + balance_deposit); + assert_eq!(Balances::reserved_balance(&dest), 0); }); } @@ -615,15 +633,18 @@ fn transfer_should_work() { #[test] fn transfer_should_update_account_balance_works() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); let collection_id = 0; - let dest = account(3); + let delegate = account(1); + let dest = account(2); let item_id = 42; - let owner = account(1); + let owner = account(3); + Balances::make_free_balance_be(&owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), owner.clone(), - default_collection_config() + collection_config_with_all_settings_enabled() )); assert_ok!(Nfts::force_mint( RuntimeOrigin::signed(owner.clone()), @@ -639,13 +660,45 @@ fn transfer_should_update_account_balance_works() { dest.clone() )); assert!(!AccountBalance::contains_key(collection_id, &owner)); - assert_eq!(AccountBalance::get(collection_id, &dest), 1); + assert_eq!( + AccountBalance::get(collection_id, &dest), + Some((1, (owner.clone(), balance_deposit))) + ); + // Reserve funds from `owner` when transferring to `dest`. + assert_eq!(Balances::reserved_balance(&owner), item_deposit() + balance_deposit); + assert_eq!(Balances::reserved_balance(&dest), 0); + + // Approve `delegate` for approved transfer case. + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(dest.clone()), + collection_id, + item_id, + delegate.clone(), + None + )); + Balances::make_free_balance_be(&dest, Balances::minimum_balance() + balance_deposit); + assert_ok!(Nfts::transfer( + RuntimeOrigin::signed(delegate.clone()), + collection_id, + item_id, + owner.clone() + )); + assert_eq!( + AccountBalance::get(collection_id, &owner), + Some((1, (dest.clone(), balance_deposit))) + ); + // Reserve funds from `dest` during a delegated transfer initiated by the + // `delegate` back to `owner`. + assert_eq!(Balances::reserved_balance(&owner), item_deposit()); + assert_eq!(Balances::reserved_balance(&delegate), 0); + assert_eq!(Balances::reserved_balance(&dest), balance_deposit); }); } #[test] fn locking_transfer_should_work() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), account(1), @@ -732,6 +785,8 @@ fn origin_guards_should_work() { #[test] fn transfer_owner_should_work() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 100); Balances::make_free_balance_be(&account(2), 100); Balances::make_free_balance_be(&account(3), 100); @@ -772,7 +827,7 @@ fn transfer_owner_should_work() { bvec![0u8; 20], )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - assert_eq!(Balances::reserved_balance(&account(1)), 1); + assert_eq!(Balances::reserved_balance(&account(1)), 1 + balance_deposit); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(3)), Some(0))); assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(3))); @@ -783,8 +838,9 @@ fn transfer_owner_should_work() { assert_eq!(Balances::reserved_balance(&account(3)), 44); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); - // reserved_balance of accounts 1 & 2 should be unchanged: - assert_eq!(Balances::reserved_balance(&account(1)), 1); + // The reserved balance of account 1 is incremented to create a new storage record for the + // account 2. + assert_eq!(Balances::reserved_balance(&account(1)), 1 + balance_deposit); assert_eq!(Balances::reserved_balance(&account(2)), 0); // 2's acceptance from before is reset when it became an owner, so it cannot be transferred @@ -960,6 +1016,8 @@ fn set_collection_metadata_should_work() { #[test] fn set_item_metadata_should_work() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 30); // Cannot add metadata to unknown item @@ -977,7 +1035,7 @@ fn set_item_metadata_should_work() { // Successfully add metadata and take deposit assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); - assert_eq!(Balances::free_balance(&account(1)), 8); + assert_eq!(Balances::free_balance(&account(1)), 8 - balance_deposit); assert!(ItemMetadataOf::::contains_key(0, 42)); // Force origin works, too. @@ -985,9 +1043,9 @@ fn set_item_metadata_should_work() { // Update deposit assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15])); - assert_eq!(Balances::free_balance(&account(1)), 13); + assert_eq!(Balances::free_balance(&account(1)), 13 - balance_deposit); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 25])); - assert_eq!(Balances::free_balance(&account(1)), 3); + assert_eq!(Balances::free_balance(&account(1)), 3 - balance_deposit); // Cannot over-reserve assert_noop!( @@ -1031,6 +1089,8 @@ fn set_item_metadata_should_work() { #[test] fn set_collection_owner_attributes_should_work() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( @@ -1072,7 +1132,7 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(account(1)), 10); + assert_eq!(Balances::reserved_balance(account(1)), 10 + balance_deposit); assert_eq!(Collection::::get(0).unwrap().owner_deposit, 9); assert_ok!(Nfts::set_attribute( @@ -1091,7 +1151,7 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(account(1)), 19); + assert_eq!(Balances::reserved_balance(account(1)), 19 + balance_deposit); assert_eq!(Collection::::get(0).unwrap().owner_deposit, 18); assert_ok!(Nfts::clear_attribute( @@ -1108,7 +1168,7 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(account(1)), 16); + assert_eq!(Balances::reserved_balance(account(1)), 16 + balance_deposit); assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 0)); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -1352,7 +1412,7 @@ fn set_item_owner_attributes_should_work() { Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); assert_eq!(deposit.account, Some(account(3))); assert_eq!(deposit.amount, 13); - assert_eq!(Balances::reserved_balance(account(2)), 3); + assert_eq!(Balances::reserved_balance(account(2)), 3 + balance_deposit()); assert_eq!(Balances::reserved_balance(account(3)), 13); // validate attributes on item deletion @@ -1602,7 +1662,7 @@ fn set_attribute_should_respect_lock() { (Some(1), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(account(1)), 11); + assert_eq!(Balances::reserved_balance(account(1)), 11 + balance_deposit()); assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![])); assert_ok!(Nfts::lock_collection( @@ -1721,6 +1781,8 @@ fn preserve_config_for_frozen_items() { #[test] fn force_update_collection_should_work() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( @@ -1743,7 +1805,7 @@ fn force_update_collection_should_work() { )); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0; 20])); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![0; 20])); - assert_eq!(Balances::reserved_balance(account(1)), 65); + assert_eq!(Balances::reserved_balance(account(1)), 65 + 2 * balance_deposit); // force item status to be free holding assert_ok!(Nfts::force_collection_config( @@ -1772,7 +1834,7 @@ fn force_update_collection_should_work() { Some(account(4)), )); assert_eq!(collections(), vec![(account(5), 0)]); - assert_eq!(Balances::reserved_balance(account(1)), 2); + assert_eq!(Balances::reserved_balance(account(1)), 2 + 2 * balance_deposit); assert_eq!(Balances::reserved_balance(account(5)), 63); assert_ok!(Nfts::redeposit( @@ -1780,7 +1842,7 @@ fn force_update_collection_should_work() { 0, bvec![0, 42, 50, 69, 100] )); - assert_eq!(Balances::reserved_balance(account(1)), 0); + assert_eq!(Balances::reserved_balance(account(1)), 2 * balance_deposit); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(5)), 0, 42, bvec![0; 20])); assert_eq!(Balances::reserved_balance(account(5)), 42); @@ -1838,6 +1900,8 @@ fn force_update_collection_should_work() { #[test] fn burn_works() { new_test_ext().execute_with(|| { + let balance_deposit = balance_deposit(); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -1871,7 +1935,7 @@ fn burn_works() { account(5), default_item_config() )); - assert_eq!(Balances::reserved_balance(account(1)), 2); + assert_eq!(Balances::reserved_balance(account(1)), 2 + balance_deposit); assert_noop!( Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), @@ -1912,10 +1976,15 @@ fn burn_should_update_account_balance_works() { )); assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 42)); - assert_eq!(AccountBalance::get(collection_id, &owner), 1); + assert_eq!( + AccountBalance::get(collection_id, &owner), + Some((1, (owner.clone(), balance_deposit()))) + ); + assert_eq!(Balances::reserved_balance(&owner), item_deposit() + balance_deposit()); assert_ok!(Nfts::burn(RuntimeOrigin::signed(owner.clone()), collection_id, 43)); assert!(!AccountBalance::contains_key(collection_id, &owner)); + assert_eq!(Balances::reserved_balance(&owner), 0); }); } @@ -2947,43 +3016,45 @@ fn buy_item_should_update_account_balance_works() { let user_1 = account(1); let user_2 = account(2); let collection_id = 0; - let item_1 = 1; - let price_1 = 20; - let initial_balance = 100; - - Balances::make_free_balance_be(&user_1, initial_balance); - Balances::make_free_balance_be(&user_2, initial_balance); + let item = 1; + let price = 20; + Balances::make_free_balance_be(&user_1, 100); + Balances::make_free_balance_be( + &user_2, + Balances::minimum_balance() + price + balance_deposit(), + ); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), user_1.clone(), - default_collection_config() + collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint( RuntimeOrigin::signed(user_1.clone()), collection_id, - item_1, + item, user_1.clone(), None )); - assert_ok!(Nfts::set_price( RuntimeOrigin::signed(user_1.clone()), collection_id, - item_1, - Some(price_1), + item, + Some(price), None, )); - assert_ok!(Nfts::buy_item( RuntimeOrigin::signed(user_2.clone()), collection_id, - item_1, - price_1 + 1, + item, + price, )); - assert_eq!(AccountBalance::get(collection_id, &user_1), 0); - assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + assert!(!AccountBalance::contains_key(collection_id, &user_1)); + assert_eq!( + AccountBalance::get(collection_id, &user_2), + Some((1, (user_2.clone(), balance_deposit()))) + ); + assert_eq!(Balances::reserved_balance(&user_2), balance_deposit()); }); } @@ -3419,14 +3490,15 @@ fn claim_swap_should_update_account_balance_works() { PriceWithDirection { amount: price, direction: PriceDirection::Receive.clone() }; Balances::make_free_balance_be(&user_1, 1000); - Balances::make_free_balance_be(&user_2, 1000); - + Balances::make_free_balance_be( + &user_2, + Balances::minimum_balance() + balance_deposit() + price, + ); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), user_1.clone(), - default_collection_config() + collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3434,13 +3506,17 @@ fn claim_swap_should_update_account_balance_works() { user_1.clone(), None, )); - assert_ok!(Nfts::force_mint( + assert_ok!(Nfts::mint( RuntimeOrigin::signed(user_1.clone()), collection_id, item_2, user_2.clone(), - default_item_config(), + None, )); + assert_eq!( + Balances::reserved_balance(&user_1), + (2 * item_deposit()) + (2 * balance_deposit()) + ); assert_ok!(Nfts::create_swap( RuntimeOrigin::signed(user_1.clone()), collection_id, @@ -3450,7 +3526,6 @@ fn claim_swap_should_update_account_balance_works() { Some(price_with_direction.clone()), 2 )); - assert_ok!(Nfts::claim_swap( RuntimeOrigin::signed(user_2.clone()), collection_id, @@ -3459,8 +3534,18 @@ fn claim_swap_should_update_account_balance_works() { item_1, Some(price_with_direction), )); - assert_eq!(AccountBalance::get(collection_id, &user_1), 1); - assert_eq!(AccountBalance::get(collection_id, &user_2), 1); + assert_eq!( + AccountBalance::get(collection_id, &user_1), + Some((1, (user_1.clone(), balance_deposit()))) + ); + assert_eq!( + AccountBalance::get(collection_id, &user_2), + Some((1, (user_2.clone(), balance_deposit()))) + ); + assert_eq!(Balances::reserved_balance(&user_1), (2 * item_deposit()) + balance_deposit()); + // User pays for its own deposit (previously paid by the account who signed the mint + // transaction). + assert_eq!(Balances::reserved_balance(&user_2), balance_deposit()); }); } @@ -3804,7 +3889,7 @@ fn pre_signed_mints_should_work() { assert_eq!(deposit.amount, 3); assert_eq!(Balances::free_balance(&user_0), 100 - 2 + 10); // 2 - collection deposit, 10 - mint price - assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6 - 10); // 1 - item deposit, 3 - metadata, 6 - attributes, 10 - mint price + assert_eq!(Balances::free_balance(&user_2), 100 - balance_deposit() - 1 - 3 - 6 - 10); // 1 - item deposit, 3 - metadata, 6 - attributes, 10 - mint price assert_noop!( Nfts::mint_pre_signed( @@ -3979,7 +4064,7 @@ fn pre_signed_attributes_should_work() { assert_eq!(deposit.account, Some(user_2.clone())); assert_eq!(deposit.amount, 3); - assert_eq!(Balances::free_balance(&user_1), 100 - 2 - 1); // 2 - collection deposit, 1 - item deposit + assert_eq!(Balances::free_balance(&user_1), 100 - 2 - 1 - balance_deposit()); // 2 - collection deposit, 1 - item deposit assert_eq!(Balances::free_balance(&user_2), 100 - 6); // 6 - attributes // validate the deposit gets returned on attribute update from collection's owner @@ -4340,7 +4425,7 @@ fn clear_collection_approvals_works() { let item_owner = account(1); let delegates = 10..20; - for origin in [root(), none()] { + for origin in [RuntimeOrigin::root(), none()] { assert_noop!( Nfts::clear_collection_approvals(origin, collection_id, 0), BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) @@ -4435,7 +4520,12 @@ fn clear_collection_approvals_works() { // Remove collection approvals while there are none. assert_eq!( - Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Nfts::force_clear_collection_approvals( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + 10 + ), Ok(Some(WeightOf::clear_collection_approvals(0)).into()) ); assert_eq!(Balances::free_balance(&item_owner), balance); @@ -4509,7 +4599,12 @@ fn force_clear_collection_approvals_works() { // Remove zero collection approvals. assert_eq!( - Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 0), + Nfts::force_clear_collection_approvals( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + 0 + ), Ok(Some(WeightOf::clear_collection_approvals(0)).into()) ); assert_eq!(Balances::free_balance(&item_owner), balance - approvals as u64); @@ -4527,7 +4622,7 @@ fn force_clear_collection_approvals_works() { let limit = 1; assert_eq!( Nfts::force_clear_collection_approvals( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, limit @@ -4549,7 +4644,12 @@ fn force_clear_collection_approvals_works() { // Successfully remove all collection approvals. Only charges post-dispatch weight for // the removed approvals. assert_eq!( - Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Nfts::force_clear_collection_approvals( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + 10 + ), Ok(Some(WeightOf::clear_collection_approvals(approvals)).into()) ); assert_eq!(Balances::free_balance(&item_owner), balance); @@ -4564,7 +4664,12 @@ fn force_clear_collection_approvals_works() { // Remove collection approvals while there are none. assert_eq!( - Nfts::force_clear_collection_approvals(root(), item_owner.clone(), collection_id, 10), + Nfts::force_clear_collection_approvals( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + 10 + ), Ok(Some(WeightOf::clear_collection_approvals(0)).into()) ); assert_eq!(Balances::free_balance(&item_owner), balance); @@ -4600,7 +4705,7 @@ fn approve_collection_transfer_works() { let item_id = 42; let item_owner = account(2); - for origin in [root(), none()] { + for origin in [RuntimeOrigin::root(), none()] { assert_noop!( Nfts::approve_collection_transfer(origin, collection_id, delegate.clone(), None), BadOrigin @@ -4617,7 +4722,7 @@ fn approve_collection_transfer_works() { Error::::NoItemOwned ); assert_ok!(Nfts::force_create( - root(), + RuntimeOrigin::root(), collection_owner.clone(), default_collection_config() )); @@ -4731,7 +4836,7 @@ fn force_approve_collection_transfer_works() { // Approve unknown collection. assert_noop!( Nfts::force_approve_collection_transfer( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone(), @@ -4747,7 +4852,7 @@ fn force_approve_collection_transfer_works() { // Approve collection without items. assert_noop!( Nfts::force_approve_collection_transfer( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone(), @@ -4765,7 +4870,7 @@ fn force_approve_collection_transfer_works() { // Approve collection without balance. assert_noop!( Nfts::force_approve_collection_transfer( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone(), @@ -4789,7 +4894,7 @@ fn force_approve_collection_transfer_works() { [None, None, Some(deadline), Some(deadline), Some(deadline * 2), Some(deadline), None] { assert_ok!(Nfts::force_approve_collection_transfer( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone(), @@ -4821,7 +4926,7 @@ fn force_approve_collection_transfer_works() { )); assert_noop!( Nfts::force_approve_collection_transfer( - root(), + RuntimeOrigin::root(), item_owner, collection_id, delegate, @@ -4841,7 +4946,7 @@ fn cancel_collection_approval_works() { let item_id = 42; let item_owner = account(2); - for origin in [root(), none()] { + for origin in [RuntimeOrigin::root(), none()] { assert_noop!( Nfts::cancel_collection_approval(origin, collection_id, delegate.clone()), BadOrigin @@ -5016,7 +5121,7 @@ fn force_cancel_collection_approval_works() { // Cancel an approval for a non existing collection. assert_noop!( Nfts::force_cancel_collection_approval( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone() @@ -5032,7 +5137,7 @@ fn force_cancel_collection_approval_works() { // Cancel an unapproved delegate. assert_noop!( Nfts::force_cancel_collection_approval( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, account(69) @@ -5041,7 +5146,7 @@ fn force_cancel_collection_approval_works() { ); // Successfully cancel a collection approval. assert_ok!(Nfts::force_cancel_collection_approval( - root(), + RuntimeOrigin::root(), item_owner.clone(), collection_id, delegate.clone() diff --git a/pallets/nfts/src/types.rs b/pallets/nfts/src/types.rs index f08f1d09..135702b0 100644 --- a/pallets/nfts/src/types.rs +++ b/pallets/nfts/src/types.rs @@ -89,6 +89,9 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< ::AccountId, BlockNumberFor, >; +/// A type alias for the depositor account and its associated deposited amount. +pub(super) type AccountDepositOf = + (::AccountId, DepositBalanceOf); /// Information about a collection. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] diff --git a/pallets/nfts/src/weights.rs b/pallets/nfts/src/weights.rs index 6e291bfc..974b1f8f 100644 --- a/pallets/nfts/src/weights.rs +++ b/pallets/nfts/src/weights.rs @@ -2,13 +2,13 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 40.0.0 -//! DATE: 2024-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-22, 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 +// ./target/production/pop-node // benchmark // pallet // --chain=dev @@ -60,14 +60,8 @@ pub trait WeightInfo { fn set_collection_metadata() -> Weight; fn clear_collection_metadata() -> Weight; fn approve_transfer() -> Weight; - fn approve_collection_transfer() -> Weight; - fn force_approve_collection_transfer() -> Weight; fn cancel_approval() -> Weight; - fn cancel_collection_approval() -> Weight; - fn force_cancel_collection_approval() -> Weight; fn clear_all_transfer_approvals() -> Weight; - fn clear_collection_approvals(n: u32, ) -> Weight; - fn force_clear_collection_approvals(n: u32, ) -> Weight; fn set_accept_ownership() -> Weight; fn set_collection_max_supply() -> Weight; fn update_mint_settings() -> Weight; @@ -79,6 +73,12 @@ pub trait WeightInfo { fn claim_swap() -> Weight; fn mint_pre_signed(n: u32, ) -> Weight; fn set_attributes_pre_signed(n: u32, ) -> Weight; + fn approve_collection_transfer() -> Weight; + fn force_approve_collection_transfer() -> Weight; + fn cancel_collection_approval() -> Weight; + fn force_cancel_collection_approval() -> Weight; + fn clear_collection_approvals(n: u32, ) -> Weight; + fn force_clear_collection_approvals(n: u32, ) -> Weight; } /// Weights for `pallet_nfts` using the Substrate node and recommended hardware. @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(37_000_000, 3549) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -117,8 +117,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_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(5_u64)) } @@ -143,14 +143,18 @@ 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: `32137 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_005_000_000 picoseconds. - Weight::from_parts(2_234_507_890, 2523990) - // Standard Error: 87_675 - .saturating_add(Weight::from_parts(5_794_302, 0).saturating_mul(a.into())) + // Minimum execution time: 893_000_000 picoseconds. + Weight::from_parts(814_084_483, 2523990) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(26_897, 0).saturating_mul(m.into())) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(87_809, 0).saturating_mul(c.into())) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(4_861_675, 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)) @@ -166,7 +170,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -175,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(43_000_000, 4326) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -189,7 +193,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -198,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + // Minimum execution time: 36_000_000 picoseconds. + Weight::from_parts(39_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -214,7 +218,7 @@ impl WeightInfo for SubstrateWeight { /// 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(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -225,10 +229,10 @@ 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: `584` + // Measured: `634` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(47_000_000, 4326) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -243,7 +247,9 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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) @@ -252,12 +258,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: `613` - // Estimated: `6084` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_000_000, 6084) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `765` + // Estimated: `6180` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(50_000_000, 6180) + .saturating_add(T::DbWeight::get().reads(8_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`) @@ -270,10 +276,10 @@ impl WeightInfo for SubstrateWeight { // 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: 33_010 - .saturating_add(Weight::from_parts(17_115_197, 0).saturating_mul(i.into())) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) + // Standard Error: 41_268 + .saturating_add(Weight::from_parts(12_689_751, 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()))) @@ -287,8 +293,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -300,8 +306,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -313,8 +319,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -330,8 +336,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(21_000_000, 3593) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -343,8 +349,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `296` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -356,8 +362,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238` // Estimated: `3549` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_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(3_u64)) } @@ -369,8 +375,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `203` // Estimated: `3549` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3549) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -382,8 +388,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -401,8 +407,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(28_000_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -414,8 +420,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3944` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(20_000_000, 3944) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -431,8 +437,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(27_000_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -444,8 +450,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 4466) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -462,10 +468,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `686 + n * (398 ±0)` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(20_000_000, 4466) - // Standard Error: 11_913 - .saturating_add(Weight::from_parts(5_265_987, 0).saturating_mul(n.into())) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4466) + // Standard Error: 11_599 + .saturating_add(Weight::from_parts(4_782_076, 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)) @@ -486,8 +492,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 32_000_000 picoseconds. - Weight::from_parts(38_000_000, 3812) + // Minimum execution time: 23_000_000 picoseconds. + Weight::from_parts(24_000_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -503,8 +509,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(33_000_000, 3812) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(23_000_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -520,8 +526,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `325` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -537,8 +543,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(23_000_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -555,36 +561,6 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::AccountBalance` (r:1 w:0) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn approve_collection_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `3602` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3602) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `Nfts::AccountBalance` (r:1 w:0) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn force_approve_collection_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `3602` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3602) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) @@ -593,33 +569,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn cancel_collection_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3602) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn force_cancel_collection_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(17_000_000, 3602) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) @@ -629,50 +583,18 @@ impl WeightInfo for SubstrateWeight { // Measured: `345` // Estimated: `4326` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + 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::CollectionApprovals` (r:1000 w:999) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1000]`. - fn clear_collection_approvals(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `327 + n * (75 ±0)` - // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) - // Standard Error: 7_954 - .saturating_add(Weight::from_parts(3_625_558, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) - } - /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1000]`. - fn force_clear_collection_approvals(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `327 + n * (75 ±0)` - // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) - // Standard Error: 5_861 - .saturating_add(Weight::from_parts(3_576_220, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) - } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// 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: `3` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -684,8 +606,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(10_000_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -697,8 +619,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -714,8 +636,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -732,19 +654,21 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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: `725` - // Estimated: `6084` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(48_000_000, 6084) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `877` + // Estimated: `6180` + // Minimum execution time: 53_000_000 picoseconds. + Weight::from_parts(55_000_000, 6180) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -752,9 +676,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_971_321, 0) - // Standard Error: 11_267 - .saturating_add(Weight::from_parts(1_831_565, 0).saturating_mul(n.into())) + Weight::from_parts(1_497_803, 0) + // Standard Error: 5_639 + .saturating_add(Weight::from_parts(1_502_698, 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`) @@ -764,8 +688,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: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -777,8 +701,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -795,19 +719,21 @@ impl WeightInfo for SubstrateWeight { /// 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(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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: `916` + // Measured: `1118` // Estimated: `7662` - // Minimum execution time: 81_000_000 picoseconds. - Weight::from_parts(87_000_000, 7662) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + // Minimum execution time: 79_000_000 picoseconds. + Weight::from_parts(82_000_000, 7662) + .saturating_add(T::DbWeight::get().reads(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`) @@ -818,11 +744,11 @@ impl WeightInfo for SubstrateWeight { /// 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(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) @@ -834,10 +760,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(115_875_572, 6078) - // Standard Error: 214_394 - .saturating_add(Weight::from_parts(29_706_731, 0).saturating_mul(n.into())) + // Minimum execution time: 91_000_000 picoseconds. + Weight::from_parts(95_221_709, 6078) + // Standard Error: 128_983 + .saturating_add(Weight::from_parts(22_458_028, 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)) @@ -861,16 +787,100 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(66_554_620, 4466) - // Standard Error: 115_497 - .saturating_add(Weight::from_parts(27_385_703, 0).saturating_mul(n.into())) + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(54_326_784, 4466) + // Standard Error: 99_430 + .saturating_add(Weight::from_parts(20_625_932, 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)) .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::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `3602` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(24_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `3602` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(24_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1000]`. + fn clear_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `327 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) + // Standard Error: 8_973 + .saturating_add(Weight::from_parts(3_888_488, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1000]`. + fn force_clear_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `327 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(33_601_852, 3602) + // Standard Error: 7_525 + .saturating_add(Weight::from_parts(3_464_828, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } } // For backwards compatibility and tests. @@ -889,8 +899,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3549` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(37_000_000, 3549) + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -908,8 +918,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3549` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(15_000_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(5_u64)) } @@ -934,14 +944,18 @@ 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: `32137 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_005_000_000 picoseconds. - Weight::from_parts(2_234_507_890, 2523990) - // Standard Error: 87_675 - .saturating_add(Weight::from_parts(5_794_302, 0).saturating_mul(a.into())) + // Minimum execution time: 893_000_000 picoseconds. + Weight::from_parts(814_084_483, 2523990) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(26_897, 0).saturating_mul(m.into())) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(87_809, 0).saturating_mul(c.into())) + // Standard Error: 18_466 + .saturating_add(Weight::from_parts(4_861_675, 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)) @@ -957,7 +971,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -966,8 +980,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(43_000_000, 4326) + // Minimum execution time: 37_000_000 picoseconds. + Weight::from_parts(38_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -980,7 +994,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::AccountBalance` (r:1 w:1) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -989,8 +1003,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `4326` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(40_000_000, 4326) + // Minimum execution time: 36_000_000 picoseconds. + Weight::from_parts(39_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1005,7 +1019,7 @@ impl WeightInfo for () { /// 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(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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) @@ -1016,10 +1030,10 @@ 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: `584` + // Measured: `634` // Estimated: `4326` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(47_000_000, 4326) + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(43_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1034,7 +1048,9 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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) @@ -1043,12 +1059,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: `613` - // Estimated: `6084` - // Minimum execution time: 39_000_000 picoseconds. - Weight::from_parts(45_000_000, 6084) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `765` + // Estimated: `6180` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(50_000_000, 6180) + .saturating_add(RocksDbWeight::get().reads(8_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`) @@ -1061,10 +1077,10 @@ impl WeightInfo for () { // 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: 33_010 - .saturating_add(Weight::from_parts(17_115_197, 0).saturating_mul(i.into())) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 3549) + // Standard Error: 41_268 + .saturating_add(Weight::from_parts(12_689_751, 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()))) @@ -1078,8 +1094,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1091,8 +1107,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3534) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1104,8 +1120,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 3549) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1121,8 +1137,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3593` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(21_000_000, 3593) + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1134,8 +1150,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `296` // Estimated: `6078` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(31_000_000, 6078) + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1147,8 +1163,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238` // Estimated: `3549` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_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(3_u64)) } @@ -1160,8 +1176,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `203` // Estimated: `3549` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3549) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1173,8 +1189,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3534` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 3534) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1192,8 +1208,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3944` - // Minimum execution time: 38_000_000 picoseconds. - Weight::from_parts(39_000_000, 3944) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(28_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1205,8 +1221,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3944` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(20_000_000, 3944) + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1222,8 +1238,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `943` // Estimated: `3944` - // Minimum execution time: 35_000_000 picoseconds. - Weight::from_parts(36_000_000, 3944) + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(27_000_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1235,8 +1251,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `308` // Estimated: `4466` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4466) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(9_000_000, 4466) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1253,10 +1269,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `686 + n * (398 ±0)` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(20_000_000, 4466) - // Standard Error: 11_913 - .saturating_add(Weight::from_parts(5_265_987, 0).saturating_mul(n.into())) + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(14_000_000, 4466) + // Standard Error: 11_599 + .saturating_add(Weight::from_parts(4_782_076, 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)) @@ -1277,8 +1293,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3812` - // Minimum execution time: 32_000_000 picoseconds. - Weight::from_parts(38_000_000, 3812) + // Minimum execution time: 23_000_000 picoseconds. + Weight::from_parts(24_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1294,8 +1310,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `809` // Estimated: `3812` - // Minimum execution time: 30_000_000 picoseconds. - Weight::from_parts(33_000_000, 3812) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(23_000_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1311,8 +1327,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `325` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(22_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1328,8 +1344,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `643` // Estimated: `3759` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 3759) + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(23_000_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1346,36 +1362,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::AccountBalance` (r:1 w:0) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn approve_collection_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `3602` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3602) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `Nfts::AccountBalance` (r:1 w:0) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, 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::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn force_approve_collection_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `3602` - // Minimum execution time: 20_000_000 picoseconds. - Weight::from_parts(21_000_000, 3602) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) @@ -1384,33 +1370,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `4326` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn cancel_collection_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(17_000_000, 3602) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - fn force_cancel_collection_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `359` - // Estimated: `3602` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(17_000_000, 3602) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Nfts::CollectionApprovals` (r:1 w:0) @@ -1420,50 +1384,18 @@ impl WeightInfo for () { // Measured: `345` // Estimated: `4326` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_000_000, 4326) + Weight::from_parts(14_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1000]`. - fn clear_collection_approvals(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `327 + n * (75 ±0)` - // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) - // Standard Error: 7_954 - .saturating_add(Weight::from_parts(3_625_558, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) - } - /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) - /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1000]`. - fn force_clear_collection_approvals(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `327 + n * (75 ±0)` - // Estimated: `3602 + n * (2612 ±0)` - // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(18_000_000, 3602) - // Standard Error: 5_861 - .saturating_add(Weight::from_parts(3_576_220, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) - } /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) /// 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: `3` // Estimated: `3517` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 3517) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1475,8 +1407,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `267` // Estimated: `3549` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(13_000_000, 3549) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(10_000_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1488,8 +1420,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250` // Estimated: `3538` - // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 3538) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(11_000_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1505,8 +1437,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `478` // Estimated: `4326` - // Minimum execution time: 17_000_000 picoseconds. - Weight::from_parts(18_000_000, 4326) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1523,19 +1455,21 @@ 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::AccountBalance` (r:2 w:2) - /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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: `725` - // Estimated: `6084` - // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(48_000_000, 6084) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `877` + // Estimated: `6180` + // Minimum execution time: 53_000_000 picoseconds. + Weight::from_parts(55_000_000, 6180) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { @@ -1543,9 +1477,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_971_321, 0) - // Standard Error: 11_267 - .saturating_add(Weight::from_parts(1_831_565, 0).saturating_mul(n.into())) + Weight::from_parts(1_497_803, 0) + // Standard Error: 5_639 + .saturating_add(Weight::from_parts(1_502_698, 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`) @@ -1555,8 +1489,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: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1568,8 +1502,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `4326` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 4326) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1586,19 +1520,21 @@ impl WeightInfo for () { /// 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(72), added: 2547, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::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: `916` + // Measured: `1118` // Estimated: `7662` - // Minimum execution time: 81_000_000 picoseconds. - Weight::from_parts(87_000_000, 7662) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + // Minimum execution time: 79_000_000 picoseconds. + Weight::from_parts(82_000_000, 7662) + .saturating_add(RocksDbWeight::get().reads(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`) @@ -1609,11 +1545,11 @@ impl WeightInfo for () { /// 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(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::ItemConfigOf` (r:1 w:1) + /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:10 w:10) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) @@ -1625,10 +1561,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `485` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 102_000_000 picoseconds. - Weight::from_parts(115_875_572, 6078) - // Standard Error: 214_394 - .saturating_add(Weight::from_parts(29_706_731, 0).saturating_mul(n.into())) + // Minimum execution time: 91_000_000 picoseconds. + Weight::from_parts(95_221_709, 6078) + // Standard Error: 128_983 + .saturating_add(Weight::from_parts(22_458_028, 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)) @@ -1652,14 +1588,98 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `514` // Estimated: `4466 + n * (2954 ±0)` - // Minimum execution time: 51_000_000 picoseconds. - Weight::from_parts(66_554_620, 4466) - // Standard Error: 115_497 - .saturating_add(Weight::from_parts(27_385_703, 0).saturating_mul(n.into())) + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(54_326_784, 4466) + // Standard Error: 99_430 + .saturating_add(Weight::from_parts(20_625_932, 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())) } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `3602` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(24_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::AccountBalance` (r:1 w:0) + /// Proof: `Nfts::AccountBalance` (`max_values`: None, `max_size`: Some(120), added: 2595, 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::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_approve_collection_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `3602` + // Minimum execution time: 21_000_000 picoseconds. + Weight::from_parts(24_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1 w:1) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + fn force_cancel_collection_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `359` + // Estimated: `3602` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 3602) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1000]`. + fn clear_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `327 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(22_000_000, 3602) + // Standard Error: 8_973 + .saturating_add(Weight::from_parts(3_888_488, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } + /// Storage: `Nfts::CollectionApprovals` (r:1000 w:999) + /// Proof: `Nfts::CollectionApprovals` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1000]`. + fn force_clear_collection_approvals(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `327 + n * (75 ±0)` + // Estimated: `3602 + n * (2612 ±0)` + // Minimum execution time: 18_000_000 picoseconds. + Weight::from_parts(33_601_852, 3602) + // Standard Error: 7_525 + .saturating_add(Weight::from_parts(3_464_828, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2612).saturating_mul(n.into())) + } } diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index e46d7dbc..6a54f368 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -29,6 +29,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) + pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); pub const NftsCollectionDeposit: Balance = 10 * UNIT; // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); @@ -44,6 +46,7 @@ impl pallet_nfts::Config for Runtime { type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; + type CollectionBalanceDeposit = NftsCollectionBalanceDeposit; type CollectionDeposit = NftsCollectionDeposit; // TODO: source from primitives type CollectionId = CollectionId; @@ -130,6 +133,15 @@ mod tests { use super::*; + #[test] + fn ensure_account_balance_deposit() { + let max_size = pallet_nfts::AccountBalance::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + } + #[test] fn ensure_collection_approval_deposit() { let max_size = pallet_nfts::CollectionApprovals::::storage_info() diff --git a/runtime/testnet/src/config/assets.rs b/runtime/testnet/src/config/assets.rs index e46d7dbc..6a54f368 100644 --- a/runtime/testnet/src/config/assets.rs +++ b/runtime/testnet/src/config/assets.rs @@ -29,6 +29,8 @@ parameter_types! { parameter_types! { pub NftsPalletFeatures: PalletFeatures = PalletFeatures::all_enabled(); + // Key = 68 bytes (4+16+32+16), Value = 52 bytes (4+32+16) + pub const NftsCollectionBalanceDeposit: Balance = deposit(1, 120); pub const NftsCollectionDeposit: Balance = 10 * UNIT; // Key = 116 bytes (4+16+32+16+32+16), Value = 21 bytes (1+4+16) pub const NftsCollectionApprovalDeposit: Balance = deposit(1, 137); @@ -44,6 +46,7 @@ impl pallet_nfts::Config for Runtime { type ApprovalsLimit = ConstU32<20>; type AttributeDepositBase = NftsAttributeDepositBase; type CollectionApprovalDeposit = NftsCollectionApprovalDeposit; + type CollectionBalanceDeposit = NftsCollectionBalanceDeposit; type CollectionDeposit = NftsCollectionDeposit; // TODO: source from primitives type CollectionId = CollectionId; @@ -130,6 +133,15 @@ mod tests { use super::*; + #[test] + fn ensure_account_balance_deposit() { + let max_size = pallet_nfts::AccountBalance::::storage_info() + .first() + .and_then(|info| info.max_size) + .unwrap_or_default(); + assert_eq!(deposit(1, max_size), NftsCollectionBalanceDeposit::get()); + } + #[test] fn ensure_collection_approval_deposit() { let max_size = pallet_nfts::CollectionApprovals::::storage_info() From 5d350b150b7f8b1e1f7d8bdbd34c28c2aa164150 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:58:48 +0700 Subject: [PATCH 97/99] fix: deposit saturation --- pallets/nfts/src/features/approvals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 218ab569..7c654d51 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -237,7 +237,7 @@ impl, I: 'static> Pallet { let deposit_required = T::CollectionApprovalDeposit::get(); let current_deposit = maybe_approval.map(|(_, deposit)| deposit).unwrap_or_default(); - T::Currency::reserve(&owner, deposit_required - current_deposit)?; + T::Currency::reserve(&owner, deposit_required.saturating_sub(current_deposit))?; *maybe_approval = Some((deadline, deposit_required)); Ok(()) }, From 3e2620a95674bdecb235705598d6d194cd5c069b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:26:48 +0700 Subject: [PATCH 98/99] chore: revert admin permission on collection approvals --- pallets/nfts/src/lib.rs | 34 ++--------- pallets/nfts/src/tests.rs | 122 +++++++------------------------------- 2 files changed, 27 insertions(+), 129 deletions(-) diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index ac9932d7..90ac9561 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -59,8 +59,8 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::WithPostDispatchInfo, traits::{ - nonfungibles_v2::InspectRole, tokens::Locker, BalanceStatus::Reserved, Currency, - EnsureOriginWithArg, Incrementable, ReservableCurrency, + tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable, + ReservableCurrency, }, }; use frame_system::Config as SystemConfig; @@ -2110,19 +2110,9 @@ pub mod pallet { 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))?; + T::ForceOrigin::ensure_origin(origin)?; let delegate = T::Lookup::lookup(delegate)?; let owner = T::Lookup::lookup(owner)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!( - Self::is_admin(&collection, &check_origin) || - Self::is_issuer(&collection, &check_origin), - Error::::NoPermission - ); - } Self::do_cancel_collection_approval(owner, collection, delegate) } @@ -2173,23 +2163,9 @@ pub mod pallet { collection: T::CollectionId, limit: u32, ) -> DispatchResultWithPostInfo { - let maybe_check_origin = - T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| { - ensure_signed(origin).map(Some).map_err(|e| { - DispatchError::from(e) - .with_weight(T::WeightInfo::clear_collection_approvals(0)) - }) - })?; + T::ForceOrigin::ensure_origin(origin) + .map_err(|e| e.with_weight(T::WeightInfo::clear_collection_approvals(0)))?; let owner = T::Lookup::lookup(owner)?; - - if let Some(check_origin) = maybe_check_origin { - ensure!( - Self::is_admin(&collection, &check_origin) || - Self::is_issuer(&collection, &check_origin), - Error::::NoPermission - .with_weight(T::WeightInfo::clear_collection_approvals(0)) - ); - } let removed_approvals = Self::do_clear_collection_approvals(owner, collection, limit)?; Ok(Some(T::WeightInfo::clear_collection_approvals(removed_approvals)).into()) } diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 0faa4185..053fa873 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4559,19 +4559,17 @@ fn force_clear_collection_approvals_works() { let item_owner = account(1); let delegates = 10..20; - assert_noop!( - Nfts::force_clear_collection_approvals( - RuntimeOrigin::signed(item_owner.clone()), - item_owner.clone(), - collection_id, - 0 - ), - Error::::NoPermission.with_weight(WeightOf::clear_collection_approvals(0)) - ); - assert_noop!( - Nfts::force_clear_collection_approvals(none(), item_owner.clone(), collection_id, 0), - BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) - ); + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_clear_collection_approvals( + origin, + item_owner.clone(), + collection_id, + 0 + ), + BadOrigin.with_weight(WeightOf::clear_collection_approvals(0)) + ); + } assert_ok!(Nfts::force_create( RuntimeOrigin::root(), item_owner.clone(), @@ -5009,75 +5007,6 @@ fn cancel_collection_approval_works() { }); } -#[test] -fn force_cancel_collection_approval_works_with_admin() { - new_test_ext().execute_with(|| { - let collection_id = 0; - let item_id = 42; - let collection_owner = account(1); - let item_owner = account(2); - let delegate = account(3); - let admin = account(4); - let issuer = account(5); - let freezer = account(6); - - Balances::make_free_balance_be(&item_owner, 100); - assert_ok!(Nfts::force_create( - RuntimeOrigin::root(), - collection_owner.clone(), - default_collection_config() - )); - assert_ok!(Nfts::set_team( - RuntimeOrigin::signed(collection_owner.clone()), - collection_id, - Some(issuer.clone()), - Some(admin.clone()), - Some(freezer.clone()) - )); - assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(issuer.clone()), - collection_id, - item_id, - item_owner.clone(), - default_item_config() - )); - - // Successfully cancel a collection approval. - for origin in [issuer, admin] { - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_ok!(Nfts::force_cancel_collection_approval( - RuntimeOrigin::signed(origin.clone()), - item_owner.clone(), - collection_id, - delegate.clone() - )); - assert_eq!(Balances::reserved_balance(&item_owner), 0); - assert!(!CollectionApprovals::contains_key((collection_id, &item_owner, &delegate))); - } - - assert_ok!(Nfts::approve_collection_transfer( - RuntimeOrigin::signed(item_owner.clone()), - collection_id, - delegate.clone(), - None - )); - assert_noop!( - Nfts::force_cancel_collection_approval( - RuntimeOrigin::signed(freezer), - item_owner, - collection_id, - delegate - ), - Error::::NoPermission - ); - }); -} - #[test] fn force_cancel_collection_approval_works() { new_test_ext().execute_with(|| { @@ -5087,24 +5016,17 @@ fn force_cancel_collection_approval_works() { let item_id = 42; let item_owner = account(2); - assert_noop!( - Nfts::force_cancel_collection_approval( - RuntimeOrigin::signed(item_owner.clone()), - item_owner.clone(), - collection_id, - delegate.clone() - ), - Error::::NoPermission - ); - assert_noop!( - Nfts::force_cancel_collection_approval( - none(), - item_owner.clone(), - collection_id, - delegate.clone() - ), - BadOrigin - ); + for origin in [RuntimeOrigin::signed(item_owner.clone()), none()] { + assert_noop!( + Nfts::force_cancel_collection_approval( + origin, + item_owner.clone(), + collection_id, + delegate.clone() + ), + BadOrigin + ); + } Balances::make_free_balance_be(&item_owner, 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), From f83bdc58782879bfa8924c983f878869e3ceca95 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 10 Jan 2025 18:05:24 +0700 Subject: [PATCH 99/99] feat: not require deposit for force_approve_collection_transfer --- pallets/nfts/src/features/approvals.rs | 7 ++++--- pallets/nfts/src/lib.rs | 21 +++++++++++++++++---- pallets/nfts/src/tests.rs | 22 +++++++++------------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/pallets/nfts/src/features/approvals.rs b/pallets/nfts/src/features/approvals.rs index 7c654d51..f7db22a7 100644 --- a/pallets/nfts/src/features/approvals.rs +++ b/pallets/nfts/src/features/approvals.rs @@ -204,12 +204,14 @@ impl, I: 'static> Pallet { /// - `owner`: The owner of the collection items. /// - `collection`: The identifier of the collection. /// - `delegate`: The account that will be approved to take control of the collection items. + /// - `deposit`: The reserved amount for granting a collection approval. /// - `maybe_deadline`: The optional deadline (in block numbers) specifying the time limit for /// the approval. pub(crate) fn do_approve_collection_transfer( owner: T::AccountId, collection: T::CollectionId, delegate: T::AccountId, + deposit: DepositBalanceOf, maybe_deadline: Option>, ) -> DispatchResult { ensure!( @@ -234,11 +236,10 @@ impl, I: 'static> Pallet { CollectionApprovals::::try_mutate_exists( (&collection, &owner, &delegate), |maybe_approval| -> DispatchResult { - let deposit_required = T::CollectionApprovalDeposit::get(); let current_deposit = maybe_approval.map(|(_, deposit)| deposit).unwrap_or_default(); - T::Currency::reserve(&owner, deposit_required.saturating_sub(current_deposit))?; - *maybe_approval = Some((deadline, deposit_required)); + T::Currency::reserve(&owner, deposit.saturating_sub(current_deposit))?; + *maybe_approval = Some((deadline, deposit)); Ok(()) }, )?; diff --git a/pallets/nfts/src/lib.rs b/pallets/nfts/src/lib.rs index 90ac9561..8d9c77fa 100644 --- a/pallets/nfts/src/lib.rs +++ b/pallets/nfts/src/lib.rs @@ -2033,15 +2033,22 @@ pub mod pallet { ) -> DispatchResult { let origin = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - Self::do_approve_collection_transfer(origin, collection, delegate, maybe_deadline) + Self::do_approve_collection_transfer( + origin, + collection, + delegate, + T::CollectionApprovalDeposit::get(), + maybe_deadline, + ) } /// Force-approve collection items owned by the `owner` to be transferred by a delegated - /// third-party account. This function reserves the required deposit - /// `CollectionApprovalDeposit` from the `owner` account. + /// third-party account. /// /// Origin must be the `ForceOrigin`. /// + /// Any deposit is left alone. + /// /// - `owner`: The owner of the collection items to be force-approved by the `origin`. /// - `collection`: The collection of the items to be approved for delegated transfer. /// - `delegate`: The account to delegate permission to transfer collection items owned by @@ -2064,7 +2071,13 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; let delegate = T::Lookup::lookup(delegate)?; let owner = T::Lookup::lookup(owner)?; - Self::do_approve_collection_transfer(owner, collection, delegate, maybe_deadline) + Self::do_approve_collection_transfer( + owner, + collection, + delegate, + Zero::zero(), + maybe_deadline, + ) } /// Cancel a collection approval. diff --git a/pallets/nfts/src/tests.rs b/pallets/nfts/src/tests.rs index 053fa873..d0c6bff9 100644 --- a/pallets/nfts/src/tests.rs +++ b/pallets/nfts/src/tests.rs @@ -4815,7 +4815,6 @@ fn force_approve_collection_transfer_works() { let collection_owner = account(1); let deadline: BlockNumberFor = 20; let delegate = account(3); - let deposit = CollectionApprovalDeposit::get(); let item_id = 42; let item_owner = account(2); @@ -4866,16 +4865,13 @@ fn force_approve_collection_transfer_works() { default_item_config() )); // Approve collection without balance. - assert_noop!( - Nfts::force_approve_collection_transfer( - RuntimeOrigin::root(), - item_owner.clone(), - collection_id, - delegate.clone(), - None - ), - BalancesError::::InsufficientBalance, - ); + assert_ok!(Nfts::force_approve_collection_transfer( + RuntimeOrigin::root(), + item_owner.clone(), + collection_id, + delegate.clone(), + None + )); Balances::make_free_balance_be(&item_owner, 100); // Approving a collection to a delegate with: @@ -4909,10 +4905,10 @@ fn force_approve_collection_transfer_works() { } .into(), ); - assert_eq!(Balances::reserved_balance(&item_owner), deposit); + assert_eq!(Balances::reserved_balance(&item_owner), 0); assert_eq!( CollectionApprovals::get((collection_id, &item_owner, &delegate)), - Some((deadline, deposit)) + Some((deadline, 0)) ); }