referrerpolicy=no-referrer-when-downgrade

pallet_uniques/
impl_nonfungibles.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//! Implementations for `nonfungibles` traits.
19
20use super::*;
21use alloc::vec::Vec;
22use frame_support::{
23	storage::KeyPrefixIterator,
24	traits::{tokens::nonfungibles::*, 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	/// Returns the attribute value of `item` of `collection` corresponding to `key`.
45	///
46	/// When `key` is empty, we return the item metadata value.
47	///
48	/// By default this is `None`; no attributes are defined.
49	fn attribute(
50		collection: &Self::CollectionId,
51		item: &Self::ItemId,
52		key: &[u8],
53	) -> Option<Vec<u8>> {
54		if key.is_empty() {
55			// We make the empty key map to the item metadata value.
56			ItemMetadataOf::<T, I>::get(collection, item).map(|m| m.data.into())
57		} else {
58			let key = BoundedSlice::<_, _>::try_from(key).ok()?;
59			Attribute::<T, I>::get((collection, Some(item), key)).map(|a| a.0.into())
60		}
61	}
62
63	/// Returns the attribute value of `item` of `collection` corresponding to `key`.
64	///
65	/// When `key` is empty, we return the item metadata value.
66	///
67	/// By default this is `None`; no attributes are defined.
68	fn collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> Option<Vec<u8>> {
69		if key.is_empty() {
70			// We make the empty key map to the item metadata value.
71			CollectionMetadataOf::<T, I>::get(collection).map(|m| m.data.into())
72		} else {
73			let key = BoundedSlice::<_, _>::try_from(key).ok()?;
74			Attribute::<T, I>::get((collection, Option::<T::ItemId>::None, key)).map(|a| a.0.into())
75		}
76	}
77
78	/// Returns `true` if the `item` of `collection` may be transferred.
79	///
80	/// Default implementation is that all items are transferable.
81	fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool {
82		match (Collection::<T, I>::get(collection), Item::<T, I>::get(collection, item)) {
83			(Some(cd), Some(id)) if !cd.is_frozen && !id.is_frozen => true,
84			_ => false,
85		}
86	}
87}
88
89impl<T: Config<I>, I: 'static> Create<<T as SystemConfig>::AccountId> for Pallet<T, I> {
90	/// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`.
91	fn create_collection(
92		collection: &Self::CollectionId,
93		who: &T::AccountId,
94		admin: &T::AccountId,
95	) -> DispatchResult {
96		Self::do_create_collection(
97			collection.clone(),
98			who.clone(),
99			admin.clone(),
100			T::CollectionDeposit::get(),
101			false,
102			Event::Created {
103				collection: collection.clone(),
104				creator: who.clone(),
105				owner: admin.clone(),
106			},
107		)
108	}
109}
110
111impl<T: Config<I>, I: 'static> Destroy<<T as SystemConfig>::AccountId> for Pallet<T, I> {
112	type DestroyWitness = DestroyWitness;
113
114	fn get_destroy_witness(collection: &Self::CollectionId) -> Option<DestroyWitness> {
115		Collection::<T, I>::get(collection).map(|a| a.destroy_witness())
116	}
117
118	fn destroy(
119		collection: Self::CollectionId,
120		witness: Self::DestroyWitness,
121		maybe_check_owner: Option<T::AccountId>,
122	) -> Result<Self::DestroyWitness, DispatchError> {
123		Self::do_destroy_collection(collection, witness, maybe_check_owner)
124	}
125}
126
127impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId> for Pallet<T, I> {
128	fn mint_into(
129		collection: &Self::CollectionId,
130		item: &Self::ItemId,
131		who: &T::AccountId,
132	) -> DispatchResult {
133		Self::do_mint(collection.clone(), *item, who.clone(), |_| Ok(()))
134	}
135
136	fn burn(
137		collection: &Self::CollectionId,
138		item: &Self::ItemId,
139		maybe_check_owner: Option<&T::AccountId>,
140	) -> DispatchResult {
141		Self::do_burn(collection.clone(), *item, |_, d| {
142			if let Some(check_owner) = maybe_check_owner {
143				if &d.owner != check_owner {
144					return Err(Error::<T, I>::NoPermission.into())
145				}
146			}
147			Ok(())
148		})
149	}
150}
151
152impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
153	fn transfer(
154		collection: &Self::CollectionId,
155		item: &Self::ItemId,
156		destination: &T::AccountId,
157	) -> DispatchResult {
158		Self::do_transfer(collection.clone(), *item, destination.clone(), |_, _| Ok(()))
159	}
160}
161
162impl<T: Config<I>, I: 'static> InspectEnumerable<T::AccountId> for Pallet<T, I> {
163	type CollectionsIterator = KeyPrefixIterator<<T as Config<I>>::CollectionId>;
164	type ItemsIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
165	type OwnedIterator =
166		KeyPrefixIterator<(<T as Config<I>>::CollectionId, <T as Config<I>>::ItemId)>;
167	type OwnedInCollectionIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
168
169	/// Returns an iterator of the collections in existence.
170	///
171	/// NOTE: iterating this list invokes a storage read per item.
172	fn collections() -> Self::CollectionsIterator {
173		CollectionMetadataOf::<T, I>::iter_keys()
174	}
175
176	/// Returns an iterator of the items of a `collection` in existence.
177	///
178	/// NOTE: iterating this list invokes a storage read per item.
179	fn items(collection: &Self::CollectionId) -> Self::ItemsIterator {
180		ItemMetadataOf::<T, I>::iter_key_prefix(collection)
181	}
182
183	/// Returns an iterator of the items of all collections owned by `who`.
184	///
185	/// NOTE: iterating this list invokes a storage read per item.
186	fn owned(who: &T::AccountId) -> Self::OwnedIterator {
187		Account::<T, I>::iter_key_prefix((who,))
188	}
189
190	/// Returns an iterator of the items of `collection` owned by `who`.
191	///
192	/// NOTE: iterating this list invokes a storage read per item.
193	fn owned_in_collection(
194		collection: &Self::CollectionId,
195		who: &T::AccountId,
196	) -> Self::OwnedInCollectionIterator {
197		Account::<T, I>::iter_key_prefix((who, collection))
198	}
199}