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}
289
290impl Fungibility {
291 pub fn is_kind(&self, w: WildFungibility) -> bool {
292 use Fungibility::*;
293 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
294 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
295 }
296}
297
298impl From<i32> for Fungibility {
299 fn from(amount: i32) -> Fungibility {
300 debug_assert_ne!(amount, 0);
301 Fungibility::Fungible(amount as u128)
302 }
303}
304
305impl From<u128> for Fungibility {
306 fn from(amount: u128) -> Fungibility {
307 debug_assert_ne!(amount, 0);
308 Fungibility::Fungible(amount)
309 }
310}
311
312impl<T: Into<AssetInstance>> From<T> for Fungibility {
313 fn from(instance: T) -> Fungibility {
314 Fungibility::NonFungible(instance.into())
315 }
316}
317
318impl TryFrom<OldFungibility> for Fungibility {
319 type Error = ();
320 fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
321 use OldFungibility::*;
322 Ok(match value {
323 Fungible(n) => Self::Fungible(n),
324 NonFungible(i) => Self::NonFungible(i.try_into()?),
325 })
326 }
327}
328
329#[derive(
331 Copy,
332 Clone,
333 Eq,
334 PartialEq,
335 Ord,
336 PartialOrd,
337 Debug,
338 Encode,
339 Decode,
340 DecodeWithMemTracking,
341 TypeInfo,
342 MaxEncodedLen,
343 serde::Serialize,
344 serde::Deserialize,
345)]
346pub enum WildFungibility {
347 Fungible,
349 NonFungible,
351}
352
353impl TryFrom<OldWildFungibility> for WildFungibility {
354 type Error = ();
355 fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
356 use OldWildFungibility::*;
357 Ok(match value {
358 Fungible => Self::Fungible,
359 NonFungible => Self::NonFungible,
360 })
361 }
362}
363
364#[derive(
366 Clone,
367 Eq,
368 PartialEq,
369 Ord,
370 PartialOrd,
371 Debug,
372 Encode,
373 Decode,
374 DecodeWithMemTracking,
375 TypeInfo,
376 MaxEncodedLen,
377 serde::Serialize,
378 serde::Deserialize,
379)]
380pub struct AssetId(pub Location);
381
382impl<T: Into<Location>> From<T> for AssetId {
383 fn from(x: T) -> Self {
384 Self(x.into())
385 }
386}
387
388impl TryFrom<OldAssetId> for AssetId {
389 type Error = ();
390 fn try_from(old: OldAssetId) -> Result<Self, ()> {
391 Ok(Self(old.0.try_into()?))
392 }
393}
394
395impl AssetId {
396 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
398 self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
399 Ok(())
400 }
401
402 pub fn into_asset(self, fun: Fungibility) -> Asset {
405 Asset { fun, id: self }
406 }
407
408 pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
411 WildAsset::AllOf { fun, id: self }
412 }
413}
414
415impl Reanchorable for AssetId {
416 type Error = ();
417
418 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
421 self.0.reanchor(target, context)?;
422 Ok(())
423 }
424
425 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
426 match self.reanchor(target, context) {
427 Ok(()) => Ok(self),
428 Err(()) => Err(()),
429 }
430 }
431}
432
433#[derive(
435 Clone,
436 Eq,
437 PartialEq,
438 Debug,
439 Encode,
440 Decode,
441 DecodeWithMemTracking,
442 TypeInfo,
443 MaxEncodedLen,
444 serde::Serialize,
445 serde::Deserialize,
446)]
447pub struct Asset {
448 pub id: AssetId,
450 pub fun: Fungibility,
453}
454
455impl PartialOrd for Asset {
456 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
457 Some(self.cmp(other))
458 }
459}
460
461impl Ord for Asset {
462 fn cmp(&self, other: &Self) -> Ordering {
463 match (&self.fun, &other.fun) {
464 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
465 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
466 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
467 }
468 }
469}
470
471impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
472 fn from((id, fun): (A, B)) -> Asset {
473 Asset { fun: fun.into(), id: id.into() }
474 }
475}
476
477impl Asset {
478 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
479 use Fungibility::*;
480 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
481 }
482
483 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
484 use Fungibility::*;
485 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
486 }
487
488 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
490 self.id.prepend_with(prepend)
491 }
492
493 pub fn contains(&self, inner: &Asset) -> bool {
495 use Fungibility::*;
496 if self.id == inner.id {
497 match (&self.fun, &inner.fun) {
498 (Fungible(a), Fungible(i)) if a >= i => return true,
499 (NonFungible(a), NonFungible(i)) if a == i => return true,
500 _ => (),
501 }
502 }
503 false
504 }
505}
506
507impl Reanchorable for Asset {
508 type Error = ();
509
510 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
513 self.id.reanchor(target, context)
514 }
515
516 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
519 self.id.reanchor(target, context)?;
520 Ok(self)
521 }
522}
523
524impl TryFrom<OldAsset> for Asset {
525 type Error = ();
526 fn try_from(old: OldAsset) -> Result<Self, ()> {
527 Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
528 }
529}
530
531#[derive(
539 Clone,
540 Eq,
541 PartialEq,
542 Ord,
543 PartialOrd,
544 Debug,
545 Encode,
546 DecodeWithMemTracking,
547 TypeInfo,
548 Default,
549 serde::Serialize,
550 serde::Deserialize,
551)]
552pub struct Assets(Vec<Asset>);
553
554pub const MAX_ITEMS_IN_ASSETS: usize = 20;
557
558impl MaxEncodedLen for Assets {
559 fn max_encoded_len() -> usize {
560 Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
561 }
562}
563
564impl Decode for Assets {
565 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
566 let bounded_instructions =
567 BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
568 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
569 .map_err(|()| "Out of order".into())
570 }
571}
572
573impl TryFrom<OldAssets> for Assets {
574 type Error = ();
575 fn try_from(old: OldAssets) -> Result<Self, ()> {
576 let v = old
577 .into_inner()
578 .into_iter()
579 .map(Asset::try_from)
580 .collect::<Result<Vec<_>, ()>>()?;
581 Ok(Assets(v))
582 }
583}
584
585impl From<Vec<Asset>> for Assets {
586 fn from(mut assets: Vec<Asset>) -> Self {
587 let mut res = Vec::with_capacity(assets.len());
588 if !assets.is_empty() {
589 assets.sort();
590 let mut iter = assets.into_iter();
591 if let Some(first) = iter.next() {
592 let last = iter.fold(first, |a, b| -> Asset {
593 match (a, b) {
594 (
595 Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
596 Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
597 ) if a_id == b_id => Asset {
598 id: a_id,
599 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
600 },
601 (
602 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
603 Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
604 ) if a_id == b_id && a_instance == b_instance => {
605 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id }
606 },
607 (to_push, to_remember) => {
608 res.push(to_push);
609 to_remember
610 },
611 }
612 });
613 res.push(last);
614 }
615 }
616 Self(res)
617 }
618}
619
620impl<T: Into<Asset>> From<T> for Assets {
621 fn from(x: T) -> Self {
622 Self(vec![x.into()])
623 }
624}
625
626impl Assets {
627 pub fn new() -> Self {
629 Self(Vec::new())
630 }
631
632 pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
639 if r.is_empty() {
640 return Ok(Self(Vec::new()));
641 }
642 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
643 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
644 Ok(b)
645 } else {
646 Err(())
647 }
648 })?;
649 Ok(Self(r))
650 }
651
652 #[cfg(test)]
659 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
660 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
661 }
662 #[cfg(not(test))]
671 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
672 Self(r)
673 }
674
675 pub fn push(&mut self, a: Asset) {
678 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
679 match (&a.fun, &mut asset.fun) {
680 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
681 *balance = balance.saturating_add(*amount);
682 return;
683 },
684 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
685 if inst1 == inst2 =>
686 {
687 return
688 },
689 _ => (),
690 }
691 }
692 self.0.push(a);
693 self.0.sort();
694 }
695
696 pub fn is_none(&self) -> bool {
698 self.0.is_empty()
699 }
700
701 pub fn contains(&self, inner: &Asset) -> bool {
703 self.0.iter().any(|i| i.contains(inner))
704 }
705
706 #[deprecated = "Use `into_inner()` instead"]
708 pub fn drain(self) -> Vec<Asset> {
709 self.0
710 }
711
712 pub fn into_inner(self) -> Vec<Asset> {
714 self.0
715 }
716
717 pub fn inner(&self) -> &Vec<Asset> {
719 &self.0
720 }
721
722 pub fn len(&self) -> usize {
724 self.0.len()
725 }
726
727 pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
729 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
730 self.0.sort();
731 Ok(())
732 }
733
734 pub fn get(&self, index: usize) -> Option<&Asset> {
736 self.0.get(index)
737 }
738}
739
740impl Reanchorable for Assets {
741 type Error = ();
742
743 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
744 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
745 self.0.sort();
746 Ok(())
747 }
748
749 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
750 match self.reanchor(target, context) {
751 Ok(()) => Ok(self),
752 Err(()) => Err(()),
753 }
754 }
755}
756
757#[derive(
759 Clone,
760 Eq,
761 PartialEq,
762 Ord,
763 PartialOrd,
764 Debug,
765 Encode,
766 Decode,
767 DecodeWithMemTracking,
768 TypeInfo,
769 MaxEncodedLen,
770 serde::Serialize,
771 serde::Deserialize,
772)]
773pub enum WildAsset {
774 All,
776 AllOf { id: AssetId, fun: WildFungibility },
778 AllCounted(#[codec(compact)] u32),
781 AllOfCounted {
784 id: AssetId,
785 fun: WildFungibility,
786 #[codec(compact)]
787 count: u32,
788 },
789}
790
791impl TryFrom<OldWildAsset> for WildAsset {
792 type Error = ();
793 fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
794 use OldWildAsset::*;
795 Ok(match old {
796 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
797 All => Self::All,
798 AllOfCounted { id, fun, count } => {
799 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }
800 },
801 AllCounted(count) => Self::AllCounted(count),
802 })
803 }
804}
805
806impl WildAsset {
807 pub fn contains(&self, inner: &Asset) -> bool {
809 use WildAsset::*;
810 match self {
811 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
812 AllOf { fun, id } | AllOfCounted { id, fun, .. } => {
813 inner.fun.is_kind(*fun) && &inner.id == id
814 },
815 All | AllCounted(_) => true,
816 }
817 }
818
819 #[deprecated = "Use `contains` instead"]
824 pub fn matches(&self, inner: &Asset) -> bool {
825 self.contains(inner)
826 }
827
828 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
831 use WildAsset::*;
832 match self {
833 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } => {
834 id.reanchor(target, context)
835 },
836 All | AllCounted(_) => Ok(()),
837 }
838 }
839
840 pub fn count(&self) -> Option<u32> {
842 use WildAsset::*;
843 match self {
844 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
845 All | AllOf { .. } => None,
846 }
847 }
848
849 pub fn limit(&self) -> Option<u32> {
851 self.count()
852 }
853
854 pub fn counted(self, count: u32) -> Self {
857 use WildAsset::*;
858 match self {
859 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
860 All | AllCounted(_) => AllCounted(count),
861 }
862 }
863}
864
865impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
866 fn from((id, fun): (A, B)) -> WildAsset {
867 WildAsset::AllOf { fun: fun.into(), id: id.into() }
868 }
869}
870
871#[derive(
873 Clone,
874 Eq,
875 PartialEq,
876 Ord,
877 PartialOrd,
878 Debug,
879 Encode,
880 Decode,
881 DecodeWithMemTracking,
882 TypeInfo,
883 MaxEncodedLen,
884 serde::Serialize,
885 serde::Deserialize,
886)]
887pub enum AssetFilter {
888 Definite(Assets),
890 Wild(WildAsset),
892}
893
894impl<T: Into<WildAsset>> From<T> for AssetFilter {
895 fn from(x: T) -> Self {
896 Self::Wild(x.into())
897 }
898}
899
900impl From<Asset> for AssetFilter {
901 fn from(x: Asset) -> Self {
902 Self::Definite(vec![x].into())
903 }
904}
905
906impl From<Vec<Asset>> for AssetFilter {
907 fn from(x: Vec<Asset>) -> Self {
908 Self::Definite(x.into())
909 }
910}
911
912impl From<Assets> for AssetFilter {
913 fn from(x: Assets) -> Self {
914 Self::Definite(x)
915 }
916}
917
918impl AssetFilter {
919 pub fn matches(&self, inner: &Asset) -> bool {
924 match self {
925 AssetFilter::Definite(ref assets) => assets.contains(inner),
926 AssetFilter::Wild(ref wild) => wild.contains(inner),
927 }
928 }
929
930 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
933 match self {
934 AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
935 AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
936 }
937 }
938
939 pub fn count(&self) -> Option<u32> {
941 use AssetFilter::*;
942 match self {
943 Definite(x) => Some(x.len() as u32),
944 Wild(x) => x.count(),
945 }
946 }
947
948 pub fn limit(&self) -> Option<u32> {
950 use AssetFilter::*;
951 match self {
952 Definite(_) => None,
953 Wild(x) => x.limit(),
954 }
955 }
956}
957
958impl TryFrom<OldAssetFilter> for AssetFilter {
959 type Error = ();
960 fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
961 Ok(match old {
962 OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
963 OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
964 })
965 }
966}
967
968#[derive(
972 Clone,
973 Eq,
974 PartialEq,
975 Ord,
976 PartialOrd,
977 Debug,
978 Encode,
979 Decode,
980 DecodeWithMemTracking,
981 TypeInfo,
982 MaxEncodedLen,
983 serde::Serialize,
984 serde::Deserialize,
985)]
986pub enum AssetTransferFilter {
987 Teleport(AssetFilter),
989 ReserveDeposit(AssetFilter),
992 ReserveWithdraw(AssetFilter),
995}
996
997impl AssetTransferFilter {
998 pub fn inner(&self) -> &AssetFilter {
1000 match self {
1001 AssetTransferFilter::Teleport(inner) => inner,
1002 AssetTransferFilter::ReserveDeposit(inner) => inner,
1003 AssetTransferFilter::ReserveWithdraw(inner) => inner,
1004 }
1005 }
1006}
1007
1008#[cfg(test)]
1009mod tests {
1010 use super::super::prelude::*;
1011
1012 #[test]
1013 fn conversion_works() {
1014 let _: Assets = (Here, 1u128).into();
1015 }
1016
1017 #[test]
1018 fn from_sorted_and_deduplicated_works() {
1019 use super::*;
1020 use alloc::vec;
1021
1022 let empty = vec![];
1023 let r = Assets::from_sorted_and_deduplicated(empty);
1024 assert_eq!(r, Ok(Assets(vec![])));
1025
1026 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1027 let r = Assets::from_sorted_and_deduplicated(dup_fun);
1028 assert!(r.is_err());
1029
1030 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1031 let r = Assets::from_sorted_and_deduplicated(dup_nft);
1032 assert!(r.is_err());
1033
1034 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1035 let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
1036 assert_eq!(r, Ok(Assets(good_fun)));
1037
1038 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1039 let r = Assets::from_sorted_and_deduplicated(bad_fun);
1040 assert!(r.is_err());
1041
1042 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1043 let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
1044 assert_eq!(r, Ok(Assets(good_nft)));
1045
1046 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1047 let r = Assets::from_sorted_and_deduplicated(bad_nft);
1048 assert!(r.is_err());
1049
1050 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1051 let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
1052 assert_eq!(r, Ok(Assets(mixed_good)));
1053
1054 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1055 let r = Assets::from_sorted_and_deduplicated(mixed_bad);
1056 assert!(r.is_err());
1057 }
1058
1059 #[test]
1060 fn reanchor_preserves_sorting() {
1061 use super::*;
1062 use alloc::vec;
1063
1064 let reanchor_context: Junctions = Parachain(2000).into();
1065 let dest = Location::new(1, []);
1066
1067 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1068 let mut asset_1_reanchored = asset_1.clone();
1069 assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1070 assert_eq!(
1071 asset_1_reanchored,
1072 (Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1073 );
1074
1075 let asset_2: Asset = (Location::new(1, []), 10).into();
1076 let mut asset_2_reanchored = asset_2.clone();
1077 assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1078 assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
1079
1080 let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
1081 let mut asset_3_reanchored = asset_3.clone();
1082 assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1083 assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
1084
1085 let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1086 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1087
1088 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1090
1091 assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
1092 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1093
1094 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1096 }
1097
1098 #[test]
1099 fn prepend_preserves_sorting() {
1100 use super::*;
1101 use alloc::vec;
1102
1103 let prefix = Location::new(0, [Parachain(1000)]);
1104
1105 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1106 let mut asset_1_prepended = asset_1.clone();
1107 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1108 assert_eq!(
1110 asset_1_prepended,
1111 (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1112 );
1113
1114 let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1115 let mut asset_2_prepended = asset_2.clone();
1116 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1117 assert_eq!(
1119 asset_2_prepended,
1120 (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1121 );
1122
1123 let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1124 let mut asset_3_prepended = asset_3.clone();
1125 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1126 assert_eq!(
1128 asset_3_prepended,
1129 (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1130 );
1131
1132 let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
1134 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1136
1137 assert!(assets.prepend_with(&prefix).is_ok());
1139 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1140
1141 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1143 }
1144
1145 #[test]
1146 fn decoding_respects_limit() {
1147 use super::*;
1148
1149 let lots_of_one_asset: Assets =
1151 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
1152 let encoded = lots_of_one_asset.encode();
1153 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1154
1155 let mut few_assets: Assets = Vec::new().into();
1157 for i in 0..MAX_ITEMS_IN_ASSETS {
1158 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1159 }
1160 let encoded = few_assets.encode();
1161 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1162
1163 let mut too_many_different_assets: Assets = Vec::new().into();
1165 for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
1166 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1167 }
1168 let encoded = too_many_different_assets.encode();
1169 assert!(Assets::decode(&mut &encoded[..]).is_err());
1170 }
1171}