Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
97a7e30
Basics
Sep 21, 2022
a85608f
WIP: change the data format
Sep 23, 2022
6db840a
Refactor
Sep 24, 2022
fa3a2a7
Remove redundant new() method
Sep 24, 2022
472a753
Rename settings
Sep 24, 2022
2611dd4
Enable tests
Sep 24, 2022
52d7d38
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-feature-f…
Sep 24, 2022
46a6b7e
Chore
Sep 24, 2022
5ff7048
Change params order
Sep 24, 2022
f7ddfed
Delete the config on collection removal
Sep 24, 2022
d0d1d60
Chore
Sep 24, 2022
7d4b31f
Remove redundant system features
Sep 24, 2022
dd84637
Rename force_item_status to force_collection_status
Sep 24, 2022
4920a0c
Update node runtime
Sep 26, 2022
7456e73
Chore
Sep 26, 2022
9ff45b8
Remove thaw_collection
Sep 26, 2022
c41a48c
Chore
Sep 26, 2022
fee3ade
Connect collection.is_frozen to config
Sep 26, 2022
a9ab6f8
Allow to lock the collection in a new way
Sep 26, 2022
254816d
Move free_holding into settings
Sep 26, 2022
5878197
Connect collection's metadata locker to feature flags
Sep 26, 2022
95e21fb
DRY
Sep 27, 2022
17b7c9e
Chore
Sep 27, 2022
dc6d2f0
Connect pallet level feature flags
Sep 27, 2022
cc64873
Prepare tests for the new changes
Sep 27, 2022
5153080
Implement Item settings
Sep 27, 2022
08a2048
Allow to lock the metadata or attributes of an item
Sep 27, 2022
1551714
Common -> Settings
Sep 27, 2022
8830a4c
Extract settings related code to a separate file
Sep 27, 2022
f8800df
Move feature flag checks inside the do_* methods
Sep 28, 2022
3ccf04e
Split settings.rs into parts
Sep 28, 2022
f83fb73
Extract repeated code into macro
Sep 28, 2022
df97cce
Extract macros into their own file
Sep 28, 2022
3bb6eb5
Chore
Sep 28, 2022
8563a31
Fix traits
Sep 29, 2022
09aca13
Fix traits
Sep 29, 2022
114e519
Test SystemFeatures
Sep 29, 2022
d6536fc
Fix benchmarks
Sep 29, 2022
09a4ed6
Add missing benchmark
Sep 29, 2022
d408b32
Fix node/runtime/lib.rs
Sep 29, 2022
fd86e41
".git/.scripts/bench-bot.sh" pallet dev pallet_nfts
Oct 3, 2022
c002f8b
Keep item's config on burn if it's not empty
Oct 5, 2022
b16435a
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-feature-f…
Oct 5, 2022
d0ee824
Fix the merge artifacts
Oct 5, 2022
0eb568e
Fmt
Oct 5, 2022
998691e
Add SystemFeature::NoSwaps check
Oct 6, 2022
b8c6f5e
Rename SystemFeatures to PalletFeatures
Oct 7, 2022
8bef776
Rename errors
Oct 7, 2022
ddaa884
Add docs
Oct 7, 2022
4c01fc5
Change error message
Oct 7, 2022
30d2bde
Change the format of CollectionConfig to store more data
Oct 10, 2022
9449641
Move max supply to the CollectionConfig and allow to change it
Oct 10, 2022
443578d
Remove ItemConfig from the mint() function and use the one set in min…
Oct 11, 2022
0efc4ec
Add different mint options
Oct 11, 2022
2ab076f
Allow to change the mint settings
Oct 11, 2022
ad083ce
Add a force_mint() method
Oct 12, 2022
4ca6f00
Check mint params
Oct 12, 2022
340cb81
Some optimisations
Oct 12, 2022
025cfdd
Cover with tests
Oct 12, 2022
50b617c
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Oct 19, 2022
6b96856
Remove merge artifacts
Oct 19, 2022
45227f5
Chore
Oct 19, 2022
f36d4b9
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Oct 20, 2022
277d1a6
Use the new has_role() method
Oct 20, 2022
9d1d11b
Rework item deposits
Oct 20, 2022
8ffe4fd
More tests
Oct 21, 2022
c7dcdb0
Refactoring
Oct 21, 2022
e1195c5
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Oct 23, 2022
1ab5043
Address comments
Nov 1, 2022
387bf2c
Refactor lock_collection()
Nov 1, 2022
1c51efd
Update frame/nfts/src/types.rs
jsidorenko Nov 8, 2022
9e9b969
Update frame/nfts/src/types.rs
jsidorenko Nov 8, 2022
b82fbe9
Update frame/nfts/src/lib.rs
jsidorenko Nov 8, 2022
e495da6
Update frame/nfts/src/lib.rs
jsidorenko Nov 8, 2022
670bb28
Private => Issuer
Nov 8, 2022
5093b89
Add more tests
Nov 8, 2022
c376b43
Fix benchmarks
Nov 8, 2022
7fe301a
Add benchmarks for new methods
Nov 8, 2022
f246c52
Merge branch 'js/uniques-v2-minting-options_' into js/uniques-v2-mint…
Nov 8, 2022
cfa90dd
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Nov 8, 2022
d667fb7
[Uniques v2] Refactoring (#12570)
jsidorenko Nov 14, 2022
0ef95b7
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Nov 14, 2022
820891c
Split force_collection_status into 2 methods
Nov 15, 2022
51328b0
Fix benchmarks
Nov 15, 2022
c1e71a2
Fix benchmarks
Nov 15, 2022
011db15
Merge branch 'js/uniques-v2-main-branch' into js/uniques-v2-minting-o…
Nov 16, 2022
67d5643
Update deps
Nov 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions frame/nfts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" }
frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" }

[dev-dependencies]
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
sp-core = { version = "6.0.0", path = "../../primitives/core" }
sp-io = { version = "6.0.0", path = "../../primitives/io" }
sp-std = { version = "4.0.0", path = "../../primitives/std" }
sp-core = { version = "7.0.0", path = "../../primitives/core" }
sp-io = { version = "7.0.0", path = "../../primitives/io" }
sp-std = { version = "5.0.0", path = "../../primitives/std" }

[features]
default = ["std"]
Expand Down
96 changes: 73 additions & 23 deletions frame/nfts/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#![cfg(feature = "runtime-benchmarks")]

use super::*;
use enumflags2::{BitFlag, BitFlags};
use frame_benchmarking::{
account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller,
};
Expand All @@ -46,7 +47,7 @@ fn create_collection<T: Config<I>, I: 'static>(
assert_ok!(Nfts::<T, I>::force_create(
SystemOrigin::Root.into(),
caller_lookup.clone(),
CollectionConfig::all_settings_enabled()
default_collection_config::<T, I>()
));
(collection, caller, caller_lookup)
}
Expand Down Expand Up @@ -78,8 +79,7 @@ fn mint_item<T: Config<I>, I: 'static>(
SystemOrigin::Signed(caller.clone()).into(),
T::Helper::collection(0),
item,
caller_lookup.clone(),
ItemConfig::all_settings_enabled(),
None,
));
(item, caller, caller_lookup)
}
Expand Down Expand Up @@ -128,6 +128,24 @@ fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::
assert_eq!(event, &system_event);
}

