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
//! - `Asset`: A description of a single asset, either an instance of a non-fungible or some amount
21
//!   of a fungible.
22
//! - `Assets`: A collection of `Asset`s. These are stored in a `Vec` and sorted with fungibles
23
//!   first.
24
//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific
25
//!   kind.
26
//! - `AssetFilter`: A combination of `Wild` and `Assets` designed for efficiently filtering an XCM
27
//!   holding account.
28

            
29
use super::{InteriorLocation, Location, Reanchorable};
30
use crate::v3::{
31
	AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
32
	MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
33
	WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
34
};
35
use alloc::{vec, vec::Vec};
36
use bounded_collections::{BoundedVec, ConstU32};
37
use codec::{self as codec, Decode, Encode, MaxEncodedLen};
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
#[derive(
43
	Copy,
44
	Clone,
45
	Eq,
46
	PartialEq,
47
	Ord,
48
	PartialOrd,
49
	Encode,
50
15
	Decode,
51
	Debug,
52
	TypeInfo,
53
	MaxEncodedLen,
54
	serde::Serialize,
55
	serde::Deserialize,
56
)]
57
pub enum AssetInstance {
58
639
	/// Undefined - used if the non-fungible asset class has only one instance.
59
639
	Undefined,
60

            
61
912
	/// A compact index. Technically this could be greater than `u128`, but this implementation
62
	/// supports only values up to `2**128 - 1`.
63
912
	Index(#[codec(compact)] u128),
64

            
65
87
	/// A 4-byte fixed-length datum.
66
87
	Array4([u8; 4]),
67

            
68
75
	/// An 8-byte fixed-length datum.
69
75
	Array8([u8; 8]),
70

            
71
63
	/// A 16-byte fixed-length datum.
72
63
	Array16([u8; 16]),
73

            
74
195
	/// A 32-byte fixed-length datum.
75
195
	Array32([u8; 32]),
76
}
77

            
78
impl TryFrom<OldAssetInstance> for AssetInstance {
79
	type Error = ();
80
410
	fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
81
		use OldAssetInstance::*;
82
410
		Ok(match value {
83
198
			Undefined => Self::Undefined,
84
74
			Index(n) => Self::Index(n),
85
20
			Array4(n) => Self::Array4(n),
86
34
			Array8(n) => Self::Array8(n),
87
48
			Array16(n) => Self::Array16(n),
88
36
			Array32(n) => Self::Array32(n),
89
		})
90
410
	}
91
}
92

            
93
impl From<()> for AssetInstance {
94
	fn from(_: ()) -> Self {
95
		Self::Undefined
96
	}
97
}
98

            
99
impl From<[u8; 4]> for AssetInstance {
100
	fn from(x: [u8; 4]) -> Self {
101
		Self::Array4(x)
102
	}
103
}
104

            
105
impl From<[u8; 8]> for AssetInstance {
106
	fn from(x: [u8; 8]) -> Self {
107
		Self::Array8(x)
108
	}
109
}
110

            
111
impl From<[u8; 16]> for AssetInstance {
112
	fn from(x: [u8; 16]) -> Self {
113
		Self::Array16(x)
114
	}
115
}
116

            
117
impl From<[u8; 32]> for AssetInstance {
118
	fn from(x: [u8; 32]) -> Self {
119
		Self::Array32(x)
120
	}
121
}
122

            
123
impl From<u8> for AssetInstance {
124
	fn from(x: u8) -> Self {
125
		Self::Index(x as u128)
126
	}
127
}
128

            
129
impl From<u16> for AssetInstance {
130
	fn from(x: u16) -> Self {
131
		Self::Index(x as u128)
132
	}
133
}
134

            
135
impl From<u32> for AssetInstance {
136
	fn from(x: u32) -> Self {
137
		Self::Index(x as u128)
138
	}
139
}
140

            
141
impl From<u64> for AssetInstance {
142
	fn from(x: u64) -> Self {
143
		Self::Index(x as u128)
144
	}
145
}
146

            
147
impl TryFrom<AssetInstance> for () {
148
	type Error = ();
149
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
150
		match x {
151
			AssetInstance::Undefined => Ok(()),
152
			_ => Err(()),
153
		}
154
	}
