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 true,
134 _ => false,
135 }
136 }
137}
138
139impl<T: Config<I>, I: 'static> InspectRole<<T as SystemConfig>::AccountId> for Pallet<T, I> {
140 fn is_issuer(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
141 Self::has_role(collection, who, CollectionRole::Issuer)
142 }
143 fn is_admin(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
144 Self::has_role(collection, who, CollectionRole::Admin)
145 }
146 fn is_freezer(collection: &Self::CollectionId, who: &<T as SystemConfig>::AccountId) -> bool {
147 Self::has_role(collection, who, CollectionRole::Freezer)
148 }
149}
150
151impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId, CollectionConfigFor<T, I>>
152 for Pallet<T, I>
153{
154 fn create_collection(
156 who: &T::AccountId,
157 admin: &T::AccountId,
158 config: &CollectionConfigFor<T, I>,
159 ) -> Result<T::CollectionId, DispatchError> {
160 ensure!(
162 !config.has_disabled_setting(CollectionSetting::DepositRequired),
163 Error::<T, I>::WrongSetting
164 );
165
166 let collection = NextCollectionId::<T, I>::get()
167 .or(T::CollectionId::initial_value())
168 .ok_or(Error::<T, I>::UnknownCollection)?;
169
170 Self::do_create_collection(
171 collection,
172 who.clone(),
173 admin.clone(),
174 *config,
175 T::CollectionDeposit::get(),
176 Event::Created { collection, creator: who.clone(), owner: admin.clone() },
177 )?;
178
179 Self::set_next_collection_id(collection);
180
181 Ok(collection)
182 }
183
184 fn create_collection_with_id(
192 collection: T::CollectionId,
193 who: &T::AccountId,
194 admin: &T::AccountId,
195 config: &CollectionConfigFor<T, I>,
196 ) -> Result<(), DispatchError> {
197 ensure!(
199 !config.has_disabled_setting(CollectionSetting::DepositRequired),
200 Error::<T, I>::WrongSetting
201 );
202
203 Self::do_create_collection(
204 collection,
205 who.clone(),
206 admin.clone(),
207 *config,
208 T::CollectionDeposit::get(),
209 Event::Created { collection, creator: who.clone(), owner: admin.clone() },
210 )
211 }
212}
213
214impl<T: Config<I>, I: 'static> Destroy<<T as SystemConfig>::AccountId> for Pallet<T, I> {
215 type DestroyWitness = DestroyWitness;
216
217 fn get_destroy_witness(collection: &Self::CollectionId) -> Option<DestroyWitness> {
218 Collection::<T, I>::get(collection).map(|a| a.destroy_witness())
219 }
220
221 fn destroy(
222 collection: Self::CollectionId,
223 witness: Self::DestroyWitness,
224 maybe_check_owner: Option<T::AccountId>,
225 ) -> Result<Self::DestroyWitness, DispatchError> {
226 Self::do_destroy_collection(collection, witness, maybe_check_owner)
227 }
228}
229
230impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId, ItemConfig> for Pallet<T, I> {
231 fn mint_into(
232 collection: &Self::CollectionId,
233 item: &Self::ItemId,
234 who: &T::AccountId,
235 item_config: &ItemConfig,
236 deposit_collection_owner: bool,
237 ) -> DispatchResult {
238 Self::do_mint(
239 *collection,
240 *item,
241 match deposit_collection_owner {
242 true => None,
243 false => Some(who.clone()),
244 },
245 who.clone(),
246 *item_config,
247 |_, _| Ok(()),
248 )
249 }
250
251 fn burn(
252 collection: &Self::CollectionId,
253 item: &Self::ItemId,
254 maybe_check_owner: Option<&T::AccountId>,
255 ) -> DispatchResult {
256 Self::do_burn(*collection, *item, |d| {
257 if let Some(check_owner) = maybe_check_owner {
258 if &d.owner != check_owner {
259 return Err(Error::<T, I>::NoPermission.into())
260 }
261 }
262 Ok(())
263 })
264 }
265
266 fn set_attribute(
267 collection: &Self::CollectionId,
268 item: &Self::ItemId,
269 key: &[u8],
270 value: &[u8],
271 ) -> DispatchResult {
272 Self::do_force_set_attribute(
273 None,
274 *collection,
275 Some(*item),
276 AttributeNamespace::Pallet,
277 Self::construct_attribute_key(key.to_vec())?,
278 Self::construct_attribute_value(value.to_vec())?,
279 )
280 }
281
282 fn set_typed_attribute<K: Encode, V: Encode>(
283 collection: &Self::CollectionId,
284 item: &Self::ItemId,
285 key: &K,
286 value: &V,
287 ) -> DispatchResult {
288 key.using_encoded(|k| {
289 value.using_encoded(|v| {
290 <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute(collection, item, k, v)
291 })
292 })
293 }
294
295 fn set_collection_attribute(
296 collection: &Self::CollectionId,
297 key: &[u8],
298 value: &[u8],
299 ) -> DispatchResult {
300 Self::do_force_set_attribute(
301 None,
302 *collection,
303 None,
304 AttributeNamespace::Pallet,
305 Self::construct_attribute_key(key.to_vec())?,
306 Self::construct_attribute_value(value.to_vec())?,
307 )
308 }
309
310 fn set_typed_collection_attribute<K: Encode, V: Encode>(
311 collection: &Self::CollectionId,
312 key: &K,
313 value: &V,
314 ) -> DispatchResult {
315 key.using_encoded(|k| {
316 value.using_encoded(|v| {
317 <Self as Mutate<T::AccountId, ItemConfig>>::set_collection_attribute(
318 collection, k, v,
319 )
320 })
321 })
322 }
323
324 fn set_item_metadata(
325 who: Option<&T::AccountId>,
326 collection: &Self::CollectionId,
327 item: &Self::ItemId,
328 data: &[u8],
329 ) -> DispatchResult {
330 Self::do_set_item_metadata(
331 who.cloned(),
332 *collection,
333 *item,
334 Self::construct_metadata(data.to_vec())?,
335 None,
336 )
337 }
338
339 fn set_collection_metadata(
340 who: Option<&T::AccountId>,
341 collection: &Self::CollectionId,
342 data: &[u8],
343 ) -> DispatchResult {
344 Self::do_set_collection_metadata(
345 who.cloned(),
346 *collection,
347 Self::construct_metadata(data.to_vec())?,
348 )
349 }
350
351 fn clear_attribute(
352 collection: &Self::CollectionId,
353 item: &Self::ItemId,
354 key: &[u8],
355 ) -> DispatchResult {
356 Self::do_clear_attribute(
357 None,
358 *collection,
359 Some(*item),
360 AttributeNamespace::Pallet,
361 Self::construct_attribute_key(key.to_vec())?,
362 )
363 }
364
365 fn clear_typed_attribute<K: Encode>(
366 collection: &Self::CollectionId,
367 item: &Self::ItemId,
368 key: &K,
369 ) -> DispatchResult {
370 key.using_encoded(|k| {
371 <Self as Mutate<T::AccountId, ItemConfig>>::clear_attribute(collection, item, k)
372 })
373 }
374
375 fn clear_collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> DispatchResult {
376 Self::do_clear_attribute(
377 None,
378 *collection,
379 None,
380 AttributeNamespace::Pallet,
381 Self::construct_attribute_key(key.to_vec())?,
382 )
383 }
384
385 fn clear_typed_collection_attribute<K: Encode>(
386 collection: &Self::CollectionId,
387 key: &K,
388 ) -> DispatchResult {
389 key.using_encoded(|k| {
390 <Self as Mutate<T::AccountId, ItemConfig>>::clear_collection_attribute(collection, k)
391 })
392 }
393
394 fn clear_item_metadata(
395 who: Option<&T::AccountId>,
396 collection: &Self::CollectionId,
397 item: &Self::ItemId,
398 ) -> DispatchResult {
399 Self::do_clear_item_metadata(who.cloned(), *collection, *item)
400 }
401
402 fn clear_collection_metadata(
403 who: Option<&T::AccountId>,
404 collection: &Self::CollectionId,
405 ) -> DispatchResult {
406 Self::do_clear_collection_metadata(who.cloned(), *collection)
407 }
408}
409
410impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
411 fn transfer(
412 collection: &Self::CollectionId,
413 item: &Self::ItemId,
414 destination: &T::AccountId,
415 ) -> DispatchResult {
416 Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(()))
417 }
418
419 fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult {
420 let transfer_disabled =
421 Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?;
422 if transfer_disabled {
424 return Err(Error::<T, I>::ItemLocked.into())
425 }
426
427 <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute(
428 collection,
429 item,
430 &PalletAttributes::<Self::CollectionId>::TransferDisabled.encode(),
431 &[],
432 )
433 }
434
435 fn enable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult {
436 <Self as Mutate<T::AccountId, ItemConfig>>::clear_attribute(
437 collection,
438 item,
439 &PalletAttributes::<Self::CollectionId>::TransferDisabled.encode(),
440 )
441 }
442}
443
444impl<T: Config<I>, I: 'static> Trading<T::AccountId, ItemPrice<T, I>> for Pallet<T, I> {
445 fn buy_item(
446 collection: &Self::CollectionId,
447 item: &Self::ItemId,
448 buyer: &T::AccountId,
449 bid_price: &ItemPrice<T, I>,
450 ) -> DispatchResult {
451 Self::do_buy_item(*collection, *item, buyer.clone(), *bid_price)
452 }
453
454 fn set_price(
455 collection: &Self::CollectionId,
456 item: &Self::ItemId,
457 sender: &T::AccountId,
458 price: Option<ItemPrice<T, I>>,
459 whitelisted_buyer: Option<T::AccountId>,
460 ) -> DispatchResult {
461 Self::do_set_price(*collection, *item, sender.clone(), price, whitelisted_buyer)
462 }
463
464 fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option<ItemPrice<T, I>> {
465 ItemPriceOf::<T, I>::get(collection, item).map(|a| a.0)
466 }
467}
468
469impl<T: Config<I>, I: 'static> InspectEnumerable<T::AccountId> for Pallet<T, I> {
470 type CollectionsIterator = KeyPrefixIterator<<T as Config<I>>::CollectionId>;
471 type ItemsIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
472 type OwnedIterator =
473 KeyPrefixIterator<(<T as Config<I>>::CollectionId, <T as Config<I>>::ItemId)>;
474 type OwnedInCollectionIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
475
476 fn collections() -> Self::CollectionsIterator {
480 Collection::<T, I>::iter_keys()
481 }
482
483 fn items(collection: &Self::CollectionId) -> Self::ItemsIterator {
487 Item::<T, I>::iter_key_prefix(collection)
488 }
489
490 fn owned(who: &T::AccountId) -> Self::OwnedIterator {
494 Account::<T, I>::iter_key_prefix((who,))
495 }
496
497 fn owned_in_collection(
501 collection: &Self::CollectionId,
502 who: &T::AccountId,
503 ) -> Self::OwnedInCollectionIterator {
504 Account::<T, I>::iter_key_prefix((who, collection))
505 }
506}