pallet_nfts/features/lock.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! This module contains helper methods to configure locks on collections and items for the NFTs
19//! pallet.
20
21use crate::*;
22use frame_support::pallet_prelude::*;
23
24impl<T: Config<I>, I: 'static> Pallet<T, I> {
25 /// Locks a collection with specified settings.
26 ///
27 /// The origin must be the owner of the collection to lock it. This function disables certain
28 /// settings on the collection. The only setting that can't be disabled is `DepositRequired`.
29 ///
30 /// Note: it's possible only to lock the setting, but not to unlock it after.
31
32 ///
33 /// - `origin`: The origin of the transaction, representing the account attempting to lock the
34 /// collection.
35 /// - `collection`: The identifier of the collection to be locked.
36 /// - `lock_settings`: The collection settings to be locked.
37 pub(crate) fn do_lock_collection(
38 origin: T::AccountId,
39 collection: T::CollectionId,
40 lock_settings: CollectionSettings,
41 ) -> DispatchResult {
42 ensure!(Self::collection_owner(collection) == Some(origin), Error::<T, I>::NoPermission);
43 ensure!(
44 !lock_settings.is_disabled(CollectionSetting::DepositRequired),
45 Error::<T, I>::WrongSetting
46 );
47 CollectionConfigOf::<T, I>::try_mutate(collection, |maybe_config| {
48 let config = maybe_config.as_mut().ok_or(Error::<T, I>::NoConfig)?;
49
50 for setting in lock_settings.get_disabled() {
51 config.disable_setting(setting);
52 }
53
54 Self::deposit_event(Event::<T, I>::CollectionLocked { collection });
55 Ok(())
56 })
57 }
58
59 /// Locks the transfer of an item within a collection.
60 ///
61 /// The origin must have the `Freezer` role within the collection to lock the transfer of the
62 /// item. This function disables the `Transferable` setting on the item, preventing it from
63 /// being transferred to other accounts.
64 ///
65 /// - `origin`: The origin of the transaction, representing the account attempting to lock the
66 /// item transfer.
67 /// - `collection`: The identifier of the collection to which the item belongs.
68 /// - `item`: The identifier of the item to be locked for transfer.
69 pub(crate) fn do_lock_item_transfer(
70 origin: T::AccountId,
71 collection: T::CollectionId,
72 item: T::ItemId,
73 ) -> DispatchResult {
74 ensure!(
75 Self::has_role(&collection, &origin, CollectionRole::Freezer),
76 Error::<T, I>::NoPermission
77 );
78
79 let mut config = Self::get_item_config(&collection, &item)?;
80 if !config.has_disabled_setting(ItemSetting::Transferable) {
81 config.disable_setting(ItemSetting::Transferable);
82 }
83 ItemConfigOf::<T, I>::insert(&collection, &item, config);
84
85 Self::deposit_event(Event::<T, I>::ItemTransferLocked { collection, item });
86 Ok(())
87 }
88
89 /// Unlocks the transfer of an item within a collection.
90 ///
91 /// The origin must have the `Freezer` role within the collection to unlock the transfer of the
92 /// item. This function enables the `Transferable` setting on the item, allowing it to be
93 /// transferred to other accounts.
94 ///
95 /// - `origin`: The origin of the transaction, representing the account attempting to unlock the
96 /// item transfer.
97 /// - `collection`: The identifier of the collection to which the item belongs.
98 /// - `item`: The identifier of the item to be unlocked for transfer.
99 pub(crate) fn do_unlock_item_transfer(
100 origin: T::AccountId,
101 collection: T::CollectionId,
102 item: T::ItemId,
103 ) -> DispatchResult {
104 ensure!(
105 Self::has_role(&collection, &origin, CollectionRole::Freezer),
106 Error::<T, I>::NoPermission
107 );
108
109 let mut config = Self::get_item_config(&collection, &item)?;
110 if config.has_disabled_setting(ItemSetting::Transferable) {
111 config.enable_setting(ItemSetting::Transferable);
112 }
113 ItemConfigOf::<T, I>::insert(&collection, &item, config);
114
115 Self::deposit_event(Event::<T, I>::ItemTransferUnlocked { collection, item });
116 Ok(())
117 }
118
119 /// Locks the metadata and attributes of an item within a collection.
120 ///
121 /// The origin must have the `Admin` role within the collection to lock the metadata and
122 /// attributes of the item. This function disables the `UnlockedMetadata` and
123 /// `UnlockedAttributes` settings on the item, preventing modifications to its metadata and
124 /// attributes.
125 ///
126 /// - `maybe_check_origin`: An optional origin representing the account attempting to lock the
127 /// item properties. If provided, this account must have the `Admin` role within the
128 /// collection. If `None`, no permission check is performed, and the function can be called
129 /// from any origin.
130 /// - `collection`: The identifier of the collection to which the item belongs.
131 /// - `item`: The identifier of the item to be locked for properties.
132 /// - `lock_metadata`: A boolean indicating whether to lock the metadata of the item.
133 /// - `lock_attributes`: A boolean indicating whether to lock the attributes of the item.
134 pub(crate) fn do_lock_item_properties(
135 maybe_check_origin: Option<T::AccountId>,
136 collection: T::CollectionId,
137 item: T::ItemId,
138 lock_metadata: bool,
139 lock_attributes: bool,
140 ) -> DispatchResult {
141 if let Some(check_origin) = &maybe_check_origin {
142 ensure!(
143 Self::has_role(&collection, &check_origin, CollectionRole::Admin),
144 Error::<T, I>::NoPermission
145 );
146 }
147
148 ItemConfigOf::<T, I>::try_mutate(collection, item, |maybe_config| {
149 let config = maybe_config.as_mut().ok_or(Error::<T, I>::UnknownItem)?;
150
151 if lock_metadata {
152 config.disable_setting(ItemSetting::UnlockedMetadata);
153 }
154 if lock_attributes {
155 config.disable_setting(ItemSetting::UnlockedAttributes);
156 }
157
158 Self::deposit_event(Event::<T, I>::ItemPropertiesLocked {
159 collection,
160 item,
161 lock_metadata,
162 lock_attributes,
163 });
164 Ok(())
165 })
166 }
167}