155
}
156

            
157
impl TryFrom<AssetInstance> for [u8; 4] {
158
	type Error = ();
159
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
160
		match x {
161
			AssetInstance::Array4(x) => Ok(x),
162
			_ => Err(()),
163
		}
164
	}
165
}
166

            
167
impl TryFrom<AssetInstance> for [u8; 8] {
168
	type Error = ();
169
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
170
		match x {
171
			AssetInstance::Array8(x) => Ok(x),
172
			_ => Err(()),
173
		}
174
	}
175
}
176

            
177
impl TryFrom<AssetInstance> for [u8; 16] {
178
	type Error = ();
179
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
180
		match x {
181
			AssetInstance::Array16(x) => Ok(x),
182
			_ => Err(()),
183
		}
184
	}
185
}
186

            
187
impl TryFrom<AssetInstance> for [u8; 32] {
188
	type Error = ();
189
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
190
		match x {
191
			AssetInstance::Array32(x) => Ok(x),
192
			_ => Err(()),
193
		}
194
	}
195
}
196

            
197
impl TryFrom<AssetInstance> for u8 {
198
	type Error = ();
199
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
200
		match x {
201
			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
202
			_ => Err(()),
203
		}
204
	}
205
}
206

            
207
impl TryFrom<AssetInstance> for u16 {
208
	type Error = ();
209
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
210
		match x {
211
			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
212
			_ => Err(()),
213
		}
214
	}
215
}
216

            
217
impl TryFrom<AssetInstance> for u32 {
218
	type Error = ();
219
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
220
		match x {
221
			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
222
			_ => Err(()),
223
		}
224
	}
225
}
226

            
227
impl TryFrom<AssetInstance> for u64 {
228
	type Error = ();
229
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
230
		match x {
231
			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
232
			_ => Err(()),
233
		}
234
	}
235
}
236

            
237
impl TryFrom<AssetInstance> for u128 {
238
	type Error = ();
239
	fn try_from(x: AssetInstance) -> Result<Self, ()> {
240
		match x {
241
			AssetInstance::Index(x) => Ok(x),
242
			_ => Err(()),
243
		}
244
	}
245
}
246

            
247
/// Classification of whether an asset is fungible or not, along with a mandatory amount or
248
/// instance.
249
#[derive(
250
	Clone,
251
	Eq,
252
	PartialEq,
253
	Ord,
254
	PartialOrd,
255
	Debug,
256
	Encode,
257
	TypeInfo,
258
	MaxEncodedLen,
259
	serde::Serialize,
260
	serde::Deserialize,
261
)]
262
pub enum Fungibility {
263
	/// A fungible asset; we record a number of units, as a `u128` in the inner item.
264
	Fungible(#[codec(compact)] u128),
265
	/// A non-fungible asset. We record the instance identifier in the inner item. Only one asset
266
	/// of each instance identifier may ever be in existence at once.
267
	NonFungible(AssetInstance),
268
}
269

            
270
117
#[derive(Decode)]
271
enum UncheckedFungibility {
272
3324
	Fungible(#[codec(compact)] u128),
273
1986
	NonFungible(AssetInstance),
274
}
275

            
276
impl Decode for Fungibility {
277
5427
	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
278
5427
		match UncheckedFungibility::decode(input)? {
279
3264
			UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
280
1938
			UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
281
			UncheckedFungibility::Fungible(_) =>
282
318
				Err("Fungible asset of zero amount is not allowed".into()),
283
		}
284
5427
	}
285
}
286

            
287
impl Fungibility {
288
1512
	pub fn is_kind(&self, w: WildFungibility) -> bool {
289
		use Fungibility::*;
290
		use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
291
1512
		matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
292
1512
	}
293
}
294

            
295
impl From<i32> for Fungibility {
296
	fn from(amount: i32) -> Fungibility {
297
		debug_assert_ne!(amount, 0);
298
		Fungibility::Fungible(amount as u128)
299
	}
300
}
301

            
302
impl From<u128> for Fungibility {
303
4350
	fn from(amount: u128) -> Fungibility {
304
4350
		debug_assert_ne!(amount, 0);
305
4350
		Fungibility::Fungible(amount)
306
4350
	}
307
}
308

            
309
impl<T: Into<AssetInstance>> From<T> for Fungibility {
310
14
	fn from(instance: T) -> Fungibility {
311
14
		Fungibility::NonFungible(instance.into())
312
14
	}
313
}
314

            
315
impl TryFrom<OldFungibility> for Fungibility {
316
	type Error = ();
317
3068
	fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
318
		use OldFungibility::*;
319
3068
		Ok(match value {
320
2658
			Fungible(n) => Self::Fungible(n),
321
410
			NonFungible(i) => Self::NonFungible(i.try_into()?),
322
		})
323
3068
	}
324
}
325

            
326
/// Classification of whether an asset is fungible or not.
327
#[derive(
328
	Copy,
