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}
293
294impl Fungibility {
295 pub fn is_kind(&self, w: WildFungibility) -> bool {
296 use Fungibility::*;
297 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
298 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
299 }
300}
301
302impl From<i32> for Fungibility {
303 fn from(amount: i32) -> Fungibility {
304 debug_assert_ne!(amount, 0);
305 Fungibility::Fungible(amount as u128)
306 }
307}
308
309impl From<u128> for Fungibility {
310 fn from(amount: u128) -> Fungibility {
311 debug_assert_ne!(amount, 0);
312 Fungibility::Fungible(amount)
313 }
314}
315
316impl<T: Into<AssetInstance>> From<T> for Fungibility {
317 fn from(instance: T) -> Fungibility {
318 Fungibility::NonFungible(instance.into())
319 }
320}
321
322impl TryFrom<NewFungibility> for Fungibility {
323 type Error = ();
324 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
325 use NewFungibility::*;
326 Ok(match value {
327 Fungible(n) => Self::Fungible(n),
328 NonFungible(i) => Self::NonFungible(i.try_into()?),
329 })
330 }
331}
332
333#[derive(
335 Copy,
336 Clone,
337 Eq,
338 PartialEq,
339 Ord,
340 PartialOrd,
341 Debug,
342 Encode,
343 Decode,
344 DecodeWithMemTracking,
345 TypeInfo,
346 MaxEncodedLen,
347 serde::Serialize,
348 serde::Deserialize,
349)]
350#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
351#[scale_info(replace_segment("staging_xcm", "xcm"))]
352pub enum WildFungibility {
353 Fungible,
355 NonFungible,
357}
358
359impl TryFrom<NewWildFungibility> for WildFungibility {
360 type Error = ();
361 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
362 use NewWildFungibility::*;
363 Ok(match value {
364 Fungible => Self::Fungible,
365 NonFungible => Self::NonFungible,
366 })
367 }
368}
369
370#[derive(
372 Copy,
373 Clone,
374 Eq,
375 PartialEq,
376 Ord,
377 PartialOrd,
378 Debug,
379 Encode,
380 Decode,
381 DecodeWithMemTracking,
382 TypeInfo,
383 MaxEncodedLen,
384 serde::Serialize,
385 serde::Deserialize,
386)]
387#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
388#[scale_info(replace_segment("staging_xcm", "xcm"))]
389pub enum AssetId {
390 Concrete(MultiLocation),
392 Abstract([u8; 32]),
395}
396
397impl<T: Into<MultiLocation>> From<T> for AssetId {
398 fn from(x: T) -> Self {
399 Self::Concrete(x.into())
400 }
401}
402
403impl From<[u8; 32]> for AssetId {
404 fn from(x: [u8; 32]) -> Self {
405 Self::Abstract(x)
406 }
407}
408
409impl TryFrom<NewAssetId> for AssetId {
410 type Error = ();
411 fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
412 Ok(Self::Concrete(new.0.try_into()?))
413 }
414}
415
416impl AssetId {
417 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
419 if let AssetId::Concrete(ref mut l) = self {
420 l.prepend_with(*prepend).map_err(|_| ())?;
421 }
422 Ok(())
423 }
424
425 pub fn reanchor(
428 &mut self,
429 target: &MultiLocation,
430 context: InteriorMultiLocation,
431 ) -> Result<(), ()> {
432 if let AssetId::Concrete(ref mut l) = self {
433 l.reanchor(target, context)?;
434 }
435 Ok(())
436 }
437
438 pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
441 MultiAsset { fun, id: self }
442 }
443
444 pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
447 WildMultiAsset::AllOf { fun, id: self }
448 }
449}
450
451#[derive(
453 Clone,
454 Eq,
455 PartialEq,
456 Debug,
457 Encode,
458 Decode,
459 DecodeWithMemTracking,
460 TypeInfo,
461 MaxEncodedLen,
462 serde::Serialize,
463 serde::Deserialize,
464)]
465#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
466#[scale_info(replace_segment("staging_xcm", "xcm"))]
467pub struct MultiAsset {
468 pub id: AssetId,
470 pub fun: Fungibility,
473}
474
475impl PartialOrd for MultiAsset {
476 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
477 Some(self.cmp(other))
478 }
479}
480
481impl Ord for MultiAsset {
482 fn cmp(&self, other: &Self) -> Ordering {
483 match (&self.fun, &other.fun) {
484 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
485 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
486 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
487 }
488 }
489}
490
491impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
492 fn from((id, fun): (A, B)) -> MultiAsset {
493 MultiAsset { fun: fun.into(), id: id.into() }
494 }
495}
496
497impl MultiAsset {
498 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
499 use Fungibility::*;
500 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
501 }
502
503 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
504 use Fungibility::*;
505 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
506 }
507
508 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
510 self.id.prepend_with(prepend)
511 }
512
513 pub fn reanchor(
516 &mut self,
517 target: &MultiLocation,
518 context: InteriorMultiLocation,
519 ) -> Result<(), ()> {
520 self.id.reanchor(target, context)
521 }
522
523 pub fn reanchored(
526 mut self,
527 target: &MultiLocation,
528 context: InteriorMultiLocation,
529 ) -> Result<Self, ()> {
530 self.id.reanchor(target, context)?;
531 Ok(self)
532 }
533
534 pub fn contains(&self, inner: &MultiAsset) -> bool {
536 use Fungibility::*;
537 if self.id == inner.id {
538 match (&self.fun, &inner.fun) {
539 (Fungible(a), Fungible(i)) if a >= i => return true,
540 (NonFungible(a), NonFungible(i)) if a == i => return true,
541 _ => (),
542 }
543 }
544 false
545 }
546}
547
548impl TryFrom<NewMultiAsset> for MultiAsset {
549 type Error = ();
550 fn try_from(new: NewMultiAsset) -> Result<Self, Self::Error> {
551 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
552 }
553}
554
555#[derive(
563 Clone,
564 Eq,
565 PartialEq,
566 Ord,
567 PartialOrd,
568 Debug,
569 Encode,
570 DecodeWithMemTracking,
571 TypeInfo,
572 Default,
573 serde::Serialize,
574 serde::Deserialize,
575)]
576#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
577#[scale_info(replace_segment("staging_xcm", "xcm"))]
578pub struct MultiAssets(Vec<MultiAsset>);
579
580pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
582
583impl MaxEncodedLen for MultiAssets {
584 fn max_encoded_len() -> usize {
585 MultiAsset::max_encoded_len() * MAX_ITEMS_IN_MULTIASSETS
586 }
587}
588
589impl Decode for MultiAssets {
590 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
591 let bounded_instructions =
592 BoundedVec::<MultiAsset, ConstU32<{ MAX_ITEMS_IN_MULTIASSETS as u32 }>>::decode(input)?;
593 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
594 .map_err(|()| "Out of order".into())
595 }
596}
597
598impl TryFrom<NewMultiAssets> for MultiAssets {
599 type Error = ();
600 fn try_from(new: NewMultiAssets) -> Result<Self, Self::Error> {
601 let v = new
602 .into_inner()
603 .into_iter()
604 .map(MultiAsset::try_from)
605 .collect::<Result<Vec<_>, ()>>()?;
606 Ok(MultiAssets(v))
607 }
608}
609
610impl From<Vec<MultiAsset>> for MultiAssets {
611 fn from(mut assets: Vec<MultiAsset>) -> Self {
612 let mut res = Vec::with_capacity(assets.len());
613 if !assets.is_empty() {
614 assets.sort();
615 let mut iter = assets.into_iter();
616 if let Some(first) = iter.next() {
617 let last = iter.fold(first, |a, b| -> MultiAsset {
618 match (a, b) {
619 (
620 MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
621 MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
622 ) if a_id == b_id => MultiAsset {
623 id: a_id,
624 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
625 },
626 (
627 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
628 MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
629 ) if a_id == b_id && a_instance == b_instance => {
630 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id }
631 },
632 (to_push, to_remember) => {
633 res.push(to_push);
634 to_remember
635 },
636 }
637 });
638 res.push(last);
639 }
640 }
641 Self(res)
642 }
643}
644
645impl<T: Into<MultiAsset>> From<T> for MultiAssets {
646 fn from(x: T) -> Self {
647 Self(vec![x.into()])
648 }
649}
650
651impl MultiAssets {
652 pub fn new() -> Self {
654 Self(Vec::new())
655 }
656
657 pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
664 if r.is_empty() {
665 return Ok(Self(Vec::new()));
666 }
667 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
668 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
669 Ok(b)
670 } else {
671 Err(())
672 }
673 })?;
674 Ok(Self(r))
675 }
676
677 #[cfg(test)]
684 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
685 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
686 }
687 #[cfg(not(test))]
696 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
697 Self(r)
698 }
699
700 pub fn push(&mut self, a: MultiAsset) {
703 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
704 match (&a.fun, &mut asset.fun) {
705 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
706 *balance = balance.saturating_add(*amount);
707 return;
708 },
709 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
710 if inst1 == inst2 =>
711 {
712 return
713 },
714 _ => (),
715 }
716 }
717 self.0.push(a);
718 self.0.sort();
719 }
720
721 pub fn is_none(&self) -> bool {
723 self.0.is_empty()
724 }
725
726 pub fn contains(&self, inner: &MultiAsset) -> bool {
728 self.0.iter().any(|i| i.contains(inner))
729 }
730
731 #[deprecated = "Use `into_inner()` instead"]
733 pub fn drain(self) -> Vec<MultiAsset> {
734 self.0
735 }
736
737 pub fn into_inner(self) -> Vec<MultiAsset> {
739 self.0
740 }
741
742 pub fn inner(&self) -> &Vec<MultiAsset> {
744 &self.0
745 }
746
747 pub fn len(&self) -> usize {
749 self.0.len()
750 }
751
752 pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
754 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
755 self.0.sort();
756 Ok(())
757 }
758
759 pub fn reanchor(
764 &mut self,
765 target: &MultiLocation,
766 context: InteriorMultiLocation,
767 ) -> Result<(), ()> {
768 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
769 self.0.sort();
770 Ok(())
771 }
772
773 pub fn get(&self, index: usize) -> Option<&MultiAsset> {
775 self.0.get(index)
776 }
777}
778
779#[derive(
781 Clone,
782 Eq,
783 PartialEq,
784 Ord,
785 PartialOrd,
786 Debug,
787 Encode,
788 Decode,
789 DecodeWithMemTracking,
790 TypeInfo,
791 MaxEncodedLen,
792 serde::Serialize,
793 serde::Deserialize,
794)]
795#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
796#[scale_info(replace_segment("staging_xcm", "xcm"))]
797pub enum WildMultiAsset {
798 All,
800 AllOf { id: AssetId, fun: WildFungibility },
802 AllCounted(#[codec(compact)] u32),
805 AllOfCounted {
808 id: AssetId,
809 fun: WildFungibility,
810 #[codec(compact)]
811 count: u32,
812 },
813}
814
815impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
816 type Error = ();
817 fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
818 use NewWildMultiAsset::*;
819 Ok(match new {
820 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
821 AllOfCounted { id, fun, count } => {
822 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }
823 },
824 All => Self::All,
825 AllCounted(count) => Self::AllCounted(count),
826 })
827 }
828}
829
830impl WildMultiAsset {
831 pub fn contains(&self, inner: &MultiAsset) -> bool {
833 use WildMultiAsset::*;
834 match self {
835 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
836 AllOf { fun, id } | AllOfCounted { id, fun, .. } => {
837 inner.fun.is_kind(*fun) && &inner.id == id
838 },
839 All | AllCounted(_) => true,
840 }
841 }
842
843 #[deprecated = "Use `contains` instead"]
848 pub fn matches(&self, inner: &MultiAsset) -> bool {
849 self.contains(inner)
850 }
851
852 pub fn reanchor(
855 &mut self,
856 target: &MultiLocation,
857 context: InteriorMultiLocation,
858 ) -> Result<(), ()> {
859 use WildMultiAsset::*;
860 match self {
861 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } => {
862 id.reanchor(target, context)
863 },
864 All | AllCounted(_) => Ok(()),
865 }
866 }
867
868 pub fn count(&self) -> Option<u32> {
870 use WildMultiAsset::*;
871 match self {
872 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
873 All | AllOf { .. } => None,
874 }
875 }
876
877 pub fn limit(&self) -> Option<u32> {
879 self.count()
880 }
881
882 pub fn counted(self, count: u32) -> Self {
885 use WildMultiAsset::*;
886 match self {
887 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
888 All | AllCounted(_) => AllCounted(count),
889 }
890 }
891}
892
893impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
894 fn from((id, fun): (A, B)) -> WildMultiAsset {
895 WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
896 }
897}
898
899#[derive(
901 Clone,
902 Eq,
903 PartialEq,
904 Ord,
905 PartialOrd,
906 Debug,
907 Encode,
908 Decode,
909 DecodeWithMemTracking,
910 TypeInfo,
911 MaxEncodedLen,
912 serde::Serialize,
913 serde::Deserialize,
914)]
915#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
916#[scale_info(replace_segment("staging_xcm", "xcm"))]
917pub enum MultiAssetFilter {
918 Definite(MultiAssets),
920 Wild(WildMultiAsset),
922}
923
924impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
925 fn from(x: T) -> Self {
926 Self::Wild(x.into())
927 }
928}
929
930impl From<MultiAsset> for MultiAssetFilter {
931 fn from(x: MultiAsset) -> Self {
932 Self::Definite(vec![x].into())
933 }
934}
935
936impl From<Vec<MultiAsset>> for MultiAssetFilter {
937 fn from(x: Vec<MultiAsset>) -> Self {
938 Self::Definite(x.into())
939 }
940}
941
942impl From<MultiAssets> for MultiAssetFilter {
943 fn from(x: MultiAssets) -> Self {
944 Self::Definite(x)
945 }
946}
947
948impl MultiAssetFilter {
949 pub fn matches(&self, inner: &MultiAsset) -> bool {
954 match self {
955 MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
956 MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
957 }
958 }
959
960 pub fn reanchor(
963 &mut self,
964 target: &MultiLocation,
965 context: InteriorMultiLocation,
966 ) -> Result<(), ()> {
967 match self {
968 MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
969 MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
970 }
971 }
972
973 pub fn count(&self) -> Option<u32> {
975 use MultiAssetFilter::*;
976 match self {
977 Definite(x) => Some(x.len() as u32),
978 Wild(x) => x.count(),
979 }
980 }
981
982 pub fn limit(&self) -> Option<u32> {
984 use MultiAssetFilter::*;
985 match self {
986 Definite(_) => None,
987 Wild(x) => x.limit(),
988 }
989 }
990}
991
992impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
993 type Error = ();
994 fn try_from(new: NewMultiAssetFilter) -> Result<MultiAssetFilter, Self::Error> {
995 use NewMultiAssetFilter::*;
996 Ok(match new {
997 Definite(x) => Self::Definite(x.try_into()?),
998 Wild(x) => Self::Wild(x.try_into()?),
999 })
1000 }
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005 use super::super::prelude::*;
1006
1007 #[test]
1008 fn conversion_works() {
1009 let _: MultiAssets = (Here, 1u128).into();
1010 }
1011
1012 #[test]
1013 fn from_sorted_and_deduplicated_works() {
1014 use super::*;
1015 use alloc::vec;
1016
1017 let empty = vec![];
1018 let r = MultiAssets::from_sorted_and_deduplicated(empty);
1019 assert_eq!(r, Ok(MultiAssets(vec![])));
1020
1021 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1022 let r = MultiAssets::from_sorted_and_deduplicated(dup_fun);
1023 assert!(r.is_err());
1024
1025 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1026 let r = MultiAssets::from_sorted_and_deduplicated(dup_nft);
1027 assert!(r.is_err());
1028
1029 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1030 let r = MultiAssets::from_sorted_and_deduplicated(good_fun.clone());
1031 assert_eq!(r, Ok(MultiAssets(good_fun)));
1032
1033 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1034 let r = MultiAssets::from_sorted_and_deduplicated(bad_fun);
1035 assert!(r.is_err());
1036
1037 let good_abstract_fun = vec![(Here, 100).into(), ([0u8; 32], 10).into()];
1038 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_fun.clone());
1039 assert_eq!(r, Ok(MultiAssets(good_abstract_fun)));
1040
1041 let bad_abstract_fun = vec![([0u8; 32], 10).into(), (Here, 10).into()];
1042 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_fun);
1043 assert!(r.is_err());
1044
1045 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1046 let r = MultiAssets::from_sorted_and_deduplicated(good_nft.clone());
1047 assert_eq!(r, Ok(MultiAssets(good_nft)));
1048
1049 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1050 let r = MultiAssets::from_sorted_and_deduplicated(bad_nft);
1051 assert!(r.is_err());
1052
1053 let good_abstract_nft = vec![(Here, ()).into(), ([0u8; 32], ()).into()];
1054 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_nft.clone());
1055 assert_eq!(r, Ok(MultiAssets(good_abstract_nft)));
1056
1057 let bad_abstract_nft = vec![([0u8; 32], ()).into(), (Here, ()).into()];
1058 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_nft);
1059 assert!(r.is_err());
1060
1061 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1062 let r = MultiAssets::from_sorted_and_deduplicated(mixed_good.clone());
1063 assert_eq!(r, Ok(MultiAssets(mixed_good)));
1064
1065 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1066 let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad);
1067 assert!(r.is_err());
1068 }
1069
1070 #[test]
1071 fn reanchor_preserves_sorting() {
1072 use super::*;
1073 use alloc::vec;
1074
1075 let reanchor_context = X1(Parachain(2000));
1076 let dest = MultiLocation::new(1, Here);
1077
1078 let asset_1: MultiAsset =
1079 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1080 let mut asset_1_reanchored = asset_1.clone();
1081 assert!(asset_1_reanchored.reanchor(&dest, reanchor_context).is_ok());
1082 assert_eq!(
1083 asset_1_reanchored,
1084 (MultiLocation::new(0, X3(Parachain(2000), PalletInstance(50), GeneralIndex(1))), 10)
1085 .into()
1086 );
1087
1088 let asset_2: MultiAsset = (MultiLocation::new(1, Here), 10).into();
1089 let mut asset_2_reanchored = asset_2.clone();
1090 assert!(asset_2_reanchored.reanchor(&dest, reanchor_context).is_ok());
1091 assert_eq!(asset_2_reanchored, (MultiLocation::new(0, Here), 10).into());
1092
1093 let asset_3: MultiAsset = (MultiLocation::new(1, X1(Parachain(1000))), 10).into();
1094 let mut asset_3_reanchored = asset_3.clone();
1095 assert!(asset_3_reanchored.reanchor(&dest, reanchor_context).is_ok());
1096 assert_eq!(asset_3_reanchored, (MultiLocation::new(0, X1(Parachain(1000))), 10).into());
1097
1098 let mut assets: MultiAssets =
1099 vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1100 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1101
1102 assert!(assets
1104 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1105 .is_ok());
1106
1107 assert!(assets.reanchor(&dest, reanchor_context).is_ok());
1108 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1109
1110 assert!(assets
1112 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1113 .is_ok());
1114 }
1115
1116 #[test]
1117 fn prepend_preserves_sorting() {
1118 use super::*;
1119 use alloc::vec;
1120
1121 let prefix = MultiLocation::new(0, X1(Parachain(1000)));
1122
1123 let asset_1: MultiAsset =
1124 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1125 let mut asset_1_prepended = asset_1.clone();
1126 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1127 assert_eq!(
1129 asset_1_prepended,
1130 (MultiLocation::new(0, X3(Parachain(1000), PalletInstance(50), GeneralIndex(1))), 10)
1131 .into()
1132 );
1133
1134 let asset_2: MultiAsset =
1135 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1136 let mut asset_2_prepended = asset_2.clone();
1137 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1138 assert_eq!(
1140 asset_2_prepended,
1141 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1142 );
1143
1144 let asset_3: MultiAsset =
1145 (MultiLocation::new(2, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1146 let mut asset_3_prepended = asset_3.clone();
1147 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1148 assert_eq!(
1150 asset_3_prepended,
1151 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1152 );
1153
1154 let mut assets: MultiAssets = vec![asset_1, asset_2, asset_3].into();
1156 assert!(assets
1158 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1159 .is_ok());
1160
1161 assert!(assets.prepend_with(&prefix).is_ok());
1163 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1164
1165 assert!(assets
1167 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1168 .is_ok());
1169 }
1170
1171 #[test]
1172 fn decoding_respects_limit() {
1173 use super::*;
1174
1175 let lots_of_one_asset: MultiAssets =
1177 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_MULTIASSETS + 1].into();
1178 let encoded = lots_of_one_asset.encode();
1179 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1180
1181 let mut few_assets: MultiAssets = Vec::new().into();
1183 for i in 0..MAX_ITEMS_IN_MULTIASSETS {
1184 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1185 }
1186 let encoded = few_assets.encode();
1187 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1188
1189 let mut too_many_different_assets: MultiAssets = Vec::new().into();
1191 for i in 0..MAX_ITEMS_IN_MULTIASSETS + 1 {
1192 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1193 }
1194 let encoded = too_many_different_assets.encode();
1195 assert!(MultiAssets::decode(&mut &encoded[..]).is_err());
1196 }
1197}