referrerpolicy=no-referrer-when-downgrade

frame_support/traits/tokens/asset_ops/
common_ops.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 super::{common_strategies::*, *};
19use crate::{
20	dispatch::DispatchResult,
21	sp_runtime::traits::Convert,
22	traits::{misc::TypedGet, EnsureOriginWithArg},
23};
24
25/// The `UseEnsuredOrigin` is an adapter that implements all the asset ops implemented by the `Op`
26/// with strategies augmented by the [CheckOrigin].
27/// The Origin will be checked according to the provided `EnsureOrigin`.
28pub struct UseEnsuredOrigin<EnsureOrigin, Op>(PhantomData<(EnsureOrigin, Op)>);
29impl<O, E, S, Op> Create<CheckOrigin<O, S>> for UseEnsuredOrigin<E, Op>
30where
31	E: EnsureOriginWithArg<O, S>,
32	S: CreateStrategy,
33	Op: Create<S>,
34{
35	fn create(strategy: CheckOrigin<O, S>) -> Result<S::Success, DispatchError> {
36		let CheckOrigin(origin, inner) = strategy;
37
38		E::ensure_origin(origin, &inner)?;
39
40		Op::create(inner)
41	}
42}
43impl<E, Op: AssetDefinition> AssetDefinition for UseEnsuredOrigin<E, Op> {
44	type Id = Op::Id;
45}
46impl<O, E, S, Op> Update<CheckOrigin<O, S>> for UseEnsuredOrigin<E, Op>
47where
48	E: EnsureOriginWithArg<O, S>,
49	S: UpdateStrategy,
50	Op: Update<S>,
51{
52	fn update(
53		id: &Self::Id,
54		strategy: CheckOrigin<O, S>,
55		update_value: S::UpdateValue<'_>,
56	) -> Result<S::Success, DispatchError> {
57		let CheckOrigin(origin, inner) = strategy;
58
59		E::ensure_origin(origin, &inner)?;
60
61		Op::update(id, inner, update_value)
62	}
63}
64impl<O, E, S, Op> Destroy<CheckOrigin<O, S>> for UseEnsuredOrigin<E, Op>
65where
66	E: EnsureOriginWithArg<O, S>,
67	S: DestroyStrategy,
68	Op: Destroy<S>,
69{
70	fn destroy(id: &Self::Id, strategy: CheckOrigin<O, S>) -> Result<S::Success, DispatchError> {
71		let CheckOrigin(origin, inner) = strategy;
72
73		E::ensure_origin(origin, &inner)?;
74
75		Op::destroy(id, inner)
76	}
77}
78impl<O, E, S, Op> Stash<CheckOrigin<O, S>> for UseEnsuredOrigin<E, Op>
79where
80	E: EnsureOriginWithArg<O, S>,
81	S: StashStrategy,
82	Op: Stash<S>,
83{
84	fn stash(id: &Self::Id, strategy: CheckOrigin<O, S>) -> Result<S::Success, DispatchError> {
85		let CheckOrigin(origin, inner) = strategy;
86
87		E::ensure_origin(origin, &inner)?;
88
89		Op::stash(id, inner)
90	}
91}
92impl<O, E, S, Op> Restore<CheckOrigin<O, S>> for UseEnsuredOrigin<E, Op>
93where
94	E: EnsureOriginWithArg<O, S>,
95	S: RestoreStrategy,
96	Op: Restore<S>,
97{
98	fn restore(id: &Self::Id, strategy: CheckOrigin<O, S>) -> Result<S::Success, DispatchError> {
99		let CheckOrigin(origin, inner) = strategy;
100
101		E::ensure_origin(origin, &inner)?;
102
103		Op::restore(id, inner)
104	}
105}
106
107/// The `MapId` is an adapter that implements all the asset ops implemented by the `Op`.
108/// The adapter allows `IdA` to be used instead of `IdB` for every `Op` operation that uses `IdB` as
109/// instance ID. The `IdA` value will be converted to `IdB` by the mapper `M` and supplied to the
110/// `Op`'s corresponding operation implementation.
111pub struct MapId<IdA, IdB, M, Op>(PhantomData<(IdA, IdB, M, Op)>);
112impl<IdA, IdB, ReportedId, M, CreateOp> Create<DeriveAndReportId<IdA, ReportedId>>
113	for MapId<IdA, IdB, M, CreateOp>
114where
115	M: Convert<IdA, Result<IdB, DispatchError>>,
116	CreateOp: Create<DeriveAndReportId<IdB, ReportedId>>,
117{
118	fn create(
119		id_assignment: DeriveAndReportId<IdA, ReportedId>,
120	) -> Result<ReportedId, DispatchError> {
121		let id_a = id_assignment.params;
122		let id_b = M::convert(id_a)?;
123
124		CreateOp::create(DeriveAndReportId::from(id_b))
125	}
126}
127impl<Config, IdA, IdB, ReportedId, M, CreateOp>
128	Create<WithConfig<Config, DeriveAndReportId<IdA, ReportedId>>> for MapId<IdA, IdB, M, CreateOp>
129where
130	Config: ConfigValueMarker,
131	M: Convert<IdA, Result<IdB, DispatchError>>,
132	CreateOp: Create<WithConfig<Config, DeriveAndReportId<IdB, ReportedId>>>,
133{
134	fn create(
135		strategy: WithConfig<Config, DeriveAndReportId<IdA, ReportedId>>,
136	) -> Result<ReportedId, DispatchError> {
137		let WithConfig { config, extra: id_assignment } = strategy;
138		let id_a = id_assignment.params;
139		let id_b = M::convert(id_a)?;
140
141		CreateOp::create(WithConfig::new(config, DeriveAndReportId::from(id_b)))
142	}
143}
144impl<Id, M: Convert<Id, Result<Op::Id, DispatchError>>, Op: AssetDefinition> AssetDefinition
145	for MapId<Id, Op::Id, M, Op>
146{
147	type Id = Id;
148}
149impl<Id, M, S, Op> Update<S> for MapId<Id, Op::Id, M, Op>
150where
151	M: Convert<Id, Result<Op::Id, DispatchError>>,
152	S: UpdateStrategy,
153	Op: Update<S>,
154	Self::Id: Clone,
155{
156	fn update(
157		id: &Self::Id,
158		strategy: S,
159		update_value: S::UpdateValue<'_>,
160	) -> Result<S::Success, DispatchError> {
161		let id = M::convert(id.clone())?;
162
163		Op::update(&id, strategy, update_value)
164	}
165}
166impl<Id, M, S, Op> Destroy<S> for MapId<Id, Op::Id, M, Op>
167where
168	M: Convert<Id, Result<Op::Id, DispatchError>>,
169	S: DestroyStrategy,
170	Op: Destroy<S>,
171	Self::Id: Clone,
172{
173	fn destroy(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
174		let id = M::convert(id.clone())?;
175
176		Op::destroy(&id, strategy)
177	}
178}
179impl<Id, M, S, Op> Stash<S> for MapId<Id, Op::Id, M, Op>
180where
181	M: Convert<Id, Result<Op::Id, DispatchError>>,
182	S: StashStrategy,
183	Op: Stash<S>,
184	Self::Id: Clone,
185{
186	fn stash(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
187		let id = M::convert(id.clone())?;
188
189		Op::stash(&id, strategy)
190	}
191}
192impl<Id, M, S, Op> Restore<S> for MapId<Id, Op::Id, M, Op>
193where
194	M: Convert<Id, Result<Op::Id, DispatchError>>,
195	S: RestoreStrategy,
196	Op: Restore<S>,
197	Self::Id: Clone,
198{
199	fn restore(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
200		let id = M::convert(id.clone())?;
201
202		Op::restore(&id, strategy)
203	}
204}
205
206/// The `CombinedAssetOps` is a tool for combining
207/// different implementations of `Restore`, `Update`, and `Stash` operations.
208///
209/// All three operations must use the same `AssetDefinition::Id`.
210pub struct CombinedAssetOps<RestoreOp, UpdateOp, StashOp>(
211	PhantomData<(RestoreOp, UpdateOp, StashOp)>,
212);
213impl<RestoreOp, UpdateOp, StashOp> AssetDefinition
214	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
215where
216	RestoreOp: AssetDefinition,
217	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
218	StashOp: AssetDefinition<Id = RestoreOp::Id>,
219{
220	type Id = RestoreOp::Id;
221}
222impl<Strategy, RestoreOp, UpdateOp, StashOp> Restore<Strategy>
223	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
224where
225	Strategy: RestoreStrategy,
226	RestoreOp: Restore<Strategy>,
227	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
228	StashOp: AssetDefinition<Id = RestoreOp::Id>,
229{
230	fn restore(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError> {
231		RestoreOp::restore(id, strategy)
232	}
233}
234impl<Strategy, RestoreOp, UpdateOp, StashOp> Update<Strategy>
235	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
236where
237	Strategy: UpdateStrategy,
238	UpdateOp: Update<Strategy>,
239	RestoreOp: AssetDefinition,
240	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
241	StashOp: AssetDefinition<Id = RestoreOp::Id>,
242{
243	fn update(
244		id: &Self::Id,
245		strategy: Strategy,
246		update: Strategy::UpdateValue<'_>,
247	) -> Result<Strategy::Success, DispatchError> {
248		UpdateOp::update(id, strategy, update)
249	}
250}
251impl<Strategy, RestoreOp, UpdateOp, StashOp> Stash<Strategy>
252	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
253where
254	Strategy: StashStrategy,
255	StashOp: Stash<Strategy>,
256	RestoreOp: AssetDefinition,
257	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
258	StashOp: AssetDefinition<Id = RestoreOp::Id>,
259{
260	fn stash(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError> {
261		StashOp::stash(id, strategy)
262	}
263}
264
265/// The `StashAccountAssetOps` adds the `Stash` and `Restore` implementations to an NFT
266/// engine capable of transferring a token from one account to another (i.e. implementing
267/// `Update<ChangeOwnerFrom<AccountId>>`).
268///
269/// On stash, it will transfer the token from the current owner to the `StashAccount`.
270/// On restore, it will transfer the token from the `StashAccount` to the given beneficiary.
271pub struct StashAccountAssetOps<StashAccount, UpdateOp>(PhantomData<(StashAccount, UpdateOp)>);
272impl<StashAccount, UpdateOp: AssetDefinition> AssetDefinition
273	for StashAccountAssetOps<StashAccount, UpdateOp>
274{
275	type Id = UpdateOp::Id;
276}
277impl<StashAccount: TypedGet, UpdateOp> Update<ChangeOwnerFrom<StashAccount::Type>>
278	for StashAccountAssetOps<StashAccount, UpdateOp>
279where
280	StashAccount::Type: 'static,
281	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
282{
283	fn update(
284		id: &Self::Id,
285		strategy: ChangeOwnerFrom<StashAccount::Type>,
286		update: &StashAccount::Type,
287	) -> DispatchResult {
288		UpdateOp::update(id, strategy, update)
289	}
290}
291impl<StashAccount, UpdateOp> Restore<WithConfig<ConfigValue<Owner<StashAccount::Type>>>>
292	for StashAccountAssetOps<StashAccount, UpdateOp>
293where
294	StashAccount: TypedGet,
295	StashAccount::Type: 'static,
296	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
297{
298	fn restore(
299		id: &Self::Id,
300		strategy: WithConfig<ConfigValue<Owner<StashAccount::Type>>>,
301	) -> DispatchResult {
302		let WithConfig { config: ConfigValue(beneficiary), .. } = strategy;
303
304		UpdateOp::update(id, ChangeOwnerFrom::check(StashAccount::get()), &beneficiary)
305	}
306}
307impl<StashAccount, UpdateOp> Stash<IfOwnedBy<StashAccount::Type>>
308	for StashAccountAssetOps<StashAccount, UpdateOp>
309where
310	StashAccount: TypedGet,
311	StashAccount::Type: 'static,
312	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
313{
314	fn stash(id: &Self::Id, strategy: IfOwnedBy<StashAccount::Type>) -> DispatchResult {
315		let CheckState(check_owner, ..) = strategy;
316
317		UpdateOp::update(id, ChangeOwnerFrom::check(check_owner), &StashAccount::get())
318	}
319}
320
321/// Unique instance operations that always fail.
322///
323/// Intended to be used to forbid certain actions.
324pub struct DisabledOps<Id>(PhantomData<Id>);
325impl<Id> AssetDefinition for DisabledOps<Id> {
326	type Id = Id;
327}
328impl<Id, S: CreateStrategy> Create<S> for DisabledOps<Id> {
329	fn create(_strategy: S) -> Result<S::Success, DispatchError> {
330		Err(DispatchError::Other("Disabled"))
331	}
332}
333impl<Id, S: DestroyStrategy> Destroy<S> for DisabledOps<Id> {
334	fn destroy(_id: &Self::Id, _strategy: S) -> Result<S::Success, DispatchError> {
335		Err(DispatchError::Other("Disabled"))
336	}
337}