fn make_collection_config<T: Config<I>, I: 'static>(
disable_settings: BitFlags<CollectionSetting>,
) -> CollectionConfigFor<T, I> {
CollectionConfig {
settings: CollectionSettings::from_disabled(disable_settings),
max_supply: None,
mint_settings: MintSettings::default(),
}
}

fn default_collection_config<T: Config<I>, I: 'static>() -> CollectionConfigFor<T, I> {
make_collection_config::<T, I>(CollectionSetting::empty())
}

fn default_item_config() -> ItemConfig {
ItemConfig { settings: ItemSettings::all_enabled() }
}

benchmarks_instance_pallet! {
create {
let collection = T::Helper::collection(0);
Expand All @@ -136,7 +154,7 @@ benchmarks_instance_pallet! {
whitelist_account!(caller);
let admin = T::Lookup::unlookup(caller.clone());
T::Currency::make_free_balance_be(&caller, DepositBalanceOf::<T, I>::max_value());
let call = Call::<T, I>::create { admin, config: CollectionConfig::all_settings_enabled() };
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());
Expand All @@ -145,7 +163,7 @@ benchmarks_instance_pallet! {
force_create {
let caller: T::AccountId = whitelisted_caller();
let caller_lookup = T::Lookup::unlookup(caller.clone());
}: _(SystemOrigin::Root, caller_lookup, CollectionConfig::all_settings_enabled())
}: _(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());
}
Expand All @@ -169,7 +187,15 @@ benchmarks_instance_pallet! {
mint {
let (collection, caller, caller_lookup) = create_collection::<T, I>();
let item = T::Helper::item(0);
}: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, ItemConfig::all_settings_enabled())
}: _(SystemOrigin::Signed(caller.clone()), collection, item, None)
verify {
assert_last_event::<T, I>(Event::Issued { collection, item, owner: caller }.into());
}

