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