329
	Clone,
330
	Eq,
331
	PartialEq,
332
	Ord,
333
	PartialOrd,
334
	Debug,
335
	Encode,
336
15
	Decode,
337
	TypeInfo,
338
	MaxEncodedLen,
339
	serde::Serialize,
340
	serde::Deserialize,
341
)]
342
pub enum WildFungibility {
343
363
	/// The asset is fungible.
344
363
	Fungible,
345
195
	/// The asset is not fungible.
346
195
	NonFungible,
347
}
348

            
349
impl TryFrom<OldWildFungibility> for WildFungibility {
350
	type Error = ();
351
476
	fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
352
		use OldWildFungibility::*;
353
476
		Ok(match value {
354
386
			Fungible => Self::Fungible,
355
90
			NonFungible => Self::NonFungible,
356
		})
357
476
	}
358
}
359

            
360
/// Location to identify an asset.
361
#[derive(
362
	Clone,
363
	Eq,
364
	PartialEq,
365
	Ord,
366
	PartialOrd,
367
	Debug,
368
	Encode,
369
	Decode,
370
	TypeInfo,
371
	MaxEncodedLen,
372
	serde::Serialize,
373
	serde::Deserialize,
374
)]
375
pub struct AssetId(pub Location);
376

            
377
impl<T: Into<Location>> From<T> for AssetId {
378
	fn from(x: T) -> Self {
379
		Self(x.into())
380
	}
381
}
382

            
383
impl TryFrom<OldAssetId> for AssetId {
384
	type Error = ();
385
4094
	fn try_from(old: OldAssetId) -> Result<Self, ()> {
386
		use OldAssetId::*;
387
4094
		Ok(match old {
388
3544
			Concrete(l) => Self(l.try_into()?),
389
550
			Abstract(_) => return Err(()),
390
		})
391
4094
	}
392
}
393

            
394
impl AssetId {
395
	/// Prepend a `Location` to an asset id, giving it a new root location.
396
	pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
397
		self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
398
		Ok(())
399
	}
400

            
401
	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
402
	/// `Asset` value.
403
	pub fn into_asset(self, fun: Fungibility) -> Asset {
404
		Asset { fun, id: self }
405
	}
406

            
407
	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
408
	/// `WildAsset` wildcard (`AllOf`) value.
409
	pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
410
		WildAsset::AllOf { fun, id: self }
411
	}
412
}
413

            
414
impl Reanchorable for AssetId {
415
	type Error = ();
416

            
417
	/// Mutate the asset to represent the same value from the perspective of a new `target`
418
	/// location. The local chain's location is provided in `context`.
419
318
	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
420
318
		self.0.reanchor(target, context)?;
421
218
		Ok(())
422
318
	}
423

            
424
	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
425
		match self.reanchor(target, context) {
426
			Ok(()) => Ok(self),
427
			Err(()) => Err(()),
428
		}
429
	}
430
}
431

            
432
/// Either an amount of a single fungible asset, or a single well-identified non-fungible asset.
433
#[derive(
434
	Clone,
435
	Eq,
436
	PartialEq,
437
	Debug,
438
	Encode,
439
	Decode,
440
	TypeInfo,
