1use super::{InteriorLocation, Location, Reanchorable};
30use crate::v3::{
31 AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
32 MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
33 WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
34};
35use alloc::{vec, vec::Vec};
36use bounded_collections::{BoundedVec, ConstU32};
37use codec::{self as codec, Decode, Encode, MaxEncodedLen};
38use core::cmp::Ordering;
39use scale_info::TypeInfo;
40
41#[derive(
43 Copy,
44 Clone,
45 Eq,
46 PartialEq,
47 Ord,
48 PartialOrd,
49 Encode,
50 Decode,
51 Debug,
52 TypeInfo,
53 MaxEncodedLen,
54 serde::Serialize,
55 serde::Deserialize,
56)]
57pub enum AssetInstance {
58 Undefined,
60
61 Index(#[codec(compact)] u128),
64
65 Array4([u8; 4]),
67
68 Array8([u8; 8]),
70
71 Array16([u8; 16]),
73
74 Array32([u8; 32]),
76}
77
78impl TryFrom<OldAssetInstance> for AssetInstance {
79 type Error = ();
80 fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
81 use OldAssetInstance::*;
82 Ok(match value {
83 Undefined => Self::Undefined,
84 Index(n) => Self::Index(n),
85 Array4(n) => Self::Array4(n),
86 Array8(n) => Self::Array8(n),
87 Array16(n) => Self::Array16(n),
88 Array32(n) => Self::Array32(n),
89 })
90 }
91}
92
93impl From<()> for AssetInstance {
94 fn from(_: ()) -> Self {
95 Self::Undefined
96 }
97}
98
99impl From<[u8; 4]> for AssetInstance {
100 fn from(x: [u8; 4]) -> Self {
101 Self::Array4(x)
102 }
103}
104
105impl From<[u8; 8]> for AssetInstance {
106 fn from(x: [u8; 8]) -> Self {
107 Self::Array8(x)
108 }
109}
110
111impl From<[u8; 16]> for AssetInstance {
112 fn from(x: [u8; 16]) -> Self {
113 Self::Array16(x)
114 }
115}
116
117impl From<[u8; 32]> for AssetInstance {
118 fn from(x: [u8; 32]) -> Self {
119 Self::Array32(x)
120 }
121}
122
123impl From<u8> for AssetInstance {
124 fn from(x: u8) -> Self {
125 Self::Index(x as u128)
126 }
127}
128
129impl From<u16> for AssetInstance {
130 fn from(x: u16) -> Self {
131 Self::Index(x as u128)
132 }
133}
134
135impl From<u32> for AssetInstance {
136 fn from(x: u32) -> Self {
137 Self::Index(x as u128)
138 }
139}
140
141impl From<u64> for AssetInstance {
142 fn from(x: u64) -> Self {
143 Self::Index(x as u128)
144 }
145}
146
147impl TryFrom<AssetInstance> for () {
148 type Error = ();
149 fn try_from(x: AssetInstance) -> Result<Self, ()> {
150 match x {
151 AssetInstance::Undefined => Ok(()),
152 _ => Err(()),
153 }
154 }
155}
156
157impl TryFrom<AssetInstance> for [u8; 4] {
158 type Error = ();
159 fn try_from(x: AssetInstance) -> Result<Self, ()> {
160 match x {
161 AssetInstance::Array4(x) => Ok(x),
162 _ => Err(()),
163 }
164 }
165}
166
167impl TryFrom<AssetInstance> for [u8; 8] {
168 type Error = ();
169 fn try_from(x: AssetInstance) -> Result<Self, ()> {
170 match x {
171 AssetInstance::Array8(x) => Ok(x),
172 _ => Err(()),
173 }
174 }
175}
176
177impl TryFrom<AssetInstance> for [u8; 16] {
178 type Error = ();
179 fn try_from(x: AssetInstance) -> Result<Self, ()> {
180 match x {
181 AssetInstance::Array16(x) => Ok(x),
182 _ => Err(()),
183 }
184 }
185}
186
187impl TryFrom<AssetInstance> for [u8; 32] {
188 type Error = ();
189 fn try_from(x: AssetInstance) -> Result<Self, ()> {
190 match x {
191 AssetInstance::Array32(x) => Ok(x),
192 _ => Err(()),
193 }
194 }
195}
196
197impl TryFrom<AssetInstance> for u8 {
198 type Error = ();
199 fn try_from(x: AssetInstance) -> Result<Self, ()> {
200 match x {
201 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
202 _ => Err(()),
203 }
204 }
205}
206
207impl TryFrom<AssetInstance> for u16 {
208 type Error = ();
209 fn try_from(x: AssetInstance) -> Result<Self, ()> {
210 match x {
211 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
212 _ => Err(()),
213 }
214 }
215}
216
217impl TryFrom<AssetInstance> for u32 {
218 type Error = ();
219 fn try_from(x: AssetInstance) -> Result<Self, ()> {
220 match x {
221 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
222 _ => Err(()),
223 }
224 }
225}
226
227impl TryFrom<AssetInstance> for u64 {
228 type Error = ();
229 fn try_from(x: AssetInstance) -> Result<Self, ()> {
230 match x {
231 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
232 _ => Err(()),
233 }
234 }
235}
236
237impl TryFrom<AssetInstance> for u128 {
238 type Error = ();
239 fn try_from(x: AssetInstance) -> Result<Self, ()> {
240 match x {
241 AssetInstance::Index(x) => Ok(x),
242 _ => Err(()),
243 }
244 }
245}
246
247#[derive(
250 Clone,
251 Eq,
252 PartialEq,
253 Ord,
254 PartialOrd,
255 Debug,
256 Encode,
257 TypeInfo,
258 MaxEncodedLen,
259 serde::Serialize,
260 serde::Deserialize,
261)]
262pub enum Fungibility {
263 Fungible(#[codec(compact)] u128),
265 NonFungible(AssetInstance),
268}
269
270#[derive(Decode)]
271enum UncheckedFungibility {
272 Fungible(#[codec(compact)] u128),
273 NonFungible(AssetInstance),
274}
275
276impl Decode for Fungibility {
277 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
278 match UncheckedFungibility::decode(input)? {
279 UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
280 UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
281 UncheckedFungibility::Fungible(_) =>
282 Err("Fungible asset of zero amount is not allowed".into()),
283 }
284 }
285}
286
287impl Fungibility {
288 pub fn is_kind(&self, w: WildFungibility) -> bool {
289 use Fungibility::*;
290 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
291 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
292 }
293}
294
295impl From<i32> for Fungibility {
296 fn from(amount: i32) -> Fungibility {
297 debug_assert_ne!(amount, 0);
298 Fungibility::Fungible(amount as u128)
299 }
300}
301
302impl From<u128> for Fungibility {
303 fn from(amount: u128) -> Fungibility {
304 debug_assert_ne!(amount, 0);
305 Fungibility::Fungible(amount)
306 }
307}
308
309impl<T: Into<AssetInstance>> From<T> for Fungibility {
310 fn from(instance: T) -> Fungibility {
311 Fungibility::NonFungible(instance.into())
312 }
313}
314
315impl TryFrom<OldFungibility> for Fungibility {
316 type Error = ();
317 fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
318 use OldFungibility::*;
319 Ok(match value {
320 Fungible(n) => Self::Fungible(n),
321 NonFungible(i) => Self::NonFungible(i.try_into()?),
322 })
323 }
324}
325
326#[derive(
328 Copy,
329 Clone,
330 Eq,
331 PartialEq,
332 Ord,
333 PartialOrd,
334 Debug,
335 Encode,
336 Decode,
337 TypeInfo,
338 MaxEncodedLen,
339 serde::Serialize,
340 serde::Deserialize,
341)]
342pub enum WildFungibility {
343 Fungible,
345 NonFungible,
347}
348
349impl TryFrom<OldWildFungibility> for WildFungibility {
350 type Error = ();
351 fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
352 use OldWildFungibility::*;
353 Ok(match value {
354 Fungible => Self::Fungible,
355 NonFungible => Self::NonFungible,
356 })
357 }
358}
359
360#[derive(
362 Clone,
363 Eq,
364 PartialEq,
365 Ord,
366 PartialOrd,
367 Debug,
368 Encode,
369 Decode,
370 TypeInfo,
371 MaxEncodedLen,
372 serde::Serialize,
373 serde::Deserialize,
374)]
375pub struct AssetId(pub Location);
376
377impl<T: Into<Location>> From<T> for AssetId {
378 fn from(x: T) -> Self {
379 Self(x.into())
380 }
381}
382
383impl TryFrom<OldAssetId> for AssetId {
384 type Error = ();
385 fn try_from(old: OldAssetId) -> Result<Self, ()> {
386 use OldAssetId::*;
387 Ok(match old {
388 Concrete(l) => Self(l.try_into()?),
389 Abstract(_) => return Err(()),
390 })
391 }
392}
393
394impl AssetId {
395 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
397 self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
398 Ok(())
399 }
400
401 pub fn into_asset(self, fun: Fungibility) -> Asset {
404 Asset { fun, id: self }
405 }
406
407 pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
410 WildAsset::AllOf { fun, id: self }
411 }
412}
413
414impl Reanchorable for AssetId {
415 type Error = ();
416
417 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
420 self.0.reanchor(target, context)?;
421 Ok(())
422 }
423
424 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
425 match self.reanchor(target, context) {
426 Ok(()) => Ok(self),
427 Err(()) => Err(()),
428 }
429 }
430}
431
432#[derive(
434 Clone,
435 Eq,
436 PartialEq,
437 Debug,
438 Encode,
439 Decode,
440 TypeInfo,
441 MaxEncodedLen,
442 serde::Serialize,
443 serde::Deserialize,
444)]
445pub struct Asset {
446 pub id: AssetId,
448 pub fun: Fungibility,
451}
452
453impl PartialOrd for Asset {
454 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
455 Some(self.cmp(other))
456 }
457}
458
459impl Ord for Asset {
460 fn cmp(&self, other: &Self) -> Ordering {
461 match (&self.fun, &other.fun) {
462 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
463 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
464 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
465 }
466 }
467}
468
469impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
470 fn from((id, fun): (A, B)) -> Asset {
471 Asset { fun: fun.into(), id: id.into() }
472 }
473}
474
475impl Asset {
476 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
477 use Fungibility::*;
478 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
479 }
480
481 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
482 use Fungibility::*;
483 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
484 }
485
486 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
488 self.id.prepend_with(prepend)
489 }
490
491 pub fn contains(&self, inner: &Asset) -> bool {
493 use Fungibility::*;
494 if self.id == inner.id {
495 match (&self.fun, &inner.fun) {
496 (Fungible(a), Fungible(i)) if a >= i => return true,
497 (NonFungible(a), NonFungible(i)) if a == i => return true,
498 _ => (),
499 }
500 }
501 false
502 }
503}
504
505impl Reanchorable for Asset {
506 type Error = ();
507
508 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
511 self.id.reanchor(target, context)
512 }
513
514 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
517 self.id.reanchor(target, context)?;
518 Ok(self)
519 }
520}
521
522impl TryFrom<OldAsset> for Asset {
523 type Error = ();
524 fn try_from(old: OldAsset) -> Result<Self, ()> {
525 Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
526 }
527}
528
529#[derive(
537 Clone,
538 Eq,
539 PartialEq,
540 Ord,
541 PartialOrd,
542 Debug,
543 Encode,
544 TypeInfo,
545 Default,
546 serde::Serialize,
547 serde::Deserialize,
548)]
549pub struct Assets(Vec<Asset>);
550
551pub const MAX_ITEMS_IN_ASSETS: usize = 20;
554
555impl MaxEncodedLen for Assets {
556 fn max_encoded_len() -> usize {
557 Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
558 }
559}
560
561impl Decode for Assets {
562 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
563 let bounded_instructions =
564 BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
565 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
566 .map_err(|()| "Out of order".into())
567 }
568}
569
570impl TryFrom<OldAssets> for Assets {
571 type Error = ();
572 fn try_from(old: OldAssets) -> Result<Self, ()> {
573 let v = old
574 .into_inner()
575 .into_iter()
576 .map(Asset::try_from)
577 .collect::<Result<Vec<_>, ()>>()?;
578 Ok(Assets(v))
579 }
580}
581
582impl From<Vec<Asset>> for Assets {
583 fn from(mut assets: Vec<Asset>) -> Self {
584 let mut res = Vec::with_capacity(assets.len());
585 if !assets.is_empty() {
586 assets.sort();
587 let mut iter = assets.into_iter();
588 if let Some(first) = iter.next() {
589 let last = iter.fold(first, |a, b| -> Asset {
590 match (a, b) {
591 (
592 Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
593 Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
594 ) if a_id == b_id => Asset {
595 id: a_id,
596 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
597 },
598 (
599 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
600 Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
601 ) if a_id == b_id && a_instance == b_instance =>
602 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
603 (to_push, to_remember) => {
604 res.push(to_push);
605 to_remember
606 },
607 }
608 });
609 res.push(last);
610 }
611 }
612 Self(res)
613 }
614}
615
616impl<T: Into<Asset>> From<T> for Assets {
617 fn from(x: T) -> Self {
618 Self(vec![x.into()])
619 }
620}
621
622impl Assets {
623 pub fn new() -> Self {
625 Self(Vec::new())
626 }
627
628 pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
635 if r.is_empty() {
636 return Ok(Self(Vec::new()))
637 }
638 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
639 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
640 Ok(b)
641 } else {
642 Err(())
643 }
644 })?;
645 Ok(Self(r))
646 }
647
648 #[cfg(test)]
655 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
656 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
657 }
658 #[cfg(not(test))]
667 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
668 Self(r)
669 }
670
671 pub fn push(&mut self, a: Asset) {
674 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
675 match (&a.fun, &mut asset.fun) {
676 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
677 *balance = balance.saturating_add(*amount);
678 return
679 },
680 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
681 if inst1 == inst2 =>
682 return,
683 _ => (),
684 }
685 }
686 self.0.push(a);
687 self.0.sort();
688 }
689
690 pub fn is_none(&self) -> bool {
692 self.0.is_empty()
693 }
694
695 pub fn contains(&self, inner: &Asset) -> bool {
697 self.0.iter().any(|i| i.contains(inner))
698 }
699
700 #[deprecated = "Use `into_inner()` instead"]
702 pub fn drain(self) -> Vec<Asset> {
703 self.0
704 }
705
706 pub fn into_inner(self) -> Vec<Asset> {
708 self.0
709 }
710
711 pub fn inner(&self) -> &Vec<Asset> {
713 &self.0
714 }
715
716 pub fn len(&self) -> usize {
718 self.0.len()
719 }
720
721 pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
723 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
724 self.0.sort();
725 Ok(())
726 }
727
728 pub fn get(&self, index: usize) -> Option<&Asset> {
730 self.0.get(index)
731 }
732}
733
734impl Reanchorable for Assets {
735 type Error = ();
736
737 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
738 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
739 self.0.sort();
740 Ok(())
741 }
742
743 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
744 match self.reanchor(target, context) {
745 Ok(()) => Ok(self),
746 Err(()) => Err(()),
747 }
748 }
749}
750
751#[derive(
753 Clone,
754 Eq,
755 PartialEq,
756 Ord,
757 PartialOrd,
758 Debug,
759 Encode,
760 Decode,
761 TypeInfo,
762 MaxEncodedLen,
763 serde::Serialize,
764 serde::Deserialize,
765)]
766pub enum WildAsset {
767 All,
769 AllOf { id: AssetId, fun: WildFungibility },
771 AllCounted(#[codec(compact)] u32),
774 AllOfCounted {
777 id: AssetId,
778 fun: WildFungibility,
779 #[codec(compact)]
780 count: u32,
781 },
782}
783
784impl TryFrom<OldWildAsset> for WildAsset {
785 type Error = ();
786 fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
787 use OldWildAsset::*;
788 Ok(match old {
789 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
790 All => Self::All,
791 AllOfCounted { id, fun, count } =>
792 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
793 AllCounted(count) => Self::AllCounted(count),
794 })
795 }
796}
797
798impl WildAsset {
799 pub fn contains(&self, inner: &Asset) -> bool {
801 use WildAsset::*;
802 match self {
803 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
804 AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
805 inner.fun.is_kind(*fun) && &inner.id == id,
806 All | AllCounted(_) => true,
807 }
808 }
809
810 #[deprecated = "Use `contains` instead"]
815 pub fn matches(&self, inner: &Asset) -> bool {
816 self.contains(inner)
817 }
818
819 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
822 use WildAsset::*;
823 match self {
824 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
825 id.reanchor(target, context),
826 All | AllCounted(_) => Ok(()),
827 }
828 }
829
830 pub fn count(&self) -> Option<u32> {
832 use WildAsset::*;
833 match self {
834 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
835 All | AllOf { .. } => None,
836 }
837 }
838
839 pub fn limit(&self) -> Option<u32> {
841 self.count()
842 }
843
844 pub fn counted(self, count: u32) -> Self {
847 use WildAsset::*;
848 match self {
849 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
850 All | AllCounted(_) => AllCounted(count),
851 }
852 }
853}
854
855impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
856 fn from((id, fun): (A, B)) -> WildAsset {
857 WildAsset::AllOf { fun: fun.into(), id: id.into() }
858 }
859}
860
861#[derive(
863 Clone,
864 Eq,
865 PartialEq,
866 Ord,
867 PartialOrd,
868 Debug,
869 Encode,
870 Decode,
871 TypeInfo,
872 MaxEncodedLen,
873 serde::Serialize,
874 serde::Deserialize,
875)]
876pub enum AssetFilter {
877 Definite(Assets),
879 Wild(WildAsset),
881}
882
883impl<T: Into<WildAsset>> From<T> for AssetFilter {
884 fn from(x: T) -> Self {
885 Self::Wild(x.into())
886 }
887}
888
889impl From<Asset> for AssetFilter {
890 fn from(x: Asset) -> Self {
891 Self::Definite(vec![x].into())
892 }
893}
894
895impl From<Vec<Asset>> for AssetFilter {
896 fn from(x: Vec<Asset>) -> Self {
897 Self::Definite(x.into())
898 }
899}
900
901impl From<Assets> for AssetFilter {
902 fn from(x: Assets) -> Self {
903 Self::Definite(x)
904 }
905}
906
907impl AssetFilter {
908 pub fn matches(&self, inner: &Asset) -> bool {
913 match self {
914 AssetFilter::Definite(ref assets) => assets.contains(inner),
915 AssetFilter::Wild(ref wild) => wild.contains(inner),
916 }
917 }
918
919 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
922 match self {
923 AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
924 AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
925 }
926 }
927
928 pub fn count(&self) -> Option<u32> {
930 use AssetFilter::*;
931 match self {
932 Definite(x) => Some(x.len() as u32),
933 Wild(x) => x.count(),
934 }
935 }
936
937 pub fn limit(&self) -> Option<u32> {
939 use AssetFilter::*;
940 match self {
941 Definite(_) => None,
942 Wild(x) => x.limit(),
943 }
944 }
945}
946
947impl TryFrom<OldAssetFilter> for AssetFilter {
948 type Error = ();
949 fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
950 Ok(match old {
951 OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
952 OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
953 })
954 }
955}
956
957#[cfg(test)]
958mod tests {
959 use super::super::prelude::*;
960
961 #[test]
962 fn conversion_works() {
963 let _: Assets = (Here, 1u128).into();
964 }
965
966 #[test]
967 fn from_sorted_and_deduplicated_works() {
968 use super::*;
969 use alloc::vec;
970
971 let empty = vec![];
972 let r = Assets::from_sorted_and_deduplicated(empty);
973 assert_eq!(r, Ok(Assets(vec![])));
974
975 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
976 let r = Assets::from_sorted_and_deduplicated(dup_fun);
977 assert!(r.is_err());
978
979 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
980 let r = Assets::from_sorted_and_deduplicated(dup_nft);
981 assert!(r.is_err());
982
983 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
984 let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
985 assert_eq!(r, Ok(Assets(good_fun)));
986
987 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
988 let r = Assets::from_sorted_and_deduplicated(bad_fun);
989 assert!(r.is_err());
990
991 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
992 let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
993 assert_eq!(r, Ok(Assets(good_nft)));
994
995 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
996 let r = Assets::from_sorted_and_deduplicated(bad_nft);
997 assert!(r.is_err());
998
999 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1000 let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
1001 assert_eq!(r, Ok(Assets(mixed_good)));
1002
1003 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1004 let r = Assets::from_sorted_and_deduplicated(mixed_bad);
1005 assert!(r.is_err());
1006 }
1007
1008 #[test]
1009 fn reanchor_preserves_sorting() {
1010 use super::*;
1011 use alloc::vec;
1012
1013 let reanchor_context: Junctions = Parachain(2000).into();
1014 let dest = Location::new(1, []);
1015
1016 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1017 let mut asset_1_reanchored = asset_1.clone();
1018 assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1019 assert_eq!(
1020 asset_1_reanchored,
1021 (Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1022 );
1023
1024 let asset_2: Asset = (Location::new(1, []), 10).into();
1025 let mut asset_2_reanchored = asset_2.clone();
1026 assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1027 assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
1028
1029 let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
1030 let mut asset_3_reanchored = asset_3.clone();
1031 assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1032 assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
1033
1034 let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1035 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1036
1037 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1039
1040 assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
1041 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1042
1043 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1045 }
1046
1047 #[test]
1048 fn prepend_preserves_sorting() {
1049 use super::*;
1050 use alloc::vec;
1051
1052 let prefix = Location::new(0, [Parachain(1000)]);
1053
1054 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1055 let mut asset_1_prepended = asset_1.clone();
1056 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1057 assert_eq!(
1059 asset_1_prepended,
1060 (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1061 );
1062
1063 let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1064 let mut asset_2_prepended = asset_2.clone();
1065 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1066 assert_eq!(
1068 asset_2_prepended,
1069 (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1070 );
1071
1072 let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1073 let mut asset_3_prepended = asset_3.clone();
1074 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1075 assert_eq!(
1077 asset_3_prepended,
1078 (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1079 );
1080
1081 let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
1083 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1085
1086 assert!(assets.prepend_with(&prefix).is_ok());
1088 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1089
1090 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1092 }
1093
1094 #[test]
1095 fn decoding_respects_limit() {
1096 use super::*;
1097
1098 let lots_of_one_asset: Assets =
1100 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
1101 let encoded = lots_of_one_asset.encode();
1102 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1103
1104 let mut few_assets: Assets = Vec::new().into();
1106 for i in 0..MAX_ITEMS_IN_ASSETS {
1107 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1108 }
1109 let encoded = few_assets.encode();
1110 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1111
1112 let mut too_many_different_assets: Assets = Vec::new().into();
1114 for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
1115 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1116 }
1117 let encoded = too_many_different_assets.encode();
1118 assert!(Assets::decode(&mut &encoded[..]).is_err());
1119 }
1120}