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