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