1use super::{InteriorLocation, Location, Reanchorable};
30use crate::{
31 v3::{
32 AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
33 MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
34 WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
35 },
36 v5::{
37 Asset as NewAsset, AssetFilter as NewAssetFilter, AssetId as NewAssetId,
38 AssetInstance as NewAssetInstance, Assets as NewAssets, Fungibility as NewFungibility,
39 WildAsset as NewWildAsset, WildFungibility as NewWildFungibility,
40 },
41};
42use alloc::{vec, vec::Vec};
43use bounded_collections::{BoundedVec, ConstU32};
44use codec::{self as codec, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
45use core::cmp::Ordering;
46use scale_info::TypeInfo;
47
48#[derive(
50 Copy,
51 Clone,
52 Eq,
53 PartialEq,
54 Ord,
55 PartialOrd,
56 Encode,
57 Decode,
58 DecodeWithMemTracking,
59 Debug,
60 TypeInfo,
61 MaxEncodedLen,
62 serde::Serialize,
63 serde::Deserialize,
64)]
65pub enum AssetInstance {
66 Undefined,
68
69 Index(#[codec(compact)] u128),
72
73 Array4([u8; 4]),
75
76 Array8([u8; 8]),
78
79 Array16([u8; 16]),
81
82 Array32([u8; 32]),
84}
85
86impl TryFrom<OldAssetInstance> for AssetInstance {
87 type Error = ();
88 fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
89 use OldAssetInstance::*;
90 Ok(match value {
91 Undefined => Self::Undefined,
92 Index(n) => Self::Index(n),
93 Array4(n) => Self::Array4(n),
94 Array8(n) => Self::Array8(n),
95 Array16(n) => Self::Array16(n),
96 Array32(n) => Self::Array32(n),
97 })
98 }
99}
100
101impl TryFrom<NewAssetInstance> for AssetInstance {
102 type Error = ();
103 fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
104 use NewAssetInstance::*;
105 Ok(match value {
106 Undefined => Self::Undefined,
107 Index(n) => Self::Index(n),
108 Array4(n) => Self::Array4(n),
109 Array8(n) => Self::Array8(n),
110 Array16(n) => Self::Array16(n),
111 Array32(n) => Self::Array32(n),
112 })
113 }
114}
115
116impl From<()> for AssetInstance {
117 fn from(_: ()) -> Self {
118 Self::Undefined
119 }
120}
121
122impl From<[u8; 4]> for AssetInstance {
123 fn from(x: [u8; 4]) -> Self {
124 Self::Array4(x)
125 }
126}
127
128impl From<[u8; 8]> for AssetInstance {
129 fn from(x: [u8; 8]) -> Self {
130 Self::Array8(x)
131 }
132}
133
134impl From<[u8; 16]> for AssetInstance {
135 fn from(x: [u8; 16]) -> Self {
136 Self::Array16(x)
137 }
138}
139
140impl From<[u8; 32]> for AssetInstance {
141 fn from(x: [u8; 32]) -> Self {
142 Self::Array32(x)
143 }
144}
145
146impl From<u8> for AssetInstance {
147 fn from(x: u8) -> Self {
148 Self::Index(x as u128)
149 }
150}
151
152impl From<u16> for AssetInstance {
153 fn from(x: u16) -> Self {
154 Self::Index(x as u128)
155 }
156}
157
158impl From<u32> for AssetInstance {
159 fn from(x: u32) -> Self {
160 Self::Index(x as u128)
161 }
162}
163
164impl From<u64> for AssetInstance {
165 fn from(x: u64) -> Self {
166 Self::Index(x as u128)
167 }
168}
169
170impl TryFrom<AssetInstance> for () {
171 type Error = ();
172 fn try_from(x: AssetInstance) -> Result<Self, ()> {
173 match x {
174 AssetInstance::Undefined => Ok(()),
175 _ => Err(()),
176 }
177 }
178}
179
180impl TryFrom<AssetInstance> for [u8; 4] {
181 type Error = ();
182 fn try_from(x: AssetInstance) -> Result<Self, ()> {
183 match x {
184 AssetInstance::Array4(x) => Ok(x),
185 _ => Err(()),
186 }
187 }
188}
189
190impl TryFrom<AssetInstance> for [u8; 8] {
191 type Error = ();
192 fn try_from(x: AssetInstance) -> Result<Self, ()> {
193 match x {
194 AssetInstance::Array8(x) => Ok(x),
195 _ => Err(()),
196 }
197 }
198}
199
200impl TryFrom<AssetInstance> for [u8; 16] {
201 type Error = ();
202 fn try_from(x: AssetInstance) -> Result<Self, ()> {
203 match x {
204 AssetInstance::Array16(x) => Ok(x),
205 _ => Err(()),
206 }
207 }
208}
209
210impl TryFrom<AssetInstance> for [u8; 32] {
211 type Error = ();
212 fn try_from(x: AssetInstance) -> Result<Self, ()> {
213 match x {
214 AssetInstance::Array32(x) => Ok(x),
215 _ => Err(()),
216 }
217 }
218}
219
220impl TryFrom<AssetInstance> for u8 {
221 type Error = ();
222 fn try_from(x: AssetInstance) -> Result<Self, ()> {
223 match x {
224 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
225 _ => Err(()),
226 }
227 }
228}
229
230impl TryFrom<AssetInstance> for u16 {
231 type Error = ();
232 fn try_from(x: AssetInstance) -> Result<Self, ()> {
233 match x {
234 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
235 _ => Err(()),
236 }
237 }
238}
239
240impl TryFrom<AssetInstance> for u32 {
241 type Error = ();
242 fn try_from(x: AssetInstance) -> Result<Self, ()> {
243 match x {
244 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
245 _ => Err(()),
246 }
247 }
248}
249
250impl TryFrom<AssetInstance> for u64 {
251 type Error = ();
252 fn try_from(x: AssetInstance) -> Result<Self, ()> {
253 match x {
254 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
255 _ => Err(()),
256 }
257 }
258}
259
260impl TryFrom<AssetInstance> for u128 {
261 type Error = ();
262 fn try_from(x: AssetInstance) -> Result<Self, ()> {
263 match x {
264 AssetInstance::Index(x) => Ok(x),
265 _ => Err(()),
266 }
267 }
268}
269
270impl TryFrom<NewFungibility> for Fungibility {
271 type Error = ();
272 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
273 use NewFungibility::*;
274 Ok(match value {
275 Fungible(n) => Self::Fungible(n),
276 NonFungible(i) => Self::NonFungible(i.try_into()?),
277 })
278 }
279}
280
281#[derive(
284 Clone,
285 Eq,
286 PartialEq,
287 Ord,
288 PartialOrd,
289 Debug,
290 Encode,
291 DecodeWithMemTracking,
292 TypeInfo,
293 MaxEncodedLen,
294 serde::Serialize,
295 serde::Deserialize,
296)]
297pub enum Fungibility {
298 Fungible(#[codec(compact)] u128),
300 NonFungible(AssetInstance),
303}
304
305#[derive(Decode)]
306enum UncheckedFungibility {
307 Fungible(#[codec(compact)] u128),
308 NonFungible(AssetInstance),
309}
310
311impl Decode for Fungibility {
312 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
313 match UncheckedFungibility::decode(input)? {
314 UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
315 UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
316 UncheckedFungibility::Fungible(_) => {
317 Err("Fungible asset of zero amount is not allowed".into())
318 },
319 }
320 }
321}
322
323impl Fungibility {
324 pub fn is_kind(&self, w: WildFungibility) -> bool {
325 use Fungibility::*;
326 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
327 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
328 }
329}
330
331impl From<i32> for Fungibility {
332 fn from(amount: i32) -> Fungibility {
333 debug_assert_ne!(amount, 0);
334 Fungibility::Fungible(amount as u128)
335 }
336}
337
338impl From<u128> for Fungibility {
339 fn from(amount: u128) -> Fungibility {
340 debug_assert_ne!(amount, 0);
341 Fungibility::Fungible(amount)
342 }
343}
344
345impl<T: Into<AssetInstance>> From<T> for Fungibility {
346 fn from(instance: T) -> Fungibility {
347 Fungibility::NonFungible(instance.into())
348 }
349}
350
351impl TryFrom<OldFungibility> for Fungibility {
352 type Error = ();
353 fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
354 use OldFungibility::*;
355 Ok(match value {
356 Fungible(n) => Self::Fungible(n),
357 NonFungible(i) => Self::NonFungible(i.try_into()?),
358 })
359 }
360}
361
362#[derive(
364 Copy,
365 Clone,
366 Eq,
367 PartialEq,
368 Ord,
369 PartialOrd,
370 Debug,
371 Encode,
372 Decode,
373 DecodeWithMemTracking,
374 TypeInfo,
375 MaxEncodedLen,
376 serde::Serialize,
377 serde::Deserialize,
378)]
379pub enum WildFungibility {
380 Fungible,
382 NonFungible,
384}
385
386impl TryFrom<OldWildFungibility> for WildFungibility {
387 type Error = ();
388 fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
389 use OldWildFungibility::*;
390 Ok(match value {
391 Fungible => Self::Fungible,
392 NonFungible => Self::NonFungible,
393 })
394 }
395}
396
397impl TryFrom<NewWildFungibility> for WildFungibility {
398 type Error = ();
399 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
400 use NewWildFungibility::*;
401 Ok(match value {
402 Fungible => Self::Fungible,
403 NonFungible => Self::NonFungible,
404 })
405 }
406}
407
408#[derive(
410 Clone,
411 Eq,
412 PartialEq,
413 Ord,
414 PartialOrd,
415 Debug,
416 Encode,
417 Decode,
418 DecodeWithMemTracking,
419 TypeInfo,
420 MaxEncodedLen,
421 serde::Serialize,
422 serde::Deserialize,
423)]
424pub struct AssetId(pub Location);
425
426impl<T: Into<Location>> From<T> for AssetId {
427 fn from(x: T) -> Self {
428 Self(x.into())
429 }
430}
431
432impl TryFrom<OldAssetId> for AssetId {
433 type Error = ();
434 fn try_from(old: OldAssetId) -> Result<Self, ()> {
435 use OldAssetId::*;
436 Ok(match old {
437 Concrete(l) => Self(l.try_into()?),
438 Abstract(_) => return Err(()),
439 })
440 }
441}
442
443impl TryFrom<NewAssetId> for AssetId {
444 type Error = ();
445 fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
446 Ok(Self(new.0.try_into()?))
447 }
448}
449
450impl AssetId {
451 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
453 self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
454 Ok(())
455 }
456
457 pub fn into_asset(self, fun: Fungibility) -> Asset {
460 Asset { fun, id: self }
461 }
462
463 pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
466 WildAsset::AllOf { fun, id: self }
467 }
468}
469
470impl Reanchorable for AssetId {
471 type Error = ();
472
473 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
476 self.0.reanchor(target, context)?;
477 Ok(())
478 }
479
480 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
481 match self.reanchor(target, context) {
482 Ok(()) => Ok(self),
483 Err(()) => Err(()),
484 }
485 }
486}
487
488#[derive(
490 Clone,
491 Eq,
492 PartialEq,
493 Debug,
494 Encode,
495 Decode,
496 DecodeWithMemTracking,
497 TypeInfo,
498 MaxEncodedLen,
499 serde::Serialize,
500 serde::Deserialize,
501)]
502pub struct Asset {
503 pub id: AssetId,
505 pub fun: Fungibility,
508}
509
510impl PartialOrd for Asset {
511 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
512 Some(self.cmp(other))
513 }
514}
515
516impl Ord for Asset {
517 fn cmp(&self, other: &Self) -> Ordering {
518 match (&self.fun, &other.fun) {
519 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
520 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
521 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
522 }
523 }
524}
525
526impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
527 fn from((id, fun): (A, B)) -> Asset {
528 Asset { fun: fun.into(), id: id.into() }
529 }
530}
531
532impl Asset {
533 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
534 use Fungibility::*;
535 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
536 }
537
538 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
539 use Fungibility::*;
540 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
541 }
542
543 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
545 self.id.prepend_with(prepend)
546 }
547
548 pub fn contains(&self, inner: &Asset) -> bool {
550 use Fungibility::*;
551 if self.id == inner.id {
552 match (&self.fun, &inner.fun) {
553 (Fungible(a), Fungible(i)) if a >= i => return true,
554 (NonFungible(a), NonFungible(i)) if a == i => return true,
555 _ => (),
556 }
557 }
558 false
559 }
560}
561
562impl Reanchorable for Asset {
563 type Error = ();
564
565 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
568 self.id.reanchor(target, context)
569 }
570
571 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
574 self.id.reanchor(target, context)?;
575 Ok(self)
576 }
577}
578
579impl TryFrom<OldAsset> for Asset {
580 type Error = ();
581 fn try_from(old: OldAsset) -> Result<Self, ()> {
582 Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
583 }
584}
585
586impl TryFrom<NewAsset> for Asset {
587 type Error = ();
588 fn try_from(new: NewAsset) -> Result<Self, Self::Error> {
589 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
590 }
591}
592
593#[derive(
601 Clone,
602 Eq,
603 PartialEq,
604 Ord,
605 PartialOrd,
606 Debug,
607 Encode,
608 DecodeWithMemTracking,
609 TypeInfo,
610 Default,
611 serde::Serialize,
612 serde::Deserialize,
613)]
614pub struct Assets(Vec<Asset>);
615
616pub const MAX_ITEMS_IN_ASSETS: usize = 20;
619
620impl MaxEncodedLen for Assets {
621 fn max_encoded_len() -> usize {
622 Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
623 }
624}
625
626impl Decode for Assets {
627 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
628 let bounded_instructions =
629 BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
630 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
631 .map_err(|()| "Out of order".into())
632 }
633}
634
635impl TryFrom<OldAssets> for Assets {
636 type Error = ();
637 fn try_from(old: OldAssets) -> Result<Self, ()> {
638 let v = old
639 .into_inner()
640 .into_iter()
641 .map(Asset::try_from)
642 .collect::<Result<Vec<_>, ()>>()?;
643 Ok(Assets(v))
644 }
645}
646
647impl TryFrom<NewAssets> for Assets {
648 type Error = ();
649 fn try_from(new: NewAssets) -> Result<Self, Self::Error> {
650 let v = new
651 .into_inner()
652 .into_iter()
653 .map(Asset::try_from)
654 .collect::<Result<Vec<_>, ()>>()?;
655 Ok(Assets(v))
656 }
657}
658
659impl From<Vec<Asset>> for Assets {
660 fn from(mut assets: Vec<Asset>) -> Self {
661 let mut res = Vec::with_capacity(assets.len());
662 if !assets.is_empty() {
663 assets.sort();
664 let mut iter = assets.into_iter();
665 if let Some(first) = iter.next() {
666 let last = iter.fold(first, |a, b| -> Asset {
667 match (a, b) {
668 (
669 Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
670 Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
671 ) if a_id == b_id => Asset {
672 id: a_id,
673 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
674 },
675 (
676 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
677 Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
678 ) if a_id == b_id && a_instance == b_instance => {
679 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id }
680 },
681 (to_push, to_remember) => {
682 res.push(to_push);
683 to_remember
684 },
685 }
686 });
687 res.push(last);
688 }
689 }
690 Self(res)
691 }
692}
693
694impl<T: Into<Asset>> From<T> for Assets {
695 fn from(x: T) -> Self {
696 Self(vec![x.into()])
697 }
698}
699
700impl Assets {
701 pub fn new() -> Self {
703 Self(Vec::new())
704 }
705
706 pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
713 if r.is_empty() {
714 return Ok(Self(Vec::new()));
715 }
716 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
717 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
718 Ok(b)
719 } else {
720 Err(())
721 }
722 })?;
723 Ok(Self(r))
724 }
725
726 #[cfg(test)]
733 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
734 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
735 }
736 #[cfg(not(test))]
745 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
746 Self(r)
747 }
748
749 pub fn push(&mut self, a: Asset) {
752 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
753 match (&a.fun, &mut asset.fun) {
754 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
755 *balance = balance.saturating_add(*amount);
756 return;
757 },
758 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
759 if inst1 == inst2 =>
760 {
761 return
762 },
763 _ => (),
764 }
765 }
766 self.0.push(a);
767 self.0.sort();
768 }
769
770 pub fn is_none(&self) -> bool {
772 self.0.is_empty()
773 }
774
775 pub fn contains(&self, inner: &Asset) -> bool {
777 self.0.iter().any(|i| i.contains(inner))
778 }
779
780 #[deprecated = "Use `into_inner()` instead"]
782 pub fn drain(self) -> Vec<Asset> {
783 self.0
784 }
785
786 pub fn into_inner(self) -> Vec<Asset> {
788 self.0
789 }
790
791 pub fn inner(&self) -> &Vec<Asset> {
793 &self.0
794 }
795
796 pub fn len(&self) -> usize {
798 self.0.len()
799 }
800
801 pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
803 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
804 self.0.sort();
805 Ok(())
806 }
807
808 pub fn get(&self, index: usize) -> Option<&Asset> {
810 self.0.get(index)
811 }
812}
813
814impl Reanchorable for Assets {
815 type Error = ();
816
817 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
818 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
819 self.0.sort();
820 Ok(())
821 }
822
823 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
824 match self.reanchor(target, context) {
825 Ok(()) => Ok(self),
826 Err(()) => Err(()),
827 }
828 }
829}
830
831#[derive(
833 Clone,
834 Eq,
835 PartialEq,
836 Ord,
837 PartialOrd,
838 Debug,
839 Encode,
840 Decode,
841 DecodeWithMemTracking,
842 TypeInfo,
843 MaxEncodedLen,
844 serde::Serialize,
845 serde::Deserialize,
846)]
847pub enum WildAsset {
848 All,
850 AllOf { id: AssetId, fun: WildFungibility },
852 AllCounted(#[codec(compact)] u32),
855 AllOfCounted {
858 id: AssetId,
859 fun: WildFungibility,
860 #[codec(compact)]
861 count: u32,
862 },
863}
864
865impl TryFrom<OldWildAsset> for WildAsset {
866 type Error = ();
867 fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
868 use OldWildAsset::*;
869 Ok(match old {
870 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
871 All => Self::All,
872 AllOfCounted { id, fun, count } => {
873 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }
874 },
875 AllCounted(count) => Self::AllCounted(count),
876 })
877 }
878}
879
880impl TryFrom<NewWildAsset> for WildAsset {
881 type Error = ();
882 fn try_from(new: NewWildAsset) -> Result<Self, ()> {
883 use NewWildAsset::*;
884 Ok(match new {
885 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
886 AllOfCounted { id, fun, count } => {
887 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }
888 },
889 All => Self::All,
890 AllCounted(count) => Self::AllCounted(count),
891 })
892 }
893}
894
895impl WildAsset {
896 pub fn contains(&self, inner: &Asset) -> bool {
898 use WildAsset::*;
899 match self {
900 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
901 AllOf { fun, id } | AllOfCounted { id, fun, .. } => {
902 inner.fun.is_kind(*fun) && &inner.id == id
903 },
904 All | AllCounted(_) => true,
905 }
906 }
907
908 #[deprecated = "Use `contains` instead"]
913 pub fn matches(&self, inner: &Asset) -> bool {
914 self.contains(inner)
915 }
916
917 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
920 use WildAsset::*;
921 match self {
922 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } => {
923 id.reanchor(target, context)
924 },
925 All | AllCounted(_) => Ok(()),
926 }
927 }
928
929 pub fn count(&self) -> Option<u32> {
931 use WildAsset::*;
932 match self {
933 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
934 All | AllOf { .. } => None,
935 }
936 }
937
938 pub fn limit(&self) -> Option<u32> {
940 self.count()
941 }
942
943 pub fn counted(self, count: u32) -> Self {
946 use WildAsset::*;
947 match self {
948 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
949 All | AllCounted(_) => AllCounted(count),
950 }
951 }
952}
953
954impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
955 fn from((id, fun): (A, B)) -> WildAsset {
956 WildAsset::AllOf { fun: fun.into(), id: id.into() }
957 }
958}
959
960#[derive(
962 Clone,
963 Eq,
964 PartialEq,
965 Ord,
966 PartialOrd,
967 Debug,
968 Encode,
969 Decode,
970 DecodeWithMemTracking,
971 TypeInfo,
972 MaxEncodedLen,
973 serde::Serialize,
974 serde::Deserialize,
975)]
976pub enum AssetFilter {
977 Definite(Assets),
979 Wild(WildAsset),
981}
982
983impl<T: Into<WildAsset>> From<T> for AssetFilter {
984 fn from(x: T) -> Self {
985 Self::Wild(x.into())
986 }
987}
988
989impl From<Asset> for AssetFilter {
990 fn from(x: Asset) -> Self {
991 Self::Definite(vec![x].into())
992 }
993}
994
995impl From<Vec<Asset>> for AssetFilter {
996 fn from(x: Vec<Asset>) -> Self {
997 Self::Definite(x.into())
998 }
999}
1000
1001impl From<Assets> for AssetFilter {
1002 fn from(x: Assets) -> Self {
1003 Self::Definite(x)
1004 }
1005}
1006
1007impl AssetFilter {
1008 pub fn matches(&self, inner: &Asset) -> bool {
1013 match self {
1014 AssetFilter::Definite(ref assets) => assets.contains(inner),
1015 AssetFilter::Wild(ref wild) => wild.contains(inner),
1016 }
1017 }
1018
1019 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
1022 match self {
1023 AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
1024 AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
1025 }
1026 }
1027
1028 pub fn count(&self) -> Option<u32> {
1030 use AssetFilter::*;
1031 match self {
1032 Definite(x) => Some(x.len() as u32),
1033 Wild(x) => x.count(),
1034 }
1035 }
1036
1037 pub fn limit(&self) -> Option<u32> {
1039 use AssetFilter::*;
1040 match self {
1041 Definite(_) => None,
1042 Wild(x) => x.limit(),
1043 }
1044 }
1045}
1046
1047impl TryFrom<NewAssetFilter> for AssetFilter {
1048 type Error = ();
1049 fn try_from(new: NewAssetFilter) -> Result<AssetFilter, Self::Error> {
1050 use NewAssetFilter::*;
1051 Ok(match new {
1052 Definite(x) => Self::Definite(x.try_into()?),
1053 Wild(x) => Self::Wild(x.try_into()?),
1054 })
1055 }
1056}
1057
1058impl TryFrom<OldAssetFilter> for AssetFilter {
1059 type Error = ();
1060 fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
1061 Ok(match old {
1062 OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
1063 OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
1064 })
1065 }
1066}
1067
1068#[cfg(test)]
1069mod tests {
1070 use super::super::prelude::*;
1071
1072 #[test]
1073 fn conversion_works() {
1074 let _: Assets = (Here, 1u128).into();
1075 }
1076
1077 #[test]
1078 fn from_sorted_and_deduplicated_works() {
1079 use super::*;
1080 use alloc::vec;
1081
1082 let empty = vec![];
1083 let r = Assets::from_sorted_and_deduplicated(empty);
1084 assert_eq!(r, Ok(Assets(vec![])));
1085
1086 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1087 let r = Assets::from_sorted_and_deduplicated(dup_fun);
1088 assert!(r.is_err());
1089
1090 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1091 let r = Assets::from_sorted_and_deduplicated(dup_nft);
1092 assert!(r.is_err());
1093
1094 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1095 let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
1096 assert_eq!(r, Ok(Assets(good_fun)));
1097
1098 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1099 let r = Assets::from_sorted_and_deduplicated(bad_fun);
1100 assert!(r.is_err());
1101
1102 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1103 let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
1104 assert_eq!(r, Ok(Assets(good_nft)));
1105
1106 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1107 let r = Assets::from_sorted_and_deduplicated(bad_nft);
1108 assert!(r.is_err());
1109
1110 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1111 let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
1112 assert_eq!(r, Ok(Assets(mixed_good)));
1113
1114 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1115 let r = Assets::from_sorted_and_deduplicated(mixed_bad);
1116 assert!(r.is_err());
1117 }
1118
1119 #[test]
1120 fn reanchor_preserves_sorting() {
1121 use super::*;
1122 use alloc::vec;
1123
1124 let reanchor_context: Junctions = Parachain(2000).into();
1125 let dest = Location::new(1, []);
1126
1127 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1128 let mut asset_1_reanchored = asset_1.clone();
1129 assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1130 assert_eq!(
1131 asset_1_reanchored,
1132 (Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1133 );
1134
1135 let asset_2: Asset = (Location::new(1, []), 10).into();
1136 let mut asset_2_reanchored = asset_2.clone();
1137 assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1138 assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
1139
1140 let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
1141 let mut asset_3_reanchored = asset_3.clone();
1142 assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1143 assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
1144
1145 let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1146 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1147
1148 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1150
1151 assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
1152 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1153
1154 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1156 }
1157
1158 #[test]
1159 fn prepend_preserves_sorting() {
1160 use super::*;
1161 use alloc::vec;
1162
1163 let prefix = Location::new(0, [Parachain(1000)]);
1164
1165 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1166 let mut asset_1_prepended = asset_1.clone();
1167 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1168 assert_eq!(
1170 asset_1_prepended,
1171 (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1172 );
1173
1174 let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1175 let mut asset_2_prepended = asset_2.clone();
1176 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1177 assert_eq!(
1179 asset_2_prepended,
1180 (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1181 );
1182
1183 let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1184 let mut asset_3_prepended = asset_3.clone();
1185 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1186 assert_eq!(
1188 asset_3_prepended,
1189 (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1190 );
1191
1192 let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
1194 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1196
1197 assert!(assets.prepend_with(&prefix).is_ok());
1199 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1200
1201 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1203 }
1204
1205 #[test]
1206 fn decoding_respects_limit() {
1207 use super::*;
1208
1209 let lots_of_one_asset: Assets =
1211 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
1212 let encoded = lots_of_one_asset.encode();
1213 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1214
1215 let mut few_assets: Assets = Vec::new().into();
1217 for i in 0..MAX_ITEMS_IN_ASSETS {
1218 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1219 }
1220 let encoded = few_assets.encode();
1221 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1222
1223 let mut too_many_different_assets: Assets = Vec::new().into();
1225 for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
1226 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1227 }
1228 let encoded = too_many_different_assets.encode();
1229 assert!(Assets::decode(&mut &encoded[..]).is_err());
1230 }
1231}