referrerpolicy=no-referrer-when-downgrade

pallet_uniques/asset_ops/
collection.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
18use core::marker::PhantomData;
19
20use crate::{
21	asset_strategies::{Attribute, WithCollectionConfig},
22	Collection as CollectionStorage, *,
23};
24use frame_support::{
25	ensure,
26	traits::{
27		tokens::asset_ops::{
28			common_strategies::{
29				Bytes, CheckOrigin, CheckState, ConfigValue, IfOwnedBy, Owner, WithConfig,
30				WithWitness,
31			},
32			AssetDefinition, Create, Destroy, Inspect,
33		},
34		EnsureOrigin, Get,
35	},
36	BoundedSlice,
37};
38use frame_system::ensure_signed;
39use sp_runtime::{DispatchError, DispatchResult};
40
41pub struct Collection<PalletInstance>(PhantomData<PalletInstance>);
42
43impl<T: Config<I>, I: 'static> AssetDefinition for Collection<Pallet<T, I>> {
44	type Id = T::CollectionId;
45}
46
47impl<T: Config<I>, I: 'static> Inspect<Owner<T::AccountId>> for Collection<Pallet<T, I>> {
48	fn inspect(
49		collection: &Self::Id,
50		_ownership: Owner<T::AccountId>,
51	) -> Result<T::AccountId, DispatchError> {
52		CollectionStorage::<T, I>::get(collection)
53			.map(|a| a.owner)
54			.ok_or(Error::<T, I>::UnknownCollection.into())
55	}
56}
57
58impl<T: Config<I>, I: 'static> Inspect<Bytes> for Collection<Pallet<T, I>> {
59	fn inspect(collection: &Self::Id, _bytes: Bytes) -> Result<Vec<u8>, DispatchError> {
60		CollectionMetadataOf::<T, I>::get(collection)
61			.map(|m| m.data.into())
62			.ok_or(Error::<T, I>::NoMetadata.into())
63	}
64}
65
66impl<'a, T: Config<I>, I: 'static> Inspect<Bytes<Attribute<'a>>> for Collection<Pallet<T, I>> {
67	fn inspect(
68		collection: &Self::Id,
69		strategy: Bytes<Attribute>,
70	) -> Result<Vec<u8>, DispatchError> {
71		let Bytes(Attribute(attribute)) = strategy;
72
73		let attribute =
74			BoundedSlice::try_from(attribute).map_err(|_| Error::<T, I>::WrongAttribute)?;
75		crate::Attribute::<T, I>::get((collection, Option::<T::ItemId>::None, attribute))
76			.map(|a| a.0.into())
77			.ok_or(Error::<T, I>::AttributeNotFound.into())
78	}
79}
80
81impl<T: Config<I>, I: 'static> Create<WithCollectionConfig<T, I>> for Collection<Pallet<T, I>> {
82	fn create(strategy: WithCollectionConfig<T, I>) -> Result<T::CollectionId, DispatchError> {
83		let WithConfig { config, extra: id_assignment } = strategy;
84		let collection = id_assignment.params;
85		let (ConfigValue(owner), ConfigValue(admin)) = config;
86
87		<Pallet<T, I>>::do_create_collection(
88			collection.clone(),
89			owner.clone(),
90			admin.clone(),
91			T::CollectionDeposit::get(),
92			false,
93			Event::Created { collection: collection.clone(), creator: owner, owner: admin },
94		)?;
95
96		Ok(collection)
97	}
98}
99
100impl<T: Config<I>, I: 'static> Create<CheckOrigin<T::RuntimeOrigin, WithCollectionConfig<T, I>>>
101	for Collection<Pallet<T, I>>
102{
103	fn create(
104		strategy: CheckOrigin<T::RuntimeOrigin, WithCollectionConfig<T, I>>,
105	) -> Result<T::CollectionId, DispatchError> {
106		let CheckOrigin(origin, creation) = strategy;
107
108		let WithConfig { config, extra: id_assignment } = &creation;
109		let collection = &id_assignment.params;
110		let (ConfigValue(owner), ..) = config;
111
112		let maybe_check_signer =
113			T::ForceOrigin::try_origin(origin).map(|_| None).or_else(|origin| {
114				T::CreateOrigin::ensure_origin(origin, collection)
115					.map(Some)
116					.map_err(DispatchError::from)
117			})?;
118
119		if let Some(signer) = maybe_check_signer {
120			ensure!(signer == *owner, Error::<T, I>::NoPermission);
121		}
122
123		Self::create(creation)
124	}
125}
126
127impl<T: Config<I>, I: 'static> Destroy<WithWitness<DestroyWitness>> for Collection<Pallet<T, I>> {
128	fn destroy(collection: &Self::Id, strategy: WithWitness<DestroyWitness>) -> DispatchResult {
129		let CheckState(witness, _) = strategy;
130
131		<Pallet<T, I>>::do_destroy_collection(collection.clone(), witness, None).map(|_witness| ())
132	}
133}
134
135impl<T: Config<I>, I: 'static> Destroy<IfOwnedBy<T::AccountId, WithWitness<DestroyWitness>>>
136	for Collection<Pallet<T, I>>
137{
138	fn destroy(
139		collection: &Self::Id,
140		strategy: IfOwnedBy<T::AccountId, WithWitness<DestroyWitness>>,
141	) -> DispatchResult {
142		let CheckState(owner, CheckState(witness, _)) = strategy;
143
144		<Pallet<T, I>>::do_destroy_collection(collection.clone(), witness, Some(owner))
145			.map(|_witness| ())
146	}
147}
148
149impl<T: Config<I>, I: 'static> Destroy<CheckOrigin<T::RuntimeOrigin, WithWitness<DestroyWitness>>>
150	for Collection<Pallet<T, I>>
151{
152	fn destroy(
153		collection: &Self::Id,
154		strategy: CheckOrigin<T::RuntimeOrigin, WithWitness<DestroyWitness>>,
155	) -> DispatchResult {
156		let CheckOrigin(origin, CheckState(witness, _)) = strategy;
157
158		let maybe_check_owner = match T::ForceOrigin::try_origin(origin) {
159			Ok(_) => None,
160			Err(origin) => Some(ensure_signed(origin)?),
161		};
162
163		<Pallet<T, I>>::do_destroy_collection(collection.clone(), witness, maybe_check_owner)
164			.map(|_witness| ())
165	}
166}