1
// Copyright (C) Parity Technologies (UK) Ltd.
2
// This file is part of Polkadot.
3

            
4
// Substrate is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Substrate is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! Cross-Consensus Message format asset data structures.
18
//!
19
//! This encompasses four types for representing assets:
20
//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some
21
//!   amount of a fungible.
22
//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with
23
//!   fungibles first.
24
//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific
25
//!   kind.
26
//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently
27
//!   filtering an XCM holding account.
28

            
29
use super::MultiLocation;
30
use 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
};
36
use alloc::{vec, vec::Vec};
37
use codec::{self as codec, Decode, Encode};
38
use core::cmp::Ordering;
39
use scale_info::TypeInfo;
40

            
41
/// A general identifier for an instance of a non-fungible asset class.
42
24
#[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"))]
45
pub enum AssetInstance {
46
756
	/// Undefined - used if the non-fungible asset class has only one instance.
47
756
	Undefined,
48

            
49
1044
	/// A compact index. Technically this could be greater than `u128`, but this implementation
50
	/// supports only values up to `2**128 - 1`.
51
1044
	Index(#[codec(compact)] u128),
52

            
53
51
	/// A 4-byte fixed-length datum.
54
51
	Array4([u8; 4]),
55

            
56
63
	/// An 8-byte fixed-length datum.
57
63
	Array8([u8; 8]),
58

            
59
108
	/// A 16-byte fixed-length datum.
60
108
	Array16([u8; 16]),
61

            
62
222
	/// A 32-byte fixed-length datum.
63
222
	Array32([u8; 32]),
64

            
65
663
	/// An arbitrary piece of data. Use only when necessary.
66
663
	Blob(Vec<u8>),
67
}
68

            
69
impl From<()> for AssetInstance {
70
	fn from(_: ()) -> Self {
71
		Self::Undefined
72
	}
73
}
74

            
75
impl From<[u8; 4]> for AssetInstance {
76
	fn from(x: [u8; 4]) -> Self {
77
		Self::Array4(x)
78
	}
79
}
80

            
81
impl From<[u8; 8]> for AssetInstance {
82
	fn from(x: [u8; 8]) -> Self {
83
		Self::Array8(x)
84
	}
85
}
86

            
87
impl From<[u8; 16]> for AssetInstance {
88
	fn from(x: [u8; 16]) -> Self {
89
		Self::Array16(x)
90
	}
91
}
92

            
93
impl From<[u8; 32]> for AssetInstance {
94
	fn from(x: [u8; 32]) -> Self {
95
		Self::Array32(x)
96
	}
97
}
98

            
99
impl From<Vec<u8>> for AssetInstance {
100
	fn from(x: Vec<u8>) -> Self {
101
		Self::Blob(x)
102
	}
103
}
104

            
105
impl 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
/// Classification of an asset being concrete or abstract.
121
288
#[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"))]
124
pub enum AssetId {
125
24102
	Concrete(MultiLocation),
126
5451
	Abstract(Vec<u8>),
127
}
128

            
129
impl<T: Into<MultiLocation>> From<T> for AssetId {
130
	fn from(x: T) -> Self {
131
		Self::Concrete(x.into())
132
	}
133
}
134

            
135
impl From<Vec<u8>> for AssetId {
136
	fn from(x: Vec<u8>) -> Self {
137
		Self::Abstract(x)
138
	}
139
}
140

            
141
impl 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

            
155
impl AssetId {
156
	/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
157
	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
	/// Mutate the asset to represent the same value from the perspective of a new `target`
165
	/// location. The local chain's location is provided in `ancestry`.
166
	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
	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
174
	/// `MultiAsset` value.
175
	pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
176
		MultiAsset { fun, id: self }
177
	}
178

            
179
	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
180
	/// `WildMultiAsset` wildcard (`AllOf`) value.
181
	pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
182
		WildMultiAsset::AllOf { fun, id: self }
183
	}