force_mint {
let (collection, caller, caller_lookup) = create_collection::<T, I>();
let item = T::Helper::item(0);
}: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, default_item_config())
verify {
assert_last_event::<T, I>(Event::Issued { collection, item, owner: caller }.into());
}
Expand All @@ -188,6 +214,7 @@ benchmarks_instance_pallet! {

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::<T, I>(Event::Transferred { collection, item, from: caller, to: target }.into());
Expand All @@ -197,14 +224,10 @@ benchmarks_instance_pallet! {
let i in 0 .. 5_000;
let (collection, caller, caller_lookup) = create_collection::<T, I>();
let items = (0..i).map(|x| mint_item::<T, I>(x as u16).0).collect::<Vec<_>>();
Nfts::<T, I>::force_collection_status(
Nfts::<T, I>::force_collection_config(
SystemOrigin::Root.into(),
collection,
caller_lookup.clone(),
caller_lookup.clone(),
caller_lookup.clone(),
caller_lookup,
CollectionConfig(CollectionSetting::DepositRequired.into()),
make_collection_config::<T, I>(CollectionSetting::DepositRequired.into()),
)?;
}: _(SystemOrigin::Signed(caller.clone()), collection, items.clone())
verify {
Expand Down Expand Up @@ -234,12 +257,13 @@ benchmarks_instance_pallet! {

lock_collection {
let (collection, caller, caller_lookup) = create_collection::<T, I>();
let lock_config = CollectionConfig(
let lock_settings = CollectionSettings::from_disabled(
CollectionSetting::TransferableItems |
CollectionSetting::UnlockedMetadata |
CollectionSetting::UnlockedAttributes,
CollectionSetting::UnlockedAttributes |
CollectionSetting::UnlockedMaxSupply,
);
}: _(SystemOrigin::Signed(caller.clone()), collection, lock_config)
}: _(SystemOrigin::Signed(caller.clone()), collection, lock_settings)
verify {
assert_last_event::<T, I>(Event::CollectionLocked { collection }.into());
}
Expand Down Expand Up @@ -271,20 +295,31 @@ benchmarks_instance_pallet! {
}.into());
}

force_collection_status {
force_collection_owner {
let (collection, _, _) = create_collection::<T, I>();
let origin = T::ForceOrigin::successful_origin();
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::<T, I>::force_collection_owner {
collection,
owner: target_lookup,
};
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_last_event::<T, I>(Event::OwnerChanged { collection, new_owner: target }.into());
}

force_collection_config {
let (collection, caller, caller_lookup) = create_collection::<T, I>();
let origin = T::ForceOrigin::successful_origin();
let call = Call::<T, I>::force_collection_status {
let call = Call::<T, I>::force_collection_config {
collection,
owner: caller_lookup.clone(),
issuer: caller_lookup.clone(),
admin: caller_lookup.clone(),
freezer: caller_lookup,
config: CollectionConfig(CollectionSetting::DepositRequired.into()),
config: make_collection_config::<T, I>(CollectionSetting::DepositRequired.into()),
};
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_last_event::<T, I>(Event::CollectionStatusChanged { collection }.into());
assert_last_event::<T, I>(Event::CollectionConfigChanged { collection }.into());
}

lock_item_properties {
Expand Down Expand Up @@ -414,6 +449,20 @@ benchmarks_instance_pallet! {
}.into());
}

update_mint_settings {
let (collection, caller, _) = create_collection::<T, I>();
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::<T, I>::from(1u32)),
default_item_settings: ItemSettings::all_enabled(),
};
}: _(SystemOrigin::Signed(caller.clone()), collection, mint_settings)
verify {
assert_last_event::<T, I>(Event::CollectionMintSettingsUpdated { collection }.into());
}

set_price {
let (collection, caller, _) = create_collection::<T, I>();
let (item, ..) = mint_item::<T, I>(0);
Expand Down Expand Up @@ -528,6 +577,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());
let origin = SystemOrigin::Signed(caller.clone());
frame_system::Pallet::<T>::set_block_number(One::one());
Nfts::<T, I>::transfer(origin.clone().into(), collection, item2, target_lookup)?;
Expand Down
42 changes: 42 additions & 0 deletions frame/nfts/src/common_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// This file is part of Substrate.

// Copyright (C) 2017-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.

//! Various pieces of common functionality.

use super::*;

impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Get the owner of the item, if the item exists.
pub fn owner(collection: T::CollectionId, item: T::ItemId) -> Option<T::AccountId> {
Item::<T, I>::get(collection, item).map(|i| i.owner)
}

/// Get the owner of the item, if the item exists.
pub fn collection_owner(collection: T::CollectionId) -> Option<T::AccountId> {
Collection::<T, I>::get(collection).map(|i| i.owner)
}

#[cfg(any(test, feature = "runtime-benchmarks"))]
pub fn set_next_id(id: T::CollectionId) {
NextCollectionId::<T, I>::set(Some(id));
}

#[cfg(test)]
pub fn get_next_id() -> T::CollectionId {
NextCollectionId::<T, I>::get().unwrap_or(T::CollectionId::initial_value())
}
}
132 changes: 132 additions & 0 deletions frame/nfts/src/features/approvals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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::*;

