changes to nfts pallet for xcm integration (#14395)

* Use Incrementable from frame_support::traits

* Chore

* make incremental fallible and new nfts function for custom collection ids

* fmt

* fix benchmark tests nfts

* add test

* fmt

* add safety comment to CollectionId

* fmt

* add comments to Incrementable

* line wrapping

* rewrap comments

* address feedback

* fmt

* change unwrap for expect

---------

Co-authored-by: Jegor Sidorenko <jegor@parity.io>
Co-authored-by: parity-processbot <>
This commit is contained in:
Just van Stam
2023-07-25 10:02:39 +02:00
committed by GitHub
parent 5e6bbfa0a6
commit ae018a01a4
9 changed files with 145 additions and 29 deletions
+2 -2
View File
@@ -247,7 +247,7 @@ benchmarks_instance_pallet! {
let call = Call::<T, I>::create { admin, config: default_collection_config::<T, I>() };
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_last_event::<T, I>(Event::Created { collection: T::Helper::collection(0), creator: caller.clone(), owner: caller }.into());
assert_last_event::<T, I>(Event::NextCollectionIdIncremented { next_id: Some(T::Helper::collection(1)) }.into());
}
force_create {
@@ -255,7 +255,7 @@ benchmarks_instance_pallet! {
let caller_lookup = T::Lookup::unlookup(caller.clone());
}: _(SystemOrigin::Root, caller_lookup, default_collection_config::<T, I>())
verify {
assert_last_event::<T, I>(Event::ForceCreated { collection: T::Helper::collection(0), owner: caller }.into());
assert_last_event::<T, I>(Event::NextCollectionIdIncremented { next_id: Some(T::Helper::collection(1)) }.into());
}
destroy {
+9 -1
View File
@@ -55,6 +55,12 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Ok(())
}
pub(crate) fn set_next_collection_id(collection: T::CollectionId) {
let next_id = collection.increment();
NextCollectionId::<T, I>::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::<T, I>::set(Some(id));
@@ -62,6 +68,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
#[cfg(test)]
pub fn get_next_id() -> T::CollectionId {
NextCollectionId::<T, I>::get().unwrap_or(T::CollectionId::initial_value())
NextCollectionId::<T, I>::get()
.or(T::CollectionId::initial_value())
.expect("Failed to get next collection ID")
}
}
@@ -50,13 +50,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
),
);
let next_id = collection.increment();
CollectionConfigOf::<T, I>::insert(&collection, config);
CollectionAccount::<T, I>::insert(&owner, &collection, ());
NextCollectionId::<T, I>::set(Some(next_id));
Self::deposit_event(Event::NextCollectionIdIncremented { next_id });
Self::deposit_event(event);
Ok(())
}
+35 -2
View File
@@ -162,8 +162,9 @@ impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId, Collection
Error::<T, I>::WrongSetting
);
let collection =
NextCollectionId::<T, I>::get().unwrap_or(T::CollectionId::initial_value());
let collection = NextCollectionId::<T, I>::get()
.or(T::CollectionId::initial_value())
.ok_or(Error::<T, I>::UnknownCollection)?;
Self::do_create_collection(
collection,
@@ -173,8 +174,40 @@ impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId, Collection
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<T, I>,
) -> Result<(), DispatchError> {
// DepositRequired can be disabled by calling the force_create() only
ensure!(
!config.has_disabled_setting(CollectionSetting::DepositRequired),
Error::<T, I>::WrongSetting
);
Self::do_create_collection(
collection,
who.clone(),
admin.clone(),
*config,
T::CollectionDeposit::get(),
Event::Created { collection, creator: who.clone(), owner: admin.clone() },
)
}
}
impl<T: Config<I>, I: 'static> Destroy<<T as SystemConfig>::AccountId> for Pallet<T, I> {
+23 -7
View File
@@ -101,6 +101,14 @@ pub mod pallet {
+ IsType<<Self as frame_system::Config>::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.
@@ -476,7 +484,7 @@ pub mod pallet {
/// Mint settings for a collection had changed.
CollectionMintSettingsUpdated { collection: T::CollectionId },
/// Event gets emitted when the `NextCollectionId` gets incremented.
NextCollectionIdIncremented { next_id: T::CollectionId },
NextCollectionIdIncremented { next_id: Option<T::CollectionId> },
/// The price was set for the item.
ItemPriceSet {
collection: T::CollectionId,
@@ -665,8 +673,9 @@ pub mod pallet {
admin: AccountIdLookupOf<T>,
config: CollectionConfigFor<T, I>,
) -> DispatchResult {
let collection =
NextCollectionId::<T, I>::get().unwrap_or(T::CollectionId::initial_value());
let collection = NextCollectionId::<T, I>::get()
.or(T::CollectionId::initial_value())
.ok_or(Error::<T, I>::UnknownCollection)?;
let owner = T::CreateOrigin::ensure_origin(origin, &collection)?;
let admin = T::Lookup::lookup(admin)?;
@@ -684,7 +693,10 @@ pub mod pallet {
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.
@@ -712,8 +724,9 @@ pub mod pallet {
T::ForceOrigin::ensure_origin(origin)?;
let owner = T::Lookup::lookup(owner)?;
let collection =
NextCollectionId::<T, I>::get().unwrap_or(T::CollectionId::initial_value());
let collection = NextCollectionId::<T, I>::get()
.or(T::CollectionId::initial_value())
.ok_or(Error::<T, I>::UnknownCollection)?;
Self::do_create_collection(
collection,
@@ -722,7 +735,10 @@ pub mod pallet {
config,
Zero::zero(),
Event::ForceCreated { collection, owner },
)
)?;
Self::set_next_collection_id(collection);
Ok(())
}
/// Destroy a collection of fungible items.
+39 -1
View File
@@ -23,7 +23,7 @@ use frame_support::{
assert_noop, assert_ok,
dispatch::Dispatchable,
traits::{
tokens::nonfungibles_v2::{Destroy, Mutate},
tokens::nonfungibles_v2::{Create, Destroy, Mutate},
Currency, Get,
},
};
@@ -3678,3 +3678,41 @@ fn pre_signed_attributes_should_work() {
);
})
}
#[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::<Test>::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::<Test>::CollectionIdInUse
);
});
}