441
	MaxEncodedLen,
442
	serde::Serialize,
443
	serde::Deserialize,
444
)]
445
pub struct Asset {
446
	/// The overall asset identity (aka *class*, in the case of a non-fungible).
447
	pub id: AssetId,
448
	/// The fungibility of the asset, which contains either the amount (in the case of a fungible
449
	/// asset) or the *instance ID*, the secondary asset identifier.
450
	pub fun: Fungibility,
451
}
452

            
453
impl PartialOrd for Asset {
454
142
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
455
142
		Some(self.cmp(other))
456
142
	}
457
}
458

            
459
impl Ord for Asset {
460
142
	fn cmp(&self, other: &Self) -> Ordering {
461
142
		match (&self.fun, &other.fun) {
462
80
			(Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
463
10
			(Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
464
52
			_ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
465
		}
466
142
	}
467
}
468

            
469
impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
470
2419
	fn from((id, fun): (A, B)) -> Asset {
471
2419
		Asset { fun: fun.into(), id: id.into() }
472
2419
	}
473
}
474

            
475
impl Asset {
476
	pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
477
		use Fungibility::*;
478
		matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
479
	}
480

            
481
172
	pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
482
		use Fungibility::*;
483
172
		matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
484
172
	}
485

            
486
	/// Prepend a `Location` to a concrete asset, giving it a new root location.
487
	pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
488
		self.id.prepend_with(prepend)
489
	}
490

            
491
	/// Returns true if `self` is a super-set of the given `inner` asset.
492
	pub fn contains(&self, inner: &Asset) -> bool {
493
		use Fungibility::*;
494
		if self.id == inner.id {
495
			match (&self.fun, &inner.fun) {
496
				(Fungible(a), Fungible(i)) if a >= i => return true,
497
				(NonFungible(a), NonFungible(i)) if a == i => return true,
498
				_ => (),
499
			}
500
		}
501
		false
502
	}
503
}
504

            
505
impl Reanchorable for Asset {
506
	type Error = ();
507

            
508
	/// Mutate the location of the asset identifier if concrete, giving it the same location
509
	/// relative to a `target` context. The local context is provided as `context`.
510
40
	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
511
40
		self.id.reanchor(target, context)
512
40
	}
513

            
514
	/// Mutate the location of the asset identifier if concrete, giving it the same location
515
	/// relative to a `target` context. The local context is provided as `context`.
516
256
	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
517
256
		self.id.reanchor(target, context)?;
518
198
		Ok(self)
519
256
	}
520
}
521

            
522
impl TryFrom<OldAsset> for Asset {
523
	type Error = ();
524
3382
	fn try_from(old: OldAsset) -> Result<Self, ()> {
525
3382
		Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
526
3382
	}
527
}
528

            
529
/// A `Vec` of `Asset`s.
530
///
531
/// There are a number of invariants which the construction and mutation functions must ensure are
532
/// maintained:
533
/// - It may contain no items of duplicate asset class;
534
/// - All items must be ordered;
535
/// - The number of items should grow no larger than `MAX_ITEMS_IN_ASSETS`.
536
#[derive(
537
	Clone,
538
	Eq,
539
	PartialEq,
540
	Ord,
541
	PartialOrd,
542
	Debug,
543
	Encode,
544
	TypeInfo,
545
	Default,
546
	serde::Serialize,
547
	serde::Deserialize,
548
)]
549
pub struct Assets(Vec<Asset>);
550

            
551
/// Maximum number of items we expect in a single `Assets` value. Note this is not (yet)
552
/// enforced, and just serves to provide a sensible `max_encoded_len` for `Assets`.
553
pub const MAX_ITEMS_IN_ASSETS: usize = 20;
554

            
555
impl MaxEncodedLen for Assets {
556
	fn max_encoded_len() -> usize {
557
		Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
558
	}
559
}
560

            
561
impl Decode for Assets {
562
265389
	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
563
263865
		let bounded_instructions =
564
265389
			BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
565
263865
		Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
566
263865
			.map_err(|()| "Out of order".into())
567
265389
	}
