1use super::MultiLocation;
30use crate::v3::{
31 AssetId as NewAssetId, AssetInstance as NewAssetInstance, Fungibility as NewFungibility,
32 MultiAsset as NewMultiAsset, MultiAssetFilter as NewMultiAssetFilter,
33 MultiAssets as NewMultiAssets, WildFungibility as NewWildFungibility,
34 WildMultiAsset as NewWildMultiAsset,
35};
36use alloc::{vec, vec::Vec};
37use codec::{self as codec, Decode, Encode};
38use core::cmp::Ordering;
39use scale_info::TypeInfo;
40
41#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)]
43#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
44#[scale_info(replace_segment("staging_xcm", "xcm"))]
45pub enum AssetInstance {
46 Undefined,
48
49 Index(#[codec(compact)] u128),
52
53 Array4([u8; 4]),
55
56 Array8([u8; 8]),
58
59 Array16([u8; 16]),
61
62 Array32([u8; 32]),
64
65 Blob(Vec<u8>),
67}
68
69impl From<()> for AssetInstance {
70 fn from(_: ()) -> Self {
71 Self::Undefined
72 }
73}
74
75impl From<[u8; 4]> for AssetInstance {
76 fn from(x: [u8; 4]) -> Self {
77 Self::Array4(x)
78 }
79}
80
81impl From<[u8; 8]> for AssetInstance {
82 fn from(x: [u8; 8]) -> Self {
83 Self::Array8(x)
84 }
85}
86
87impl From<[u8; 16]> for AssetInstance {
88 fn from(x: [u8; 16]) -> Self {
89 Self::Array16(x)
90 }
91}
92
93impl From<[u8; 32]> for AssetInstance {
94 fn from(x: [u8; 32]) -> Self {
95 Self::Array32(x)
96 }
97}
98
99impl From<Vec<u8>> for AssetInstance {
100 fn from(x: Vec<u8>) -> Self {
101 Self::Blob(x)
102 }
103}
104
105impl TryFrom<NewAssetInstance> for AssetInstance {
106 type Error = ();
107 fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
108 use NewAssetInstance::*;
109 Ok(match value {
110 Undefined => Self::Undefined,
111 Index(n) => Self::Index(n),
112 Array4(n) => Self::Array4(n),
113 Array8(n) => Self::Array8(n),
114 Array16(n) => Self::Array16(n),
115 Array32(n) => Self::Array32(n),
116 })
117 }
118}
119
120#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
122#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
123#[scale_info(replace_segment("staging_xcm", "xcm"))]
124pub enum AssetId {
125 Concrete(MultiLocation),
126 Abstract(Vec<u8>),
127}
128
129impl<T: Into<MultiLocation>> From<T> for AssetId {
130 fn from(x: T) -> Self {
131 Self::Concrete(x.into())
132 }
133}
134
135impl From<Vec<u8>> for AssetId {
136 fn from(x: Vec<u8>) -> Self {
137 Self::Abstract(x)
138 }
139}
140
141impl TryFrom<NewAssetId> for AssetId {
142 type Error = ();
143 fn try_from(old: NewAssetId) -> Result<Self, ()> {
144 use NewAssetId::*;
145 Ok(match old {
146 Concrete(l) => Self::Concrete(l.try_into()?),
147 Abstract(v) => {
148 let zeroes = v.iter().rev().position(|n| *n != 0).unwrap_or(v.len());
149 Self::Abstract(v[0..(32 - zeroes)].to_vec())
150 },
151 })
152 }
153}
154
155impl AssetId {
156 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
158 if let AssetId::Concrete(ref mut l) = self {
159 l.prepend_with(prepend.clone()).map_err(|_| ())?;
160 }
161 Ok(())
162 }
163
164 pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
167 if let AssetId::Concrete(ref mut l) = self {
168 l.reanchor(target, ancestry)?;
169 }
170 Ok(())
171 }
172
173 pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
176 MultiAsset { fun, id: self }
177 }
178
179 pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
182 WildMultiAsset::AllOf { fun, id: self }
183 }
184}
185
186#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
189#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
190#[scale_info(replace_segment("staging_xcm", "xcm"))]
191pub enum Fungibility {
192 Fungible(#[codec(compact)] u128),
193 NonFungible(AssetInstance),
194}
195
196impl Fungibility {
197 pub fn is_kind(&self, w: WildFungibility) -> bool {
198 use Fungibility::*;
199 use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
200 matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
201 }
202}
203
204impl From<u128> for Fungibility {
205 fn from(amount: u128) -> Fungibility {
206 debug_assert_ne!(amount, 0);
207 Fungibility::Fungible(amount)
208 }
209}
210
211impl<T: Into<AssetInstance>> From<T> for Fungibility {
212 fn from(instance: T) -> Fungibility {
213 Fungibility::NonFungible(instance.into())
214 }
215}
216
217impl TryFrom<NewFungibility> for Fungibility {
218 type Error = ();
219 fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
220 use NewFungibility::*;
221 Ok(match value {
222 Fungible(n) => Self::Fungible(n),
223 NonFungible(i) => Self::NonFungible(i.try_into()?),
224 })
225 }
226}
227
228#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
229#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
230#[scale_info(replace_segment("staging_xcm", "xcm"))]
231pub struct MultiAsset {
232 pub id: AssetId,
233 pub fun: Fungibility,
234}
235
236impl PartialOrd for MultiAsset {
237 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
238 Some(self.cmp(other))
239 }
240}
241
242impl Ord for MultiAsset {
243 fn cmp(&self, other: &Self) -> Ordering {
244 match (&self.fun, &other.fun) {
245 (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
246 (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
247 _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
248 }
249 }
250}
251
252impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
253 fn from((id, fun): (A, B)) -> MultiAsset {
254 MultiAsset { fun: fun.into(), id: id.into() }
255 }
256}
257
258impl MultiAsset {
259 pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
260 use Fungibility::*;
261 matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
262 }
263
264 pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
265 use Fungibility::*;
266 matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
267 }
268
269 pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
271 self.id.prepend_with(prepend)
272 }
273
274 pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
277 self.id.reanchor(target, ancestry)
278 }
279
280 pub fn reanchored(
283 mut self,
284 target: &MultiLocation,
285 ancestry: &MultiLocation,
286 ) -> Result<Self, ()> {
287 self.id.reanchor(target, ancestry)?;
288 Ok(self)
289 }
290
291 pub fn contains(&self, inner: &MultiAsset) -> bool {
293 use Fungibility::*;
294 if self.id == inner.id {
295 match (&self.fun, &inner.fun) {
296 (Fungible(a), Fungible(i)) if a >= i => return true,
297 (NonFungible(a), NonFungible(i)) if a == i => return true,
298 _ => (),
299 }
300 }
301 false
302 }
303}
304
305impl TryFrom<NewMultiAsset> for MultiAsset {
306 type Error = ();
307 fn try_from(new: NewMultiAsset) -> Result<Self, ()> {
308 Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
309 }
310}
311
312#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)]
315#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
316#[scale_info(replace_segment("staging_xcm", "xcm"))]
317pub struct MultiAssets(Vec<MultiAsset>);
318
319impl Decode for MultiAssets {
320 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
321 Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?)
322 .map_err(|()| "Out of order".into())
323 }
324}
325
326impl TryFrom<NewMultiAssets> for MultiAssets {
327 type Error = ();
328 fn try_from(new: NewMultiAssets) -> Result<Self, ()> {
329 let v = new
330 .into_inner()
331 .into_iter()
332 .map(MultiAsset::try_from)
333 .collect::<Result<Vec<_>, ()>>()?;
334 Ok(MultiAssets(v))
335 }
336}
337
338impl From<Vec<MultiAsset>> for MultiAssets {
339 fn from(mut assets: Vec<MultiAsset>) -> Self {
340 let mut res = Vec::with_capacity(assets.len());
341 if !assets.is_empty() {
342 assets.sort();
343 let mut iter = assets.into_iter();
344 if let Some(first) = iter.next() {
345 let last = iter.fold(first, |a, b| -> MultiAsset {
346 match (a, b) {
347 (
348 MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
349 MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
350 ) if a_id == b_id => MultiAsset {
351 id: a_id,
352 fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
353 },
354 (
355 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
356 MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
357 ) if a_id == b_id && a_instance == b_instance =>
358 MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
359 (to_push, to_remember) => {
360 res.push(to_push);
361 to_remember
362 },
363 }
364 });
365 res.push(last);
366 }
367 }
368 Self(res)
369 }
370}
371
372impl<T: Into<MultiAsset>> From<T> for MultiAssets {
373 fn from(x: T) -> Self {
374 Self(vec![x.into()])
375 }
376}
377
378impl MultiAssets {
379 pub fn new() -> Self {
381 Self(Vec::new())
382 }
383
384 pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
391 if r.is_empty() {
392 return Ok(Self(Vec::new()))
393 }
394 r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
395 if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
396 Ok(b)
397 } else {
398 Err(())
399 }
400 })?;
401 Ok(Self(r))
402 }
403
404 #[cfg(test)]
411 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
412 Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
413 }
414 #[cfg(not(test))]
423 pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
424 Self(r)
425 }
426
427 pub fn push(&mut self, a: MultiAsset) {
430 if let Fungibility::Fungible(ref amount) = a.fun {
431 for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
432 if let Fungibility::Fungible(ref mut balance) = asset.fun {
433 *balance = balance.saturating_add(*amount);
434 return
435 }
436 }
437 }
438 self.0.push(a);
439 self.0.sort();
440 }
441
442 pub fn is_none(&self) -> bool {
444 self.0.is_empty()
445 }
446
447 pub fn contains(&self, inner: &MultiAsset) -> bool {
449 self.0.iter().any(|i| i.contains(inner))
450 }
451
452 pub fn drain(self) -> Vec<MultiAsset> {
454 self.0
455 }
456
457 pub fn inner(&self) -> &Vec<MultiAsset> {
459 &self.0
460 }
461
462 pub fn len(&self) -> usize {
464 self.0.len()
465 }
466
467 pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
469 self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
470 }
471
472 pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
475 self.0.iter_mut().try_for_each(|i| i.reanchor(target, ancestry))
476 }
477
478 pub fn get(&self, index: usize) -> Option<&MultiAsset> {
480 self.0.get(index)
481 }
482}
483
484#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
486#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
487#[scale_info(replace_segment("staging_xcm", "xcm"))]
488pub enum WildFungibility {
489 Fungible,
490 NonFungible,
491}
492
493impl TryFrom<NewWildFungibility> for WildFungibility {
494 type Error = ();
495 fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
496 use NewWildFungibility::*;
497 Ok(match value {
498 Fungible => Self::Fungible,
499 NonFungible => Self::NonFungible,
500 })
501 }
502}
503
504#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
506#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
507#[scale_info(replace_segment("staging_xcm", "xcm"))]
508pub enum WildMultiAsset {
509 All,
512 AllOf { id: AssetId, fun: WildFungibility },
515}
516
517impl WildMultiAsset {
518 pub fn contains(&self, inner: &MultiAsset) -> bool {
523 use WildMultiAsset::*;
524 match self {
525 AllOf { fun, id } => inner.fun.is_kind(*fun) && &inner.id == id,
526 All => true,
527 }
528 }
529
530 pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
533 use WildMultiAsset::*;
534 match self {
535 AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()),
536 All => Ok(()),
537 }
538 }
539}
540
541impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
542 fn from((id, fun): (A, B)) -> WildMultiAsset {
543 WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
544 }
545}
546
547#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
552#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
553#[scale_info(replace_segment("staging_xcm", "xcm"))]
554pub enum MultiAssetFilter {
555 Definite(MultiAssets),
556 Wild(WildMultiAsset),
557}
558
559impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
560 fn from(x: T) -> Self {
561 Self::Wild(x.into())
562 }
563}
564
565impl From<MultiAsset> for MultiAssetFilter {
566 fn from(x: MultiAsset) -> Self {
567 Self::Definite(vec![x].into())
568 }
569}
570
571impl From<Vec<MultiAsset>> for MultiAssetFilter {
572 fn from(x: Vec<MultiAsset>) -> Self {
573 Self::Definite(x.into())
574 }
575}
576
577impl From<MultiAssets> for MultiAssetFilter {
578 fn from(x: MultiAssets) -> Self {
579 Self::Definite(x)
580 }
581}
582
583impl MultiAssetFilter {
584 pub fn contains(&self, inner: &MultiAsset) -> bool {
589 match self {
590 MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
591 MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
592 }
593 }
594
595 pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
598 match self {
599 MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry),
600 MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry),
601 }
602 }
603}
604
605impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
606 type Error = ();
607 fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
608 use NewWildMultiAsset::*;
609 Ok(match new {
610 AllOf { id, fun } | AllOfCounted { id, fun, .. } =>
611 Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
612 All | AllCounted(_) => Self::All,
613 })
614 }
615}
616
617impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
618 type Error = ();
619 fn try_from(old: NewMultiAssetFilter) -> Result<Self, ()> {
620 use NewMultiAssetFilter::*;
621 Ok(match old {
622 Definite(x) => Self::Definite(x.try_into()?),
623 Wild(x) => Self::Wild(x.try_into()?),
624 })
625 }
626}