1use super::*;
21use frame_support::{
22 ensure,
23 storage::KeyPrefixIterator,
24 traits::{tokens::nonfungibles_v2::*, Get},
25 BoundedSlice,
26};
27use sp_runtime::{DispatchError, DispatchResult};
28
29impl<T: Config<I>, I: 'static> Inspect<<T as SystemConfig>::AccountId> for Pallet<T, I> {
30 type ItemId = T::ItemId;
31 type CollectionId = T::CollectionId;
32
33 fn owner(
34 collection: &Self::CollectionId,
35 item: &Self::ItemId,
36 ) -> Option<<T as SystemConfig>::AccountId> {
37 Item::<T, I>::get(collection, item).map(|a| a.owner)
38 }
39
40 fn collection_owner(collection: &Self::CollectionId) -> Option<<T as SystemConfig>::AccountId> {
41 Collection::<T, I>::get(collection).map(|a| a.owner)
42 }
43
44 fn attribute(
50 collection: &Self::CollectionId,
51 item: &Self::ItemId,
52 key: &[u8],
53 ) -> Option<Vec<u8>> {
54 if key.is_empty() {
55 ItemMetadataOf::<T, I>::get(collection, item).map(|m| m.data.into())
57 } else {
58 let namespace = AttributeNamespace::CollectionOwner;
59 let key = BoundedSlice::<_, _>::try_from(key).ok()?;
60 Attribute::<T, I>::get((collection, Some(item), namespace, key)).map(|a| a.0.into())
61 }
62 }
63
64 fn custom_attribute(
68 account: &T::AccountId,
69 collection: &Self::CollectionId,
70 item: &Self::ItemId,
71 key: &[u8],
72 ) -> Option<Vec<u8>> {
73 let namespace = Account::<T, I>::get((account, collection, item))
74 .map(|_| AttributeNamespace::ItemOwner)
75 .unwrap_or_else(|| AttributeNamespace::Account(account.clone()));
76
77 let key = BoundedSlice::<_, _>::try_from(key).ok()?;
78 Attribute::<T, I>::get((collection, Some(item), namespace, key)).map(|a| a.0.into())
79 }
80
81 fn system_attribute(
87 collection: &Self::CollectionId,
88 item: Option<&Self::ItemId>,
89 key: &[u8],
90 ) -> Option<Vec<u8>> {
91 let namespace = AttributeNamespace::Pallet;
92 let key = BoundedSlice::<_, _>::try_from(key).ok()?;
93 Attribute::<T, I>::get((collection, item, namespace, key)).map(|a| a.0.into())
94 }
95
96 fn collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> Option<Vec<u8>> {
102 if key.is_empty() {
103 CollectionMetadataOf::<T, I>::get(collection).map(|m| m.data.into())
105 } else {
106 let key = BoundedSlice::<_, _>::try_from(key).ok()?;
107 Attribute::<T, I>::get((
108 collection,
109 Option::<T::ItemId>::None,
110 AttributeNamespace::CollectionOwner,
111 key,
112 ))
113 .map(|a| a.0.into())
114 }
115 }
116
117 fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool {
121 use PalletAttributes::TransferDisabled;
122 match Self::has_system_attribute(&collection, &item, TransferDisabled) {
123 Ok(transfer_disabled) if transfer_disabled => return false,
124 _ => (),
125 }
126 match (
127 CollectionConfigOf::<T, I>::get(collection),
128 ItemConfigOf::<T, I>::get(collection, item),
129 ) {
130 (Some(cc), Some(ic))
131 if cc.is_setting_enabled(CollectionSetting::TransferableItems) &&
132 ic.is_setting_enabled(ItemSetting::Transferable) =>
133 {
134 true
135 },
136 _ => false,
137 }
138 }
139}
140
141impl<T: Config<I>, I: 'static> InspectRole<<T as SystemConfig>::AccountId> for Pallet<T, I> {
142 fn is_issuer(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
143 Self::has_role(collection, who, CollectionRole::Issuer)
144 }
145 fn is_admin(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
146 Self::has_role(collection, who, CollectionRole::Admin)
147 }
148 fn is_freezer(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
149 Self::has_role(collection, who, CollectionRole::Freezer)
150 }
151}
152
153impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId, CollectionConfigFor<T, I>>
154 for Pallet<T, I>
155{
156 fn create_collection(
158 who: &T::AccountId,
159 admin: &T::AccountId,
160 config: &CollectionConfigFor<T, I>,
161 ) -> Result<T::CollectionId, DispatchError> {
162 ensure!(
164 !config.has_disabled_setting(CollectionSetting::DepositRequired),
165 Error::<T, I>::WrongSetting
166 );
167
168 let collection = NextCollectionId::<T, I>::get()
169 .or(T::CollectionId::initial_value())
170 .ok_or(Error::<T, I>::UnknownCollection)?;
171
172 Self::do_create_collection(
173 collection,
174 who.clone(),
175 admin.clone(),
176 *config,
177 T::CollectionDeposit::get(),
178 Event::Created { collection, creator: who.clone(), owner: admin.clone() },
179 )?;
180
181 Self::set_next_collection_id(collection);
182
183 Ok(collection)
184 }
185
186 fn create_collection_with_id(
194 collection: T::CollectionId,
195 who: &T::AccountId,
196 admin: &T::AccountId,
197 config: &CollectionConfigFor<T, I>,
198 ) -> Result<(), DispatchError> {
199 ensure!(
201 !config.has_disabled_setting(CollectionSetting::DepositRequired),
202 Error::<T, I>::WrongSetting
203 );
204
205 Self::do_create_collection(
206 collection,
207 who.clone(),
208 admin.clone(),
209 *config,
210 T::CollectionDeposit::get(),
211 Event::Created { collection, creator: who.clone(), owner: admin.clone() },
212 )
213 }
214}
215
216impl<T: Config<I>, I: 'static> Destroy<<T as SystemConfig>::AccountId> for Pallet<T, I> {
217 type DestroyWitness = DestroyWitness;
218
219 fn get_destroy_witness(collection: &Self::CollectionId) -> Option<DestroyWitness> {
220 Collection::<T, I>::get(collection).map(|a| a.destroy_witness())
221 }
222
223 fn destroy(
224 collection: Self::CollectionId,
225 witness: Self::DestroyWitness,
226 maybe_check_owner: Option<T::AccountId>,
227 ) -> Result<Self::DestroyWitness, DispatchError> {
228 Self::do_destroy_collection(collection, witness, maybe_check_owner)
229 }
230}
231
232impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId, ItemConfig> for Pallet<T, I> {
233 fn mint_into(
234 collection: &Self::CollectionId,
235 item: &Self::ItemId,
236 who: &T::AccountId,
237 item_config: &ItemConfig,
238 deposit_collection_owner: bool,
239 ) -> DispatchResult {
240 Self::do_mint(
241 *collection,
242 *item,
243 match deposit_collection_owner {
244 true => None,
245 false => Some(who.clone()),
246 },
247 who.clone(),
248 *item_config,
249 |_, _| Ok(()),
250 )
251 }
252
253 fn burn(
254 collection: &Self::CollectionId,
255 item: &Self::ItemId,
256 maybe_check_owner: Option<&T::AccountId>,
257 ) -> DispatchResult {
258 Self::do_burn(*collection, *item, |d| {
259 if let Some(check_owner) = maybe_check_owner {
260 if &d.owner != check_owner {
261 return Err(Error::<T, I>::NoPermission.into());
262 }
263 }
264 Ok(())
265 })
266 }
267
268 fn set_attribute(
269 collection: &Self::CollectionId,
270 item: &Self::ItemId,
271 key: &[u8],
272 value: &[u8],
273 ) -> DispatchResult {
274 Self::do_force_set_attribute(
275 None,
276 *collection,
277 Some(*item),
278 AttributeNamespace::Pallet,
279 Self::construct_attribute_key(key.to_vec())?,
280 Self::construct_attribute_value(value.to_vec())?,
281 )
282 }
283
284 fn set_typed_attribute<K: Encode, V: Encode>(
285 collection: &Self::CollectionId,
286 item: &Self::ItemId,
287 key: &K,
288 value: &V,
289 ) -> DispatchResult {
290 key.using_encoded(|k| {
291 value.using_encoded(|v| {
292 <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute(collection, item, k, v)
293 })
294 })
295 }
296
297 fn set_collection_attribute(
298 collection: &Self::CollectionId,
299 key: &[u8],
300 value: &[u8],
301 ) -> DispatchResult {
302 Self::do_force_set_attribute(
303 None,
304 *collection,
305 None,
306 AttributeNamespace::Pallet,
307 Self::construct_attribute_key(key.to_vec())?,
308 Self::construct_attribute_value(value.to_vec())?,
309 )
310 }
311
312 fn set_typed_collection_attribute<K: Encode, V: Encode>(
313 collection: &Self::CollectionId,
314 key: &K,
315 value: &V,
316 ) -> DispatchResult {
317 key.using_encoded(|k| {
318 value.using_encoded(|v| {
319 <Self as Mutate<T::AccountId, ItemConfig>>::set_collection_attribute(
320 collection, k, v,
321 )
322 })
323 })
324 }
325
326 fn set_item_metadata(
327 who: Option<&T::AccountId>,
328 collection: &Self::CollectionId,
329 item: &Self::ItemId,
330 data: &[u8],
331 ) -> DispatchResult {
332 Self::do_set_item_metadata(
333 who.cloned(),
334 *collection,
335 *item,
336 Self::construct_metadata(data.to_vec())?,
337 None,
338 )
339 }
340
341 fn set_collection_metadata(
342 who: Option<&T::AccountId>,
343 collection: &Self::CollectionId,
344 data: &[u8],
345 ) -> DispatchResult {
346 Self::do_set_collection_metadata(
347 who.cloned(),
348 *collection,
349 Self::construct_metadata(data.to_vec())?,
350 )
351 }
352
353 fn clear_attribute(
354 collection: &Self::CollectionId,
355 item: &Self::ItemId,
356 key: &[u8],
357 ) -> DispatchResult {
358 Self::do_clear_attribute(
359 None,
360 *collection,
361 Some(*item),
362 AttributeNamespace::Pallet,
363 Self::construct_attribute_key(key.to_vec())?,
364 )
365 }
366
367 fn clear_typed_attribute<K: Encode>(
368 collection: &Self::CollectionId,
369 item: &Self::ItemId,
370 key: &K,
371 ) -> DispatchResult {
372 key.using_encoded(|k| {
373 <Self as Mutate<T::AccountId, ItemConfig>>::clear_attribute(collection, item, k)
374 })
375 }
376
377 fn clear_collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> DispatchResult {
378 Self::do_clear_attribute(
379 None,
380 *collection,
381 None,
382 AttributeNamespace::Pallet,
383 Self::construct_attribute_key(key.to_vec())?,
384 )
385 }
386
387 fn clear_typed_collection_attribute<K: Encode>(
388 collection: &Self::CollectionId,
389 key: &K,
390 ) -> DispatchResult {
391 key.using_encoded(|k| {
392 <Self as Mutate<T::AccountId, ItemConfig>>::clear_collection_attribute(collection, k)
393 })
394 }
395
396 fn clear_item_metadata(
397 who: Option<&T::AccountId>,
398 collection: &Self::CollectionId,
399 item: &Self::ItemId,
400 ) -> DispatchResult {
401 Self::do_clear_item_metadata(who.cloned(), *collection, *item)
402 }
403
404 fn clear_collection_metadata(
405 who: Option<&T::AccountId>,
406 collection: &Self::CollectionId,
407 ) -> DispatchResult {
408 Self::do_clear_collection_metadata(who.cloned(), *collection)
409 }
410}
411
412impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
413 fn transfer(
414 collection: &Self::CollectionId,
415 item: &Self::ItemId,
416 destination: &T::AccountId,
417 ) -> DispatchResult {
418 Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(()))
419 }
420
421 fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult {
422 let transfer_disabled =
423 Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?;
424 if transfer_disabled {
426 return Err(Error::<T, I>::ItemLocked.into());
427 }
428
429 <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute(
430 collection,
431 item,
432 &PalletAttributes::<Self::CollectionId>::TransferDisabled.encode(),
433 &[],
434 )
435 }
436
437 fn enable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult {
438 <Self as Mutate<T::AccountId, ItemConfig>>::clear_attribute(
439 collection,
440 item,
441 &PalletAttributes::<Self::CollectionId>::TransferDisabled.encode(),
442 )
443 }
444}
445
446impl<T: Config<I>, I: 'static> Trading<T::AccountId, ItemPrice<T, I>> for Pallet<T, I> {
447 fn buy_item(
448 collection: &Self::CollectionId,
449 item: &Self::ItemId,
450 buyer: &T::AccountId,
451 bid_price: &ItemPrice<T, I>,
452 ) -> DispatchResult {
453 Self::do_buy_item(*collection, *item, buyer.clone(), *bid_price)
454 }
455
456 fn set_price(
457 collection: &Self::CollectionId,
458 item: &Self::ItemId,
459 sender: &T::AccountId,
460 price: Option<ItemPrice<T, I>>,
461 whitelisted_buyer: Option<T::AccountId>,
462 ) -> DispatchResult {
463 Self::do_set_price(*collection, *item, sender.clone(), price, whitelisted_buyer)
464 }
465
466 fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option<ItemPrice<T, I>> {
467 ItemPriceOf::<T, I>::get(collection, item).map(|a| a.0)
468 }
469}
470
471impl<T: Config<I>, I: 'static> InspectEnumerable<T::AccountId> for Pallet<T, I> {
472 type CollectionsIterator = KeyPrefixIterator<<T as Config<I>>::CollectionId>;
473 type ItemsIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
474 type OwnedIterator =
475 KeyPrefixIterator<(<T as Config<I>>::CollectionId, <T as Config<I>>::ItemId)>;
476 type OwnedInCollectionIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
477
478 fn collections() -> Self::CollectionsIterator {
482 Collection::<T, I>::iter_keys()
483 }
484
485 fn items(collection: &Self::CollectionId) -> Self::ItemsIterator {
489 Item::<T, I>::iter_key_prefix(collection)
490 }
491
492 fn owned(who: &T::AccountId) -> Self::OwnedIterator {
496 Account::<T, I>::iter_key_prefix((who,))
497 }
498
499 fn owned_in_collection(
503 collection: &Self::CollectionId,
504 who: &T::AccountId,
505 ) -> Self::OwnedInCollectionIterator {
506 Account::<T, I>::iter_key_prefix((who, collection))
507 }
508}