568
}
569

            
570
impl TryFrom<OldAssets> for Assets {
571
	type Error = ();
572
97772
	fn try_from(old: OldAssets) -> Result<Self, ()> {
573
97772
		let v = old
574
97772
			.into_inner()
575
97772
			.into_iter()
576
97772
			.map(Asset::try_from)
577
97772
			.collect::<Result<Vec<_>, ()>>()?;
578
97528
		Ok(Assets(v))
579
97772
	}
580
}
581

            
582
impl From<Vec<Asset>> for Assets {
583
1928
	fn from(mut assets: Vec<Asset>) -> Self {
584
1928
		let mut res = Vec::with_capacity(assets.len());
585
1928
		if !assets.is_empty() {
586
270
			assets.sort();
587
270
			let mut iter = assets.into_iter();
588
270
			if let Some(first) = iter.next() {
589
270
				let last = iter.fold(first, |a, b| -> Asset {
590
					match (a, b) {
591
						(
592
							Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
593
							Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
594
						) if a_id == b_id => Asset {
595
							id: a_id,
596
							fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
597
						},
598
						(
599
							Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
600
							Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
601
						) if a_id == b_id && a_instance == b_instance =>
602
							Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
603
						(to_push, to_remember) => {
604
							res.push(to_push);
605
							to_remember
606
						},
607
					}
608
270
				});
609
270
				res.push(last);
610
270
			}
611
1658
		}
612
1928
		Self(res)
613
1928
	}
614
}
615

            
616
impl<T: Into<Asset>> From<T> for Assets {
617
1995
	fn from(x: T) -> Self {
618
1995
		Self(vec![x.into()])
619
1995
	}
620
}
621

            
622
impl Assets {
623
	/// A new (empty) value.
624
996
	pub fn new() -> Self {
625
996
		Self(Vec::new())
626
996
	}
627

            
628
	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
629
	/// and which contain no duplicates.
630
	///
631
	/// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates.
632
	/// If you can't guarantee that `r` is sorted and deduplicated, then use
633
	/// `From::<Vec<Asset>>::from` which is infallible.
634
175910
	pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
635
175910
		if r.is_empty() {
636
174692
			return Ok(Self(Vec::new()))
637
1218
		}
638
1218
		r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
639
356
			if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
640
294
				Ok(b)
641
			} else {
642
62
				Err(())
643
			}
644
1218
		})?;
645
1156
		Ok(Self(r))
646
175910
	}
647

            
648
	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
649
	/// and which contain no duplicates.
650
	///
651
	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
652
	/// negligible-cost operation. Generally though you should avoid using it unless you have a
653
	/// strict proof that `r` is valid.
654
	#[cfg(test)]
655
	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
656
		Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
657
	}
658
	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
659
	/// and which contain no duplicates.
660
	///
661
	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
662
	/// negligible-cost operation. Generally though you should avoid using it unless you have a
663
	/// strict proof that `r` is valid.
664
	///
665
	/// In test mode, this checks anyway and panics on fail.
666
	#[cfg(not(test))]
667
	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
668
		Self(r)
669
	}
670

            
671
	/// Add some asset onto the list, saturating. This is quite a laborious operation since it
672
	/// maintains the ordering.
673
	pub fn push(&mut self, a: Asset) {
674
		for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
675
			match (&a.fun, &mut asset.fun) {
676
				(Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
677
					*balance = balance.saturating_add(*amount);
678
					return
679
				},
680
				(Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
681
					if inst1 == inst2 =>
682
					return,
683
				_ => (),
684
			}
685
		}
686
		self.0.push(a);
687
		self.0.sort();
688
	}
689

            
690
	/// Returns `true` if this definitely represents no asset.
691
	pub fn is_none(&self) -> bool {
692
		self.0.is_empty()
693
	}
694

            
695
	/// Returns true if `self` is a super-set of the given `inner` asset.
696
	pub fn contains(&self, inner: &Asset) -> bool {
697
		self.0.iter().any(|i| i.contains(inner))
698
	}
699

            
700
	/// Consume `self` and return the inner vec.
701
	#[deprecated = "Use `into_inner()` instead"]
