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