1use super::{InteriorMultiLocation, MultiLocation};
30use crate::{
31 v2::{
32 AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
33 MultiAsset as OldMultiAsset, MultiAssetFilter as OldMultiAssetFilter,
34 MultiAssets as OldMultiAssets, WildFungibility as OldWildFungibility,
35 WildMultiAsset as OldWildMultiAsset,
36 },
37 v4::{
38 Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId,
39 AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility,
40 WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility,
41 },
42};
43use alloc::{vec, vec::Vec};
44use bounded_collections::{BoundedVec, ConstU32};
45use codec::{self as codec, Decode, Encode, MaxEncodedLen};
46use core::cmp::Ordering;
47use scale_info::TypeInfo;
48
49#[derive(
51 Copy,
52 Clone,
53 Eq,
54 PartialEq,
55 Ord,
56 PartialOrd,
57 Encode,
58 Decode,
59 Debug,
60 TypeInfo,
61 MaxEncodedLen,
62 serde::Serialize,
63 serde::Deserialize,
64)]
65#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
66#[scale_info(replace_segment("staging_xcm", "xcm"))]
67pub enum AssetInstance {
68 Undefined,
70
71 Index(#[codec(compact)] u128),
74
75 Array4([u8; 4]),
77
78 Array8([u8; 8]),
80
81 Array16([u8; 16]),
83
84 Array32([u8; 32]),
86}
87
88impl TryFrom<OldAssetInstance> for AssetInstance {
89 type Error = ();
90 fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
91 use OldAssetInstance::*;
92 Ok(match value {
93 Undefined => Self::Undefined,
94 Index(n) => Self::Index(n),
95 Array4(n) => Self::Array4(n),
96 Array8(n) => Self::Array8(n),
97 Array16(n) => Self::Array16(n),
98 Array32(n) => Self::Array32(n),
99 Blob(_) => return Err(()),
100 })
101 }
102}
103
104impl TryFrom<NewAssetInstance> for AssetInstance {
105 type Error = ();
106 fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
107 use NewAssetInstance::*;
108 Ok(match value {
109 Undefined => Self::Undefined,
110 Index(n) => Self::Index(n),
111 Array4(n) => Self::Array4(n),
112 Array8(n) => Self::Array8(n),
113 Array16(n) => Self::Array16(n),
114 Array32(n) => Self::Array32(n),
115 })
116 }
117}
118
119impl From<()> for AssetInstance {
120 fn from(_: ()) -> Self {
121 Self::Undefined
122 }
123}
124
125impl From<[u8; 4]> for AssetInstance {
126 fn from(x: [u8; 4]) -> Self {
127 Self::Array4(x)
128 }
129}
130
131impl From<[u8; 8]> for AssetInstance {
132 fn from(x: [u8; 8]) -> Self {
133 Self::Array8(x)
134 }
135}
136
137impl From<[u8; 16]> for AssetInstance {
138 fn from(x: [u8; 16]) -> Self {
139 Self::Array16(x)
140 }
141}
142
143impl From<[u8; 32]> for AssetInstance {
144 fn from(x: [u8; 32]) -> Self {
145 Self::Array32(x)
146 }
147}
148
149impl From<u8> for AssetInstance {
150 fn from(x: u8) -> Self {
151 Self::Index(x as u128)
152 }
153}
154
155impl From<u16> for AssetInstance {
156 fn from(x: u16) -> Self {
157 Self::Index(x as u128)
158 }
159}
160
161impl From<u32> for AssetInstance {
162 fn from(x: u32) -> Self {
163 Self::Index(x as u128)
164 }
165}
166
167impl From<u64> for AssetInstance {
168 fn from(x: u64) -> Self {
169 Self::Index(x as u128)
170 }
171}
172
173impl TryFrom<AssetInstance> for () {
174 type Error = ();
175 fn try_from(x: AssetInstance) -> Result<Self, ()> {
176 match x {
177 AssetInstance::Undefined => Ok(()),
178 _ => Err(()),
179 }
180 }
181}
182
183impl TryFrom<AssetInstance> for [u8; 4] {
184 type Error = ();
185 fn try_from(x: AssetInstance) -> Result<Self, ()> {
186 match x {
187 AssetInstance::Array4(x) => Ok(x),
188 _ => Err(()),
189 }
190 }
191}
192
193impl TryFrom<AssetInstance> for [u8; 8] {
194 type Error = ();
195 fn try_from(x: AssetInstance) -> Result<Self, ()> {
196 match x {
197 AssetInstance::Array8(x) => Ok(x),
198 _ => Err(()),
199 }
200 }
201}
202
203impl TryFrom<AssetInstance> for [u8; 16] {
204 type Error = ();
205 fn try_from(x: AssetInstance) -> Result<Self, ()> {
206 match x {
207 AssetInstance::Array16(x) => Ok(x),
208 _ => Err(()),
209 }
210 }
211}
212
213impl TryFrom<AssetInstance> for [u8; 32] {
214 type Error = ();
215 fn try_from(x: AssetInstance) -> Result<Self, ()> {
216 match x {
217 AssetInstance::Array32(x) => Ok(x),
218 _ => Err(()),
219 }
220 }
221}
222
223impl TryFrom<AssetInstance> for u8 {
224 type Error = ();
225 fn try_from(x: AssetInstance) -> Result<Self, ()> {
226 match x {
227 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
228 _ => Err(()),
229 }
230 }
231}
232
233impl TryFrom<AssetInstance> for u16 {
234 type Error = ();
235 fn try_from(x: AssetInstance) -> Result<Self, ()> {
236 match x {
237 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
238 _ => Err(()),
239 }
240 }
241}
242
243impl TryFrom<AssetInstance> for u32 {
244 type Error = ();
245 fn try_from(x: AssetInstance) -> Result<Self, ()> {
246 match x {
247 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
248 _ => Err(()),
249 }
250 }
251}
252
253impl TryFrom<AssetInstance> for u64 {
254 type Error = ();
255 fn try_from(x: AssetInstance) -> Result<Self, ()> {
256 match x {
257 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
258 _ => Err(()),
259 }
260 }
261}
262
263impl TryFrom<AssetInstance> for u128 {
264 type Error = ();
265 fn try_from(x: AssetInstance) -> Result<Self, ()> {
266 match x {
267 AssetInstance::Index(x) => Ok(x),
268 _ => Err(()),
269 }
270 }
271}
272
273#[derive(
276 Clone,
277 Eq,
278 PartialEq,
279 Ord,
280 PartialOrd,
281 Debug,
282 Encode,
283 TypeInfo,
284 MaxEncodedLen,
285 serde::Serialize,
286 serde::Deserialize,
287)]
288#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
289#[scale_info(replace_segment("staging_xcm", "xcm"))]
290pub enum Fungibility {
291 Fungible(#[codec(compact)] u128),
293 NonFungible(AssetInstance),
296}
297
298#[derive(Decode)]
299enum UncheckedFungibility {
300 Fungible(#[codec(compact)] u128),
301 NonFungible(AssetInstance),
302}
303
304impl Decode for Fungibility {
305 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
306 match UncheckedFungibility::decode(input)? {
307 UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
308 UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
309 UncheckedFungibility::Fungible(_) =>
310 Err("Fungible asset of zero amount is not allowed".into()),
311 }
312 }
313}
314
315impl Fungibility {
316 pub fn is_kind(&self, w: WildFungibility) -> bool {
317 use Fungibility::*;
318 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
319 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
320 }
321}
322
323impl From<i32> for Fungibility {
324 fn from(amount: i32) -> Fungibility {
325 debug_assert_ne!(amount, 0);
326 Fungibility::Fungible(amount as u128)
327 }
328}
329
330impl From<u128> for Fungibility {
331 fn from(amount: u128) -> Fungibility {
332 debug_assert_ne!(amount, 0);
333 Fungibility::Fungible(amount)
334 }
335}
336
337impl<T: Into<AssetInstance>> From<T> for Fungibility {
338 fn from(instance: T) -> Fungibility {
339 Fungibility::NonFungible(instance.into())
340 }
341}
342
343impl TryFrom<OldFungibility> for Fungibility {
344 type Error = ();
345 fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
346 use OldFungibility::*;
347 Ok(match value {
348 Fungible(n) => Self::Fungible(n),
349 NonFungible(i) => Self::NonFungible(i.try_into()?),
350 })
351 }
352}
353
354impl TryFrom<NewFungibility> for Fungibility {
355 type Error = ();
356 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
357 use NewFungibility::*;
358 Ok(match value {
359 Fungible(n) => Self::Fungible(n),
360 NonFungible(i) => Self::NonFungible(i.try_into()?),
361 })
362 }
363}
364
365#[derive(
367 Copy,
368 Clone,
369 Eq,
370 PartialEq,
371 Ord,
372 PartialOrd,
373 Debug,
374 Encode,
375 Decode,
376 TypeInfo,
377 MaxEncodedLen,
378 serde::Serialize,
379 serde::Deserialize,
380)]
381#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
382#[scale_info(replace_segment("staging_xcm", "xcm"))]
383pub enum WildFungibility {
384 Fungible,
386 NonFungible,
388}
389
390impl TryFrom<OldWildFungibility> for WildFungibility {
391 type Error = ();
392 fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
393 use OldWildFungibility::*;
394 Ok(match value {
395 Fungible => Self::Fungible,
396 NonFungible => Self::NonFungible,
397 })
398 }
399}
400
401impl TryFrom<NewWildFungibility> for WildFungibility {
402 type Error = ();
403 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
404 use NewWildFungibility::*;
405 Ok(match value {
406 Fungible => Self::Fungible,
407 NonFungible => Self::NonFungible,
408 })
409 }
410}
411
412#[derive(
414 Copy,
415 Clone,
416 Eq,
417 PartialEq,
418 Ord,
419 PartialOrd,
420 Debug,
421 Encode,
422 Decode,
423 TypeInfo,
424 MaxEncodedLen,
425 serde::Serialize,
426 serde::Deserialize,
427)]
428#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
429#[scale_info(replace_segment("staging_xcm", "xcm"))]
430pub enum AssetId {
431 Concrete(MultiLocation),
433 Abstract([u8; 32]),
436}
437
438impl<T: Into<MultiLocation>> From<T> for AssetId {
439 fn from(x: T) -> Self {
440 Self::Concrete(x.into())
441 }
442}
443
444impl From<[u8; 32]> for AssetId {
445 fn from(x: [u8; 32]) -> Self {
446 Self::Abstract(x)
447 }
448}
449
450impl TryFrom<OldAssetId> for AssetId {
451 type Error = ();
452 fn try_from(old: OldAssetId) -> Result<Self, ()> {
453 use OldAssetId::*;
454 Ok(match old {
455 Concrete(l) => Self::Concrete(l.try_into()?),
456 Abstract(v) if v.len() <= 32 => {
457 let mut r = [0u8; 32];
458 r[..v.len()].copy_from_slice(&v[..]);
459 Self::Abstract(r)
460 },
461 _ => return Err(()),
462 })
463 }
464}
465
466impl TryFrom<NewAssetId> for AssetId {
467 type Error = ();
468 fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
469 Ok(Self::Concrete(new.0.try_into()?))
470 }
471}
472
473impl AssetId {
474 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
476 if let AssetId::Concrete(ref mut l) = self {
477 l.prepend_with(*prepend).map_err(|_| ())?;
478 }
479 Ok(())
480 }
481
482 pub fn reanchor(
485 &mut self,
486 target: &MultiLocation,
487 context: InteriorMultiLocation,
488 ) -> Result<(), ()> {
489 if let AssetId::Concrete(ref mut l) = self {
490 l.reanchor(target, context)?;
491 }
492 Ok(())
493 }
494
495 pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
498 MultiAsset { fun, id: self }
499 }
500
501 pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
504 WildMultiAsset::AllOf { fun, id: self }
505 }
506}
507
508#[derive(
510 Clone,
511 Eq,
512 PartialEq,
513 Debug,
514 Encode,
515 Decode,
516 TypeInfo,
517 MaxEncodedLen,
518 serde::Serialize,
519 serde::Deserialize,
520)]
521#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
522#[scale_info(replace_segment("staging_xcm", "xcm"))]
523pub struct MultiAsset {
524 pub id: AssetId,
526 pub fun: Fungibility,
529}
530
531impl PartialOrd for MultiAsset {
532 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
533 Some(self.cmp(other))
534 }
535}
536
537impl Ord for MultiAsset {
538 fn cmp(&self, other: &Self) -> Ordering {
539 match (&self.fun, &other.fun) {
540 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
541 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
542 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
543 }
544 }
545}
546
547impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
548 fn from((id, fun): (A, B)) -> MultiAsset {
549 MultiAsset { fun: fun.into(), id: id.into() }
550 }
551}
552
553impl MultiAsset {
554 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
555 use Fungibility::*;
556 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
557 }
558
559 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
560 use Fungibility::*;
561 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
562 }
563
564 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
566 self.id.prepend_with(prepend)
567 }
568
569 pub fn reanchor(
572 &mut self,
573 target: &MultiLocation,
574 context: InteriorMultiLocation,
575 ) -> Result<(), ()> {
576 self.id.reanchor(target, context)
577 }
578
579 pub fn reanchored(
582 mut self,
583 target: &MultiLocation,
584 context: InteriorMultiLocation,
585 ) -> Result<Self, ()> {
586 self.id.reanchor(target, context)?;
587 Ok(self)
588 }
589
590 pub fn contains(&self, inner: &MultiAsset) -> bool {
592 use Fungibility::*;
593 if self.id == inner.id {
594 match (&self.fun, &inner.fun) {
595 (Fungible(a), Fungible(i)) if a >= i => return true,
596 (NonFungible(a), NonFungible(i)) if a == i => return true,
597 _ => (),
598 }
599 }
600 false
601 }
602}
603
604impl TryFrom<OldMultiAsset> for MultiAsset {
605 type Error = ();
606 fn try_from(old: OldMultiAsset) -> Result<Self, ()> {
607 Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
608 }
609}
610
611impl TryFrom<NewMultiAsset> for MultiAsset {
612 type Error = ();
613 fn try_from(new: NewMultiAsset) -> Result<Self, Self::Error> {
614 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
615 }
616}
617
618#[derive(
626 Clone,
627 Eq,
628 PartialEq,
629 Ord,
630 PartialOrd,
631 Debug,
632 Encode,
633 TypeInfo,
634 Default,
635 serde::Serialize,
636 serde::Deserialize,
637)]
638#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
639#[scale_info(replace_segment("staging_xcm", "xcm"))]
640pub struct MultiAssets(Vec<MultiAsset>);
641
642pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
644
645impl MaxEncodedLen for MultiAssets {
646 fn max_encoded_len() -> usize {
647 MultiAsset::max_encoded_len() * MAX_ITEMS_IN_MULTIASSETS
648 }
649}
650
651impl Decode for MultiAssets {
652 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
653 let bounded_instructions =
654 BoundedVec::<MultiAsset, ConstU32<{ MAX_ITEMS_IN_MULTIASSETS as u32 }>>::decode(input)?;
655 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
656 .map_err(|()| "Out of order".into())
657 }
658}
659
660impl TryFrom<OldMultiAssets> for MultiAssets {
661 type Error = ();
662 fn try_from(old: OldMultiAssets) -> Result<Self, ()> {
663 let v = old
664 .drain()
665 .into_iter()
666 .map(MultiAsset::try_from)
667 .collect::<Result<Vec<_>, ()>>()?;
668 Ok(MultiAssets(v))
669 }
670}
671
672impl TryFrom<NewMultiAssets> for MultiAssets {
673 type Error = ();
674 fn try_from(new: NewMultiAssets) -> Result<Self, Self::Error> {
675 let v = new
676 .into_inner()
677 .into_iter()
678 .map(MultiAsset::try_from)
679 .collect::<Result<Vec<_>, ()>>()?;
680 Ok(MultiAssets(v))
681 }
682}
683
684impl From<Vec<MultiAsset>> for MultiAssets {
685 fn from(mut assets: Vec<MultiAsset>) -> Self {
686 let mut res = Vec::with_capacity(assets.len());
687 if !assets.is_empty() {
688 assets.sort();
689 let mut iter = assets.into_iter();
690 if let Some(first) = iter.next() {
691 let last = iter.fold(first, |a, b| -> MultiAsset {
692 match (a, b) {
693 (
694 MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
695 MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
696 ) if a_id == b_id => MultiAsset {
697 id: a_id,
698 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
699 },
700 (
701 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
702 MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
703 ) if a_id == b_id && a_instance == b_instance =>
704 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
705 (to_push, to_remember) => {
706 res.push(to_push);
707 to_remember
708 },
709 }
710 });
711 res.push(last);
712 }
713 }
714 Self(res)
715 }
716}
717
718impl<T: Into<MultiAsset>> From<T> for MultiAssets {
719 fn from(x: T) -> Self {
720 Self(vec![x.into()])
721 }
722}
723
724impl MultiAssets {
725 pub fn new() -> Self {
727 Self(Vec::new())
728 }
729
730 pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
737 if r.is_empty() {
738 return Ok(Self(Vec::new()))
739 }
740 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
741 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
742 Ok(b)
743 } else {
744 Err(())
745 }
746 })?;
747 Ok(Self(r))
748 }
749
750 #[cfg(test)]
757 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
758 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
759 }
760 #[cfg(not(test))]
769 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
770 Self(r)
771 }
772
773 pub fn push(&mut self, a: MultiAsset) {
776 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
777 match (&a.fun, &mut asset.fun) {
778 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
779 *balance = balance.saturating_add(*amount);
780 return
781 },
782 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
783 if inst1 == inst2 =>
784 return,
785 _ => (),
786 }
787 }
788 self.0.push(a);
789 self.0.sort();
790 }
791
792 pub fn is_none(&self) -> bool {
794 self.0.is_empty()
795 }
796
797 pub fn contains(&self, inner: &MultiAsset) -> bool {
799 self.0.iter().any(|i| i.contains(inner))
800 }
801
802 #[deprecated = "Use `into_inner()` instead"]
804 pub fn drain(self) -> Vec<MultiAsset> {
805 self.0
806 }
807
808 pub fn into_inner(self) -> Vec<MultiAsset> {
810 self.0
811 }
812
813 pub fn inner(&self) -> &Vec<MultiAsset> {
815 &self.0
816 }
817
818 pub fn len(&self) -> usize {
820 self.0.len()
821 }
822
823 pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
825 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
826 self.0.sort();
827 Ok(())
828 }
829
830 pub fn reanchor(
835 &mut self,
836 target: &MultiLocation,
837 context: InteriorMultiLocation,
838 ) -> Result<(), ()> {
839 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
840 self.0.sort();
841 Ok(())
842 }
843
844 pub fn get(&self, index: usize) -> Option<&MultiAsset> {
846 self.0.get(index)
847 }
848}
849
850#[derive(
852 Clone,
853 Eq,
854 PartialEq,
855 Ord,
856 PartialOrd,
857 Debug,
858 Encode,
859 Decode,
860 TypeInfo,
861 MaxEncodedLen,
862 serde::Serialize,
863 serde::Deserialize,
864)]
865#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
866#[scale_info(replace_segment("staging_xcm", "xcm"))]
867pub enum WildMultiAsset {
868 All,
870 AllOf { id: AssetId, fun: WildFungibility },
872 AllCounted(#[codec(compact)] u32),
875 AllOfCounted {
878 id: AssetId,
879 fun: WildFungibility,
880 #[codec(compact)]
881 count: u32,
882 },
883}
884
885impl TryFrom<OldWildMultiAsset> for WildMultiAsset {
886 type Error = ();
887 fn try_from(old: OldWildMultiAsset) -> Result<WildMultiAsset, ()> {
888 use OldWildMultiAsset::*;
889 Ok(match old {
890 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
891 All => Self::All,
892 })
893 }
894}
895
896impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
897 type Error = ();
898 fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
899 use NewWildMultiAsset::*;
900 Ok(match new {
901 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
902 AllOfCounted { id, fun, count } =>
903 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
904 All => Self::All,
905 AllCounted(count) => Self::AllCounted(count),
906 })
907 }
908}
909
910impl TryFrom<(OldWildMultiAsset, u32)> for WildMultiAsset {
911 type Error = ();
912 fn try_from(old: (OldWildMultiAsset, u32)) -> Result<WildMultiAsset, ()> {
913 use OldWildMultiAsset::*;
914 let count = old.1;
915 Ok(match old.0 {
916 AllOf { id, fun } =>
917 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
918 All => Self::AllCounted(count),
919 })
920 }
921}
922
923impl WildMultiAsset {
924 pub fn contains(&self, inner: &MultiAsset) -> bool {
926 use WildMultiAsset::*;
927 match self {
928 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
929 AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
930 inner.fun.is_kind(*fun) && &inner.id == id,
931 All | AllCounted(_) => true,
932 }
933 }
934
935 #[deprecated = "Use `contains` instead"]
940 pub fn matches(&self, inner: &MultiAsset) -> bool {
941 self.contains(inner)
942 }
943
944 pub fn reanchor(
947 &mut self,
948 target: &MultiLocation,
949 context: InteriorMultiLocation,
950 ) -> Result<(), ()> {
951 use WildMultiAsset::*;
952 match self {
953 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
954 id.reanchor(target, context),
955 All | AllCounted(_) => Ok(()),
956 }
957 }
958
959 pub fn count(&self) -> Option<u32> {
961 use WildMultiAsset::*;
962 match self {
963 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
964 All | AllOf { .. } => None,
965 }
966 }
967
968 pub fn limit(&self) -> Option<u32> {
970 self.count()
971 }
972
973 pub fn counted(self, count: u32) -> Self {
976 use WildMultiAsset::*;
977 match self {
978 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
979 All | AllCounted(_) => AllCounted(count),
980 }
981 }
982}
983
984impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
985 fn from((id, fun): (A, B)) -> WildMultiAsset {
986 WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
987 }
988}
989
990#[derive(
992 Clone,
993 Eq,
994 PartialEq,
995 Ord,
996 PartialOrd,
997 Debug,
998 Encode,
999 Decode,
1000 TypeInfo,
1001 MaxEncodedLen,
1002 serde::Serialize,
1003 serde::Deserialize,
1004)]
1005#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1006#[scale_info(replace_segment("staging_xcm", "xcm"))]
1007pub enum MultiAssetFilter {
1008 Definite(MultiAssets),
1010 Wild(WildMultiAsset),
1012}
1013
1014impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
1015 fn from(x: T) -> Self {
1016 Self::Wild(x.into())
1017 }
1018}
1019
1020impl From<MultiAsset> for MultiAssetFilter {
1021 fn from(x: MultiAsset) -> Self {
1022 Self::Definite(vec![x].into())
1023 }
1024}
1025
1026impl From<Vec<MultiAsset>> for MultiAssetFilter {
1027 fn from(x: Vec<MultiAsset>) -> Self {
1028 Self::Definite(x.into())
1029 }
1030}
1031
1032impl From<MultiAssets> for MultiAssetFilter {
1033 fn from(x: MultiAssets) -> Self {
1034 Self::Definite(x)
1035 }
1036}
1037
1038impl MultiAssetFilter {
1039 pub fn matches(&self, inner: &MultiAsset) -> bool {
1044 match self {
1045 MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
1046 MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
1047 }
1048 }
1049
1050 pub fn reanchor(
1053 &mut self,
1054 target: &MultiLocation,
1055 context: InteriorMultiLocation,
1056 ) -> Result<(), ()> {
1057 match self {
1058 MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
1059 MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
1060 }
1061 }
1062
1063 pub fn count(&self) -> Option<u32> {
1065 use MultiAssetFilter::*;
1066 match self {
1067 Definite(x) => Some(x.len() as u32),
1068 Wild(x) => x.count(),
1069 }
1070 }
1071
1072 pub fn limit(&self) -> Option<u32> {
1074 use MultiAssetFilter::*;
1075 match self {
1076 Definite(_) => None,
1077 Wild(x) => x.limit(),
1078 }
1079 }
1080}
1081
1082impl TryFrom<OldMultiAssetFilter> for MultiAssetFilter {
1083 type Error = ();
1084 fn try_from(old: OldMultiAssetFilter) -> Result<MultiAssetFilter, ()> {
1085 Ok(match old {
1086 OldMultiAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
1087 OldMultiAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
1088 })
1089 }
1090}
1091
1092impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
1093 type Error = ();
1094 fn try_from(new: NewMultiAssetFilter) -> Result<MultiAssetFilter, Self::Error> {
1095 use NewMultiAssetFilter::*;
1096 Ok(match new {
1097 Definite(x) => Self::Definite(x.try_into()?),
1098 Wild(x) => Self::Wild(x.try_into()?),
1099 })
1100 }
1101}
1102
1103impl TryFrom<(OldMultiAssetFilter, u32)> for MultiAssetFilter {
1104 type Error = ();
1105 fn try_from(old: (OldMultiAssetFilter, u32)) -> Result<MultiAssetFilter, ()> {
1106 let count = old.1;
1107 Ok(match old.0 {
1108 OldMultiAssetFilter::Definite(x) if count >= x.len() as u32 =>
1109 Self::Definite(x.try_into()?),
1110 OldMultiAssetFilter::Wild(x) => Self::Wild((x, count).try_into()?),
1111 _ => return Err(()),
1112 })
1113 }
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118 use super::super::prelude::*;
1119
1120 #[test]
1121 fn conversion_works() {
1122 let _: MultiAssets = (Here, 1u128).into();
1123 }
1124
1125 #[test]
1126 fn from_sorted_and_deduplicated_works() {
1127 use super::*;
1128 use alloc::vec;
1129
1130 let empty = vec![];
1131 let r = MultiAssets::from_sorted_and_deduplicated(empty);
1132 assert_eq!(r, Ok(MultiAssets(vec![])));
1133
1134 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1135 let r = MultiAssets::from_sorted_and_deduplicated(dup_fun);
1136 assert!(r.is_err());
1137
1138 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1139 let r = MultiAssets::from_sorted_and_deduplicated(dup_nft);
1140 assert!(r.is_err());
1141
1142 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1143 let r = MultiAssets::from_sorted_and_deduplicated(good_fun.clone());
1144 assert_eq!(r, Ok(MultiAssets(good_fun)));
1145
1146 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1147 let r = MultiAssets::from_sorted_and_deduplicated(bad_fun);
1148 assert!(r.is_err());
1149
1150 let good_abstract_fun = vec![(Here, 100).into(), ([0u8; 32], 10).into()];
1151 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_fun.clone());
1152 assert_eq!(r, Ok(MultiAssets(good_abstract_fun)));
1153
1154 let bad_abstract_fun = vec![([0u8; 32], 10).into(), (Here, 10).into()];
1155 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_fun);
1156 assert!(r.is_err());
1157
1158 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1159 let r = MultiAssets::from_sorted_and_deduplicated(good_nft.clone());
1160 assert_eq!(r, Ok(MultiAssets(good_nft)));
1161
1162 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1163 let r = MultiAssets::from_sorted_and_deduplicated(bad_nft);
1164 assert!(r.is_err());
1165
1166 let good_abstract_nft = vec![(Here, ()).into(), ([0u8; 32], ()).into()];
1167 let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_nft.clone());
1168 assert_eq!(r, Ok(MultiAssets(good_abstract_nft)));
1169
1170 let bad_abstract_nft = vec![([0u8; 32], ()).into(), (Here, ()).into()];
1171 let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_nft);
1172 assert!(r.is_err());
1173
1174 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1175 let r = MultiAssets::from_sorted_and_deduplicated(mixed_good.clone());
1176 assert_eq!(r, Ok(MultiAssets(mixed_good)));
1177
1178 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1179 let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad);
1180 assert!(r.is_err());
1181 }
1182
1183 #[test]
1184 fn reanchor_preserves_sorting() {
1185 use super::*;
1186 use alloc::vec;
1187
1188 let reanchor_context = X1(Parachain(2000));
1189 let dest = MultiLocation::new(1, Here);
1190
1191 let asset_1: MultiAsset =
1192 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1193 let mut asset_1_reanchored = asset_1.clone();
1194 assert!(asset_1_reanchored.reanchor(&dest, reanchor_context).is_ok());
1195 assert_eq!(
1196 asset_1_reanchored,
1197 (MultiLocation::new(0, X3(Parachain(2000), PalletInstance(50), GeneralIndex(1))), 10)
1198 .into()
1199 );
1200
1201 let asset_2: MultiAsset = (MultiLocation::new(1, Here), 10).into();
1202 let mut asset_2_reanchored = asset_2.clone();
1203 assert!(asset_2_reanchored.reanchor(&dest, reanchor_context).is_ok());
1204 assert_eq!(asset_2_reanchored, (MultiLocation::new(0, Here), 10).into());
1205
1206 let asset_3: MultiAsset = (MultiLocation::new(1, X1(Parachain(1000))), 10).into();
1207 let mut asset_3_reanchored = asset_3.clone();
1208 assert!(asset_3_reanchored.reanchor(&dest, reanchor_context).is_ok());
1209 assert_eq!(asset_3_reanchored, (MultiLocation::new(0, X1(Parachain(1000))), 10).into());
1210
1211 let mut assets: MultiAssets =
1212 vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1213 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1214
1215 assert!(assets
1217 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1218 .is_ok());
1219
1220 assert!(assets.reanchor(&dest, reanchor_context).is_ok());
1221 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1222
1223 assert!(assets
1225 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1226 .is_ok());
1227 }
1228
1229 #[test]
1230 fn prepend_preserves_sorting() {
1231 use super::*;
1232 use alloc::vec;
1233
1234 let prefix = MultiLocation::new(0, X1(Parachain(1000)));
1235
1236 let asset_1: MultiAsset =
1237 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1238 let mut asset_1_prepended = asset_1.clone();
1239 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1240 assert_eq!(
1242 asset_1_prepended,
1243 (MultiLocation::new(0, X3(Parachain(1000), PalletInstance(50), GeneralIndex(1))), 10)
1244 .into()
1245 );
1246
1247 let asset_2: MultiAsset =
1248 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1249 let mut asset_2_prepended = asset_2.clone();
1250 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1251 assert_eq!(
1253 asset_2_prepended,
1254 (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1255 );
1256
1257 let asset_3: MultiAsset =
1258 (MultiLocation::new(2, X2(PalletInstance(50), GeneralIndex(1))), 10).into();
1259 let mut asset_3_prepended = asset_3.clone();
1260 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1261 assert_eq!(
1263 asset_3_prepended,
1264 (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into()
1265 );
1266
1267 let mut assets: MultiAssets = vec![asset_1, asset_2, asset_3].into();
1269 assert!(assets
1271 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1272 .is_ok());
1273
1274 assert!(assets.prepend_with(&prefix).is_ok());
1276 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1277
1278 assert!(assets
1280 .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ()))
1281 .is_ok());
1282 }
1283
1284 #[test]
1285 fn decoding_respects_limit() {
1286 use super::*;
1287
1288 let lots_of_one_asset: MultiAssets =
1290 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_MULTIASSETS + 1].into();
1291 let encoded = lots_of_one_asset.encode();
1292 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1293
1294 let mut few_assets: MultiAssets = Vec::new().into();
1296 for i in 0..MAX_ITEMS_IN_MULTIASSETS {
1297 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1298 }
1299 let encoded = few_assets.encode();
1300 assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
1301
1302 let mut too_many_different_assets: MultiAssets = Vec::new().into();
1304 for i in 0..MAX_ITEMS_IN_MULTIASSETS + 1 {
1305 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1306 }
1307 let encoded = too_many_different_assets.encode();
1308 assert!(MultiAssets::decode(&mut &encoded[..]).is_err());
1309 }
1310}