184
}
185

            
186
/// Classification of whether an asset is fungible or not, along with a mandatory amount or
187
/// instance.
188
153
#[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"))]
191
pub enum Fungibility {
192
21768
	Fungible(#[codec(compact)] u128),
193
2931
	NonFungible(AssetInstance),
194
}
195

            
196
impl 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

            
204
impl From<u128> for Fungibility {
205
	fn from(amount: u128) -> Fungibility {
206
		debug_assert_ne!(amount, 0);
207
		Fungibility::Fungible(amount)
208
	}
209
}
210

            
211
impl<T: Into<AssetInstance>> From<T> for Fungibility {
212
	fn from(instance: T) -> Fungibility {
213
		Fungibility::NonFungible(instance.into())
214
	}
215
}
216

            
217
impl 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"))]
231
pub struct MultiAsset {
232
	pub id: AssetId,
233
	pub fun: Fungibility,
234
}
235

            
236
impl PartialOrd for MultiAsset {
237
492
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
238
492
		Some(self.cmp(other))
239
492
	}
240
}
241

            
242
impl Ord for MultiAsset {
243
492
	fn cmp(&self, other: &Self) -> Ordering {
244
492
		match (&self.fun, &other.fun) {
245
182
			(Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
246
22
			(Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
247
288
			_ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
248
		}
249
492
	}
250
}
251

            
252
impl<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

            
258
impl 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
412
	pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
265
		use Fungibility::*;
266
412
		matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
267
412
	}
268

            
269
	/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
270
	pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
271
		self.id.prepend_with(prepend)
272
	}
273

            
274
	/// Mutate the location of the asset identifier if concrete, giving it the same location
275
	/// relative to a `target` context. The local context is provided as `ancestry`.
276
	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
277
		self.id.reanchor(target, ancestry)
278
	}
279

            
280
	/// Mutate the location of the asset identifier if concrete, giving it the same location
281
	/// relative to a `target` context. The local context is provided as `ancestry`.
282
	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
	/// Returns true if `self` is a super-set of the given `inner`.
292
	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

            
305
impl 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
/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding,
313
/// they must be sorted.
314
#[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"))]
317
pub struct MultiAssets(Vec<MultiAsset>);
318

            
319
impl Decode for MultiAssets {
320
251787
	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
321
251787
		Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?)
322
250407
			.map_err(|()| "Out of order".into())
323
251787
	}
324
}
325

            
326
impl TryFrom<NewMultiAssets> for MultiAssets {
327
	type Error = ();
328
2
	fn try_from(new: NewMultiAssets) -> Result<Self, ()> {
329
2
		let v = new
330
2
			.into_inner()
331
2
			.into_iter()
332
2
			.map(MultiAsset::try_from)
333
2
			.collect::<Result<Vec<_>, ()>>()?;
334
2
		Ok(MultiAssets(v))
335
2
	}
336
}
337

            
338
impl 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

            
372
impl<T: Into<MultiAsset>> From<T> for MultiAssets {
373
	fn from(x: T) -> Self {
374
		Self(vec![x.into()])
375
	}
376
}
377

            
378
impl MultiAssets {
379
	/// A new (empty) value.
380
	pub fn new() -> Self {
381
		Self(Vec::new())
382
	}
383

            
384
	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
385
	/// and which contain no duplicates.
386
	///
387
	/// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates.
388
	/// If you can't guarantee that `r` is sorted and deduplicated, then use
389
	/// `From::<Vec<MultiAsset>>::from` which is infallible.
390
166938
	pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
391
166938
		if r.is_empty() {
392
161642
			return Ok(Self(Vec::new()))
393
5296
		}
394
5296
		r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
395
2028
			if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
396
1762
				Ok(b)
397
			} else {
398
266
				Err(())
399
			}
400
5296
		})?;
401
5030
		Ok(Self(r))
402
166938
	}
403

            
404
	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
405
	/// and which contain no duplicates.
406
	///
407
	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
408
	/// negligible-cost operation. Generally though you should avoid using it unless you have a
409
	/// strict proof that `r` is valid.
410
	#[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
	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
415
	/// and which contain no duplicates.
416
	///
417
	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
418
	/// negligible-cost operation. Generally though you should avoid using it unless you have a
419
	/// strict proof that `r` is valid.
420
	///
421
	/// In test mode, this checks anyway and panics on fail.
422
	#[cfg(not(test))]
423
	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
424
		Self(r)
425
	}
