diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index eb6941e85215c..875346472f21a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1473,6 +1473,7 @@ parameter_types! { pub const ValueLimit: u32 = 256; pub const ApprovalsLimit: u32 = 20; pub const MaxTips: u32 = 10; + pub const MaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } impl pallet_uniques::Config for Runtime { @@ -1512,6 +1513,7 @@ impl pallet_nfts::Config for Runtime { type ValueLimit = ValueLimit; type ApprovalsLimit = ApprovalsLimit; type MaxTips = MaxTips; + type MaxDeadlineDuration = MaxDeadlineDuration; type WeightInfo = pallet_nfts::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type Helper = (); diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 00527abc99e02..b35122cf919c7 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -29,7 +29,7 @@ use frame_support::{ BoundedVec, }; use frame_system::RawOrigin as SystemOrigin; -use sp_runtime::traits::Bounded; +use sp_runtime::traits::{Bounded, One}; use sp_std::prelude::*; use crate::Pallet as Nfts; @@ -476,5 +476,87 @@ benchmarks_instance_pallet! { } } + 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()); + 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()); + } + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/nfts/src/features/atomic_swap.rs b/frame/nfts/src/features/atomic_swap.rs new file mode 100644 index 0000000000000..116da57477f4e --- /dev/null +++ b/frame/nfts/src/features/atomic_swap.rs @@ -0,0 +1,175 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 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 crate::*; +use frame_support::{ + pallet_prelude::*, + traits::{Currency, ExistenceRequirement::KeepAlive}, +}; + +impl, I: 'static> Pallet { + pub 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: ::BlockNumber, + ) -> DispatchResult { + 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(()) + } + + pub 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(()) + } + + pub 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 { + 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/frame/nfts/src/features/mod.rs b/frame/nfts/src/features/mod.rs index 5661797978439..24b58dee5f3a0 100644 --- a/frame/nfts/src/features/mod.rs +++ b/frame/nfts/src/features/mod.rs @@ -15,4 +15,5 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub mod atomic_swap; pub mod buy_sell; diff --git a/frame/nfts/src/functions.rs b/frame/nfts/src/functions.rs index f935a5b2eba90..17be672834bf2 100644 --- a/frame/nfts/src/functions.rs +++ b/frame/nfts/src/functions.rs @@ -56,6 +56,7 @@ impl, I: 'static> Pallet { Item::::insert(&collection, &item, &details); ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); Self::deposit_event(Event::Transferred { collection, @@ -129,6 +130,8 @@ impl, I: 'static> Pallet { ItemMetadataOf::::remove_prefix(&collection, None); #[allow(deprecated)] ItemPriceOf::::remove_prefix(&collection, None); + #[allow(deprecated)] + PendingSwapOf::::remove_prefix(&collection, None); CollectionMetadataOf::::remove(&collection); #[allow(deprecated)] Attribute::::remove_prefix((&collection,), None); @@ -219,6 +222,7 @@ impl, I: 'static> Pallet { Item::::remove(&collection, &item); Account::::remove((&owner, &collection, &item)); ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); Self::deposit_event(Event::Burned { collection, item, owner }); Ok(()) diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index a4555cd655a08..7e9b2a42f7e14 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -182,6 +182,10 @@ pub mod pallet { #[pallet::constant] type MaxTips: Get; + /// The max duration in blocks for deadlines. + #[pallet::constant] + type MaxDeadlineDuration: Get<::BlockNumber>; + #[cfg(feature = "runtime-benchmarks")] /// A set of helper functions for benchmarking. type Helper: BenchmarkHelper; @@ -312,6 +316,23 @@ pub mod pallet { pub(super) type NextCollectionId, I: 'static = ()> = StorageValue<_, T::CollectionId, OptionQuery>; + #[pallet::storage] + /// Handles all the pending swaps. + pub(super) type PendingSwapOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + PendingSwap< + T::CollectionId, + T::ItemId, + PriceWithDirection>, + ::BlockNumber, + >, + OptionQuery, + >; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -433,6 +454,35 @@ pub mod pallet { 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: ::BlockNumber, + }, + /// The swap was cancelled. + SwapCancelled { + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + desired_item: Option, + price: Option>>, + deadline: ::BlockNumber, + }, + /// 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: ::BlockNumber, + }, } #[pallet::error] @@ -471,12 +521,18 @@ pub mod pallet { MaxSupplyTooSmall, /// The given item ID is unknown. UnknownItem, + /// Swap doesn't exist. + UnknownSwap, /// 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 or equal to MaxDeadlineDuration. + WrongDuration, } impl, I: 'static> Pallet { @@ -1638,5 +1694,94 @@ pub mod pallet { 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`. + /// - `maybe_duration`: Optional deadline for the swap. Specified by providing the + /// number of blocks after which the swap will expire. + /// + /// Emits `SwapCreated` on success. + #[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: ::BlockNumber, + ) -> 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::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::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, + ) + } } } diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index c13298aa8162d..23493829eaca7 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -102,6 +102,7 @@ impl Config for Test { type ValueLimit = ConstU32<50>; type ApprovalsLimit = ConstU32<10>; type MaxTips = ConstU32<10>; + type MaxDeadlineDuration = ConstU64<10000>; type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 7004fb1f4e93b..0d2d0c661b273 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -18,7 +18,11 @@ //! Tests for Nfts pallet. use crate::{mock::*, Event, *}; -use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::Currency}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Dispatchable, + traits::{Currency, Get}, +}; use pallet_balances::Error as BalancesError; use sp_std::prelude::*; @@ -1105,3 +1109,312 @@ fn pay_tips_should_work() { })); }); } + +#[test] +fn create_cancel_swap_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_id = 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, true)); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, item_1, user_id)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, item_2, user_id)); + + // validate desired item and the collection exists + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id), + 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), + 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), + 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), + 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), 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), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + assert_noop!( + Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), collection_id, item_1), + Error::::NoPermission + ); + System::set_block_number(expect_deadline + 1); + assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), 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 = 1; + let user_2 = 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, true)); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_1, user_1)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_2, user_2)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_3, user_2)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_4, user_1)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_5, user_2)); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1), + 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), + 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), + 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), + 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), + 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), + 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), + 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), + 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); + let item = Item::::get(collection_id, item_2).unwrap(); + assert_eq!(item.owner, user_1); + + // 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, + received_collection: collection_id, + received_item: item_1, + received_item_owner: user_1, + 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), + collection_id, + item_4, + collection_id, + None, + Some(price_with_direction.clone()), + duration, + )); + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + 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); + }); +} diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index e91c513e4c4c2..399de3c5dad1e 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -146,3 +146,29 @@ pub struct ItemTip { /// An amount the sender is willing to tip. pub(super) amount: Amount, } + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +pub struct PendingSwap { + /// A collection of the item user wants to receive. + pub(super) desired_collection: CollectionId, + /// An item user wants to receive. + pub(super) desired_item: Option, + /// A price for the desired `item` with the direction. + pub(super) price: Option, + /// An optional deadline for the swap. + pub(super) deadline: Deadline, +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum PriceDirection { + Send, + Receive, +} + +#[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, +} diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 1dab0838f32b2..9d62db0f8d85d 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -74,6 +74,9 @@ pub trait WeightInfo { 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; } /// Weights for pallet_nfts using the Substrate node and recommended hardware. @@ -83,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(37_627_000 as u64) + Weight::from_ref_time(38_062_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -91,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(25_748_000 as u64) + Weight::from_ref_time(25_917_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -107,13 +110,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(2_449_817_000 as u64) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(8_423_500 as u64).saturating_mul(n as u64)) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(315_839 as u64).saturating_mul(m as u64)) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(217_497 as u64).saturating_mul(a as u64)) + Weight::from_ref_time(2_432_555_000 as u64) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(8_474_465 as u64).saturating_mul(n as u64)) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(333_758 as u64).saturating_mul(m as u64)) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(222_052 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(2004 as u64)) @@ -124,7 +127,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts CollectionMaxSupply (r:1 w:0) // Storage: Nfts Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(43_014_000 as u64) + Weight::from_ref_time(43_755_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -132,27 +135,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Account (r:0 w:1) // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(44_421_000 as u64) + Weight::from_ref_time(46_768_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Account (r:0 w:2) // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(34_315_000 as u64) + Weight::from_ref_time(36_282_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(22_836_000 as u64) - // Standard Error: 9_131 - .saturating_add(Weight::from_ref_time(10_894_264 as u64).saturating_mul(i as u64)) + Weight::from_ref_time(23_359_000 as u64) + // Standard Error: 9_645 + .saturating_add(Weight::from_ref_time(10_822_144 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -161,26 +166,26 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(27_329_000 as u64) + Weight::from_ref_time(27_805_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(27_842_000 as u64) + Weight::from_ref_time(27_712_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(23_129_000 as u64) + Weight::from_ref_time(23_068_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(22_584_000 as u64) + Weight::from_ref_time(23_200_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -188,20 +193,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(31_684_000 as u64) + Weight::from_ref_time(31_800_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Nfts Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(23_143_000 as u64) + Weight::from_ref_time(23_959_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(25_684_000 as u64) + Weight::from_ref_time(26_334_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -209,7 +214,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts InstanceMetadataOf (r:1 w:0) // Storage: Nfts Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(50_159_000 as u64) + Weight::from_ref_time(50_978_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -217,76 +222,76 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts InstanceMetadataOf (r:1 w:0) // Storage: Nfts Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(47_824_000 as u64) + Weight::from_ref_time(49_555_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(39_968_000 as u64) + Weight::from_ref_time(41_099_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(42_182_000 as u64) + Weight::from_ref_time(42_893_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(39_330_000 as u64) + Weight::from_ref_time(39_785_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(38_351_000 as u64) + Weight::from_ref_time(39_764_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(29_530_000 as u64) + Weight::from_ref_time(29_577_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(29_417_000 as u64) + Weight::from_ref_time(29_696_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn clear_all_transfer_approvals() -> Weight { - Weight::from_ref_time(28_482_000 as u64) + Weight::from_ref_time(28_692_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(25_851_000 as u64) + Weight::from_ref_time(26_345_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts CollectionMaxSupply (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(24_836_000 as u64) + Weight::from_ref_time(24_826_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Nfts Asset (r:1 w:0) // Storage: Nfts ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(25_665_000 as u64) + Weight::from_ref_time(26_376_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -294,16 +299,41 @@ impl WeightInfo for SubstrateWeight { // Storage: Nfts ItemPriceOf (r:1 w:1) // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn buy_item() -> Weight { - Weight::from_ref_time(47_502_000 as u64) + Weight::from_ref_time(49_140_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { - Weight::from_ref_time(5_417_000 as u64) - // Standard Error: 32_526 - .saturating_add(Weight::from_ref_time(4_304_363 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(5_477_000 as u64) + // Standard Error: 33_188 + .saturating_add(Weight::from_ref_time(4_285_339 as u64).saturating_mul(n as u64)) + } + // Storage: Nfts Asset (r:2 w:0) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn create_swap() -> Weight { + Weight::from_ref_time(30_330_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Nfts PendingSwapOf (r:1 w:1) + // Storage: Nfts Asset (r:1 w:0) + fn cancel_swap() -> Weight { + Weight::from_ref_time(30_516_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Nfts Asset (r:2 w:2) + // Storage: Nfts PendingSwapOf (r:1 w:2) + // Storage: Nfts Class (r:1 w:0) + // Storage: Nfts Account (r:0 w:4) + // Storage: Nfts ItemPriceOf (r:0 w:2) + fn claim_swap() -> Weight { + Weight::from_ref_time(66_191_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(10 as u64)) } } @@ -313,7 +343,7 @@ impl WeightInfo for () { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(37_627_000 as u64) + Weight::from_ref_time(38_062_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -321,7 +351,7 @@ impl WeightInfo for () { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(25_748_000 as u64) + Weight::from_ref_time(25_917_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -337,13 +367,13 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(2_449_817_000 as u64) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(8_423_500 as u64).saturating_mul(n as u64)) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(315_839 as u64).saturating_mul(m as u64)) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(217_497 as u64).saturating_mul(a as u64)) + Weight::from_ref_time(2_432_555_000 as u64) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(8_474_465 as u64).saturating_mul(n as u64)) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(333_758 as u64).saturating_mul(m as u64)) + // Standard Error: 28_964 + .saturating_add(Weight::from_ref_time(222_052 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(2004 as u64)) @@ -354,7 +384,7 @@ impl WeightInfo for () { // Storage: Nfts CollectionMaxSupply (r:1 w:0) // Storage: Nfts Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(43_014_000 as u64) + Weight::from_ref_time(43_755_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -362,27 +392,29 @@ impl WeightInfo for () { // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Account (r:0 w:1) // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(44_421_000 as u64) + Weight::from_ref_time(46_768_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Account (r:0 w:2) // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(34_315_000 as u64) + Weight::from_ref_time(36_282_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(22_836_000 as u64) - // Standard Error: 9_131 - .saturating_add(Weight::from_ref_time(10_894_264 as u64).saturating_mul(i as u64)) + Weight::from_ref_time(23_359_000 as u64) + // Standard Error: 9_645 + .saturating_add(Weight::from_ref_time(10_822_144 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -391,26 +423,26 @@ impl WeightInfo for () { // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(27_329_000 as u64) + Weight::from_ref_time(27_805_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Asset (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(27_842_000 as u64) + Weight::from_ref_time(27_712_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(23_129_000 as u64) + Weight::from_ref_time(23_068_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(22_584_000 as u64) + Weight::from_ref_time(23_200_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -418,20 +450,20 @@ impl WeightInfo for () { // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(31_684_000 as u64) + Weight::from_ref_time(31_800_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Nfts Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(23_143_000 as u64) + Weight::from_ref_time(23_959_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(25_684_000 as u64) + Weight::from_ref_time(26_334_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -439,7 +471,7 @@ impl WeightInfo for () { // Storage: Nfts InstanceMetadataOf (r:1 w:0) // Storage: Nfts Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(50_159_000 as u64) + Weight::from_ref_time(50_978_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -447,76 +479,76 @@ impl WeightInfo for () { // Storage: Nfts InstanceMetadataOf (r:1 w:0) // Storage: Nfts Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(47_824_000 as u64) + Weight::from_ref_time(49_555_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(39_968_000 as u64) + Weight::from_ref_time(41_099_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(42_182_000 as u64) + Weight::from_ref_time(42_893_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:1) // Storage: Nfts ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(39_330_000 as u64) + Weight::from_ref_time(39_785_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(38_351_000 as u64) + Weight::from_ref_time(39_764_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(29_530_000 as u64) + Weight::from_ref_time(29_577_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(29_417_000 as u64) + Weight::from_ref_time(29_696_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Asset (r:1 w:1) fn clear_all_transfer_approvals() -> Weight { - Weight::from_ref_time(28_482_000 as u64) + Weight::from_ref_time(28_692_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(25_851_000 as u64) + Weight::from_ref_time(26_345_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts CollectionMaxSupply (r:1 w:1) // Storage: Nfts Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(24_836_000 as u64) + Weight::from_ref_time(24_826_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Nfts Asset (r:1 w:0) // Storage: Nfts ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(25_665_000 as u64) + Weight::from_ref_time(26_376_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -524,15 +556,40 @@ impl WeightInfo for () { // Storage: Nfts ItemPriceOf (r:1 w:1) // Storage: Nfts Class (r:1 w:0) // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts PendingSwapOf (r:0 w:1) fn buy_item() -> Weight { - Weight::from_ref_time(47_502_000 as u64) + Weight::from_ref_time(49_140_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { - Weight::from_ref_time(5_417_000 as u64) - // Standard Error: 32_526 - .saturating_add(Weight::from_ref_time(4_304_363 as u64).saturating_mul(n as u64)) + Weight::from_ref_time(5_477_000 as u64) + // Standard Error: 33_188 + .saturating_add(Weight::from_ref_time(4_285_339 as u64).saturating_mul(n as u64)) + } + // Storage: Nfts Asset (r:2 w:0) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn create_swap() -> Weight { + Weight::from_ref_time(30_330_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Nfts PendingSwapOf (r:1 w:1) + // Storage: Nfts Asset (r:1 w:0) + fn cancel_swap() -> Weight { + Weight::from_ref_time(30_516_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Nfts Asset (r:2 w:2) + // Storage: Nfts PendingSwapOf (r:1 w:2) + // Storage: Nfts Class (r:1 w:0) + // Storage: Nfts Account (r:0 w:4) + // Storage: Nfts ItemPriceOf (r:0 w:2) + fn claim_swap() -> Weight { + Weight::from_ref_time(66_191_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(10 as u64)) } }