referrerpolicy=no-referrer-when-downgrade

frame_support/traits/tokens/fungibles/
union_of.rs

1// This file is part of Substrate.
2
3// Copyright (Criterion) 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//! Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation.
19//!
20//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
21
22use frame_support::traits::{
23	tokens::{
24		fungibles, fungibles::imbalance, AssetId, DepositConsequence, Fortitude, Precision,
25		Preservation, Provenance, Restriction, WithdrawConsequence,
26	},
27	AccountTouch,
28};
29use sp_runtime::{
30	traits::Convert,
31	DispatchError, DispatchResult, Either,
32	Either::{Left, Right},
33};
34
35/// Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation.
36///
37/// ### Parameters:
38/// - `Left` is `fungibles::*` implementation that is incorporated into the resulting union.
39/// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union.
40/// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set.
41/// - `AssetKind` is a superset type encompassing asset kinds from `Left` and `Right` sets.
42/// - `AccountId` is an account identifier type.
43pub struct UnionOf<Left, Right, Criterion, AssetKind, AccountId>(
44	core::marker::PhantomData<(Left, Right, Criterion, AssetKind, AccountId)>,
45);
46
47impl<
48		Left: fungibles::Inspect<AccountId>,
49		Right: fungibles::Inspect<AccountId, Balance = Left::Balance>,
50		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
51		AssetKind: AssetId,
52		AccountId,
53	> fungibles::Inspect<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
54{
55	type AssetId = AssetKind;
56	type Balance = Left::Balance;
57
58	fn total_issuance(asset: Self::AssetId) -> Self::Balance {
59		match Criterion::convert(asset) {
60			Left(a) => <Left as fungibles::Inspect<AccountId>>::total_issuance(a),
61			Right(a) => <Right as fungibles::Inspect<AccountId>>::total_issuance(a),
62		}
63	}
64	fn active_issuance(asset: Self::AssetId) -> Self::Balance {
65		match Criterion::convert(asset) {
66			Left(a) => <Left as fungibles::Inspect<AccountId>>::active_issuance(a),
67			Right(a) => <Right as fungibles::Inspect<AccountId>>::active_issuance(a),
68		}
69	}
70	fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
71		match Criterion::convert(asset) {
72			Left(a) => <Left as fungibles::Inspect<AccountId>>::minimum_balance(a),
73			Right(a) => <Right as fungibles::Inspect<AccountId>>::minimum_balance(a),
74		}
75	}
76	fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
77		match Criterion::convert(asset) {
78			Left(a) => <Left as fungibles::Inspect<AccountId>>::balance(a, who),
79			Right(a) => <Right as fungibles::Inspect<AccountId>>::balance(a, who),
80		}
81	}
82	fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
83		match Criterion::convert(asset) {
84			Left(a) => <Left as fungibles::Inspect<AccountId>>::total_balance(a, who),
85			Right(a) => <Right as fungibles::Inspect<AccountId>>::total_balance(a, who),
86		}
87	}
88	fn reducible_balance(
89		asset: Self::AssetId,
90		who: &AccountId,
91		preservation: Preservation,
92		force: Fortitude,
93	) -> Self::Balance {
94		match Criterion::convert(asset) {
95			Left(a) => <Left as fungibles::Inspect<AccountId>>::reducible_balance(
96				a,
97				who,
98				preservation,
99				force,
100			),
101			Right(a) => <Right as fungibles::Inspect<AccountId>>::reducible_balance(
102				a,
103				who,
104				preservation,
105				force,
106			),
107		}
108	}
109	fn can_deposit(
110		asset: Self::AssetId,
111		who: &AccountId,
112		amount: Self::Balance,
113		provenance: Provenance,
114	) -> DepositConsequence {
115		match Criterion::convert(asset) {
116			Left(a) => {
117				<Left as fungibles::Inspect<AccountId>>::can_deposit(a, who, amount, provenance)
118			},
119			Right(a) => {
120				<Right as fungibles::Inspect<AccountId>>::can_deposit(a, who, amount, provenance)
121			},
122		}
123	}
124	fn can_withdraw(
125		asset: Self::AssetId,
126		who: &AccountId,
127		amount: Self::Balance,
128	) -> WithdrawConsequence<Self::Balance> {
129		match Criterion::convert(asset) {
130			Left(a) => <Left as fungibles::Inspect<AccountId>>::can_withdraw(a, who, amount),
131			Right(a) => <Right as fungibles::Inspect<AccountId>>::can_withdraw(a, who, amount),
132		}
133	}
134	fn asset_exists(asset: Self::AssetId) -> bool {
135		match Criterion::convert(asset) {
136			Left(a) => <Left as fungibles::Inspect<AccountId>>::asset_exists(a),
137			Right(a) => <Right as fungibles::Inspect<AccountId>>::asset_exists(a),
138		}
139	}
140	fn is_sufficient(asset: Self::AssetId) -> bool {
141		match Criterion::convert(asset) {
142			Left(a) => <Left as fungibles::Inspect<AccountId>>::is_sufficient(a),
143			Right(a) => <Right as fungibles::Inspect<AccountId>>::is_sufficient(a),
144		}
145	}
146}
147
148impl<
149		Left: fungibles::Inspect<AccountId> + fungibles::metadata::Inspect<AccountId>,
150		Right: fungibles::Inspect<AccountId, Balance = Left::Balance>
151			+ fungibles::metadata::Inspect<AccountId>,
152		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
153		AssetKind: AssetId,
154		AccountId,
155	> fungibles::metadata::Inspect<AccountId>
156	for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
157{
158	fn name(asset: Self::AssetId) -> alloc::vec::Vec<u8> {
159		match Criterion::convert(asset) {
160			Left(a) => <Left as fungibles::metadata::Inspect<AccountId>>::name(a),
161			Right(a) => <Right as fungibles::metadata::Inspect<AccountId>>::name(a),
162		}
163	}
164	fn symbol(asset: Self::AssetId) -> alloc::vec::Vec<u8> {
165		match Criterion::convert(asset) {
166			Left(a) => <Left as fungibles::metadata::Inspect<AccountId>>::symbol(a),
167			Right(a) => <Right as fungibles::metadata::Inspect<AccountId>>::symbol(a),
168		}
169	}
170	fn decimals(asset: Self::AssetId) -> u8 {
171		match Criterion::convert(asset) {
172			Left(a) => <Left as fungibles::metadata::Inspect<AccountId>>::decimals(a),
173			Right(a) => <Right as fungibles::metadata::Inspect<AccountId>>::decimals(a),
174		}
175	}
176}
177
178impl<
179		Left: fungibles::Inspect<AccountId> + fungibles::roles::Inspect<AccountId>,
180		Right: fungibles::Inspect<AccountId, Balance = Left::Balance>
181			+ fungibles::roles::Inspect<AccountId>,
182		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
183		AssetKind: AssetId,
184		AccountId,
185	> fungibles::roles::Inspect<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
186{
187	fn owner(asset: Self::AssetId) -> Option<AccountId> {
188		match Criterion::convert(asset) {
189			Left(a) => <Left as fungibles::roles::Inspect<AccountId>>::owner(a),
190			Right(a) => <Right as fungibles::roles::Inspect<AccountId>>::owner(a),
191		}
192	}
193	fn issuer(asset: Self::AssetId) -> Option<AccountId> {
194		match Criterion::convert(asset) {
195			Left(a) => <Left as fungibles::roles::Inspect<AccountId>>::issuer(a),
196			Right(a) => <Right as fungibles::roles::Inspect<AccountId>>::issuer(a),
197		}
198	}
199	fn admin(asset: Self::AssetId) -> Option<AccountId> {
200		match Criterion::convert(asset) {
201			Left(a) => <Left as fungibles::roles::Inspect<AccountId>>::admin(a),
202			Right(a) => <Right as fungibles::roles::Inspect<AccountId>>::admin(a),
203		}
204	}
205	fn freezer(asset: Self::AssetId) -> Option<AccountId> {
206		match Criterion::convert(asset) {
207			Left(a) => <Left as fungibles::roles::Inspect<AccountId>>::freezer(a),
208			Right(a) => <Right as fungibles::roles::Inspect<AccountId>>::freezer(a),
209		}
210	}
211}
212
213impl<
214		Left: fungibles::Inspect<AccountId>
215			+ fungibles::metadata::Inspect<AccountId>
216			+ fungibles::metadata::Mutate<AccountId>,
217		Right: fungibles::Inspect<AccountId, Balance = Left::Balance>
218			+ fungibles::metadata::Inspect<AccountId>
219			+ fungibles::metadata::Mutate<AccountId>,
220		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
221		AssetKind: AssetId,
222		AccountId,
223	> fungibles::metadata::Mutate<AccountId>
224	for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
225{
226	fn set(
227		asset: Self::AssetId,
228		from: &AccountId,
229		name: alloc::vec::Vec<u8>,
230		symbol: alloc::vec::Vec<u8>,
231		decimals: u8,
232	) -> DispatchResult {
233		match Criterion::convert(asset) {
234			Left(a) => <Left as fungibles::metadata::Mutate<AccountId>>::set(
235				a, from, name, symbol, decimals,
236			),
237			Right(a) => <Right as fungibles::metadata::Mutate<AccountId>>::set(
238				a, from, name, symbol, decimals,
239			),
240		}
241	}
242}
243
244impl<
245		Left: fungibles::InspectHold<AccountId>,
246		Right: fungibles::InspectHold<AccountId, Balance = Left::Balance, Reason = Left::Reason>,
247		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
248		AssetKind: AssetId,
249		AccountId,
250	> fungibles::InspectHold<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
251{
252	type Reason = Left::Reason;
253
254	fn reducible_total_balance_on_hold(
255		asset: Self::AssetId,
256		who: &AccountId,
257		force: Fortitude,
258	) -> Self::Balance {
259		match Criterion::convert(asset) {
260			Left(a) => {
261				<Left as fungibles::InspectHold<AccountId>>::reducible_total_balance_on_hold(
262					a, who, force,
263				)
264			},
265			Right(a) => {
266				<Right as fungibles::InspectHold<AccountId>>::reducible_total_balance_on_hold(
267					a, who, force,
268				)
269			},
270		}
271	}
272	fn hold_available(asset: Self::AssetId, reason: &Self::Reason, who: &AccountId) -> bool {
273		match Criterion::convert(asset) {
274			Left(a) => <Left as fungibles::InspectHold<AccountId>>::hold_available(a, reason, who),
275			Right(a) => {
276				<Right as fungibles::InspectHold<AccountId>>::hold_available(a, reason, who)
277			},
278		}
279	}
280	fn total_balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
281		match Criterion::convert(asset) {
282			Left(a) => <Left as fungibles::InspectHold<AccountId>>::total_balance_on_hold(a, who),
283			Right(a) => <Right as fungibles::InspectHold<AccountId>>::total_balance_on_hold(a, who),
284		}
285	}
286	fn balance_on_hold(
287		asset: Self::AssetId,
288		reason: &Self::Reason,
289		who: &AccountId,
290	) -> Self::Balance {
291		match Criterion::convert(asset) {
292			Left(a) => <Left as fungibles::InspectHold<AccountId>>::balance_on_hold(a, reason, who),
293			Right(a) => {
294				<Right as fungibles::InspectHold<AccountId>>::balance_on_hold(a, reason, who)
295			},
296		}
297	}
298	fn can_hold(
299		asset: Self::AssetId,
300		reason: &Self::Reason,
301		who: &AccountId,
302		amount: Self::Balance,
303	) -> bool {
304		match Criterion::convert(asset) {
305			Left(a) => {
306				<Left as fungibles::InspectHold<AccountId>>::can_hold(a, reason, who, amount)
307			},
308			Right(a) => {
309				<Right as fungibles::InspectHold<AccountId>>::can_hold(a, reason, who, amount)
310			},
311		}
312	}
313}
314
315impl<
316		Left: fungibles::InspectFreeze<AccountId>,
317		Right: fungibles::InspectFreeze<AccountId, Balance = Left::Balance, Id = Left::Id>,
318		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
319		AssetKind: AssetId,
320		AccountId,
321	> fungibles::InspectFreeze<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
322{
323	type Id = Left::Id;
324	fn balance_frozen(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> Self::Balance {
325		match Criterion::convert(asset) {
326			Left(a) => <Left as fungibles::InspectFreeze<AccountId>>::balance_frozen(a, id, who),
327			Right(a) => <Right as fungibles::InspectFreeze<AccountId>>::balance_frozen(a, id, who),
328		}
329	}
330	fn balance_freezable(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
331		match Criterion::convert(asset) {
332			Left(a) => <Left as fungibles::InspectFreeze<AccountId>>::balance_freezable(a, who),
333			Right(a) => <Right as fungibles::InspectFreeze<AccountId>>::balance_freezable(a, who),
334		}
335	}
336	fn can_freeze(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> bool {
337		match Criterion::convert(asset) {
338			Left(a) => <Left as fungibles::InspectFreeze<AccountId>>::can_freeze(a, id, who),
339			Right(a) => <Right as fungibles::InspectFreeze<AccountId>>::can_freeze(a, id, who),
340		}
341	}
342}
343
344impl<
345		Left: fungibles::Unbalanced<AccountId>,
346		Right: fungibles::Unbalanced<AccountId, Balance = Left::Balance>,
347		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
348		AssetKind: AssetId,
349		AccountId,
350	> fungibles::Unbalanced<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
351{
352	fn handle_dust(dust: fungibles::Dust<AccountId, Self>)
353	where
354		Self: Sized,
355	{
356		match Criterion::convert(dust.0) {
357			Left(a) => {
358				<Left as fungibles::Unbalanced<AccountId>>::handle_dust(fungibles::Dust(a, dust.1))
359			},
360			Right(a) => {
361				<Right as fungibles::Unbalanced<AccountId>>::handle_dust(fungibles::Dust(a, dust.1))
362			},
363		}
364	}
365	fn write_balance(
366		asset: Self::AssetId,
367		who: &AccountId,
368		amount: Self::Balance,
369	) -> Result<Option<Self::Balance>, DispatchError> {
370		match Criterion::convert(asset) {
371			Left(a) => <Left as fungibles::Unbalanced<AccountId>>::write_balance(a, who, amount),
372			Right(a) => <Right as fungibles::Unbalanced<AccountId>>::write_balance(a, who, amount),
373		}
374	}
375	fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) -> () {
376		match Criterion::convert(asset) {
377			Left(a) => <Left as fungibles::Unbalanced<AccountId>>::set_total_issuance(a, amount),
378			Right(a) => <Right as fungibles::Unbalanced<AccountId>>::set_total_issuance(a, amount),
379		}
380	}
381	fn decrease_balance(
382		asset: Self::AssetId,
383		who: &AccountId,
384		amount: Self::Balance,
385		precision: Precision,
386		preservation: Preservation,
387		force: Fortitude,
388	) -> Result<Self::Balance, DispatchError> {
389		match Criterion::convert(asset) {
390			Left(a) => <Left as fungibles::Unbalanced<AccountId>>::decrease_balance(
391				a,
392				who,
393				amount,
394				precision,
395				preservation,
396				force,
397			),
398			Right(a) => <Right as fungibles::Unbalanced<AccountId>>::decrease_balance(
399				a,
400				who,
401				amount,
402				precision,
403				preservation,
404				force,
405			),
406		}
407	}
408	fn increase_balance(
409		asset: Self::AssetId,
410		who: &AccountId,
411		amount: Self::Balance,
412		precision: Precision,
413	) -> Result<Self::Balance, DispatchError> {
414		match Criterion::convert(asset) {
415			Left(a) => <Left as fungibles::Unbalanced<AccountId>>::increase_balance(
416				a, who, amount, precision,
417			),
418			Right(a) => <Right as fungibles::Unbalanced<AccountId>>::increase_balance(
419				a, who, amount, precision,
420			),
421		}
422	}
423}
424
425impl<
426		Left: fungibles::UnbalancedHold<AccountId>,
427		Right: fungibles::UnbalancedHold<AccountId, Balance = Left::Balance, Reason = Left::Reason>,
428		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
429		AssetKind: AssetId,
430		AccountId,
431	> fungibles::UnbalancedHold<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
432{
433	fn set_balance_on_hold(
434		asset: Self::AssetId,
435		reason: &Self::Reason,
436		who: &AccountId,
437		amount: Self::Balance,
438	) -> DispatchResult {
439		match Criterion::convert(asset) {
440			Left(a) => <Left as fungibles::UnbalancedHold<AccountId>>::set_balance_on_hold(
441				a, reason, who, amount,
442			),
443			Right(a) => <Right as fungibles::UnbalancedHold<AccountId>>::set_balance_on_hold(
444				a, reason, who, amount,
445			),
446		}
447	}
448	fn decrease_balance_on_hold(
449		asset: Self::AssetId,
450		reason: &Self::Reason,
451		who: &AccountId,
452		amount: Self::Balance,
453		precision: Precision,
454	) -> Result<Self::Balance, DispatchError> {
455		match Criterion::convert(asset) {
456			Left(a) => <Left as fungibles::UnbalancedHold<AccountId>>::decrease_balance_on_hold(
457				a, reason, who, amount, precision,
458			),
459			Right(a) => <Right as fungibles::UnbalancedHold<AccountId>>::decrease_balance_on_hold(
460				a, reason, who, amount, precision,
461			),
462		}
463	}
464	fn increase_balance_on_hold(
465		asset: Self::AssetId,
466		reason: &Self::Reason,
467		who: &AccountId,
468		amount: Self::Balance,
469		precision: Precision,
470	) -> Result<Self::Balance, DispatchError> {
471		match Criterion::convert(asset) {
472			Left(a) => <Left as fungibles::UnbalancedHold<AccountId>>::increase_balance_on_hold(
473				a, reason, who, amount, precision,
474			),
475			Right(a) => <Right as fungibles::UnbalancedHold<AccountId>>::increase_balance_on_hold(
476				a, reason, who, amount, precision,
477			),
478		}
479	}
480}
481
482impl<
483		Left: fungibles::Mutate<AccountId>,
484		Right: fungibles::Mutate<AccountId, Balance = Left::Balance>,
485		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
486		AssetKind: AssetId,
487		AccountId: Eq,
488	> fungibles::Mutate<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
489{
490	fn mint_into(
491		asset: Self::AssetId,
492		who: &AccountId,
493		amount: Self::Balance,
494	) -> Result<Self::Balance, DispatchError> {
495		match Criterion::convert(asset) {
496			Left(a) => <Left as fungibles::Mutate<AccountId>>::mint_into(a, who, amount),
497			Right(a) => <Right as fungibles::Mutate<AccountId>>::mint_into(a, who, amount),
498		}
499	}
500	fn burn_from(
501		asset: Self::AssetId,
502		who: &AccountId,
503		amount: Self::Balance,
504		preservation: Preservation,
505		precision: Precision,
506		force: Fortitude,
507	) -> Result<Self::Balance, DispatchError> {
508		match Criterion::convert(asset) {
509			Left(a) => <Left as fungibles::Mutate<AccountId>>::burn_from(
510				a,
511				who,
512				amount,
513				preservation,
514				precision,
515				force,
516			),
517			Right(a) => <Right as fungibles::Mutate<AccountId>>::burn_from(
518				a,
519				who,
520				amount,
521				preservation,
522				precision,
523				force,
524			),
525		}
526	}
527	fn shelve(
528		asset: Self::AssetId,
529		who: &AccountId,
530		amount: Self::Balance,
531	) -> Result<Self::Balance, DispatchError> {
532		match Criterion::convert(asset) {
533			Left(a) => <Left as fungibles::Mutate<AccountId>>::shelve(a, who, amount),
534			Right(a) => <Right as fungibles::Mutate<AccountId>>::shelve(a, who, amount),
535		}
536	}
537	fn restore(
538		asset: Self::AssetId,
539		who: &AccountId,
540		amount: Self::Balance,
541	) -> Result<Self::Balance, DispatchError> {
542		match Criterion::convert(asset) {
543			Left(a) => <Left as fungibles::Mutate<AccountId>>::restore(a, who, amount),
544			Right(a) => <Right as fungibles::Mutate<AccountId>>::restore(a, who, amount),
545		}
546	}
547	fn transfer(
548		asset: Self::AssetId,
549		source: &AccountId,
550		dest: &AccountId,
551		amount: Self::Balance,
552		preservation: Preservation,
553	) -> Result<Self::Balance, DispatchError> {
554		match Criterion::convert(asset) {
555			Left(a) => <Left as fungibles::Mutate<AccountId>>::transfer(
556				a,
557				source,
558				dest,
559				amount,
560				preservation,
561			),
562			Right(a) => <Right as fungibles::Mutate<AccountId>>::transfer(
563				a,
564				source,
565				dest,
566				amount,
567				preservation,
568			),
569		}
570	}
571
572	fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance {
573		match Criterion::convert(asset) {
574			Left(a) => <Left as fungibles::Mutate<AccountId>>::set_balance(a, who, amount),
575			Right(a) => <Right as fungibles::Mutate<AccountId>>::set_balance(a, who, amount),
576		}
577	}
578}
579
580impl<
581		Left: fungibles::MutateHold<AccountId>,
582		Right: fungibles::MutateHold<AccountId, Balance = Left::Balance, Reason = Left::Reason>,
583		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
584		AssetKind: AssetId,
585		AccountId,
586	> fungibles::MutateHold<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
587{
588	fn hold(
589		asset: Self::AssetId,
590		reason: &Self::Reason,
591		who: &AccountId,
592		amount: Self::Balance,
593	) -> DispatchResult {
594		match Criterion::convert(asset) {
595			Left(a) => <Left as fungibles::MutateHold<AccountId>>::hold(a, reason, who, amount),
596			Right(a) => <Right as fungibles::MutateHold<AccountId>>::hold(a, reason, who, amount),
597		}
598	}
599	fn release(
600		asset: Self::AssetId,
601		reason: &Self::Reason,
602		who: &AccountId,
603		amount: Self::Balance,
604		precision: Precision,
605	) -> Result<Self::Balance, DispatchError> {
606		match Criterion::convert(asset) {
607			Left(a) => <Left as fungibles::MutateHold<AccountId>>::release(
608				a, reason, who, amount, precision,
609			),
610			Right(a) => <Right as fungibles::MutateHold<AccountId>>::release(
611				a, reason, who, amount, precision,
612			),
613		}
614	}
615	fn burn_held(
616		asset: Self::AssetId,
617		reason: &Self::Reason,
618		who: &AccountId,
619		amount: Self::Balance,
620		precision: Precision,
621		force: Fortitude,
622	) -> Result<Self::Balance, DispatchError> {
623		match Criterion::convert(asset) {
624			Left(a) => <Left as fungibles::MutateHold<AccountId>>::burn_held(
625				a, reason, who, amount, precision, force,
626			),
627			Right(a) => <Right as fungibles::MutateHold<AccountId>>::burn_held(
628				a, reason, who, amount, precision, force,
629			),
630		}
631	}
632	fn transfer_on_hold(
633		asset: Self::AssetId,
634		reason: &Self::Reason,
635		source: &AccountId,
636		dest: &AccountId,
637		amount: Self::Balance,
638		precision: Precision,
639		mode: Restriction,
640		force: Fortitude,
641	) -> Result<Self::Balance, DispatchError> {
642		match Criterion::convert(asset) {
643			Left(a) => <Left as fungibles::MutateHold<AccountId>>::transfer_on_hold(
644				a, reason, source, dest, amount, precision, mode, force,
645			),
646			Right(a) => <Right as fungibles::MutateHold<AccountId>>::transfer_on_hold(
647				a, reason, source, dest, amount, precision, mode, force,
648			),
649		}
650	}
651	fn transfer_and_hold(
652		asset: Self::AssetId,
653		reason: &Self::Reason,
654		source: &AccountId,
655		dest: &AccountId,
656		amount: Self::Balance,
657		precision: Precision,
658		preservation: Preservation,
659		force: Fortitude,
660	) -> Result<Self::Balance, DispatchError> {
661		match Criterion::convert(asset) {
662			Left(a) => <Left as fungibles::MutateHold<AccountId>>::transfer_and_hold(
663				a,
664				reason,
665				source,
666				dest,
667				amount,
668				precision,
669				preservation,
670				force,
671			),
672			Right(a) => <Right as fungibles::MutateHold<AccountId>>::transfer_and_hold(
673				a,
674				reason,
675				source,
676				dest,
677				amount,
678				precision,
679				preservation,
680				force,
681			),
682		}
683	}
684}
685
686impl<
687		Left: fungibles::MutateFreeze<AccountId>,
688		Right: fungibles::MutateFreeze<AccountId, Balance = Left::Balance, Id = Left::Id>,
689		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
690		AssetKind: AssetId,
691		AccountId,
692	> fungibles::MutateFreeze<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
693{
694	fn set_freeze(
695		asset: Self::AssetId,
696		id: &Self::Id,
697		who: &AccountId,
698		amount: Self::Balance,
699	) -> DispatchResult {
700		match Criterion::convert(asset) {
701			Left(a) => <Left as fungibles::MutateFreeze<AccountId>>::set_freeze(a, id, who, amount),
702			Right(a) => {
703				<Right as fungibles::MutateFreeze<AccountId>>::set_freeze(a, id, who, amount)
704			},
705		}
706	}
707	fn extend_freeze(
708		asset: Self::AssetId,
709		id: &Self::Id,
710		who: &AccountId,
711		amount: Self::Balance,
712	) -> DispatchResult {
713		match Criterion::convert(asset) {
714			Left(a) => {
715				<Left as fungibles::MutateFreeze<AccountId>>::extend_freeze(a, id, who, amount)
716			},
717			Right(a) => {
718				<Right as fungibles::MutateFreeze<AccountId>>::extend_freeze(a, id, who, amount)
719			},
720		}
721	}
722	fn thaw(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> DispatchResult {
723		match Criterion::convert(asset) {
724			Left(a) => <Left as fungibles::MutateFreeze<AccountId>>::thaw(a, id, who),
725			Right(a) => <Right as fungibles::MutateFreeze<AccountId>>::thaw(a, id, who),
726		}
727	}
728}
729
730pub struct ConvertImbalanceDropHandler<
731	Left,
732	Right,
733	LeftAssetId,
734	RightAssetId,
735	Criterion,
736	AssetKind,
737	Balance,
738	AccountId,
739>(
740	core::marker::PhantomData<(
741		Left,
742		Right,
743		LeftAssetId,
744		RightAssetId,
745		Criterion,
746		AssetKind,
747		Balance,
748		AccountId,
749	)>,
750);
751
752impl<
753		Left: fungibles::HandleImbalanceDrop<LeftAssetId, Balance>,
754		Right: fungibles::HandleImbalanceDrop<RightAssetId, Balance>,
755		LeftAssetId,
756		RightAssetId,
757		Criterion: Convert<AssetKind, Either<LeftAssetId, RightAssetId>>,
758		AssetKind,
759		Balance,
760		AccountId,
761	> fungibles::HandleImbalanceDrop<AssetKind, Balance>
762	for ConvertImbalanceDropHandler<
763		Left,
764		Right,
765		LeftAssetId,
766		RightAssetId,
767		Criterion,
768		AssetKind,
769		Balance,
770		AccountId,
771	>
772{
773	fn handle(asset: AssetKind, amount: Balance) {
774		match Criterion::convert(asset) {
775			Left(a) => Left::handle(a, amount),
776			Right(a) => Right::handle(a, amount),
777		}
778	}
779}
780
781impl<
782		Left: fungibles::Balanced<AccountId>,
783		Right: fungibles::Balanced<AccountId, Balance = Left::Balance>,
784		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
785		AssetKind: AssetId,
786		AccountId,
787	> fungibles::Balanced<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
788{
789	type OnDropDebt = ConvertImbalanceDropHandler<
790		Left::OnDropDebt,
791		Right::OnDropDebt,
792		Left::AssetId,
793		Right::AssetId,
794		Criterion,
795		AssetKind,
796		Left::Balance,
797		AccountId,
798	>;
799	type OnDropCredit = ConvertImbalanceDropHandler<
800		Left::OnDropCredit,
801		Right::OnDropCredit,
802		Left::AssetId,
803		Right::AssetId,
804		Criterion,
805		AssetKind,
806		Left::Balance,
807		AccountId,
808	>;
809
810	fn deposit(
811		asset: Self::AssetId,
812		who: &AccountId,
813		value: Self::Balance,
814		precision: Precision,
815	) -> Result<fungibles::Debt<AccountId, Self>, DispatchError> {
816		match Criterion::convert(asset.clone()) {
817			Left(a) => <Left as fungibles::Balanced<AccountId>>::deposit(a, who, value, precision)
818				.map(|debt| imbalance::from_fungibles(debt, asset)),
819			Right(a) => {
820				<Right as fungibles::Balanced<AccountId>>::deposit(a, who, value, precision)
821					.map(|debt| imbalance::from_fungibles(debt, asset))
822			},
823		}
824	}
825	fn issue(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Credit<AccountId, Self> {
826		match Criterion::convert(asset.clone()) {
827			Left(a) => {
828				let credit = <Left as fungibles::Balanced<AccountId>>::issue(a, amount);
829				imbalance::from_fungibles(credit, asset)
830			},
831			Right(a) => {
832				let credit = <Right as fungibles::Balanced<AccountId>>::issue(a, amount);
833				imbalance::from_fungibles(credit, asset)
834			},
835		}
836	}
837	fn pair(
838		asset: Self::AssetId,
839		amount: Self::Balance,
840	) -> Result<(fungibles::Debt<AccountId, Self>, fungibles::Credit<AccountId, Self>), DispatchError>
841	{
842		match Criterion::convert(asset.clone()) {
843			Left(a) => {
844				let (a, b) = <Left as fungibles::Balanced<AccountId>>::pair(a, amount)?;
845				Ok((
846					imbalance::from_fungibles(a, asset.clone()),
847					imbalance::from_fungibles(b, asset),
848				))
849			},
850			Right(a) => {
851				let (a, b) = <Right as fungibles::Balanced<AccountId>>::pair(a, amount)?;
852				Ok((
853					imbalance::from_fungibles(a, asset.clone()),
854					imbalance::from_fungibles(b, asset),
855				))
856			},
857		}
858	}
859	fn rescind(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Debt<AccountId, Self> {
860		match Criterion::convert(asset.clone()) {
861			Left(a) => {
862				let debt = <Left as fungibles::Balanced<AccountId>>::rescind(a, amount);
863				imbalance::from_fungibles(debt, asset)
864			},
865			Right(a) => {
866				let debt = <Right as fungibles::Balanced<AccountId>>::rescind(a, amount);
867				imbalance::from_fungibles(debt, asset)
868			},
869		}
870	}
871	fn resolve(
872		who: &AccountId,
873		credit: fungibles::Credit<AccountId, Self>,
874	) -> Result<(), fungibles::Credit<AccountId, Self>> {
875		let asset = credit.asset();
876		match Criterion::convert(asset.clone()) {
877			Left(a) => {
878				let credit = imbalance::from_fungibles(credit, a);
879				<Left as fungibles::Balanced<AccountId>>::resolve(who, credit)
880					.map_err(|credit| imbalance::from_fungibles(credit, asset))
881			},
882			Right(a) => {
883				let credit = imbalance::from_fungibles(credit, a);
884				<Right as fungibles::Balanced<AccountId>>::resolve(who, credit)
885					.map_err(|credit| imbalance::from_fungibles(credit, asset))
886			},
887		}
888	}
889	fn settle(
890		who: &AccountId,
891		debt: fungibles::Debt<AccountId, Self>,
892		preservation: Preservation,
893	) -> Result<fungibles::Credit<AccountId, Self>, fungibles::Debt<AccountId, Self>> {
894		let asset = debt.asset();
895		match Criterion::convert(asset.clone()) {
896			Left(a) => {
897				let debt = imbalance::from_fungibles(debt, a);
898				match <Left as fungibles::Balanced<AccountId>>::settle(who, debt, preservation) {
899					Ok(credit) => Ok(imbalance::from_fungibles(credit, asset)),
900					Err(debt) => Err(imbalance::from_fungibles(debt, asset)),
901				}
902			},
903			Right(a) => {
904				let debt = imbalance::from_fungibles(debt, a);
905				match <Right as fungibles::Balanced<AccountId>>::settle(who, debt, preservation) {
906					Ok(credit) => Ok(imbalance::from_fungibles(credit, asset)),
907					Err(debt) => Err(imbalance::from_fungibles(debt, asset)),
908				}
909			},
910		}
911	}
912	fn withdraw(
913		asset: Self::AssetId,
914		who: &AccountId,
915		value: Self::Balance,
916		precision: Precision,
917		preservation: Preservation,
918		force: Fortitude,
919	) -> Result<fungibles::Credit<AccountId, Self>, DispatchError> {
920		match Criterion::convert(asset.clone()) {
921			Left(a) => <Left as fungibles::Balanced<AccountId>>::withdraw(
922				a,
923				who,
924				value,
925				precision,
926				preservation,
927				force,
928			)
929			.map(|credit| imbalance::from_fungibles(credit, asset)),
930			Right(a) => <Right as fungibles::Balanced<AccountId>>::withdraw(
931				a,
932				who,
933				value,
934				precision,
935				preservation,
936				force,
937			)
938			.map(|credit| imbalance::from_fungibles(credit, asset)),
939		}
940	}
941}
942
943impl<
944		Left: fungibles::BalancedHold<AccountId>
945			+ fungibles::hold::DoneSlash<Self::AssetId, Self::Reason, AccountId, Self::Balance>,
946		Right: fungibles::BalancedHold<AccountId, Balance = Left::Balance, Reason = Left::Reason>
947			+ fungibles::hold::DoneSlash<Self::AssetId, Self::Reason, AccountId, Self::Balance>,
948		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
949		AssetKind: AssetId,
950		AccountId,
951	> fungibles::BalancedHold<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
952{
953	fn slash(
954		asset: Self::AssetId,
955		reason: &Self::Reason,
956		who: &AccountId,
957		amount: Self::Balance,
958	) -> (fungibles::Credit<AccountId, Self>, Self::Balance) {
959		match Criterion::convert(asset.clone()) {
960			Left(a) => {
961				let (credit, amount) =
962					<Left as fungibles::BalancedHold<AccountId>>::slash(a, reason, who, amount);
963				(imbalance::from_fungibles(credit, asset), amount)
964			},
965			Right(a) => {
966				let (credit, amount) =
967					<Right as fungibles::BalancedHold<AccountId>>::slash(a, reason, who, amount);
968				(imbalance::from_fungibles(credit, asset), amount)
969			},
970		}
971	}
972}
973
974impl<
975		Reason,
976		Balance,
977		Left: fungibles::Inspect<AccountId>
978			+ fungibles::hold::DoneSlash<Left::AssetId, Reason, AccountId, Balance>,
979		Right: fungibles::Inspect<AccountId>
980			+ fungibles::hold::DoneSlash<Right::AssetId, Reason, AccountId, Balance>,
981		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
982		AssetKind: AssetId,
983		AccountId,
984	> fungibles::hold::DoneSlash<AssetKind, Reason, AccountId, Balance>
985	for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
986{
987	fn done_slash(asset: AssetKind, reason: &Reason, who: &AccountId, amount: Balance) {
988		match Criterion::convert(asset.clone()) {
989			Left(a) => {
990				Left::done_slash(a, reason, who, amount);
991			},
992			Right(a) => {
993				Right::done_slash(a, reason, who, amount);
994			},
995		}
996	}
997}
998
999impl<
1000		Left: fungibles::Inspect<AccountId> + fungibles::Create<AccountId>,
1001		Right: fungibles::Inspect<AccountId, Balance = Left::Balance> + fungibles::Create<AccountId>,
1002		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
1003		AssetKind: AssetId,
1004		AccountId,
1005	> fungibles::Create<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
1006{
1007	fn create(
1008		asset: AssetKind,
1009		admin: AccountId,
1010		is_sufficient: bool,
1011		min_balance: Self::Balance,
1012	) -> DispatchResult {
1013		match Criterion::convert(asset) {
1014			Left(a) => {
1015				<Left as fungibles::Create<AccountId>>::create(a, admin, is_sufficient, min_balance)
1016			},
1017			Right(a) => <Right as fungibles::Create<AccountId>>::create(
1018				a,
1019				admin,
1020				is_sufficient,
1021				min_balance,
1022			),
1023		}
1024	}
1025}
1026
1027impl<
1028		Left: fungibles::Inspect<AccountId> + AccountTouch<Left::AssetId, AccountId>,
1029		Right: fungibles::Inspect<AccountId>
1030			+ AccountTouch<
1031				Right::AssetId,
1032				AccountId,
1033				Balance = <Left as AccountTouch<Left::AssetId, AccountId>>::Balance,
1034			>,
1035		Criterion: Convert<AssetKind, Either<Left::AssetId, Right::AssetId>>,
1036		AssetKind: AssetId,
1037		AccountId,
1038	> AccountTouch<AssetKind, AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
1039{
1040	type Balance = <Left as AccountTouch<Left::AssetId, AccountId>>::Balance;
1041
1042	fn deposit_required(asset: AssetKind) -> Self::Balance {
1043		match Criterion::convert(asset) {
1044			Left(a) => <Left as AccountTouch<Left::AssetId, AccountId>>::deposit_required(a),
1045			Right(a) => <Right as AccountTouch<Right::AssetId, AccountId>>::deposit_required(a),
1046		}
1047	}
1048
1049	fn should_touch(asset: AssetKind, who: &AccountId) -> bool {
1050		match Criterion::convert(asset) {
1051			Left(a) => <Left as AccountTouch<Left::AssetId, AccountId>>::should_touch(a, who),
1052			Right(a) => <Right as AccountTouch<Right::AssetId, AccountId>>::should_touch(a, who),
1053		}
1054	}
1055
1056	fn touch(asset: AssetKind, who: &AccountId, depositor: &AccountId) -> DispatchResult {
1057		match Criterion::convert(asset) {
1058			Left(a) => <Left as AccountTouch<Left::AssetId, AccountId>>::touch(a, who, depositor),
1059			Right(a) => {
1060				<Right as AccountTouch<Right::AssetId, AccountId>>::touch(a, who, depositor)
1061			},
1062		}
1063	}
1064}
1065
1066impl<
1067		Left: fungibles::Inspect<AccountId> + fungibles::Refund<AccountId>,
1068		Right: fungibles::Inspect<AccountId>
1069			+ fungibles::Refund<AccountId, Balance = <Left as fungibles::Refund<AccountId>>::Balance>,
1070		Criterion: Convert<
1071			AssetKind,
1072			Either<
1073				<Left as fungibles::Refund<AccountId>>::AssetId,
1074				<Right as fungibles::Refund<AccountId>>::AssetId,
1075			>,
1076		>,
1077		AssetKind: AssetId,
1078		AccountId,
1079	> fungibles::Refund<AccountId> for UnionOf<Left, Right, Criterion, AssetKind, AccountId>
1080{
1081	type AssetId = AssetKind;
1082	type Balance = <Left as fungibles::Refund<AccountId>>::Balance;
1083
1084	fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> {
1085		match Criterion::convert(asset) {
1086			Left(a) => <Left as fungibles::Refund<AccountId>>::deposit_held(a, who),
1087			Right(a) => <Right as fungibles::Refund<AccountId>>::deposit_held(a, who),
1088		}
1089	}
1090	fn refund(asset: AssetKind, who: AccountId) -> DispatchResult {
1091		match Criterion::convert(asset) {
1092			Left(a) => <Left as fungibles::Refund<AccountId>>::refund(a, who),
1093			Right(a) => <Right as fungibles::Refund<AccountId>>::refund(a, who),
1094		}
1095	}
1096}