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> Inspect<S> for MapId<Id, Op::Id, M, Op>
150where
151	M: Convert<Id, Result<Op::Id, DispatchError>>,
152	S: InspectStrategy,
153	Op: Inspect<S>,
154	Self::Id: Clone,
155{
156	fn inspect(id: &Self::Id, strategy: S) -> Result<S::Value, DispatchError> {
157		let id = M::convert(id.clone())?;
158
159		Op::inspect(&id, strategy)
160	}
161}
162impl<Id, M, S, Op> Update<S> for MapId<Id, Op::Id, M, Op>
163where
164	M: Convert<Id, Result<Op::Id, DispatchError>>,
165	S: UpdateStrategy,
166	Op: Update<S>,
167	Self::Id: Clone,
168{
169	fn update(
170		id: &Self::Id,
171		strategy: S,
172		update_value: S::UpdateValue<'_>,
173	) -> Result<S::Success, DispatchError> {
174		let id = M::convert(id.clone())?;
175
176		Op::update(&id, strategy, update_value)
177	}
178}
179impl<Id, M, S, Op> Destroy<S> for MapId<Id, Op::Id, M, Op>
180where
181	M: Convert<Id, Result<Op::Id, DispatchError>>,
182	S: DestroyStrategy,
183	Op: Destroy<S>,
184	Self::Id: Clone,
185{
186	fn destroy(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
187		let id = M::convert(id.clone())?;
188
189		Op::destroy(&id, strategy)
190	}
191}
192impl<Id, M, S, Op> Stash<S> for MapId<Id, Op::Id, M, Op>
193where
194	M: Convert<Id, Result<Op::Id, DispatchError>>,
195	S: StashStrategy,
196	Op: Stash<S>,
197	Self::Id: Clone,
198{
199	fn stash(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
200		let id = M::convert(id.clone())?;
201
202		Op::stash(&id, strategy)
203	}
204}
205impl<Id, M, S, Op> Restore<S> for MapId<Id, Op::Id, M, Op>
206where
207	M: Convert<Id, Result<Op::Id, DispatchError>>,
208	S: RestoreStrategy,
209	Op: Restore<S>,
210	Self::Id: Clone,
211{
212	fn restore(id: &Self::Id, strategy: S) -> Result<S::Success, DispatchError> {
213		let id = M::convert(id.clone())?;
214
215		Op::restore(&id, strategy)
216	}
217}
218
219/// The `CombinedAssetOps` is a tool for combining
220/// different implementations of `Restore`, `Update`, and `Stash` operations.
221///
222/// All three operations must use the same `AssetDefinition::Id`.
223pub struct CombinedAssetOps<RestoreOp, UpdateOp, StashOp>(
224	PhantomData<(RestoreOp, UpdateOp, StashOp)>,
225);
226impl<RestoreOp, UpdateOp, StashOp> AssetDefinition
227	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
228where
229	RestoreOp: AssetDefinition,
230	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
231	StashOp: AssetDefinition<Id = RestoreOp::Id>,
232{
233	type Id = RestoreOp::Id;
234}
235impl<Strategy, RestoreOp, UpdateOp, StashOp> Restore<Strategy>
236	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
237where
238	Strategy: RestoreStrategy,
239	RestoreOp: Restore<Strategy>,
240	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
241	StashOp: AssetDefinition<Id = RestoreOp::Id>,
242{
243	fn restore(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError> {
244		RestoreOp::restore(id, strategy)
245	}
246}
247impl<Strategy, RestoreOp, UpdateOp, StashOp> Update<Strategy>
248	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
249where
250	Strategy: UpdateStrategy,
251	UpdateOp: Update<Strategy>,
252	RestoreOp: AssetDefinition,
253	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
254	StashOp: AssetDefinition<Id = RestoreOp::Id>,
255{
256	fn update(
257		id: &Self::Id,
258		strategy: Strategy,
259		update: Strategy::UpdateValue<'_>,
260	) -> Result<Strategy::Success, DispatchError> {
261		UpdateOp::update(id, strategy, update)
262	}
263}
264impl<Strategy, RestoreOp, UpdateOp, StashOp> Stash<Strategy>
265	for CombinedAssetOps<RestoreOp, UpdateOp, StashOp>
266where
267	Strategy: StashStrategy,
268	StashOp: Stash<Strategy>,
269	RestoreOp: AssetDefinition,
270	UpdateOp: AssetDefinition<Id = RestoreOp::Id>,
271	StashOp: AssetDefinition<Id = RestoreOp::Id>,
272{
273	fn stash(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError> {
274		StashOp::stash(id, strategy)
275	}
276}
277
278/// The `StashAccountAssetOps` adds the `Stash` and `Restore` implementations to an NFT
279/// engine capable of transferring a token from one account to another (i.e. implementing
280/// `Update<ChangeOwnerFrom<AccountId>>`).
281///
282/// On stash, it will transfer the token from the current owner to the `StashAccount`.
283/// On restore, it will transfer the token from the `StashAccount` to the given beneficiary.
284pub struct StashAccountAssetOps<StashAccount, UpdateOp>(PhantomData<(StashAccount, UpdateOp)>);
285impl<StashAccount, UpdateOp: AssetDefinition> AssetDefinition
286	for StashAccountAssetOps<StashAccount, UpdateOp>
287{
288	type Id = UpdateOp::Id;
289}
290impl<StashAccount: TypedGet, UpdateOp> Update<ChangeOwnerFrom<StashAccount::Type>>
291	for StashAccountAssetOps<StashAccount, UpdateOp>
292where
293	StashAccount::Type: 'static,
294	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
295{
296	fn update(
297		id: &Self::Id,
298		strategy: ChangeOwnerFrom<StashAccount::Type>,
299		update: &StashAccount::Type,
300	) -> DispatchResult {
301		UpdateOp::update(id, strategy, update)
302	}
303}
304impl<StashAccount, UpdateOp> Restore<WithConfig<ConfigValue<Owner<StashAccount::Type>>>>
305	for StashAccountAssetOps<StashAccount, UpdateOp>
306where
307	StashAccount: TypedGet,
308	StashAccount::Type: 'static,
309	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
310{
311	fn restore(
312		id: &Self::Id,
313		strategy: WithConfig<ConfigValue<Owner<StashAccount::Type>>>,
314	) -> DispatchResult {
315		let WithConfig { config: ConfigValue(beneficiary), .. } = strategy;
316
317		UpdateOp::update(id, ChangeOwnerFrom::check(StashAccount::get()), &beneficiary)
318	}
319}
320impl<StashAccount, UpdateOp> Stash<IfOwnedBy<StashAccount::Type>>
321	for StashAccountAssetOps<StashAccount, UpdateOp>
322where
323	StashAccount: TypedGet,
324	StashAccount::Type: 'static,
325	UpdateOp: Update<ChangeOwnerFrom<StashAccount::Type>>,
326{
327	fn stash(id: &Self::Id, strategy: IfOwnedBy<StashAccount::Type>) -> DispatchResult {
328		let CheckState(check_owner, ..) = strategy;
329
330		UpdateOp::update(id, ChangeOwnerFrom::check(check_owner), &StashAccount::get())
331	}
332}
333
334/// Unique instance operations that always fail.
335///
336/// Intended to be used to forbid certain actions.
337pub struct DisabledOps<Id>(PhantomData<Id>);
338impl<Id> AssetDefinition for DisabledOps<Id> {
339	type Id = Id;
340}
341impl<Id, S: CreateStrategy> Create<S> for DisabledOps<Id> {
342	fn create(_strategy: S) -> Result<S::Success, DispatchError> {
343		Err(DispatchError::Other("Disabled"))
344	}
345}
346impl<Id, S: DestroyStrategy> Destroy<S> for DisabledOps<Id> {
347	fn destroy(_id: &Self::Id, _strategy: S) -> Result<S::Success, DispatchError> {
348		Err(DispatchError::Other("Disabled"))
349	}
350}