702
	pub fn drain(self) -> Vec<Asset> {
703
		self.0
704
	}
705

            
706
	/// Consume `self` and return the inner vec.
707
46560
	pub fn into_inner(self) -> Vec<Asset> {
708
46560
		self.0
709
46560
	}
710

            
711
	/// Return a reference to the inner vec.
712
47636
	pub fn inner(&self) -> &Vec<Asset> {
713
47636
		&self.0
714
47636
	}
715

            
716
	/// Return the number of distinct asset instances contained.
717
44108
	pub fn len(&self) -> usize {
718
44108
		self.0.len()
719
44108
	}
720

            
721
	/// Prepend a `Location` to any concrete asset items, giving it a new root location.
722
	pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
723
		self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
724
		self.0.sort();
725
		Ok(())
726
	}
727

            
728
	/// Return a reference to an item at a specific index or `None` if it doesn't exist.
729
	pub fn get(&self, index: usize) -> Option<&Asset> {
730
		self.0.get(index)
731
	}
732
}
733

            
734
impl Reanchorable for Assets {
735
	type Error = ();
736

            
737
528
	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
738
528
		self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
739
492
		self.0.sort();
740
492
		Ok(())
741
528
	}
742

            
743
	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
744
		match self.reanchor(target, context) {
745
			Ok(()) => Ok(self),
746
			Err(()) => Err(()),
747
		}
748
	}
749
}
750

            
751
/// A wildcard representing a set of assets.
752
#[derive(
753
	Clone,
754
	Eq,
755
	PartialEq,
756
	Ord,
757
	PartialOrd,
758
	Debug,
759
	Encode,
760
15
	Decode,
761
	TypeInfo,
762
	MaxEncodedLen,
763
	serde::Serialize,
764
	serde::Deserialize,
765
)]
766
pub enum WildAsset {
767
678
	/// All assets in Holding.
768
678
	All,
769
492
	/// All assets in Holding of a given fungibility and ID.
770
492
	AllOf { id: AssetId, fun: WildFungibility },
771
45
	/// All assets in Holding, up to `u32` individual assets (different instances of non-fungibles
772
	/// are separate assets).
773
45
	AllCounted(#[codec(compact)] u32),
774
93
	/// All assets in Holding of a given fungibility and ID up to `count` individual assets
775
	/// (different instances of non-fungibles are separate assets).
776
	AllOfCounted {
777
3
		id: AssetId,
778
6
		fun: WildFungibility,
779
3
		#[codec(compact)]
780
3
		count: u32,
781
93
	},
782
}
783

            
784
impl TryFrom<OldWildAsset> for WildAsset {
785
	type Error = ();
786
1906
	fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
787
		use OldWildAsset::*;
788
1906
		Ok(match old {
789
514
			AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
790
802
			All => Self::All,
791
198
			AllOfCounted { id, fun, count } =>
792
198
				Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
793
392
			AllCounted(count) => Self::AllCounted(count),
794
		})
795
1906
	}
796
}
797

            
798
impl WildAsset {
799
	/// Returns true if `self` is a super-set of the given `inner` asset.
800
1512
	pub fn contains(&self, inner: &Asset) -> bool {
801
		use WildAsset::*;
802
1512
		match self {
803
			AllOfCounted { count: 0, .. } | AllCounted(0) => false,
804
1512
			AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
805
1512
				inner.fun.is_kind(*fun) && &inner.id == id,
806
			All | AllCounted(_) => true,
807
		}
808
1512
	}
809

            
810
	/// Returns true if the wild element of `self` matches `inner`.
811
	///
812
	/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
813
	/// always returning `false` when equal to 0.
814
	#[deprecated = "Use `contains` instead"]
815
	pub fn matches(&self, inner: &Asset) -> bool {
816
		self.contains(inner)
817
	}
818

            
819
	/// Mutate the asset to represent the same value from the perspective of a new `target`
820
	/// location. The local chain's location is provided in `context`.
821
	pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
822
		use WildAsset::*;
823
		match self {
824
			AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
825
				id.reanchor(target, context),
826
			All | AllCounted(_) => Ok(()),
827
		}
828
	}
