1use super::{InteriorLocation, Location, Reanchorable};
30use crate::{
31 v3::{
32 AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
33 MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
34 WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
35 },
36 v5::{
37 Asset as NewAsset, AssetFilter as NewAssetFilter, AssetId as NewAssetId,
38 AssetInstance as NewAssetInstance, Assets as NewAssets, Fungibility as NewFungibility,
39 WildAsset as NewWildAsset, WildFungibility as NewWildFungibility,
40 },
41};
42use alloc::{vec, vec::Vec};
43use bounded_collections::{BoundedVec, ConstU32};
44use codec::{self as codec, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
45use core::cmp::Ordering;
46use scale_info::TypeInfo;
47
48#[derive(
50 Copy,
51 Clone,
52 Eq,
53 PartialEq,
54 Ord,
55 PartialOrd,
56 Encode,
57 Decode,
58 DecodeWithMemTracking,
59 Debug,
60 TypeInfo,
61 MaxEncodedLen,
62 serde::Serialize,
63 serde::Deserialize,
64)]
65pub enum AssetInstance {
66 Undefined,
68
69 Index(#[codec(compact)] u128),
72
73 Array4([u8; 4]),
75
76 Array8([u8; 8]),
78
79 Array16([u8; 16]),
81
82 Array32([u8; 32]),
84}
85
86impl TryFrom<OldAssetInstance> for AssetInstance {
87 type Error = ();
88 fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
89 use OldAssetInstance::*;
90 Ok(match value {
91 Undefined => Self::Undefined,
92 Index(n) => Self::Index(n),
93 Array4(n) => Self::Array4(n),
94 Array8(n) => Self::Array8(n),
95 Array16(n) => Self::Array16(n),
96 Array32(n) => Self::Array32(n),
97 })
98 }
99}
100
101impl TryFrom<NewAssetInstance> for AssetInstance {
102 type Error = ();
103 fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
104 use NewAssetInstance::*;
105 Ok(match value {
106 Undefined => Self::Undefined,
107 Index(n) => Self::Index(n),
108 Array4(n) => Self::Array4(n),
109 Array8(n) => Self::Array8(n),
110 Array16(n) => Self::Array16(n),
111 Array32(n) => Self::Array32(n),
112 })
113 }
114}
115
116impl From<()> for AssetInstance {
117 fn from(_: ()) -> Self {
118 Self::Undefined
119 }
120}
121
122impl From<[u8; 4]> for AssetInstance {
123 fn from(x: [u8; 4]) -> Self {
124 Self::Array4(x)
125 }
126}
127
128impl From<[u8; 8]> for AssetInstance {
129 fn from(x: [u8; 8]) -> Self {
130 Self::Array8(x)
131 }
132}
133
134impl From<[u8; 16]> for AssetInstance {
135 fn from(x: [u8; 16]) -> Self {
136 Self::Array16(x)
137 }
138}
139
140impl From<[u8; 32]> for AssetInstance {
141 fn from(x: [u8; 32]) -> Self {
142 Self::Array32(x)
143 }
144}
145
146impl From<u8> for AssetInstance {
147 fn from(x: u8) -> Self {
148 Self::Index(x as u128)
149 }
150}
151
152impl From<u16> for AssetInstance {
153 fn from(x: u16) -> Self {
154 Self::Index(x as u128)
155 }
156}
157
158impl From<u32> for AssetInstance {
159 fn from(x: u32) -> Self {
160 Self::Index(x as u128)
161 }
162}
163
164impl From<u64> for AssetInstance {
165 fn from(x: u64) -> Self {
166 Self::Index(x as u128)
167 }
168}
169
170impl TryFrom<AssetInstance> for () {
171 type Error = ();
172 fn try_from(x: AssetInstance) -> Result<Self, ()> {
173 match x {
174 AssetInstance::Undefined => Ok(()),
175 _ => Err(()),
176 }
177 }
178}
179
180impl TryFrom<AssetInstance> for [u8; 4] {
181 type Error = ();
182 fn try_from(x: AssetInstance) -> Result<Self, ()> {
183 match x {
184 AssetInstance::Array4(x) => Ok(x),
185 _ => Err(()),
186 }
187 }
188}
189
190impl TryFrom<AssetInstance> for [u8; 8] {
191 type Error = ();
192 fn try_from(x: AssetInstance) -> Result<Self, ()> {
193 match x {
194 AssetInstance::Array8(x) => Ok(x),
195 _ => Err(()),
196 }
197 }
198}
199
200impl TryFrom<AssetInstance> for [u8; 16] {
201 type Error = ();
202 fn try_from(x: AssetInstance) -> Result<Self, ()> {
203 match x {
204 AssetInstance::Array16(x) => Ok(x),
205 _ => Err(()),
206 }
207 }
208}
209
210impl TryFrom<AssetInstance> for [u8; 32] {
211 type Error = ();
212 fn try_from(x: AssetInstance) -> Result<Self, ()> {
213 match x {
214 AssetInstance::Array32(x) => Ok(x),
215 _ => Err(()),
216 }
217 }
218}
219
220impl TryFrom<AssetInstance> for u8 {
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 u16 {
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 u32 {
241 type Error = ();
242 fn try_from(x: AssetInstance) -> Result<Self, ()> {
243 match x {
244 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
245 _ => Err(()),
246 }
247 }
248}
249
250impl TryFrom<AssetInstance> for u64 {
251 type Error = ();
252 fn try_from(x: AssetInstance) -> Result<Self, ()> {
253 match x {
254 AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
255 _ => Err(()),
256 }
257 }
258}
259
260impl TryFrom<AssetInstance> for u128 {
261 type Error = ();
262 fn try_from(x: AssetInstance) -> Result<Self, ()> {
263 match x {
264 AssetInstance::Index(x) => Ok(x),
265 _ => Err(()),
266 }
267 }
268}
269
270impl TryFrom<NewFungibility> for Fungibility {
271 type Error = ();
272 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
273 use NewFungibility::*;
274 Ok(match value {
275 Fungible(n) => Self::Fungible(n),
276 NonFungible(i) => Self::NonFungible(i.try_into()?),
277 })
278 }
279}
280
281#[derive(
284 Clone,
285 Eq,
286 PartialEq,
287 Ord,
288 PartialOrd,
289 Debug,
290 Encode,
291 DecodeWithMemTracking,
292 TypeInfo,
293 MaxEncodedLen,
294 serde::Serialize,
295 serde::Deserialize,
296)]
297pub enum Fungibility {
298 Fungible(#[codec(compact)] u128),
300 NonFungible(AssetInstance),
303}
304
305#[derive(Decode)]
306enum UncheckedFungibility {
307 Fungible(#[codec(compact)] u128),
308 NonFungible(AssetInstance),
309}
310
311impl Decode for Fungibility {
312 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
313 match UncheckedFungibility::decode(input)? {
314 UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
315 UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
316 UncheckedFungibility::Fungible(_) =>
317 Err("Fungible asset of zero amount is not allowed".into()),
318 }
319 }
320}
321
322impl Fungibility {
323 pub fn is_kind(&self, w: WildFungibility) -> bool {
324 use Fungibility::*;
325 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
326 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
327 }
328}
329
330impl From<i32> for Fungibility {
331 fn from(amount: i32) -> Fungibility {
332 debug_assert_ne!(amount, 0);
333 Fungibility::Fungible(amount as u128)
334 }
335}
336
337impl From<u128> for Fungibility {
338 fn from(amount: u128) -> Fungibility {
339 debug_assert_ne!(amount, 0);
340 Fungibility::Fungible(amount)
341 }
342}
343
344impl<T: Into<AssetInstance>> From<T> for Fungibility {
345 fn from(instance: T) -> Fungibility {
346 Fungibility::NonFungible(instance.into())
347 }
348}
349
350impl TryFrom<OldFungibility> for Fungibility {
351 type Error = ();
352 fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
353 use OldFungibility::*;
354 Ok(match value {
355 Fungible(n) => Self::Fungible(n),
356 NonFungible(i) => Self::NonFungible(i.try_into()?),
357 })
358 }
359}
360
361#[derive(
363 Copy,
364 Clone,
365 Eq,
366 PartialEq,
367 Ord,
368 PartialOrd,
369 Debug,
370 Encode,
371 Decode,
372 DecodeWithMemTracking,
373 TypeInfo,
374 MaxEncodedLen,
375 serde::Serialize,
376 serde::Deserialize,
377)]
378pub enum WildFungibility {
379 Fungible,
381 NonFungible,
383}
384
385impl TryFrom<OldWildFungibility> for WildFungibility {
386 type Error = ();
387 fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
388 use OldWildFungibility::*;
389 Ok(match value {
390 Fungible => Self::Fungible,
391 NonFungible => Self::NonFungible,
392 })
393 }
394}
395
396impl TryFrom<NewWildFungibility> for WildFungibility {
397 type Error = ();
398 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
399 use NewWildFungibility::*;
400 Ok(match value {
401 Fungible => Self::Fungible,
402 NonFungible => Self::NonFungible,
403 })
404 }
405}
406
407#[derive(
409 Clone,
410 Eq,
411 PartialEq,
412 Ord,
413 PartialOrd,
414 Debug,
415 Encode,
416 Decode,
417 DecodeWithMemTracking,
418 TypeInfo,
419 MaxEncodedLen,
420 serde::Serialize,
421 serde::Deserialize,
422)]
423pub struct AssetId(pub Location);
424
425impl<T: Into<Location>> From<T> for AssetId {
426 fn from(x: T) -> Self {
427 Self(x.into())
428 }
429}
430
431impl TryFrom<OldAssetId> for AssetId {
432 type Error = ();
433 fn try_from(old: OldAssetId) -> Result<Self, ()> {
434 use OldAssetId::*;
435 Ok(match old {
436 Concrete(l) => Self(l.try_into()?),
437 Abstract(_) => return Err(()),
438 })
439 }
440}
441
442impl TryFrom<NewAssetId> for AssetId {
443 type Error = ();
444 fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
445 Ok(Self(new.0.try_into()?))
446 }
447}
448
449impl AssetId {
450 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
452 self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
453 Ok(())
454 }
455
456 pub fn into_asset(self, fun: Fungibility) -> Asset {
459 Asset { fun, id: self }
460 }
461
462 pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
465 WildAsset::AllOf { fun, id: self }
466 }
467}
468
469impl Reanchorable for AssetId {
470 type Error = ();
471
472 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
475 self.0.reanchor(target, context)?;
476 Ok(())
477 }
478
479 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
480 match self.reanchor(target, context) {
481 Ok(()) => Ok(self),
482 Err(()) => Err(()),
483 }
484 }
485}
486
487#[derive(
489 Clone,
490 Eq,
491 PartialEq,
492 Debug,
493 Encode,
494 Decode,
495 DecodeWithMemTracking,
496 TypeInfo,
497 MaxEncodedLen,
498 serde::Serialize,
499 serde::Deserialize,
500)]
501pub struct Asset {
502 pub id: AssetId,
504 pub fun: Fungibility,
507}
508
509impl PartialOrd for Asset {
510 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
511 Some(self.cmp(other))
512 }
513}
514
515impl Ord for Asset {
516 fn cmp(&self, other: &Self) -> Ordering {
517 match (&self.fun, &other.fun) {
518 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
519 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
520 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
521 }
522 }
523}
524
525impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
526 fn from((id, fun): (A, B)) -> Asset {
527 Asset { fun: fun.into(), id: id.into() }
528 }
529}
530
531impl Asset {
532 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
533 use Fungibility::*;
534 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
535 }
536
537 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
538 use Fungibility::*;
539 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
540 }
541
542 pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
544 self.id.prepend_with(prepend)
545 }
546
547 pub fn contains(&self, inner: &Asset) -> bool {
549 use Fungibility::*;
550 if self.id == inner.id {
551 match (&self.fun, &inner.fun) {
552 (Fungible(a), Fungible(i)) if a >= i => return true,
553 (NonFungible(a), NonFungible(i)) if a == i => return true,
554 _ => (),
555 }
556 }
557 false
558 }
559}
560
561impl Reanchorable for Asset {
562 type Error = ();
563
564 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
567 self.id.reanchor(target, context)
568 }
569
570 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
573 self.id.reanchor(target, context)?;
574 Ok(self)
575 }
576}
577
578impl TryFrom<OldAsset> for Asset {
579 type Error = ();
580 fn try_from(old: OldAsset) -> Result<Self, ()> {
581 Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
582 }
583}
584
585impl TryFrom<NewAsset> for Asset {
586 type Error = ();
587 fn try_from(new: NewAsset) -> Result<Self, Self::Error> {
588 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
589 }
590}
591
592#[derive(
600 Clone,
601 Eq,
602 PartialEq,
603 Ord,
604 PartialOrd,
605 Debug,
606 Encode,
607 DecodeWithMemTracking,
608 TypeInfo,
609 Default,
610 serde::Serialize,
611 serde::Deserialize,
612)]
613pub struct Assets(Vec<Asset>);
614
615pub const MAX_ITEMS_IN_ASSETS: usize = 20;
618
619impl MaxEncodedLen for Assets {
620 fn max_encoded_len() -> usize {
621 Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
622 }
623}
624
625impl Decode for Assets {
626 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
627 let bounded_instructions =
628 BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
629 Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
630 .map_err(|()| "Out of order".into())
631 }
632}
633
634impl TryFrom<OldAssets> for Assets {
635 type Error = ();
636 fn try_from(old: OldAssets) -> Result<Self, ()> {
637 let v = old
638 .into_inner()
639 .into_iter()
640 .map(Asset::try_from)
641 .collect::<Result<Vec<_>, ()>>()?;
642 Ok(Assets(v))
643 }
644}
645
646impl TryFrom<NewAssets> for Assets {
647 type Error = ();
648 fn try_from(new: NewAssets) -> Result<Self, Self::Error> {
649 let v = new
650 .into_inner()
651 .into_iter()
652 .map(Asset::try_from)
653 .collect::<Result<Vec<_>, ()>>()?;
654 Ok(Assets(v))
655 }
656}
657
658impl From<Vec<Asset>> for Assets {
659 fn from(mut assets: Vec<Asset>) -> Self {
660 let mut res = Vec::with_capacity(assets.len());
661 if !assets.is_empty() {
662 assets.sort();
663 let mut iter = assets.into_iter();
664 if let Some(first) = iter.next() {
665 let last = iter.fold(first, |a, b| -> Asset {
666 match (a, b) {
667 (
668 Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
669 Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
670 ) if a_id == b_id => Asset {
671 id: a_id,
672 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
673 },
674 (
675 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
676 Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
677 ) if a_id == b_id && a_instance == b_instance =>
678 Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
679 (to_push, to_remember) => {
680 res.push(to_push);
681 to_remember
682 },
683 }
684 });
685 res.push(last);
686 }
687 }
688 Self(res)
689 }
690}
691
692impl<T: Into<Asset>> From<T> for Assets {
693 fn from(x: T) -> Self {
694 Self(vec![x.into()])
695 }
696}
697
698impl Assets {
699 pub fn new() -> Self {
701 Self(Vec::new())
702 }
703
704 pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
711 if r.is_empty() {
712 return Ok(Self(Vec::new()))
713 }
714 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
715 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
716 Ok(b)
717 } else {
718 Err(())
719 }
720 })?;
721 Ok(Self(r))
722 }
723
724 #[cfg(test)]
731 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
732 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
733 }
734 #[cfg(not(test))]
743 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
744 Self(r)
745 }
746
747 pub fn push(&mut self, a: Asset) {
750 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
751 match (&a.fun, &mut asset.fun) {
752 (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
753 *balance = balance.saturating_add(*amount);
754 return
755 },
756 (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
757 if inst1 == inst2 =>
758 return,
759 _ => (),
760 }
761 }
762 self.0.push(a);
763 self.0.sort();
764 }
765
766 pub fn is_none(&self) -> bool {
768 self.0.is_empty()
769 }
770
771 pub fn contains(&self, inner: &Asset) -> bool {
773 self.0.iter().any(|i| i.contains(inner))
774 }
775
776 #[deprecated = "Use `into_inner()` instead"]
778 pub fn drain(self) -> Vec<Asset> {
779 self.0
780 }
781
782 pub fn into_inner(self) -> Vec<Asset> {
784 self.0
785 }
786
787 pub fn inner(&self) -> &Vec<Asset> {
789 &self.0
790 }
791
792 pub fn len(&self) -> usize {
794 self.0.len()
795 }
796
797 pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
799 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
800 self.0.sort();
801 Ok(())
802 }
803
804 pub fn get(&self, index: usize) -> Option<&Asset> {
806 self.0.get(index)
807 }
808}
809
810impl Reanchorable for Assets {
811 type Error = ();
812
813 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
814 self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
815 self.0.sort();
816 Ok(())
817 }
818
819 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
820 match self.reanchor(target, context) {
821 Ok(()) => Ok(self),
822 Err(()) => Err(()),
823 }
824 }
825}
826
827#[derive(
829 Clone,
830 Eq,
831 PartialEq,
832 Ord,
833 PartialOrd,
834 Debug,
835 Encode,
836 Decode,
837 DecodeWithMemTracking,
838 TypeInfo,
839 MaxEncodedLen,
840 serde::Serialize,
841 serde::Deserialize,
842)]
843pub enum WildAsset {
844 All,
846 AllOf { id: AssetId, fun: WildFungibility },
848 AllCounted(#[codec(compact)] u32),
851 AllOfCounted {
854 id: AssetId,
855 fun: WildFungibility,
856 #[codec(compact)]
857 count: u32,
858 },
859}
860
861impl TryFrom<OldWildAsset> for WildAsset {
862 type Error = ();
863 fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
864 use OldWildAsset::*;
865 Ok(match old {
866 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
867 All => Self::All,
868 AllOfCounted { id, fun, count } =>
869 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
870 AllCounted(count) => Self::AllCounted(count),
871 })
872 }
873}
874
875impl TryFrom<NewWildAsset> for WildAsset {
876 type Error = ();
877 fn try_from(new: NewWildAsset) -> Result<Self, ()> {
878 use NewWildAsset::*;
879 Ok(match new {
880 AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
881 AllOfCounted { id, fun, count } =>
882 Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
883 All => Self::All,
884 AllCounted(count) => Self::AllCounted(count),
885 })
886 }
887}
888
889impl WildAsset {
890 pub fn contains(&self, inner: &Asset) -> bool {
892 use WildAsset::*;
893 match self {
894 AllOfCounted { count: 0, .. } | AllCounted(0) => false,
895 AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
896 inner.fun.is_kind(*fun) && &inner.id == id,
897 All | AllCounted(_) => true,
898 }
899 }
900
901 #[deprecated = "Use `contains` instead"]
906 pub fn matches(&self, inner: &Asset) -> bool {
907 self.contains(inner)
908 }
909
910 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
913 use WildAsset::*;
914 match self {
915 AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
916 id.reanchor(target, context),
917 All | AllCounted(_) => Ok(()),
918 }
919 }
920
921 pub fn count(&self) -> Option<u32> {
923 use WildAsset::*;
924 match self {
925 AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
926 All | AllOf { .. } => None,
927 }
928 }
929
930 pub fn limit(&self) -> Option<u32> {
932 self.count()
933 }
934
935 pub fn counted(self, count: u32) -> Self {
938 use WildAsset::*;
939 match self {
940 AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
941 All | AllCounted(_) => AllCounted(count),
942 }
943 }
944}
945
946impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
947 fn from((id, fun): (A, B)) -> WildAsset {
948 WildAsset::AllOf { fun: fun.into(), id: id.into() }
949 }
950}
951
952#[derive(
954 Clone,
955 Eq,
956 PartialEq,
957 Ord,
958 PartialOrd,
959 Debug,
960 Encode,
961 Decode,
962 DecodeWithMemTracking,
963 TypeInfo,
964 MaxEncodedLen,
965 serde::Serialize,
966 serde::Deserialize,
967)]
968pub enum AssetFilter {
969 Definite(Assets),
971 Wild(WildAsset),
973}
974
975impl<T: Into<WildAsset>> From<T> for AssetFilter {
976 fn from(x: T) -> Self {
977 Self::Wild(x.into())
978 }
979}
980
981impl From<Asset> for AssetFilter {
982 fn from(x: Asset) -> Self {
983 Self::Definite(vec![x].into())
984 }
985}
986
987impl From<Vec<Asset>> for AssetFilter {
988 fn from(x: Vec<Asset>) -> Self {
989 Self::Definite(x.into())
990 }
991}
992
993impl From<Assets> for AssetFilter {
994 fn from(x: Assets) -> Self {
995 Self::Definite(x)
996 }
997}
998
999impl AssetFilter {
1000 pub fn matches(&self, inner: &Asset) -> bool {
1005 match self {
1006 AssetFilter::Definite(ref assets) => assets.contains(inner),
1007 AssetFilter::Wild(ref wild) => wild.contains(inner),
1008 }
1009 }
1010
1011 pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
1014 match self {
1015 AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
1016 AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
1017 }
1018 }
1019
1020 pub fn count(&self) -> Option<u32> {
1022 use AssetFilter::*;
1023 match self {
1024 Definite(x) => Some(x.len() as u32),
1025 Wild(x) => x.count(),
1026 }
1027 }
1028
1029 pub fn limit(&self) -> Option<u32> {
1031 use AssetFilter::*;
1032 match self {
1033 Definite(_) => None,
1034 Wild(x) => x.limit(),
1035 }
1036 }
1037}
1038
1039impl TryFrom<NewAssetFilter> for AssetFilter {
1040 type Error = ();
1041 fn try_from(new: NewAssetFilter) -> Result<AssetFilter, Self::Error> {
1042 use NewAssetFilter::*;
1043 Ok(match new {
1044 Definite(x) => Self::Definite(x.try_into()?),
1045 Wild(x) => Self::Wild(x.try_into()?),
1046 })
1047 }
1048}
1049
1050impl TryFrom<OldAssetFilter> for AssetFilter {
1051 type Error = ();
1052 fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
1053 Ok(match old {
1054 OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
1055 OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
1056 })
1057 }
1058}
1059
1060#[cfg(test)]
1061mod tests {
1062 use super::super::prelude::*;
1063
1064 #[test]
1065 fn conversion_works() {
1066 let _: Assets = (Here, 1u128).into();
1067 }
1068
1069 #[test]
1070 fn from_sorted_and_deduplicated_works() {
1071 use super::*;
1072 use alloc::vec;
1073
1074 let empty = vec![];
1075 let r = Assets::from_sorted_and_deduplicated(empty);
1076 assert_eq!(r, Ok(Assets(vec![])));
1077
1078 let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
1079 let r = Assets::from_sorted_and_deduplicated(dup_fun);
1080 assert!(r.is_err());
1081
1082 let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
1083 let r = Assets::from_sorted_and_deduplicated(dup_nft);
1084 assert!(r.is_err());
1085
1086 let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
1087 let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
1088 assert_eq!(r, Ok(Assets(good_fun)));
1089
1090 let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
1091 let r = Assets::from_sorted_and_deduplicated(bad_fun);
1092 assert!(r.is_err());
1093
1094 let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
1095 let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
1096 assert_eq!(r, Ok(Assets(good_nft)));
1097
1098 let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
1099 let r = Assets::from_sorted_and_deduplicated(bad_nft);
1100 assert!(r.is_err());
1101
1102 let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
1103 let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
1104 assert_eq!(r, Ok(Assets(mixed_good)));
1105
1106 let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
1107 let r = Assets::from_sorted_and_deduplicated(mixed_bad);
1108 assert!(r.is_err());
1109 }
1110
1111 #[test]
1112 fn reanchor_preserves_sorting() {
1113 use super::*;
1114 use alloc::vec;
1115
1116 let reanchor_context: Junctions = Parachain(2000).into();
1117 let dest = Location::new(1, []);
1118
1119 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1120 let mut asset_1_reanchored = asset_1.clone();
1121 assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1122 assert_eq!(
1123 asset_1_reanchored,
1124 (Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1125 );
1126
1127 let asset_2: Asset = (Location::new(1, []), 10).into();
1128 let mut asset_2_reanchored = asset_2.clone();
1129 assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1130 assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
1131
1132 let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
1133 let mut asset_3_reanchored = asset_3.clone();
1134 assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
1135 assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
1136
1137 let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
1138 assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
1139
1140 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1142
1143 assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
1144 assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
1145
1146 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1148 }
1149
1150 #[test]
1151 fn prepend_preserves_sorting() {
1152 use super::*;
1153 use alloc::vec;
1154
1155 let prefix = Location::new(0, [Parachain(1000)]);
1156
1157 let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1158 let mut asset_1_prepended = asset_1.clone();
1159 assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
1160 assert_eq!(
1162 asset_1_prepended,
1163 (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
1164 );
1165
1166 let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1167 let mut asset_2_prepended = asset_2.clone();
1168 assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
1169 assert_eq!(
1171 asset_2_prepended,
1172 (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1173 );
1174
1175 let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
1176 let mut asset_3_prepended = asset_3.clone();
1177 assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
1178 assert_eq!(
1180 asset_3_prepended,
1181 (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
1182 );
1183
1184 let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
1186 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1188
1189 assert!(assets.prepend_with(&prefix).is_ok());
1191 assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
1192
1193 assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
1195 }
1196
1197 #[test]
1198 fn decoding_respects_limit() {
1199 use super::*;
1200
1201 let lots_of_one_asset: Assets =
1203 vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
1204 let encoded = lots_of_one_asset.encode();
1205 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1206
1207 let mut few_assets: Assets = Vec::new().into();
1209 for i in 0..MAX_ITEMS_IN_ASSETS {
1210 few_assets.push((GeneralIndex(i as u128), 1u128).into());
1211 }
1212 let encoded = few_assets.encode();
1213 assert!(Assets::decode(&mut &encoded[..]).is_ok());
1214
1215 let mut too_many_different_assets: Assets = Vec::new().into();
1217 for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
1218 too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1219 }
1220 let encoded = too_many_different_assets.encode();
1221 assert!(Assets::decode(&mut &encoded[..]).is_err());
1222 }
1223}