impl<T: Config<I>, I: 'static> Pallet<T, I> {
pub(crate) fn do_approve_transfer(
maybe_check_origin: Option<T::AccountId>,
collection: T::CollectionId,
item: T::ItemId,
delegate: T::AccountId,
maybe_deadline: Option<<T as SystemConfig>::BlockNumber>,
) -> DispatchResult {
ensure!(
Self::is_pallet_feature_enabled(PalletFeature::Approvals),
Error::<T, I>::MethodDisabled
);
let mut details =
Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;

let collection_config = Self::get_collection_config(&collection)?;
ensure!(
collection_config.is_setting_enabled(CollectionSetting::TransferableItems),
Error::<T, I>::ItemsNonTransferable
);

if let Some(check_origin) = maybe_check_origin {
let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin);
let permitted = is_admin || check_origin == details.owner;
ensure!(permitted, Error::<T, I>::NoPermission);
}

let now = frame_system::Pallet::<T>::block_number();
let deadline = maybe_deadline.map(|d| d.saturating_add(now));

details
.approvals
.try_insert(delegate.clone(), deadline)
.map_err(|_| Error::<T, I>::ReachedApprovalLimit)?;
Item::<T, I>::insert(&collection, &item, &details);

Self::deposit_event(Event::ApprovedTransfer {
collection,
item,
owner: details.owner,
delegate,
deadline,
});

Ok(())
}

pub(crate) fn do_cancel_approval(
maybe_check_origin: Option<T::AccountId>,
collection: T::CollectionId,
item: T::ItemId,
delegate: T::AccountId,
) -> DispatchResult {
let mut details =
Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownItem)?;

let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::<T, I>::NotDelegate)?;

let is_past_deadline = if let Some(deadline) = maybe_deadline {
let now = frame_system::Pallet::<T>::block_number();
now > *deadline
} else {
false
};

if !is_past_deadline {
if let Some(check_origin) = maybe_check_origin {
let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin);
let permitted = is_admin || check_origin == details.owner;
ensure!(permitted, Error::<T, I>::NoPermission);
}
}

details.approvals.remove(&delegate);
Item::<T, I>::insert(&collection, &item, &details);

Self::deposit_event(Event::ApprovalCancelled {
collection,
item,
owner: details.owner,
delegate,
});

Ok(())
}

pub(crate) fn do_clear_all_transfer_approvals(
maybe_check_origin: Option<T::AccountId>,
collection: T::CollectionId,
item: T::ItemId,
) -> DispatchResult {
let mut details =
Item::<T, I>::get(&collection, &item).ok_or(Error::<T, I>::UnknownCollection)?;

if let Some(check_origin) = maybe_check_origin {
let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin);
let permitted = is_admin || check_origin == details.owner;
ensure!(permitted, Error::<T, I>::NoPermission);
}

details.approvals.clear();
Item::<T, I>::insert(&collection, &item, &details);

Self::deposit_event(Event::AllApprovalsCancelled {
collection,
item,
owner: details.owner,
});

Ok(())
}
}
Loading