829

            
830
	/// Maximum count of assets allowed to match, if any.
831
990
	pub fn count(&self) -> Option<u32> {
832
		use WildAsset::*;
833
990
		match self {
834
350
			AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
835
640
			All | AllOf { .. } => None,
836
		}
837
990
	}
838

            
839
	/// Explicit limit on number of assets allowed to match, if any.
840
990
	pub fn limit(&self) -> Option<u32> {
841
990
		self.count()
842
990
	}
843

            
844
	/// Consume self and return the equivalent version but counted and with the `count` set to the
845
	/// given parameter.
846
	pub fn counted(self, count: u32) -> Self {
847
		use WildAsset::*;
848
		match self {
849
			AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
850
			All | AllCounted(_) => AllCounted(count),
851
		}
852
	}
853
}
854

            
855
impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
856
	fn from((id, fun): (A, B)) -> WildAsset {
857
		WildAsset::AllOf { fun: fun.into(), id: id.into() }
858
	}
859
}
860

            
861
/// `Asset` collection, defined either by a number of `Assets` or a single wildcard.
862
#[derive(
863
	Clone,
864
	Eq,
865
	PartialEq,
866
	Ord,
867
	PartialOrd,
868
	Debug,
869
	Encode,
870
78
	Decode,
871
	TypeInfo,
872
	MaxEncodedLen,
873
	serde::Serialize,
874
	serde::Deserialize,
875
)]
876
pub enum AssetFilter {
877
6324
	/// Specify the filter as being everything contained by the given `Assets` inner.
878
6324
	Definite(Assets),
879
1323
	/// Specify the filter as the given `WildAsset` wildcard.
880
1323
	Wild(WildAsset),
881
}
882

            
883
impl<T: Into<WildAsset>> From<T> for AssetFilter {
884
57
	fn from(x: T) -> Self {
885
57
		Self::Wild(x.into())
886
57
	}
887
}
888

            
889
impl From<Asset> for AssetFilter {
890
18
	fn from(x: Asset) -> Self {
891
18
		Self::Definite(vec![x].into())
892
18
	}
893
}
894

            
895
impl From<Vec<Asset>> for AssetFilter {
896
	fn from(x: Vec<Asset>) -> Self {
897
		Self::Definite(x.into())
898
	}
899
}
900

            
901
impl From<Assets> for AssetFilter {
902
964
	fn from(x: Assets) -> Self {
903
964
		Self::Definite(x)
904
964
	}
905
}
906

            
907
impl AssetFilter {
908
	/// Returns true if `inner` would be matched by `self`.
909
	///
910
	/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
911
	/// always returning `false` when equal to 0.
912
1512
	pub fn matches(&self, inner: &Asset) -> bool {
913
1512
		match self {
914
			AssetFilter::Definite(ref assets) => assets.contains(inner),
915
1512
			AssetFilter::Wild(ref wild) => wild.contains(inner),
916
		}
917
1512
	}
918

            
919
	/// Mutate the location of the asset identifier if concrete, giving it the same location
920
	/// relative to a `target` context. The local context is provided as `context`.
921
	pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
922
		match self {
923
			AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
924
			AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
925
		}
926
	}
927

            
928
	/// Maximum count of assets it is possible to match, if known.
929
	pub fn count(&self) -> Option<u32> {
930
		use AssetFilter::*;
931
		match self {
932
			Definite(x) => Some(x.len() as u32),
933
			Wild(x) => x.count(),
934
		}
935
	}
936

            
937
	/// Explicit limit placed on the number of items, if any.
938
2620
	pub fn limit(&self) -> Option<u32> {
939
		use AssetFilter::*;
940
2620
		match self {
941
1630
			Definite(_) => None,
942
990
			Wild(x) => x.limit(),
943
		}
944
2620
	}
945
}
946

            
947
impl TryFrom<OldAssetFilter> for AssetFilter {
948
	type Error = ();
949
5914
	fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
950
5914
		Ok(match old {
951
4008
			OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
952
1906
			OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
953
		})
954
5914
	}
