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