426

            
427
	/// Add some asset onto the list, saturating. This is quite a laborious operation since it
428
	/// maintains the ordering.
429
	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
	/// Returns `true` if this definitely represents no asset.
443
	pub fn is_none(&self) -> bool {
444
		self.0.is_empty()
445
	}
446

            
447
	/// Returns true if `self` is a super-set of the given `inner`.
448
	pub fn contains(&self, inner: &MultiAsset) -> bool {
449
		self.0.iter().any(|i| i.contains(inner))
450
	}
451

            
452
	/// Consume `self` and return the inner vec.
453
61090
	pub fn drain(self) -> Vec<MultiAsset> {
454
61090
		self.0
455
61090
	}
456

            
457
	/// Return a reference to the inner vec.
458
12
	pub fn inner(&self) -> &Vec<MultiAsset> {
459
12
		&self.0
460
12
	}
461

            
462
	/// Return the number of distinct asset instances contained.
463
984
	pub fn len(&self) -> usize {
464
984
		self.0.len()
465
984
	}
466

            
467
	/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
468
	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
	/// Mutate the location of the asset identifier if concrete, giving it the same location
473
	/// relative to a `target` context. The local context is provided as `ancestry`.
474
	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
	/// Return a reference to an item at a specific index or `None` if it doesn't exist.
479
	pub fn get(&self, index: usize) -> Option<&MultiAsset> {
480
		self.0.get(index)
481
	}
482
}
483

            
484
/// Classification of whether an asset is fungible or not.
485
18
#[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"))]
488
pub enum WildFungibility {
489
3720
	Fungible,
490
627
	NonFungible,
491
}
492

            
493
impl 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
/// A wildcard representing a set of assets.
505
30
#[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"))]
508
pub enum WildMultiAsset {
509
3837
	/// All assets in the holding register, up to `usize` individual assets (different instances of
510
3837
	/// non-fungibles could be separate assets).
511
3837
	All,
512
4380
	/// All assets in the holding register of a given fungibility and ID. If operating on
513
	/// non-fungibles, then a limit is provided for the maximum amount of matching instances.
514
4380
	AllOf { id: AssetId, fun: WildFungibility },
515
}
516

            
517
impl WildMultiAsset {
518
	/// Returns true if `self` is a super-set of the given `inner`.
519
	///
520
	/// Typically, any wildcard is never contained in anything else, and a wildcard can contain any
521
	/// other non-wildcard. For more details, see the implementation and tests.
522
	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
	/// Mutate the location of the asset identifier if concrete, giving it the same location
531
	/// relative to a `target` context. The local context is provided as `ancestry`.
532
	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

            
541
impl<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
/// `MultiAsset` collection, either `MultiAssets` or a single wildcard.
548
///
549
/// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported
550
/// in this implementation and will result in a decode error.
551
84
#[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"))]
554
pub enum MultiAssetFilter {
555
8604
	Definite(MultiAssets),
556
8247
	Wild(WildMultiAsset),
557
}
558

            
559
impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
560
	fn from(x: T) -> Self {
561
		Self::Wild(x.into())
562
	}
563
}
564

            
565
impl From<MultiAsset> for MultiAssetFilter {
566
	fn from(x: MultiAsset) -> Self {
567
		Self::Definite(vec![x].into())
568
	}
569
}
570

            
571
impl From<Vec<MultiAsset>> for MultiAssetFilter {
572
	fn from(x: Vec<MultiAsset>) -> Self {
573
		Self::Definite(x.into())
574
	}
575
}
576

            
577
impl From<MultiAssets> for MultiAssetFilter {
578
	fn from(x: MultiAssets) -> Self {
579
		Self::Definite(x)
580
	}
581
}
582

            
583
impl MultiAssetFilter {
584
	/// Returns true if `self` is a super-set of the given `inner`.
585
	///
586
	/// Typically, any wildcard is never contained in anything else, and a wildcard can contain any
587
	/// other non-wildcard. For more details, see the implementation and tests.
588
	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
	/// Mutate the location of the asset identifier if concrete, giving it the same location
596
	/// relative to a `target` context. The local context is provided as `ancestry`.
597
	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

            
605
impl 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

            
617
impl 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
}