955
}
956

            
957
#[cfg(test)]
958
mod tests {
959
	use super::super::prelude::*;
960

            
961
	#[test]
962
	fn conversion_works() {
963
		let _: Assets = (Here, 1u128).into();
964
	}
965

            
966
	#[test]
967
	fn from_sorted_and_deduplicated_works() {
968
		use super::*;
969
		use alloc::vec;
970

            
971
		let empty = vec![];
972
		let r = Assets::from_sorted_and_deduplicated(empty);
973
		assert_eq!(r, Ok(Assets(vec![])));
974

            
975
		let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
976
		let r = Assets::from_sorted_and_deduplicated(dup_fun);
977
		assert!(r.is_err());
978

            
979
		let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
980
		let r = Assets::from_sorted_and_deduplicated(dup_nft);
981
		assert!(r.is_err());
982

            
983
		let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
984
		let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
985
		assert_eq!(r, Ok(Assets(good_fun)));
986

            
987
		let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
988
		let r = Assets::from_sorted_and_deduplicated(bad_fun);
989
		assert!(r.is_err());
990

            
991
		let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
992
		let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
993
		assert_eq!(r, Ok(Assets(good_nft)));
994

            
995
		let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
996
		let r = Assets::from_sorted_and_deduplicated(bad_nft);
997
		assert!(r.is_err());
998

            
999
		let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
		let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
		assert_eq!(r, Ok(Assets(mixed_good)));
		let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
		let r = Assets::from_sorted_and_deduplicated(mixed_bad);
		assert!(r.is_err());
	}
	#[test]
	fn reanchor_preserves_sorting() {
		use super::*;
		use alloc::vec;
		let reanchor_context: Junctions = Parachain(2000).into();
		let dest = Location::new(1, []);
		let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
		let mut asset_1_reanchored = asset_1.clone();
		assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
		assert_eq!(
			asset_1_reanchored,
			(Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
		);
		let asset_2: Asset = (Location::new(1, []), 10).into();
		let mut asset_2_reanchored = asset_2.clone();
		assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
		assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
		let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
		let mut asset_3_reanchored = asset_3.clone();
		assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
		assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
		let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
		assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
		// decoding respects limits and sorting
		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
		assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
		assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
		// decoding respects limits and sorting
		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
	}
	#[test]
	fn prepend_preserves_sorting() {
		use super::*;
		use alloc::vec;
		let prefix = Location::new(0, [Parachain(1000)]);
		let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
		let mut asset_1_prepended = asset_1.clone();
		assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
		// changes interior X2->X3
		assert_eq!(
			asset_1_prepended,
			(Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
		);
		let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
		let mut asset_2_prepended = asset_2.clone();
		assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
		// changes parent
		assert_eq!(
			asset_2_prepended,
			(Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
		);
		let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
		let mut asset_3_prepended = asset_3.clone();
		assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
		// changes parent
		assert_eq!(
			asset_3_prepended,
			(Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
		);
		// `From` impl does sorting.
		let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
		// decoding respects limits and sorting
		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
		// let's do `prepend_with`
		assert!(assets.prepend_with(&prefix).is_ok());
		assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
		// decoding respects limits and sorting
		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
	}
	#[test]
	fn decoding_respects_limit() {
		use super::*;
		// Having lots of one asset will work since they are deduplicated
		let lots_of_one_asset: Assets =
			vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
		let encoded = lots_of_one_asset.encode();
		assert!(Assets::decode(&mut &encoded[..]).is_ok());
		// Fewer assets than the limit works
		let mut few_assets: Assets = Vec::new().into();
		for i in 0..MAX_ITEMS_IN_ASSETS {
			few_assets.push((GeneralIndex(i as u128), 1u128).into());
		}
		let encoded = few_assets.encode();
		assert!(Assets::decode(&mut &encoded[..]).is_ok());
		// Having lots of different assets will not work
		let mut too_many_different_assets: Assets = Vec::new().into();
		for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
			too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
		}
		let encoded = too_many_different_assets.encode();
		assert!(Assets::decode(&mut &encoded[..]).is_err());
	}
}