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