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