1use crate::*;
21use alloc::vec::Vec;
22use frame_support::pallet_prelude::*;
23
24impl<T: Config<I>, I: 'static> Pallet<T, I> {
25 pub(crate) fn do_set_item_metadata(
43 maybe_check_origin: Option<T::AccountId>,
44 collection: T::CollectionId,
45 item: T::ItemId,
46 data: BoundedVec<u8, T::StringLimit>,
47 maybe_depositor: Option<T::AccountId>,
48 ) -> DispatchResult {
49 if let Some(check_origin) = &maybe_check_origin {
50 ensure!(
51 Self::has_role(&collection, &check_origin, CollectionRole::Admin),
52 Error::<T, I>::NoPermission
53 );
54 }
55
56 let is_root = maybe_check_origin.is_none();
57 let mut collection_details =
58 Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
59
60 let item_config = Self::get_item_config(&collection, &item)?;
61 ensure!(
62 is_root || item_config.is_setting_enabled(ItemSetting::UnlockedMetadata),
63 Error::<T, I>::LockedItemMetadata
64 );
65
66 let collection_config = Self::get_collection_config(&collection)?;
67
68 ItemMetadataOf::<T, I>::try_mutate_exists(collection, item, |metadata| {
69 if metadata.is_none() {
70 collection_details.item_metadatas.saturating_inc();
71 }
72
73 let old_deposit = metadata
74 .take()
75 .map_or(ItemMetadataDeposit { account: None, amount: Zero::zero() }, |m| m.deposit);
76
77 let mut deposit = Zero::zero();
78 if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) && !is_root
79 {
80 deposit = T::DepositPerByte::get()
81 .saturating_mul(((data.len()) as u32).into())
82 .saturating_add(T::MetadataDepositBase::get());
83 }
84
85 let depositor = maybe_depositor.clone().unwrap_or(collection_details.owner.clone());
86 let old_depositor = old_deposit.account.unwrap_or(collection_details.owner.clone());
87
88 if depositor != old_depositor {
89 T::Currency::unreserve(&old_depositor, old_deposit.amount);
90 T::Currency::reserve(&depositor, deposit)?;
91 } else if deposit > old_deposit.amount {
92 T::Currency::reserve(&depositor, deposit - old_deposit.amount)?;
93 } else if deposit < old_deposit.amount {
94 T::Currency::unreserve(&depositor, old_deposit.amount - deposit);
95 }
96
97 if maybe_depositor.is_none() {
98 collection_details.owner_deposit.saturating_accrue(deposit);
99 collection_details.owner_deposit.saturating_reduce(old_deposit.amount);
100 }
101
102 *metadata = Some(ItemMetadata {
103 deposit: ItemMetadataDeposit { account: maybe_depositor, amount: deposit },
104 data: data.clone(),
105 });
106
107 Collection::<T, I>::insert(&collection, &collection_details);
108 Self::deposit_event(Event::ItemMetadataSet { collection, item, data });
109 Ok(())
110 })
111 }
112
113 pub(crate) fn do_clear_item_metadata(
127 maybe_check_origin: Option<T::AccountId>,
128 collection: T::CollectionId,
129 item: T::ItemId,
130 ) -> DispatchResult {
131 if let Some(check_origin) = &maybe_check_origin {
132 ensure!(
133 Self::has_role(&collection, &check_origin, CollectionRole::Admin),
134 Error::<T, I>::NoPermission
135 );
136 }
137
138 let is_root = maybe_check_origin.is_none();
139 let metadata = ItemMetadataOf::<T, I>::take(collection, item)
140 .ok_or(Error::<T, I>::MetadataNotFound)?;
141 let mut collection_details =
142 Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
143
144 let depositor_account =
145 metadata.deposit.account.unwrap_or(collection_details.owner.clone());
146
147 let is_locked = Self::get_item_config(&collection, &item)
149 .map_or(false, |c| c.has_disabled_setting(ItemSetting::UnlockedMetadata));
150
151 ensure!(is_root || !is_locked, Error::<T, I>::LockedItemMetadata);
152
153 collection_details.item_metadatas.saturating_dec();
154 T::Currency::unreserve(&depositor_account, metadata.deposit.amount);
155
156 if depositor_account == collection_details.owner {
157 collection_details.owner_deposit.saturating_reduce(metadata.deposit.amount);
158 }
159
160 Collection::<T, I>::insert(&collection, &collection_details);
161 Self::deposit_event(Event::ItemMetadataCleared { collection, item });
162
163 Ok(())
164 }
165
166 pub(crate) fn do_set_collection_metadata(
180 maybe_check_origin: Option<T::AccountId>,
181 collection: T::CollectionId,
182 data: BoundedVec<u8, T::StringLimit>,
183 ) -> DispatchResult {
184 if let Some(check_origin) = &maybe_check_origin {
185 ensure!(
186 Self::has_role(&collection, &check_origin, CollectionRole::Admin),
187 Error::<T, I>::NoPermission
188 );
189 }
190
191 let is_root = maybe_check_origin.is_none();
192 let collection_config = Self::get_collection_config(&collection)?;
193 ensure!(
194 is_root || collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata),
195 Error::<T, I>::LockedCollectionMetadata
196 );
197
198 let mut details =
199 Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
200
201 CollectionMetadataOf::<T, I>::try_mutate_exists(collection, |metadata| {
202 let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit);
203 details.owner_deposit.saturating_reduce(old_deposit);
204 let mut deposit = Zero::zero();
205 if !is_root && collection_config.is_setting_enabled(CollectionSetting::DepositRequired)
206 {
207 deposit = T::DepositPerByte::get()
208 .saturating_mul(((data.len()) as u32).into())
209 .saturating_add(T::MetadataDepositBase::get());
210 }
211 if deposit > old_deposit {
212 T::Currency::reserve(&details.owner, deposit - old_deposit)?;
213 } else if deposit < old_deposit {
214 T::Currency::unreserve(&details.owner, old_deposit - deposit);
215 }
216 details.owner_deposit.saturating_accrue(deposit);
217
218 Collection::<T, I>::insert(&collection, details);
219
220 *metadata = Some(CollectionMetadata { deposit, data: data.clone() });
221
222 Self::deposit_event(Event::CollectionMetadataSet { collection, data });
223 Ok(())
224 })
225 }
226
227 pub(crate) fn do_clear_collection_metadata(
241 maybe_check_origin: Option<T::AccountId>,
242 collection: T::CollectionId,
243 ) -> DispatchResult {
244 if let Some(check_origin) = &maybe_check_origin {
245 ensure!(
246 Self::has_role(&collection, &check_origin, CollectionRole::Admin),
247 Error::<T, I>::NoPermission
248 );
249 }
250
251 let mut details =
252 Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
253 let collection_config = Self::get_collection_config(&collection)?;
254
255 ensure!(
256 maybe_check_origin.is_none() ||
257 collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata),
258 Error::<T, I>::LockedCollectionMetadata
259 );
260
261 CollectionMetadataOf::<T, I>::try_mutate_exists(collection, |metadata| {
262 let deposit = metadata.take().ok_or(Error::<T, I>::UnknownCollection)?.deposit;
263 T::Currency::unreserve(&details.owner, deposit);
264 details.owner_deposit.saturating_reduce(deposit);
265 Collection::<T, I>::insert(&collection, details);
266 Self::deposit_event(Event::CollectionMetadataCleared { collection });
267 Ok(())
268 })
269 }
270
271 pub fn construct_metadata(
278 metadata: Vec<u8>,
279 ) -> Result<BoundedVec<u8, T::StringLimit>, DispatchError> {
280 Ok(BoundedVec::try_from(metadata).map_err(|_| Error::<T, I>::IncorrectMetadata)?)
281 }
282}