1use super::{InteriorMultiLocation, MultiLocation};
30use crate::v4::{
31 Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId,
32 AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility,
33 WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility,
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)]
58#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
59#[scale_info(replace_segment("staging_xcm", "xcm"))]
60pub enum AssetInstance {
61 Undefined,
63
64 Index(#[codec(compact)] u128),
67
68 Array4([u8; 4]),
70
71 Array8([u8; 8]),
73
74 Array16([u8; 16]),
76
77 Array32([u8; 32]),
79}
80
81impl TryFrom<NewAssetInstance> for AssetInstance {
82 type Error = ();
83 fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
84 use NewAssetInstance::*;
85 Ok(match value {
86 Undefined => Self::Undefined,
87 Index(n) => Self::Index(n),
88 Array4(n) => Self::Array4(n),
89 Array8(n) => Self::Array8(n),
90 Array16(n) => Self::Array16(n),
91 Array32(n) => Self::Array32(n),
92 })
93 }
94}
95
96impl From<()> for AssetInstance {
97 fn from(_: ()) -> Self {
98 Self::Undefined
99 }
100}
101
102impl From<[u8; 4]> for AssetInstance {
103 fn from(x: [u8; 4]) -> Self {
104 Self::Array4(x)
105 }
106}
107
108impl From<[u8; 8]> for AssetInstance {
109 fn from(x: [u8; 8]) -> Self {
110 Self::Array8(x)
111 }
112}
113
114impl From<[u8; 16]> for AssetInstance {
115 fn from(x: [u8; 16]) -> Self {
116 Self::Array16(x)
117 }
118}
119
120impl From<[u8; 32]> for AssetInstance {
121 fn from(x: [u8; 32]) -> Self {
122 Self::Array32(x)
123 }
124}
125
126impl From<u8> for AssetInstance {
127 fn from(x: u8) -> Self {
128 Self::Index(x as u128)
129 }
130}
131
132impl From<u16> for AssetInstance {
133 fn from(x: u16) -> Self {
134 Self::Index(x as u128)
135 }
136}
137
138impl From<u32> for AssetInstance {
139 fn from(x: u32) -> Self {
140 Self::Index(x as u128)
141 }
142}
143
144impl From<u64> for AssetInstance {
145 fn from(x: u64) -> Self {
146 Self::Index(x as u128)
147 }
148}
149
150impl TryFrom<AssetInstance> for () {
151 type Error = ();
152 fn try_from(x: AssetInstance) -> Result<Self, ()> {
153 match x {
154 AssetInstance::Undefined => Ok(()),
155 _ => Err(()),
156 }
157 }
158}
159
160impl TryFrom<AssetInstance> for [u8; 4] {
161 type Error = ();
162 fn try_from(x: AssetInstance) -> Result<Self, ()> {
163 match x {
164 AssetInstance::Array4(x) => Ok(x),
165 _ => Err(()),
166 }
167 }
168}
169
170impl TryFrom<AssetInstance> for [u8; 8] {
171 type Error = ();
172 fn try_from(x: AssetInstance) -> Result<Self, ()> {
173 match x {
174 AssetInstance::Array8(x) => Ok(x),
175 _ => Err(()),
176 }
177 }
178}
179
180impl TryFrom<AssetInstance> for [u8; 16] {
181 type Error = ();
182 fn try_from(x: AssetInstance) -> Result<Self, ()> {
183 match x {
184 AssetInstance::Array16(x) => Ok(x),
185 _ => Err(()),
186 }
187 }
188}
189
190impl TryFrom<AssetInstance> for [u8; 32] {
191 type Error = ();
192 fn try_from(x: AssetInstance) -> Result<Self, ()> {
193 match x {
194 AssetInstance::Array32(x) => Ok(x),
195 _ => Err(()),
196 }
197 }
198}
199
200impl TryFrom<AssetInstance> for u8 {
201 type Error = ();
202 fn try_from(x: AssetInstance) -> Result<Self, ()> {
203 match x {
204 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
205 _ => Err(()),
206 }
207 }
208}
209
210impl TryFrom<AssetInstance> for u16 {
211 type Error = ();
212 fn try_from(x: AssetInstance) -> Result<Self, ()> {
213 match x {
214 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
215 _ => Err(()),
216 }
217 }
218}
219
220impl TryFrom<AssetInstance> for u32 {
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 u64 {
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 u128 {
241 type Error = ();
242 fn try_from(x: AssetInstance) -> Result<Self, ()> {
243 match x {
244 AssetInstance::Index(x) => Ok(x),
245 _ => Err(()),
246 }
247 }
248}
249
250#[derive(
253 Clone,
254 Eq,
255 PartialEq,
256 Ord,
257 PartialOrd,
258 Debug,
259 Encode,
260 DecodeWithMemTracking,
261 TypeInfo,
262 MaxEncodedLen,
263 serde::Serialize,
264 serde::Deserialize,
265)]
266#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
267#[scale_info(replace_segment("staging_xcm", "xcm"))]
268pub enum Fungibility {
269 Fungible(#[codec(compact)] u128),
271 NonFungible(AssetInstance),
274}
275
276#[derive(Decode)]
277enum UncheckedFungibility {
278 Fungible(#[codec(compact)] u128),
279 NonFungible(AssetInstance),
280}
281
282impl Decode for Fungibility {
283 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
284 match UncheckedFungibility::decode(input)? {
285 UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
286 UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
287 UncheckedFungibility::Fungible(_) =>
288 Err("Fungible asset of zero amount is not allowed".into()),
289 }
290 }
291}
292
293impl Fungibility {
294 pub fn is_kind(&self, w: WildFungibility) -> bool {
295 use Fungibility::*;
296 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
297 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
298 }
299}
300
301impl From<i32> for Fungibility {
302 fn from(amount: i32) -> Fungibility {
303 debug_assert_ne!(amount, 0);
304 Fungibility::Fungible(amount as u128)
305 }
306}
307
308impl From<u128> for Fungibility {
309 fn from(amount: u128) -> Fungibility {
310 debug_assert_ne!(amount, 0);
311 Fungibility::Fungible(amount)
312 }
313}
314
315impl<T: Into<AssetInstance>> From<T> for Fungibility {
316 fn from(instance: T) -> Fungibility {
317 Fungibility::NonFungible(instance.into())
318 }
319}
320
321impl TryFrom<NewFungibility> for Fungibility {
322 type Error = ();
323 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
324 use NewFungibility::*;
325 Ok(match value {
326 Fungible(n) => Self::Fungible(n),
327 NonFungible(i) => Self::NonFungible(i.try_into()?),
328 })
329 }
330}
331
332#[derive(
334 Copy,
335 Clone,
336 Eq,
337 PartialEq,
338 Ord,
339 PartialOrd,
340 Debug,
341 Encode,
342 Decode,
343 DecodeWithMemTracking,
344 TypeInfo,
345 MaxEncodedLen,
346 serde::Serialize,
347 serde::Deserialize,
348)]
349#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
350#[scale_info(replace_segment("staging_xcm", "xcm"))]
351pub enum WildFungibility {
352 Fungible,
354 NonFungible,
356}
357
358impl TryFrom<NewWildFungibility> for WildFungibility {
359 type Error = ();
360 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
361 use NewWildFungibility::*;
362 Ok(match value {
363 Fungible => Self::Fungible,
364 NonFungible => Self::NonFungible,
365 })
366 }
367}
368
369#[derive(
371 Copy,
372 Clone,
373 Eq,
374 PartialEq,
375 Ord,
376 PartialOrd,
377 Debug,
378 Encode,
379 Decode,
380 DecodeWithMemTracking,
381 TypeInfo,
382 MaxEncodedLen,
383 serde::Serialize,
384 serde::Deserialize,
385)]
386#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
387#[scale_info(replace_segment("staging_xcm", "xcm"))]
388pub enum AssetId {
389 Concrete(MultiLocation),
391 Abstract([u8; 32]),
394}
395
396impl<T: Into<MultiLocation>> From<T> for AssetId {
397 fn from(x: T) -> Self {
398 Self::Concrete(x.into())
399 }
400}
401
402impl From<[u8; 32]> for AssetId {
403 fn from(x: [u8; 32]) -> Self {
404 Self::Abstract(x)
405 }
406}
407
408impl TryFrom<NewAssetId> for AssetId {
409 type Error = ();
410 fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
411 Ok(Self::Concrete(new.0.try_into()?))
412 }
413}
414
415impl AssetId {
416 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
418 if let AssetId::Concrete(ref mut l) = self {
419 l.prepend_with(*prepend).map_err(|_| ())?;
420 }
421 Ok(())
422 }
423
424 pub fn reanchor(
427 &mut self,
428 target: &MultiLocation,
429 context: InteriorMultiLocation,
430 ) -> Result<(), ()> {
431 if let AssetId::Concrete(ref mut l) = self {
432 l.reanchor(target, context)?;
433 }
434 Ok(())
435 }
436
437 pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
440 MultiAsset { fun, id: self }
441 }
442
443 pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
446 WildMultiAsset::AllOf { fun, id: self }
447 }
448}
449
450#[derive(
452 Clone,
453 Eq,
454 PartialEq,
455 Debug,
456 Encode,
457 Decode,
458 DecodeWithMemTracking,
459 TypeInfo,
460 MaxEncodedLen,
461 serde::Serialize,
462 serde::Deserialize,
463)]
464#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
465#[scale_info(replace_segment("staging_xcm", "xcm"))]
466pub struct MultiAsset {
467 pub id: AssetId,
469 pub fun: Fungibility,
472}
473
474impl PartialOrd for MultiAsset {
475 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
476 Some(self.cmp(other))
477 }
478}
479
480impl Ord for MultiAsset {
481 fn cmp(&self, other: &Self) -> Ordering {
482 match (&self.fun, &other.fun) {
483 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
484 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
485 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
486 }
487 }
488}
489
490impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
491 fn from((id, fun): (A, B)) -> MultiAsset {
492 MultiAsset { fun: fun.into(), id: id.into() }
493 }
494}
495
496impl MultiAsset {
497 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
498 use Fungibility::*;
499 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
500 }
501
502 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
503 use Fungibility::*;
504 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
505 }
506
507 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
509 self.id.prepend_with(prepend)
510 }
511
512 pub fn reanchor(
515 &mut self,
516 target: &MultiLocation,
517 context: InteriorMultiLocation,
518 ) -> Result<(), ()> {
519 self.id.reanchor(target, context)
520 }
521
522 pub fn reanchored(
525 mut self,
526 target: &MultiLocation,
527 context: InteriorMultiLocation,
528 ) -> Result<Self, ()> {
529 self.id.reanchor(target, context)?;
530 Ok(self)
531 }
532
533 pub fn contains(&self, inner: &MultiAsset) -> bool {
535 use Fungibility::*;
536 if self.id == inner.id {
537 match (&self.fun, &inner.fun) {
538 (Fungible(a), Fungible(i)) if a >= i => return true,
539 (NonFungible(a), NonFungible(i)) if a == i => return true,
540 _ => (),
541 }
542 }
543 false
544 }
545}
546
547impl TryFrom<NewMultiAsset> for MultiAsset {
548 type Error = ();
549 fn try_from(new: NewMultiAsset) -> Result<Self, Self::Error> {
550 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
551 }
552}
553
554#[derive(
562 Clone,
563 Eq,
564 PartialEq,
565 Ord,
566 PartialOrd,
567 Debug,
568 Encode,
569 DecodeWithMemTracking,
570 TypeInfo,
571 Default,
572 serde::Serialize,
573 serde::Deserialize,
574)]
575#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
576#[scale_info(replace_segment("staging_xcm", "xcm"))]
577pub struct MultiAssets(Vec<MultiAsset>);
578
579pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
581
582impl MaxEncodedLen for MultiAssets {
583 fn max_encoded_len() -> usize {
584 MultiAsset::max_encoded_len() * MAX_ITEMS_IN_MULTIASSETS
585 }
586}
587
588impl Decode for MultiAssets {
589 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
590 let bounded_instructions =
591 BoundedVec::<MultiAsset, ConstU32<{ MAX_ITEMS_IN_MULTIASSETS as u32 }>>::decode(input)?;
592 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
593 .map_err(|()| "Out of order".into())
594 }
595}
596
597impl TryFrom<NewMultiAssets> for MultiAssets {
598 type Error = ();
599 fn try_from(new: NewMultiAssets) -> Result<Self, Self::Error> {
600 let v = new
601 .into_inner()
602 .into_iter()
603 .map(MultiAsset::try_from)
604 .collect::<Result<Vec<_>, ()>>()?;
605 Ok(MultiAssets(v))
606 }
607}
608
609impl From<Vec<MultiAsset>> for MultiAssets {
610 fn from(mut assets: Vec<MultiAsset>) -> Self {
611 let mut res = Vec::with_capacity(assets.len());
612 if !assets.is_empty() {
613 assets.sort();
614 let mut iter = assets.into_iter();
615 if let Some(first) = iter.next() {
616 let last = iter.fold(first, |a, b| -> MultiAsset {
617 match (a, b) {
618 (
619 MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
620 MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
621 ) if a_id == b_id => MultiAsset {
622 id: a_id,
623 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
624 },
625 (
626 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
627 MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
628 ) if a_id == b_id && a_instance == b_instance =>
629 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
630 (to_push, to_remember) => {
631 res.push(to_push);
632 to_remember
633 },
634 }
635 });
636 res.push(last);
637 }
638 }
639 Self(res)
640 }
641}
642
643impl<T: Into<MultiAsset>> From<T> for MultiAssets {
644 fn from(x: T) -> Self {
645 Self(vec![x.into()])
646 }
647}
648
649impl MultiAssets {
650 pub fn new() -> Self {
652 Self(Vec::new())
653 }
654
655 pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
662 if r.is_empty() {
663 return Ok(Self(Vec::new()))
664 }
665 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
666 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
667 Ok(b)
668 } else {
669 Err(())
670 }
671 })?;
672 Ok(Self(r))
673 }
674
675 #[cfg(test)]
682 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
683 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
684 }
685 #[cfg(not(test))]
694 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
695 Self(r)
696 }
697
698 pub fn push(&mut self, a: MultiAsset) {
701 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
702 match (&a.fun, &mut asset.fun) {
703 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
704 *balance = balance.saturating_add(*amount);
705 return
706 },
707 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
708 if inst1 == inst2 =>
709 return,
710 _ => (),
711 }
712 }
713 self.0.push(a);
714 self.0.sort();
715 }
716
717 pub fn is_none(&self) -> bool {
719 self.0.is_empty()
720 }
721
722 pub fn contains(&self, inner: &MultiAsset) -> bool {
724 self.0.iter().any(|i| i.contains(inner))
725 }
726
727 #[deprecated = "Use `into_inner()` instead"]
729 pub fn drain(self) -> Vec<MultiAsset> {
730 self.0
731 }
732
733 pub fn into_inner(self) -> Vec<MultiAsset> {
735 self.0
736 }
737
738 pub fn inner(&self) -> &Vec<MultiAsset> {
740 &self.0
741 }
742
743 pub fn len(&self) -> usize {
745 self.0.len()
746 }
747
748 pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
750 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
751 self.0.sort();
752 Ok(())
753 }
754
755 pub fn reanchor(
760 &mut self,
761 target: &MultiLocation,
762 context: InteriorMultiLocation,
763 ) -> Result<(), ()> {
764 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
765 self.0.sort();
766 Ok(())
767 }
768
769 pub fn get(&self, index: usize) -> Option<&MultiAsset> {
771 self.0.get(index)
772 }
773}
774
775#[derive(
777 Clone,
778 Eq,
779 PartialEq,
780 Ord,
781 PartialOrd,
782 Debug,
783 Encode,
784 Decode,
785 DecodeWithMemTracking,
786 TypeInfo,
787 MaxEncodedLen,
788 serde::Serialize,
789 serde::Deserialize,
790)]
791#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
792#[scale_info(replace_segment("staging_xcm", "xcm"))]
793pub enum WildMultiAsset {
794 All,
796 AllOf { id: AssetId, fun: WildFungibility },
798 AllCounted(#[codec(compact)] u32),
801 AllOfCounted {
804 id: AssetId,
805 fun: WildFungibility,
806 #[codec(compact)]
807 count: u32,
808 },
809}
810
811impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
812 type Error = ();
813 fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
814 use NewWildMultiAsset::*;
815 Ok(match new {
816 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
817 AllOfCounted { id, fun, count } =>
818 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
819 All => Self::All,
820 AllCounted(count) => Self::AllCounted(count),
821 })
822 }
823}
824
825impl WildMultiAsset {
826 pub fn contains(&self, inner: &MultiAsset) -> bool {
828 use WildMultiAsset::*;
829 match self {
830 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
831 AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
832 inner.fun.is_kind(*fun) && &inner.id == id,
833 All | AllCounted(_) => true,
834 }
835 }
836
837 #[deprecated = "Use `contains` instead"]
842 pub fn matches(&self, inner: &MultiAsset) -> bool {
843 self.contains(inner)
844 }
845
846 pub fn reanchor(
849 &mut self,
850 target: &MultiLocation,
851 context: InteriorMultiLocation,
852 ) -> Result<(), ()> {
853 use WildMultiAsset::*;
854 match self {
855 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
856 id.reanchor(target, context),
857 All | AllCounted(_) => Ok(()),
858 }
859 }
860
861 pub fn count(&self) -> Option<u32> {
863 use WildMultiAsset::*;
864 match self {
865 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
866 All | AllOf { .. } => None,
867 }
868 }
869
870 pub fn limit(&self) -> Option<u32> {
872 self.count()
873 }
874
875 pub fn counted(self, count: u32) -> Self {
878 use WildMultiAsset::*;
879 match self {
880 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
881 All | AllCounted(_) => AllCounted(count),
882 }
883 }
884}
885
886impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
887 fn from((id, fun): (A, B)) -> WildMultiAsset {
888 WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
889 }
890}
891
892#[derive(
894 Clone,
895 Eq,
896 PartialEq,
897 Ord,
898 PartialOrd,
899 Debug,
900 Encode,
901 Decode,
902 DecodeWithMemTracking,
903 TypeInfo,
904 MaxEncodedLen,
905 serde::Serialize,
906 serde::Deserialize,
907)]
908#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
909#[scale_info(replace_segment("staging_xcm", "xcm"))]
910pub enum MultiAssetFilter {
911 Definite(MultiAssets),
913 Wild(WildMultiAsset),
915}
916
917impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
918 fn from(x: T) -> Self {
919 Self::Wild(x.into())
920 }
921}
922
923impl From<MultiAsset> for MultiAssetFilter {
924 fn from(x: MultiAsset) -> Self {
925 Self::Definite(vec![x].into())
926 }
927}
928
929impl From<Vec<MultiAsset>> for MultiAssetFilter {
930 fn from(x: Vec<MultiAsset>) -> Self {
931 Self::Definite(x.into())
932 }
933}
934
935impl From<MultiAssets> for MultiAssetFilter {
936 fn from(x: MultiAssets) -> Self {
937 Self::Definite(x)
938 }
939}
940
941impl MultiAssetFilter {
942 pub fn matches(&self, inner: &MultiAsset) -> bool {
947 match self {
948 MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
949 MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
950 }
951 }
952
953 pub fn reanchor(
956 &mut self,
957 target: &MultiLocation,
958 context: InteriorMultiLocation,
959 ) -> Result<(), ()> {
960 match self {
961 MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
962 MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
963 }
964 }
965
966 pub fn count(&self) -> Option<u32> {
968 use MultiAssetFilter::*;
969 match self {
970 Definite(x) => Some(x.len() as u32),
971 Wild(x) => x.count(),
972 }
973 }
974
975 pub fn limit(&self) -> Option<u32> {
977 use MultiAssetFilter::*;
978 match self {
979 Definite(_) => None,
980 Wild(x) => x.limit(),
981 }
982 }
983}
984
985impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
986 type Error = ();
987 fn try_from(new: NewMultiAssetFilter) -> Result<MultiAssetFilter, Self::Error> {
988 use NewMultiAssetFilter::*;
989 Ok(match new {
990 Definite(x) => Self::Definite(x.try_into()?),
991 Wild(x) => Self::Wild(x.try_into()?),
992 })
993 }
994}
995
996#[cfg(test)]
997mod tests {
998 use super::super::prelude::*;
999
1000 #[test]
1001 fn conversion_works() {
1002 let _: MultiAssets = (Here, 1u128).into();
1003 }
1004
1005 #[test]
1006 fn from_sorted_and_deduplicated_works() {
1007 use super::*;
1008 use alloc::vec;
1009
1010 let empty = vec![];
1011 let r = MultiAssets::from_sorted_and_deduplicated(empty);
1012 assert_eq!(r, Ok(MultiAssets(vec![])));
1013
1014 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1015 let r = MultiAssets::from_sorted_and_deduplicated(dup_fun);
1016 assert!(r.is_err());
1017
1018 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1019 let r = MultiAssets::from_sorted_and_deduplicated(dup_nft);
1020 assert!(r.is_err());
1021
1022 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1023 let r = MultiAssets::from_sorted_and_deduplicated(good_fun.clone());
1024 assert_eq!(r, Ok(MultiAssets(good_fun)));
1025
1026 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1027 let r = MultiAssets::from_sorted_and_deduplicated(bad_fun);
1028 assert!(r.is_err());
1029
1030 let good_abstract_fun = vec![(Here, 100).into(), ([0u8; 32], 10).into()];
1031 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_fun.clone());
1032 assert_eq!(r, Ok(MultiAssets(good_abstract_fun)));
1033
1034 let bad_abstract_fun = vec![([0u8; 32], 10).into(), (Here, 10).into()];
1035 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_fun);
1036 assert!(r.is_err());
1037
1038 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1039 let r = MultiAssets::from_sorted_and_deduplicated(good_nft.clone());
1040 assert_eq!(r, Ok(MultiAssets(good_nft)));
1041
1042 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1043 let r = MultiAssets::from_sorted_and_deduplicated(bad_nft);
1044 assert!(r.is_err());
1045
1046 let good_abstract_nft = vec![(Here, ()).into(), ([0u8; 32], ()).into()];
1047 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_nft.clone());
1048 assert_eq!(r, Ok(MultiAssets(good_abstract_nft)));
1049
1050 let bad_abstract_nft = vec![([0u8; 32], ()).into(), (Here, ()).into()];
1051 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_nft);
1052 assert!(r.is_err());
1053
1054 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1055 let r = MultiAssets::from_sorted_and_deduplicated(mixed_good.clone());
1056 assert_eq!(r, Ok(MultiAssets(mixed_good)));
1057
1058 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1059 let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad);
1060 assert!(r.is_err());
1061 }
1062
1063 #[test]
1064 fn reanchor_preserves_sorting() {
1065 use super::*;
1066 use alloc::vec;
1067
1068 let reanchor_context = X1(Parachain(2000));
1069 let dest = MultiLocation::new(1, Here);
1070
1071 let asset_1: MultiAsset =
1072 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1073 let mut asset_1_reanchored = asset_1.clone();
1074 assert!(asset_1_reanchored.reanchor(&dest, reanchor_context).is_ok());
1075 assert_eq!(
1076 asset_1_reanchored,
1077 (MultiLocation::new(0, X3(Parachain(2000), PalletInstance(50), GeneralIndex(1))), 10)
1078 .into()
1079 );
1080
1081 let asset_2: MultiAsset = (MultiLocation::new(1, Here), 10).into();
1082 let mut asset_2_reanchored = asset_2.clone();
1083 assert!(asset_2_reanchored.reanchor(&dest, reanchor_context).is_ok());
1084 assert_eq!(asset_2_reanchored, (MultiLocation::new(0, Here), 10).into());
1085
1086 let asset_3: MultiAsset = (MultiLocation::new(1, X1(Parachain(1000))), 10).into();
1087 let mut asset_3_reanchored = asset_3.clone();
1088 assert!(asset_3_reanchored.reanchor(&dest, reanchor_context).is_ok());
1089 assert_eq!(asset_3_reanchored, (MultiLocation::new(0, X1(Parachain(1000))), 10).into());
1090
1091 let mut assets: MultiAssets =
1092 vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1093 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1094
1095 assert!(assets
1097 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1098 .is_ok());
1099
1100 assert!(assets.reanchor(&dest, reanchor_context).is_ok());
1101 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1102
1103 assert!(assets
1105 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1106 .is_ok());
1107 }
1108
1109 #[test]
1110 fn prepend_preserves_sorting() {
1111 use super::*;
1112 use alloc::vec;
1113
1114 let prefix = MultiLocation::new(0, X1(Parachain(1000)));
1115
1116 let asset_1: MultiAsset =
1117 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1118 let mut asset_1_prepended = asset_1.clone();
1119 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1120 assert_eq!(
1122 asset_1_prepended,
1123 (MultiLocation::new(0, X3(Parachain(1000), PalletInstance(50), GeneralIndex(1))), 10)
1124 .into()
1125 );
1126
1127 let asset_2: MultiAsset =
1128 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1129 let mut asset_2_prepended = asset_2.clone();
1130 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1131 assert_eq!(
1133 asset_2_prepended,
1134 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1135 );
1136
1137 let asset_3: MultiAsset =
1138 (MultiLocation::new(2, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1139 let mut asset_3_prepended = asset_3.clone();
1140 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1141 assert_eq!(
1143 asset_3_prepended,
1144 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1145 );
1146
1147 let mut assets: MultiAssets = vec![asset_1, asset_2, asset_3].into();
1149 assert!(assets
1151 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1152 .is_ok());
1153
1154 assert!(assets.prepend_with(&prefix).is_ok());
1156 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1157
1158 assert!(assets
1160 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1161 .is_ok());
1162 }
1163
1164 #[test]
1165 fn decoding_respects_limit() {
1166 use super::*;
1167
1168 let lots_of_one_asset: MultiAssets =
1170 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_MULTIASSETS + 1].into();
1171 let encoded = lots_of_one_asset.encode();
1172 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1173
1174 let mut few_assets: MultiAssets = Vec::new().into();
1176 for i in 0..MAX_ITEMS_IN_MULTIASSETS {
1177 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1178 }
1179 let encoded = few_assets.encode();
1180 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1181
1182 let mut too_many_different_assets: MultiAssets = Vec::new().into();
1184 for i in 0..MAX_ITEMS_IN_MULTIASSETS + 1 {
1185 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1186 }
1187 let encoded = too_many_different_assets.encode();
1188 assert!(MultiAssets::decode(&mut &encoded[..]).is_err());
1189 }
1190}