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