1
// Copyright 2019-2022 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam 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
// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! Moonbase Runtime Xcm Tests
18

            
19
mod xcm_mock;
20
use frame_support::{
21
	assert_ok,
22
	traits::{ConstU32, PalletInfo, PalletInfoAccess},
23
	weights::constants::WEIGHT_REF_TIME_PER_SECOND,
24
	weights::Weight,
25
	BoundedVec,
26
};
27
use pallet_xcm_transactor::{
28
	Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights,
29
};
30
use sp_runtime::traits::{Convert, MaybeEquivalence};
31
use sp_std::boxed::Box;
32
use xcm::{
33
	latest::prelude::{
34
		AccountId32, AccountKey20, All, Asset, AssetId, Assets as XcmAssets, BuyExecution,
35
		ClearOrigin, DepositAsset, Fungibility, GeneralIndex, Junction, Junctions, Limited,
36
		Location, OriginKind, PalletInstance, Parachain, QueryResponse, Reanchorable, Response,
37
		WeightLimit, WithdrawAsset, Xcm,
38
	},
39
	VersionedAssets,
40
};
41
use xcm::{IntoVersion, VersionedLocation, WrapVersion};
42
use xcm_executor::traits::ConvertLocation;
43
use xcm_mock::*;
44
use xcm_primitives::{
45
	split_location_into_chain_part_and_beneficiary, UtilityEncodeCall, DEFAULT_PROOF_SIZE,
46
};
47
use xcm_simulator::TestExt;
48
mod common;
49
use cumulus_primitives_core::relay_chain::HrmpChannelId;
50
use parachain::PolkadotXcm;
51

            
52
28
fn add_supported_asset(asset_type: parachain::AssetType, units_per_second: u128) -> Result<(), ()> {
53
28
	let parachain::AssetType::Xcm(location_v3) = asset_type;
54
28
	let VersionedLocation::V4(location_v4) = VersionedLocation::V3(location_v3)
55
28
		.into_version(4)
56
28
		.map_err(|_| ())?
57
	else {
58
		return Err(());
59
	};
60
	use frame_support::weights::WeightToFee as _;
61
28
	let native_amount_per_second: u128 =
62
28
		<parachain::Runtime as pallet_xcm_weight_trader::Config>::WeightToFee::weight_to_fee(
63
28
			&Weight::from_parts(
64
28
				frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
65
28
				0,
66
28
			),
67
28
		)
68
28
		.try_into()
69
28
		.map_err(|_| ())?;
70
28
	let precision_factor = 10u128.pow(pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS);
71
28
	let relative_price: u128 = if units_per_second > 0u128 {
72
10
		native_amount_per_second
73
10
			.saturating_mul(precision_factor)
74
10
			.saturating_div(units_per_second)
75
	} else {
76
18
		0u128
77
	};
78
28
	pallet_xcm_weight_trader::SupportedAssets::<parachain::Runtime>::insert(
79
28
		location_v4,
80
28
		(true, relative_price),
81
28
	);
82
28
	Ok(())
83
28
}
84

            
85
25
fn currency_to_asset(currency_id: parachain::CurrencyId, amount: u128) -> Asset {
86
25
	Asset {
87
25
		id: AssetId(
88
25
			<parachain::Runtime as pallet_xcm_transactor::Config>::CurrencyIdToLocation::convert(
89
25
				currency_id,
90
25
			)
91
25
			.unwrap(),
92
25
		),
93
25
		fun: Fungibility::Fungible(amount),
94
25
	}
95
25
}
96

            
97
// Send a relay asset (like DOT) to a parachain A
98
#[test]
99
1
fn receive_relay_asset_from_relay() {
100
1
	MockNet::reset();
101
1

            
102
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
103
1
	let source_id: parachain::AssetId = source_location.clone().into();
104
1
	let asset_metadata = parachain::AssetMetadata {
105
1
		name: b"RelayToken".to_vec(),
106
1
		symbol: b"Relay".to_vec(),
107
1
		decimals: 12,
108
1
	};
109
1
	// register relay asset in parachain A
110
1
	ParaA::execute_with(|| {
111
1
		assert_ok!(AssetManager::register_foreign_asset(
112
1
			parachain::RuntimeOrigin::root(),
113
1
			source_location.clone(),
114
1
			asset_metadata,
115
1
			1u128,
116
1
			true
117
1
		));
118
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
119
1
	});
120
1

            
121
1
	// Actually send relay asset to parachain
122
1
	let dest: Location = AccountKey20 {
123
1
		network: None,
124
1
		key: PARAALICE,
125
1
	}
126
1
	.into();
127
1
	Relay::execute_with(|| {
128
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
129
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
130
1
			Box::new(Parachain(1).into()),
131
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
132
1
			Box::new(([], 123).into()),
133
1
			0,
134
1
			WeightLimit::Unlimited
135
1
		));
136
1
	});
137
1

            
138
1
	// Verify that parachain received the asset
139
1
	ParaA::execute_with(|| {
140
1
		// free execution, full amount received
141
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123);
142
1
	});
143
1
}
144

            
145
// Send relay asset (like DOT) back from Parachain A to relaychain
146
#[test]
147
1
fn send_relay_asset_to_relay() {
148
1
	MockNet::reset();
149
1

            
150
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
151
1
	let source_id: parachain::AssetId = source_location.clone().into();
152
1

            
153
1
	let asset_metadata = parachain::AssetMetadata {
154
1
		name: b"RelayToken".to_vec(),
155
1
		symbol: b"Relay".to_vec(),
156
1
		decimals: 12,
157
1
	};
158
1

            
159
1
	// Register relay asset in paraA
160
1
	ParaA::execute_with(|| {
161
1
		assert_ok!(AssetManager::register_foreign_asset(
162
1
			parachain::RuntimeOrigin::root(),
163
1
			source_location.clone(),
164
1
			asset_metadata,
165
1
			1u128,
166
1
			true
167
1
		));
168
		// Free execution
169
1
		assert_ok!(add_supported_asset(source_location, 0));
170
1
	});
171
1

            
172
1
	let dest: Location = Junction::AccountKey20 {
173
1
		network: None,
174
1
		key: PARAALICE,
175
1
	}
176
1
	.into();
177
1

            
178
1
	// First send relay chain asset to Parachain like in previous test
179
1
	Relay::execute_with(|| {
180
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
181
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
182
1
			Box::new(Parachain(1).into()),
183
1
			Box::new(VersionedLocation::V4(dest.clone()).into()),
184
1
			Box::new(([], 123).into()),
185
1
			0,
186
1
			WeightLimit::Unlimited
187
1
		));
188
1
	});
189
1

            
190
1
	ParaA::execute_with(|| {
191
1
		// Free execution, full amount received
192
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123);
193
1
	});
194
1

            
195
1
	// Lets gather the balance before sending back money
196
1
	let mut balance_before_sending = 0;
197
1
	Relay::execute_with(|| {
198
1
		balance_before_sending = RelayBalances::free_balance(&RELAYALICE);
199
1
	});
200
1

            
201
1
	// We now send back some money to the relay
202
1
	let dest = Location {
203
1
		parents: 1,
204
1
		interior: [AccountId32 {
205
1
			network: None,
206
1
			id: RELAYALICE.into(),
207
1
		}]
208
1
		.into(),
209
1
	};
210
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
211
1

            
212
1
	ParaA::execute_with(|| {
213
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 123);
214
1
		// free execution, full amount received
215
1
		assert_ok!(PolkadotXcm::transfer_assets(
216
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
217
1
			Box::new(VersionedLocation::V4(chain_part)),
218
1
			Box::new(VersionedLocation::V4(beneficiary)),
219
1
			Box::new(VersionedAssets::V4(asset.into())),
220
1
			0,
221
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
222
1
		));
223
1
	});
224
1

            
225
1
	// The balances in paraAlice should have been substracted
226
1
	ParaA::execute_with(|| {
227
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0);
228
1
	});
229
1

            
230
1
	// Balances in the relay should have been received
231
1
	Relay::execute_with(|| {
232
1
		// Free execution,x	 full amount received
233
1
		assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending);
234
1
	});
235
1
}
236

            
237
#[test]
238
1
fn send_relay_asset_to_para_b() {
239
1
	MockNet::reset();
240
1

            
241
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
242
1
	let source_id: parachain::AssetId = source_location.clone().into();
243
1

            
244
1
	let asset_metadata = parachain::AssetMetadata {
245
1
		name: b"RelayToken".to_vec(),
246
1
		symbol: b"Relay".to_vec(),
247
1
		decimals: 12,
248
1
	};
249
1

            
250
1
	// Register asset in paraA. Free execution
251
1
	ParaA::execute_with(|| {
252
1
		assert_ok!(AssetManager::register_foreign_asset(
253
1
			parachain::RuntimeOrigin::root(),
254
1
			source_location.clone(),
255
1
			asset_metadata.clone(),
256
1
			1u128,
257
1
			true
258
1
		));
259
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
260
1
	});
261
1

            
262
1
	// Register asset in paraB. Free execution
263
1
	ParaB::execute_with(|| {
264
1
		assert_ok!(AssetManager::register_foreign_asset(
265
1
			parachain::RuntimeOrigin::root(),
266
1
			source_location.clone(),
267
1
			asset_metadata,
268
1
			1u128,
269
1
			true
270
1
		));
271
1
		assert_ok!(add_supported_asset(source_location, 0));
272
1
	});
273
1

            
274
1
	// First send relay chain asset to Parachain A like in previous test
275
1
	let dest: Location = Junction::AccountKey20 {
276
1
		network: None,
277
1
		key: PARAALICE,
278
1
	}
279
1
	.into();
280
1
	Relay::execute_with(|| {
281
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
282
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
283
1
			Box::new(Parachain(1).into()),
284
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
285
1
			Box::new(([], 123).into()),
286
1
			0,
287
1
			WeightLimit::Unlimited
288
1
		));
289
1
	});
290
1

            
291
1
	ParaA::execute_with(|| {
292
1
		// Free execution, full amount received
293
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123);
294
1
	});
295
1

            
296
1
	// Now send relay asset from para A to para B
297
1
	let dest = Location {
298
1
		parents: 1,
299
1
		interior: [
300
1
			Parachain(2),
301
1
			AccountKey20 {
302
1
				network: None,
303
1
				key: PARAALICE.into(),
304
1
			},
305
1
		]
306
1
		.into(),
307
1
	};
308
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
309
1

            
310
1
	ParaA::execute_with(|| {
311
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
312
1
		assert_ok!(PolkadotXcm::transfer_assets(
313
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
314
1
			Box::new(VersionedLocation::V4(chain_part)),
315
1
			Box::new(VersionedLocation::V4(beneficiary)),
316
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
317
1
			0,
318
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
319
1
		));
320
1
	});
321
1

            
322
1
	// Para A balances should have been substracted
323
1
	ParaA::execute_with(|| {
324
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23);
325
1
	});
326
1

            
327
1
	// Para B balances should have been credited
328
1
	ParaB::execute_with(|| {
329
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
330
1
	});
331
1
}
332

            
333
#[test]
334
1
fn send_para_a_asset_to_para_b() {
335
1
	MockNet::reset();
336
1

            
337
1
	// this represents the asset in paraA
338
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
339
1
	let source_location = parachain::AssetType::Xcm(
340
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
341
1
	);
342
1
	let source_id: parachain::AssetId = source_location.clone().into();
343
1

            
344
1
	let asset_metadata = parachain::AssetMetadata {
345
1
		name: b"ParaAToken".to_vec(),
346
1
		symbol: b"ParaA".to_vec(),
347
1
		decimals: 18,
348
1
	};
349
1

            
350
1
	// Register asset in paraB. Free execution
351
1
	ParaB::execute_with(|| {
352
1
		assert_ok!(AssetManager::register_foreign_asset(
353
1
			parachain::RuntimeOrigin::root(),
354
1
			source_location.clone(),
355
1
			asset_metadata,
356
1
			1u128,
357
1
			true
358
1
		));
359
1
		assert_ok!(add_supported_asset(source_location, 0));
360
1
	});
361
1

            
362
1
	// Send para A asset from para A to para B
363
1
	let dest = Location {
364
1
		parents: 1,
365
1
		interior: [
366
1
			Parachain(2),
367
1
			AccountKey20 {
368
1
				network: None,
369
1
				key: PARAALICE.into(),
370
1
			},
371
1
		]
372
1
		.into(),
373
1
	};
374
1

            
375
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
376
1

            
377
1
	ParaA::execute_with(|| {
378
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
379
1
		// Free execution, full amount received
380
1
		assert_ok!(PolkadotXcm::transfer_assets(
381
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
382
1
			Box::new(VersionedLocation::V4(chain_part)),
383
1
			Box::new(VersionedLocation::V4(beneficiary)),
384
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
385
1
			0,
386
1
			WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE))
387
1
		));
388
1
	});
389
1

            
390
1
	// Native token is substracted in paraA
391
1
	ParaA::execute_with(|| {
392
1
		assert_eq!(
393
1
			ParaBalances::free_balance(&PARAALICE.into()),
394
1
			INITIAL_BALANCE - 100
395
1
		);
396
1
	});
397
1

            
398
1
	// Asset is minted in paraB
399
1
	ParaB::execute_with(|| {
400
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
401
1
	});
402
1
}
403

            
404
#[test]
405
1
fn send_para_a_asset_from_para_b_to_para_c() {
406
1
	MockNet::reset();
407
1

            
408
1
	// Represents para A asset
409
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
410
1
	let source_location = parachain::AssetType::Xcm(
411
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
412
1
	);
413
1
	let source_id: parachain::AssetId = source_location.clone().into();
414
1

            
415
1
	let asset_metadata = parachain::AssetMetadata {
416
1
		name: b"ParaAToken".to_vec(),
417
1
		symbol: b"ParaA".to_vec(),
418
1
		decimals: 18,
419
1
	};
420
1

            
421
1
	// Register para A asset in parachain B. Free execution
422
1
	ParaB::execute_with(|| {
423
1
		assert_ok!(AssetManager::register_foreign_asset(
424
1
			parachain::RuntimeOrigin::root(),
425
1
			source_location.clone(),
426
1
			asset_metadata.clone(),
427
1
			1u128,
428
1
			true
429
1
		));
430
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
431
1
	});
432
1

            
433
1
	// Register para A asset in parachain C. Free execution
434
1
	ParaC::execute_with(|| {
435
1
		assert_ok!(AssetManager::register_foreign_asset(
436
1
			parachain::RuntimeOrigin::root(),
437
1
			source_location.clone(),
438
1
			asset_metadata,
439
1
			1u128,
440
1
			true
441
1
		));
442
1
		assert_ok!(add_supported_asset(source_location, 0));
443
1
	});
444
1

            
445
1
	// Send para A asset to para B
446
1
	let dest = Location {
447
1
		parents: 1,
448
1
		interior: [
449
1
			Parachain(2),
450
1
			AccountKey20 {
451
1
				network: None,
452
1
				key: PARAALICE.into(),
453
1
			},
454
1
		]
455
1
		.into(),
456
1
	};
457
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
458
1

            
459
1
	ParaA::execute_with(|| {
460
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
461
1
		// free execution, full amount received
462
1
		assert_ok!(PolkadotXcm::transfer_assets(
463
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
464
1
			Box::new(VersionedLocation::V4(chain_part)),
465
1
			Box::new(VersionedLocation::V4(beneficiary)),
466
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
467
1
			0,
468
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
469
1
		));
470
1
	});
471
1

            
472
1
	// Para A balances have been substracted
473
1
	ParaA::execute_with(|| {
474
1
		assert_eq!(
475
1
			ParaBalances::free_balance(&PARAALICE.into()),
476
1
			INITIAL_BALANCE - 100
477
1
		);
478
1
	});
479
1

            
480
1
	// Para B balances have been credited
481
1
	ParaB::execute_with(|| {
482
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
483
1
	});
484
1

            
485
1
	// Send para A asset from para B to para C
486
1
	let dest = Location {
487
1
		parents: 1,
488
1
		interior: [
489
1
			Parachain(3),
490
1
			AccountKey20 {
491
1
				network: None,
492
1
				key: PARAALICE.into(),
493
1
			},
494
1
		]
495
1
		.into(),
496
1
	};
497
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
498
1

            
499
1
	ParaB::execute_with(|| {
500
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
501
1
		assert_ok!(PolkadotXcm::transfer_assets(
502
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
503
1
			Box::new(VersionedLocation::V4(chain_part)),
504
1
			Box::new(VersionedLocation::V4(beneficiary)),
505
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
506
1
			0,
507
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
508
1
		));
509
1
	});
510
1

            
511
1
	// The message passed through parachainA so we needed to pay since its the native token
512
1
	// The message passed through parachainA so we needed to pay since its the native token
513
1
	ParaC::execute_with(|| {
514
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96);
515
1
	});
516
1
}
517

            
518
#[test]
519
1
fn send_para_a_asset_to_para_b_and_back_to_para_a() {
520
1
	MockNet::reset();
521
1

            
522
1
	// Para A asset
523
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
524
1
	let source_location = parachain::AssetType::Xcm(
525
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
526
1
	);
527
1
	let source_id: parachain::AssetId = source_location.clone().into();
528
1

            
529
1
	let asset_metadata = parachain::AssetMetadata {
530
1
		name: b"ParaAToken".to_vec(),
531
1
		symbol: b"ParaA".to_vec(),
532
1
		decimals: 18,
533
1
	};
534
1

            
535
1
	// Register para A asset in para B
536
1
	ParaB::execute_with(|| {
537
1
		assert_ok!(AssetManager::register_foreign_asset(
538
1
			parachain::RuntimeOrigin::root(),
539
1
			source_location.clone(),
540
1
			asset_metadata,
541
1
			1u128,
542
1
			true
543
1
		));
544
1
		assert_ok!(add_supported_asset(source_location, 0));
545
1
	});
546
1

            
547
1
	// Send para A asset to para B
548
1
	let dest = Location {
549
1
		parents: 1,
550
1
		interior: [
551
1
			Parachain(2),
552
1
			AccountKey20 {
553
1
				network: None,
554
1
				key: PARAALICE.into(),
555
1
			},
556
1
		]
557
1
		.into(),
558
1
	};
559
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
560
1

            
561
1
	ParaA::execute_with(|| {
562
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
563
1
		assert_ok!(PolkadotXcm::transfer_assets(
564
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
565
1
			Box::new(VersionedLocation::V4(chain_part)),
566
1
			Box::new(VersionedLocation::V4(beneficiary)),
567
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
568
1
			0,
569
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
570
1
		));
571
1
	});
572
1

            
573
1
	// Balances have been substracted
574
1
	ParaA::execute_with(|| {
575
1
		assert_eq!(
576
1
			ParaBalances::free_balance(&PARAALICE.into()),
577
1
			INITIAL_BALANCE - 100
578
1
		);
579
1
	});
580
1

            
581
1
	// Para B balances have been credited
582
1
	ParaB::execute_with(|| {
583
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
584
1
	});
585
1

            
586
1
	// Send back para A asset to para A
587
1
	let dest = Location {
588
1
		parents: 1,
589
1
		interior: [
590
1
			Parachain(1),
591
1
			AccountKey20 {
592
1
				network: None,
593
1
				key: PARAALICE.into(),
594
1
			},
595
1
		]
596
1
		.into(),
597
1
	};
598
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
599
1

            
600
1
	ParaB::execute_with(|| {
601
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
602
1
		assert_ok!(PolkadotXcm::transfer_assets(
603
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
604
1
			Box::new(VersionedLocation::V4(chain_part)),
605
1
			Box::new(VersionedLocation::V4(beneficiary)),
606
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
607
1
			0,
608
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
609
1
		));
610
1
	});
611
1

            
612
1
	ParaA::execute_with(|| {
613
1
		// Weight used is 4
614
1
		assert_eq!(
615
1
			ParaBalances::free_balance(&PARAALICE.into()),
616
1
			INITIAL_BALANCE - 4
617
1
		);
618
1
	});
619
1
}
620

            
621
#[test]
622
1
fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() {
623
1
	MockNet::reset();
624
1

            
625
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
626
1
	let source_location = parachain::AssetType::Xcm(
627
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
628
1
	);
629
1
	let source_id: parachain::AssetId = source_location.clone().into();
630
1

            
631
1
	let asset_metadata = parachain::AssetMetadata {
632
1
		name: b"ParaAToken".to_vec(),
633
1
		symbol: b"ParaA".to_vec(),
634
1
		decimals: 18,
635
1
	};
636
1

            
637
1
	ParaB::execute_with(|| {
638
1
		assert_ok!(AssetManager::register_foreign_asset(
639
1
			parachain::RuntimeOrigin::root(),
640
1
			source_location.clone(),
641
1
			asset_metadata,
642
1
			1u128,
643
1
			true
644
1
		));
645
1
		assert_ok!(add_supported_asset(source_location, 0));
646
1
	});
647
1

            
648
1
	let dest = Location {
649
1
		parents: 1,
650
1
		interior: [
651
1
			Parachain(2),
652
1
			AccountKey20 {
653
1
				network: None,
654
1
				key: PARAALICE.into(),
655
1
			},
656
1
		]
657
1
		.into(),
658
1
	};
659
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
660
1

            
661
1
	ParaA::execute_with(|| {
662
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
663
1
		assert_ok!(PolkadotXcm::transfer_assets(
664
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
665
1
			Box::new(VersionedLocation::V4(chain_part)),
666
1
			Box::new(VersionedLocation::V4(beneficiary)),
667
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
668
1
			0,
669
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
670
1
		));
671
1
	});
672
1

            
673
1
	// Para A asset has been credited
674
1
	ParaA::execute_with(|| {
675
1
		assert_eq!(
676
1
			ParaBalances::free_balance(&PARAALICE.into()),
677
1
			INITIAL_BALANCE - 100
678
1
		);
679
1
	});
680
1

            
681
1
	ParaB::execute_with(|| {
682
1
		// free execution, full amount received
683
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
684
1
	});
685
1

            
686
1
	// This time we will force the new reanchoring by manually sending the
687
1
	// Message through polkadotXCM pallet
688
1

            
689
1
	let dest = Location {
690
1
		parents: 1,
691
1
		interior: [Parachain(1)].into(),
692
1
	};
693
1

            
694
1
	let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]);
695
1

            
696
1
	let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![
697
1
		WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()),
698
1
		ClearOrigin,
699
1
		BuyExecution {
700
1
			fees: (reanchored_para_a_balances, 100).into(),
701
1
			weight_limit: Limited(80.into()),
702
1
		},
703
1
		DepositAsset {
704
1
			assets: All.into(),
705
1
			beneficiary: Location::new(
706
1
				0,
707
1
				[AccountKey20 {
708
1
					network: None,
709
1
					key: PARAALICE,
710
1
				}],
711
1
			),
712
1
		},
713
1
	]));
714
1
	ParaB::execute_with(|| {
715
1
		// Send a message to the sovereign account in ParaA to withdraw
716
1
		// and deposit asset
717
1
		assert_ok!(ParachainPalletXcm::send(
718
1
			parachain::RuntimeOrigin::root(),
719
1
			Box::new(dest.into()),
720
1
			Box::new(message),
721
1
		));
722
1
	});
723
1

            
724
1
	ParaA::execute_with(|| {
725
1
		// Weight used is 4
726
1
		assert_eq!(
727
1
			ParaBalances::free_balance(&PARAALICE.into()),
728
1
			INITIAL_BALANCE - 4
729
1
		);
730
1
	});
731
1
}
732

            
733
#[test]
734
1
fn receive_relay_asset_with_trader() {
735
1
	MockNet::reset();
736
1

            
737
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
738
1
	let source_id: parachain::AssetId = source_location.clone().into();
739
1

            
740
1
	let asset_metadata = parachain::AssetMetadata {
741
1
		name: b"RelayToken".to_vec(),
742
1
		symbol: b"Relay".to_vec(),
743
1
		decimals: 12,
744
1
	};
745
1

            
746
1
	// This time we are gonna put a rather high number of units per second
747
1
	// we know later we will divide by 1e12
748
1
	// Lets put 1e6 as units per second
749
1
	ParaA::execute_with(|| {
750
1
		assert_ok!(AssetManager::register_foreign_asset(
751
1
			parachain::RuntimeOrigin::root(),
752
1
			source_location.clone(),
753
1
			asset_metadata,
754
1
			1u128,
755
1
			true
756
1
		));
757
1
		assert_ok!(add_supported_asset(source_location, 2_500_000_000_000));
758
1
	});
759
1

            
760
1
	let dest: Location = Junction::AccountKey20 {
761
1
		network: None,
762
1
		key: PARAALICE,
763
1
	}
764
1
	.into();
765
1
	// We are sending 100 tokens from relay.
766
1
	// Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second)
767
1
	// weight is 4 since we are executing 4 instructions with a unitweightcost of 1.
768
1
	// Units per second should be 2_500_000_000_000_000
769
1
	// Therefore with no refund, we should receive 10 tokens less
770
1
	// Native trader fails for this, and we use the asset trader
771
1
	Relay::execute_with(|| {
772
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
773
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
774
1
			Box::new(Parachain(1).into()),
775
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
776
1
			Box::new(([], 100).into()),
777
1
			0,
778
1
			WeightLimit::Unlimited
779
1
		));
780
1
	});
781
1

            
782
1
	ParaA::execute_with(|| {
783
1
		// non-free execution, not full amount received
784
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90);
785
		// Fee should have been received by treasury
786
1
		assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10);
787
1
	});
788
1
}
789

            
790
#[test]
791
1
fn send_para_a_asset_to_para_b_with_trader() {
792
1
	MockNet::reset();
793
1

            
794
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
795
1
	let source_location = parachain::AssetType::Xcm(
796
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
797
1
	);
798
1
	let source_id: parachain::AssetId = source_location.clone().into();
799
1

            
800
1
	let asset_metadata = parachain::AssetMetadata {
801
1
		name: b"ParaAToken".to_vec(),
802
1
		symbol: b"ParaA".to_vec(),
803
1
		decimals: 18,
804
1
	};
805
1

            
806
1
	ParaB::execute_with(|| {
807
1
		assert_ok!(AssetManager::register_foreign_asset(
808
1
			parachain::RuntimeOrigin::root(),
809
1
			source_location.clone(),
810
1
			asset_metadata,
811
1
			1u128,
812
1
			true
813
1
		));
814
1
		assert_ok!(add_supported_asset(source_location, 2500000000000));
815
1
	});
816
1

            
817
1
	let dest = Location {
818
1
		parents: 1,
819
1
		interior: [
820
1
			Parachain(2),
821
1
			AccountKey20 {
822
1
				network: None,
823
1
				key: PARAALICE.into(),
824
1
			},
825
1
		]
826
1
		.into(),
827
1
	};
828
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
829
1

            
830
1
	// In destination chain, we only need 4 weight
831
1
	// We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury
832
1
	ParaA::execute_with(|| {
833
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
834
1
		assert_ok!(PolkadotXcm::transfer_assets(
835
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
836
1
			Box::new(VersionedLocation::V4(chain_part)),
837
1
			Box::new(VersionedLocation::V4(beneficiary)),
838
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
839
1
			0,
840
1
			WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE))
841
1
		));
842
1
	});
843
1
	ParaA::execute_with(|| {
844
1
		// free execution, full amount received
845
1
		assert_eq!(
846
1
			ParaBalances::free_balance(&PARAALICE.into()),
847
1
			INITIAL_BALANCE - 100
848
1
		);
849
1
	});
850
1

            
851
1
	// We are sending 100 tokens from para A.
852
1
	// Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second)
853
1
	// weight is 4 since we are executing 4 instructions with a unitweightcost of 1.
854
1
	// Units per second should be 2_500_000_000_000_000
855
1
	// Since we set 10 weight in destination chain, 25 will be charged upfront
856
1
	// 15 of those will be refunded, while 10 will go to treasury as the true weight used
857
1
	// will be 4
858
1
	ParaB::execute_with(|| {
859
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90);
860
		// Fee should have been received by treasury
861
1
		assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10);
862
1
	});
863
1
}
864

            
865
#[test]
866
1
fn send_para_a_asset_to_para_b_with_trader_and_fee() {
867
1
	MockNet::reset();
868
1

            
869
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
870
1
	let source_location = parachain::AssetType::Xcm(
871
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
872
1
	);
873
1
	let source_id: parachain::AssetId = source_location.clone().into();
874
1

            
875
1
	let asset_metadata = parachain::AssetMetadata {
876
1
		name: b"ParaAToken".to_vec(),
877
1
		symbol: b"ParaA".to_vec(),
878
1
		decimals: 18,
879
1
	};
880
1

            
881
1
	ParaB::execute_with(|| {
882
1
		assert_ok!(AssetManager::register_foreign_asset(
883
1
			parachain::RuntimeOrigin::root(),
884
1
			source_location.clone(),
885
1
			asset_metadata,
886
1
			1u128,
887
1
			true
888
1
		));
889
		// With these units per second, 80K weight convrets to 1 asset unit
890
1
		assert_ok!(add_supported_asset(source_location, 12500000));
891
1
	});
892
1

            
893
1
	let dest = Location {
894
1
		parents: 1,
895
1
		interior: [
896
1
			Parachain(2),
897
1
			AccountKey20 {
898
1
				network: None,
899
1
				key: PARAALICE.into(),
900
1
			},
901
1
		]
902
1
		.into(),
903
1
	};
904
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
905
1
	// we use transfer_with_fee
906
1
	ParaA::execute_with(|| {
907
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
908
1
		let asset_fee = currency_to_asset(parachain::CurrencyId::SelfReserve, 1);
909
1
		assert_ok!(PolkadotXcm::transfer_assets(
910
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
911
1
			Box::new(VersionedLocation::V4(chain_part)),
912
1
			Box::new(VersionedLocation::V4(beneficiary)),
913
1
			Box::new(VersionedAssets::V4(vec![asset_fee, asset].into())),
914
1
			0,
915
1
			WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE))
916
1
		));
917
1
	});
918
1
	ParaA::execute_with(|| {
919
1
		// 100 tokens transferred plus 1 taken from fees
920
1
		assert_eq!(
921
1
			ParaBalances::free_balance(&PARAALICE.into()),
922
1
			INITIAL_BALANCE - 100 - 1
923
1
		);
924
1
	});
925
1

            
926
1
	ParaB::execute_with(|| {
927
1
		// free execution, full amount received because the xcm instruction does not cost
928
1
		// what it is specified
929
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101);
930
1
	});
931
1
}
932

            
933
#[test]
934
1
fn error_when_not_paying_enough() {
935
1
	MockNet::reset();
936
1

            
937
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
938
1
	let source_id: parachain::AssetId = source_location.clone().into();
939
1

            
940
1
	let asset_metadata = parachain::AssetMetadata {
941
1
		name: b"RelayToken".to_vec(),
942
1
		symbol: b"Relay".to_vec(),
943
1
		decimals: 12,
944
1
	};
945
1

            
946
1
	let dest: Location = Junction::AccountKey20 {
947
1
		network: None,
948
1
		key: PARAALICE,
949
1
	}
950
1
	.into();
951
1
	// This time we are gonna put a rather high number of units per second
952
1
	// we know later we will divide by 1e12
953
1
	// Lets put 1e6 as units per second
954
1
	ParaA::execute_with(|| {
955
1
		assert_ok!(AssetManager::register_foreign_asset(
956
1
			parachain::RuntimeOrigin::root(),
957
1
			source_location.clone(),
958
1
			asset_metadata,
959
1
			1u128,
960
1
			true
961
1
		));
962
1
		assert_ok!(add_supported_asset(source_location, 2500000000000));
963
1
	});
964
1

            
965
1
	ParaA::execute_with(|| {
966
1
		// amount not received as it is not paying enough
967
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0);
968
1
	});
969
1

            
970
1
	// We are sending 100 tokens from relay.
971
1
	// If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10
972
1
	// Therefore with no refund, we should receive 10 tokens less
973
1
	Relay::execute_with(|| {
974
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
975
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
976
1
			Box::new(Parachain(1).into()),
977
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
978
1
			Box::new(([], 5).into()),
979
1
			0,
980
1
			WeightLimit::Unlimited
981
1
		));
982
1
	});
983
1

            
984
1
	ParaA::execute_with(|| {
985
1
		// amount not received as it is not paying enough
986
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0);
987
1
	});
988
1
}
989

            
990
#[test]
991
1
fn transact_through_derivative_multilocation() {
992
1
	MockNet::reset();
993
1

            
994
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
995
1
	let source_id: parachain::AssetId = source_location.clone().into();
996
1

            
997
1
	let asset_metadata = parachain::AssetMetadata {
998
1
		name: b"RelayToken".to_vec(),
999
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			WEIGHT_REF_TIME_PER_SECOND as u128,
1
		));
1
	});
1

            
1
	// Let's construct the call to know how much weight it is going to require
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		// 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000003100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1

            
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			parachain::MockTransactors::Relay,
1
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			// 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller
1
			encoded,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
14
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
14
				_ => None,
14
			});
1
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&registered_address) == 0);
1
	});
1
}
#[test]
1
fn transact_through_derivative_with_custom_fee_weight() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1

            
1
	// Let's construct the call to know how much weight it is going to require
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		// 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000003100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1

            
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let overall_weight = 4000003000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			parachain::MockTransactors::Relay,
1
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				// 1-1 fee weight mapping
1
				fee_amount: Some(overall_weight as u128)
1
			},
1
			// 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller
1
			encoded,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(overall_weight.into()))
1
			},
1
			false
1
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
12
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
12
				_ => None,
12
			});
1
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&registered_address) == 0);
1
	});
1
}
#[test]
1
fn transact_through_derivative_with_custom_fee_weight_refund() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1

            
1
	// Let's construct the call to know how much weight it is going to require
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		// 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000009100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1

            
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000009000);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let overall_weight = 4000009000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			parachain::MockTransactors::Relay,
1
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				// 1-1 fee weight mapping
1
				fee_amount: Some(overall_weight as u128)
1
			},
1
			encoded,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(overall_weight.into()))
1
			},
1
			true
1
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
12
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
12
				_ => None,
12
			});
1
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		// 4000005186 refunded + 100 transferred = 4000005286
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 4000005286);
1
		assert_eq!(RelayBalances::free_balance(&registered_address), 0);
1
	});
1
}
#[test]
1
fn transact_through_sovereign() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			WEIGHT_REF_TIME_PER_SECOND as u128,
1
		));
1
	});
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000003100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
		0
1
	});
1

            
1
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let utility_bytes = parachain::MockTransactors::Relay.encode_call(
1
		xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
1
	);
1

            
1
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			utility_bytes,
1
			OriginKind::SovereignAccount,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&registered_address) == 0);
1
	});
1
}
#[test]
1
fn transact_through_sovereign_fee_payer_none() {
1
	MockNet::reset();
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			WEIGHT_REF_TIME_PER_SECOND as u128,
1
		));
1
	});
1

            
1
	let derivative_address = derivative_account_id(para_a_account(), 0);
1

            
1
	Relay::execute_with(|| {
1
		// Transfer 100 tokens to derivative_address on the relay
1
		assert_ok!(RelayBalances::transfer_keep_alive(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derivative_address.clone(),
1
			100u128
1
		));
		// Transfer the XCM execution fee amount to ParaA's sovereign account
1
		assert_ok!(RelayBalances::transfer_keep_alive(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_a_account(),
1
			4000003000u128
1
		));
1
	});
1

            
1
	// Check balances before the transact call
1
	Relay::execute_with(|| {
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 4000003000);
1
		assert_eq!(RelayBalances::free_balance(&derivative_address), 100);
1
		assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0);
1
	});
1

            
1
	// Encode the call. Balances transfer of 100 relay tokens to RELAYBOB
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: RELAYBOB,
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	// The final call will be an AsDerivative using index 0
1
	let utility_bytes = parachain::MockTransactors::Relay.encode_call(
1
		xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
1
	);
1

            
1
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: /* Here */ [].into(),
1
	};
1

            
1
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(dest)),
1
			// No fee_payer here. The sovereign account will pay the fees on destination.
1
			None,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			utility_bytes,
1
			OriginKind::SovereignAccount,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	// Check balances after the transact call are correct
1
	Relay::execute_with(|| {
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 0);
1
		assert_eq!(RelayBalances::free_balance(&derivative_address), 0);
1
		assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100);
1
	});
1
}
#[test]
1
fn transact_through_sovereign_with_custom_fee_weight() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000003100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
		0
1
	});
1

            
1
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let utility_bytes = parachain::MockTransactors::Relay.encode_call(
1
		xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
1
	);
1

            
1
	let total_weight = 4000003000u64;
1
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				// 1-1 fee-weight mapping
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			utility_bytes,
1
			OriginKind::SovereignAccount,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			},
1
			false
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&registered_address) == 0);
1
	});
1
}
#[test]
1
fn transact_through_sovereign_with_custom_fee_weight_refund() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1

            
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 4000009100u128).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100);
1
	});
1

            
1
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
1
			0,
1
		));
1
	});
1

            
1
	// Send to registered address
1
	let registered_address = derivative_account_id(para_a_account(), 0);
1
	let dest = Location {
1
		parents: 1,
1
		interior: [AccountId32 {
1
			network: None,
1
			id: registered_address.clone().into(),
1
		}]
1
		.into(),
1
	};
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000);
1
	});
1

            
1
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
1
	// again
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000009000);
1
		0
1
	});
1

            
1
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let utility_bytes = parachain::MockTransactors::Relay.encode_call(
1
		xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
1
	);
1

            
1
	let total_weight = 4000009000u64;
1
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				// 1-1 fee-weight mapping
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			utility_bytes,
1
			OriginKind::SovereignAccount,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			},
1
			true
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// free execution,x	 full amount received
1
		// 4000005186 refunded + 100 transferred = 4000005286
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 4000005286);
1
		assert_eq!(RelayBalances::free_balance(&registered_address), 0);
1
	});
1
}
#[test]
1
fn test_automatic_versioning_on_runtime_upgrade_with_relay() {
1
	MockNet::reset();
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	// register relay asset in parachain A and set XCM version to 1
1
	ParaA::execute_with(|| {
1
		parachain::XcmVersioner::set_version(1);
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	let response = Response::Version(2);
1
	let querier: Location = [].into();
1

            
1
	// This is irrelevant, nothing will be done with this message,
1
	// but we need to pass a message as an argument to trigger the storage change
1
	let mock_message: Xcm<()> = Xcm(vec![QueryResponse {
1
		query_id: 0,
1
		response,
1
		max_weight: Weight::zero(),
1
		querier: Some(querier),
1
	}]);
1
	// The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force
1
	// it directly here
1
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	Relay::execute_with(|| {
1
		// This sets the default version, for not known destinations
1
		assert_ok!(RelayChainPalletXcm::force_default_xcm_version(
1
			relay_chain::RuntimeOrigin::root(),
1
			Some(2)
1
		));
		// Wrap version, which sets VersionedStorage
		// This is necessary because the mock router does not use wrap_version, but
		// this is not necessary in prod
1
		assert_ok!(<RelayChainPalletXcm as WrapVersion>::wrap_version(
1
			&Parachain(1).into(),
1
			mock_message
1
		));
		// Transfer assets. Since it is an unknown destination, it will query for version
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// Let's advance the relay. This should trigger the subscription message
1
		relay_chain::relay_roll_to(2);
1

            
1
		// queries should have been updated
1
		assert!(RelayChainPalletXcm::query(0).is_some());
1
	});
1

            
1
	let expected_supported_version: relay_chain::RuntimeEvent =
1
		pallet_xcm::Event::SupportedVersionChanged {
1
			location: Location {
1
				parents: 0,
1
				interior: [Parachain(1)].into(),
1
			},
1
			version: 1,
1
		}
1
		.into();
1

            
1
	Relay::execute_with(|| {
1
		// Assert that the events vector contains the version change
1
		assert!(relay_chain::relay_events().contains(&expected_supported_version));
1
	});
1

            
1
	// ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets
1
	// of the new version change
1
	ParaA::execute_with(|| {
1
		// Set version
1
		parachain::XcmVersioner::set_version(2);
1
		// Do runtime upgrade
1
		parachain::on_runtime_upgrade();
1
		// Initialize block, to call on_initialize and notify targets
1
		parachain::para_roll_to(2);
1
		// Expect the event in the parachain
10
		assert!(parachain::para_events().iter().any(|e| matches!(
2
			e,
			parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified {
				result: 2,
				..
			})
10
		)));
1
	});
1

            
1
	// This event should have been seen in the relay
1
	let expected_supported_version_2: relay_chain::RuntimeEvent =
1
		pallet_xcm::Event::SupportedVersionChanged {
1
			location: Location {
1
				parents: 0,
1
				interior: [Parachain(1)].into(),
1
			},
1
			version: 2,
1
		}
1
		.into();
1

            
1
	Relay::execute_with(|| {
1
		// Assert that the events vector contains the new version change
1
		assert!(relay_chain::relay_events().contains(&expected_supported_version_2));
1
	});
1
}
#[test]
1
fn test_automatic_versioning_on_runtime_upgrade_with_para_b() {
1
	MockNet::reset();
1

            
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
1
	let source_location = parachain::AssetType::Xcm(
1
		xcm_builder::WithLatestLocationConverter::convert(&para_a_balances).expect("convert to v3"),
1
	);
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"ParaAToken".to_vec(),
1
		symbol: b"ParaA".to_vec(),
1
		decimals: 18,
1
	};
1
	let response = Response::Version(2);
1
	let querier: Location = [].into();
1

            
1
	// This is irrelevant, nothing will be done with this message,
1
	// but we need to pass a message as an argument to trigger the storage change
1
	let mock_message: Xcm<()> = Xcm(vec![QueryResponse {
1
		query_id: 0,
1
		response,
1
		max_weight: Weight::zero(),
1
		querier: Some(querier),
1
	}]);
1

            
1
	ParaA::execute_with(|| {
1
		// advertised version
1
		parachain::XcmVersioner::set_version(2);
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// Let's try with v0
1
		parachain::XcmVersioner::set_version(0);
1

            
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// This sets the default version, for not known destinations
1
		assert_ok!(ParachainPalletXcm::force_default_xcm_version(
1
			parachain::RuntimeOrigin::root(),
1
			Some(2)
1
		));
		// Wrap version, which sets VersionedStorage
1
		assert_ok!(<ParachainPalletXcm as WrapVersion>::wrap_version(
1
			&Location::new(1, [Parachain(2)]).into(),
1
			mock_message
1
		));
1
		parachain::para_roll_to(2);
1

            
1
		// queries should have been updated
1
		assert!(ParachainPalletXcm::query(0).is_some());
1
	});
1

            
1
	let expected_supported_version: parachain::RuntimeEvent =
1
		pallet_xcm::Event::SupportedVersionChanged {
1
			location: Location {
1
				parents: 1,
1
				interior: [Parachain(2)].into(),
1
			},
1
			version: 0,
1
		}
1
		.into();
1

            
1
	ParaA::execute_with(|| {
1
		// Assert that the events vector contains the version change
1
		assert!(parachain::para_events().contains(&expected_supported_version));
1
	});
1

            
1
	// Let's ensure talking in v0 works
1
	let dest = Location {
1
		parents: 1,
1
		interior: [
1
			Parachain(2),
1
			AccountKey20 {
1
				network: None,
1
				key: PARAALICE.into(),
1
			},
1
		]
1
		.into(),
1
	}
1
	.into();
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
1
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
1
		));
		// free execution, full amount received
1
		assert_eq!(
1
			ParaBalances::free_balance(&PARAALICE.into()),
1
			INITIAL_BALANCE - 100
1
		);
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	// ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets
1
	// of the new version change
1
	ParaB::execute_with(|| {
1
		// Set version
1
		parachain::XcmVersioner::set_version(2);
1
		// Do runtime upgrade
1
		parachain::on_runtime_upgrade();
1
		// Initialize block, to call on_initialize and notify targets
1
		parachain::para_roll_to(2);
1
		// Expect the event in the parachain
10
		assert!(parachain::para_events().iter().any(|e| matches!(
2
			e,
			parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified {
				result: 2,
				..
			})
10
		)));
1
	});
1

            
1
	// This event should have been seen in para A
1
	let expected_supported_version_2: parachain::RuntimeEvent =
1
		pallet_xcm::Event::SupportedVersionChanged {
1
			location: Location {
1
				parents: 1,
1
				interior: [Parachain(2)].into(),
1
			},
1
			version: 2,
1
		}
1
		.into();
1

            
1
	// Para A should have received the version change
1
	ParaA::execute_with(|| {
1
		// Assert that the events vector contains the new version change
1
		assert!(parachain::para_events().contains(&expected_supported_version_2));
1
	});
1
}
#[test]
1
fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() {
1
	MockNet::reset();
1

            
1
	let fresh_account = [2u8; 20];
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			false
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: fresh_account,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest.clone()).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// parachain should not have received assets
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0);
1
	});
1

            
1
	// Send native token to fresh_account
1
	ParaA::execute_with(|| {
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			fresh_account.into(),
1
			100
1
		));
1
	});
1

            
1
	// Re-send tokens
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// parachain should have received assets
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123);
1
	});
1
}
#[test]
1
fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() {
1
	MockNet::reset();
1

            
1
	let fresh_account = [2u8; 20];
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: fresh_account,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest.clone()).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// parachain should have received assets
1
	ParaA::execute_with(|| {
1
		// free execution, full amount received
1
		assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123);
1
	});
1
}
#[test]
1
fn evm_account_receiving_assets_should_handle_sufficients_ref_count() {
1
	MockNet::reset();
1

            
1
	let mut sufficient_account = [0u8; 20];
1
	sufficient_account[0..20].copy_from_slice(&evm_account()[..]);
1

            
1
	let evm_account_id = parachain::AccountId::from(sufficient_account);
1

            
1
	// Evm account is self sufficient
1
	ParaA::execute_with(|| {
1
		assert_eq!(parachain::System::account(evm_account_id).sufficients, 1);
1
	});
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: sufficient_account,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest.clone()).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Evm account sufficient ref count increased by 1.
1
	ParaA::execute_with(|| {
1
		// TODO: since the suicided logic was introduced the data of the smart contract is not
1
		// removed, it will have to be updated in a future release when there is the ability to
1
		// remove contract data
1
		// assert_eq!(parachain::System::account(evm_account_id).sufficients, 2);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Remove the account from the evm context.
1
		parachain::EVM::remove_account(&evm_account());
1
		// Evm account sufficient ref count decreased by 1.
1
		// TODO: since the suicided logic was introduced the data of the smart contract is not
1
		// removed, it will have to be updated in a future release when there is the ability to
1
		// remove contract data
1
		// assert_eq!(parachain::System::account(evm_account_id).sufficients, 1);
1
	});
1
}
#[test]
1
fn empty_account_should_not_be_reset() {
1
	MockNet::reset();
1

            
1
	// Test account has nonce 1 on genesis.
1
	let mut sufficient_account = [0u8; 20];
1
	sufficient_account[0..20].copy_from_slice(&evm_account()[..]);
1

            
1
	let evm_account_id = parachain::AccountId::from(sufficient_account);
1

            
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_id: parachain::AssetId = source_location.clone().into();
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata,
1
			1u128,
1
			false
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	// Send native token to evm_account
1
	ParaA::execute_with(|| {
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			evm_account_id,
1
			100
1
		));
1
	});
1

            
1
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: sufficient_account,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(VersionedLocation::V4(dest.clone()).clone().into()),
1
			Box::new(([], 123).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Empty the assets from the account.
1
		// As this makes the account go below the `min_balance`, the account is considered dead
1
		// at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero.
1
		assert_ok!(parachain::Assets::transfer(
1
			parachain::RuntimeOrigin::signed(evm_account_id),
1
			source_id,
1
			PARAALICE.into(),
1
			123
1
		));
		// Verify account asset balance is Zero.
1
		assert_eq!(
1
			parachain::Assets::balance(source_id, &evm_account_id.into()),
1
			0
1
		);
		// Because we no longer have consumer references, we can set the balance to Zero.
		// This would reset the account if our ED were to be > than Zero.
1
		assert_ok!(ParaBalances::force_set_balance(
1
			parachain::RuntimeOrigin::root(),
1
			evm_account_id,
1
			0,
1
		));
		// Verify account native balance is Zero.
1
		assert_eq!(ParaBalances::free_balance(&evm_account_id), 0);
		// Remove the account from the evm context.
		// This decreases the sufficients reference by 1 and now is Zero.
1
		parachain::EVM::remove_account(&evm_account());
1
		// Verify reference count.
1
		let account = parachain::System::account(evm_account_id);
1
		assert_eq!(account.sufficients, 0);
1
		assert_eq!(account.consumers, 0);
1
		assert_eq!(account.providers, 1);
		// We expect the account to be alive in a Zero ED context.
1
		assert_eq!(parachain::System::account_nonce(evm_account_id), 1);
1
	});
1
}
#[test]
1
fn test_statemint_like() {
1
	MockNet::reset();
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	let statemint_asset_a_balances = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			PalletInstance(5),
1
			xcm::latest::prelude::GeneralIndex(0u128),
1
		],
1
	);
1
	let source_location = parachain::AssetType::Xcm(
1
		xcm_builder::WithLatestLocationConverter::convert(&statemint_asset_a_balances)
1
			.expect("convert to v3"),
1
	);
1
	let source_id: parachain::AssetId = source_location.clone().into();
1

            
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"StatemintToken".to_vec(),
1
		symbol: b"StatemintToken".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			source_location.clone(),
1
			asset_metadata.clone(),
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Set new prefix
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
1
		);
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			0,
1
			RELAYALICE,
1
			1
1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			0,
1
			RELAYALICE,
1
			300000000000000
1
		));
		// This is needed, since the asset is created as non-sufficient
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			100000000000000
1
		));
		// Actually send relay asset to parachain
1
		let dest: Location = AccountKey20 {
1
			network: None,
1
			key: PARAALICE,
1
		}
1
		.into();
1

            
1
		// Send asset with previous prefix
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(VersionedLocation::V4(dest).clone().into()),
1
			Box::new(
1
				(
1
					[
1
						xcm::latest::prelude::PalletInstance(
1
							<StatemintAssets as PalletInfoAccess>::index() as u8
1
						),
1
						xcm::latest::prelude::GeneralIndex(0),
1
					],
1
					123
1
				)
1
					.into()
1
			),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123);
1
	});
1
}
#[test]
1
fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	// Statemint asset
1
	let statemint_asset = Location::new(
1
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
1
	);
1
	let statemint_location_asset = parachain::AssetType::Xcm(
1
		xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"),
1
	);
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
1

            
1
	let asset_metadata_statemint_asset = parachain::AssetMetadata {
1
		name: b"USDC".to_vec(),
1
		symbol: b"USDC".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(relay_location, 0));
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			statemint_location_asset.clone(),
1
			asset_metadata_statemint_asset,
1
			1u128,
1
			true
1
		));
1
		assert_ok!(add_supported_asset(statemint_location_asset, 0));
1
	});
1

            
1
	let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	// Send relay chain asset to Alice in Parachain A
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_from_relay)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Set new prefix
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
1
		);
1

            
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			1
1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			300000000000000
1
		));
		// Send some native statemint tokens to sovereign for fees.
		// We can't pay fees with USDC as the asset is minted as non-sufficient.
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			100000000000000
1
		));
		// Send statemint USDC asset to Alice in Parachain A
1
		let parachain_beneficiary_from_statemint: Location = AccountKey20 {
1
			network: None,
1
			key: PARAALICE,
1
		}
1
		.into();
1

            
1
		// Send with new prefix
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_from_statemint)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(
1
				(
1
					[
1
						xcm::latest::prelude::PalletInstance(
1
							<StatemintAssets as PalletInfoAccess>::index() as u8
1
						),
1
						GeneralIndex(10),
1
					],
1
					125
1
				)
1
					.into()
1
			),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	let statemint_beneficiary = Location {
1
		parents: 1,
1
		interior: [
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		]
1
		.into(),
1
	};
1

            
1
	ParaA::execute_with(|| {
1
		// Alice has received 125 USDC
1
		assert_eq!(
1
			Assets::balance(source_statemint_asset_id, &PARAALICE.into()),
1
			125
1
		);
		// Alice has received 200 Relay assets
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that BOB's balance is empty before the transfer
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]);
1
	});
1

            
1
	let (chain_part, beneficiary) =
1
		split_location_into_chain_part_and_beneficiary(statemint_beneficiary).unwrap();
1

            
1
	// Transfer USDC from Parachain A to Statemint using Relay asset as fee
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(
1
			parachain::CurrencyId::ForeignAsset(source_statemint_asset_id),
1
			100,
1
		);
1
		let asset_fee =
1
			currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset_fee, asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice has 100 USDC less
1
		assert_eq!(
1
			Assets::balance(source_statemint_asset_id, &PARAALICE.into()),
1
			25
1
		);
		// Alice has 100 relay asset less
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that BOB received 100 USDC on statemint
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
	});
1

            
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
1

            
1
	// First we send relay chain asset to Alice in AssetHub (via teleport)
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_teleport_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1000).into()),
1
			Box::new(
1
				VersionedLocation::V4(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
1
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
1
			INITIAL_BALANCE + 200
1
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			110000000000000
1
		));
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received the DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1

            
1
	let dest = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
1
	);
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 100
1
		);
1
	});
1

            
1
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
1
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 100).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received 100 DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_with_fee() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
	});
1

            
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
1

            
1
	// First we send relay chain asset to Alice in AssetHub (via teleport)
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_teleport_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1000).into()),
1
			Box::new(
1
				VersionedLocation::V4(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
1
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
1
			INITIAL_BALANCE + 200
1
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			110000000000000
1
		));
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received the DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1

            
1
	let dest = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
1
	);
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1

            
1
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		let asset_fee = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 10);
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset_fee, asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 90);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Free execution: check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 110
1
		);
1
	});
1

            
1
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
1
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 100).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 10
1
		);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received 100 DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 190);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiasset() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
	});
1

            
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
1

            
1
	// First we send relay chain asset to Alice in AssetHub (via teleport)
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_teleport_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1000).into()),
1
			Box::new(
1
				VersionedLocation::V4(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
1
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
1
			INITIAL_BALANCE + 200
1
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			110000000000000
1
		));
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received the DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1

            
1
	let dest = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
1
	);
1

            
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1
	let asset = Asset {
1
		id: AssetId(Location::parent()),
1
		fun: Fungibility::Fungible(100),
1
	};
1
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(asset.into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
1
		));
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 100
1
		);
1
	});
1

            
1
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
1
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 100).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received 100 DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multicurrencies() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	// Statemint asset
1
	let statemint_asset = Location::new(
1
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
1
	);
1
	let statemint_location_asset = parachain::AssetType::Xcm(
1
		xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"),
1
	);
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
1

            
1
	let asset_metadata_statemint_asset = parachain::AssetMetadata {
1
		name: b"USDC".to_vec(),
1
		symbol: b"USDC".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1

            
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			statemint_location_asset.clone(),
1
			asset_metadata_statemint_asset,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(statemint_asset, 0u128);
1
	});
1

            
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
1

            
1
	// First we send relay chain asset to Alice in AssetHub (via teleport)
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_teleport_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1000).into()),
1
			Box::new(
1
				VersionedLocation::V4(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Send DOTs and USDC from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
1
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
1
			INITIAL_BALANCE + 200
1
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			110000000000000
1
		));
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
1
		);
1

            
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			1
1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			300000000000000
1
		));
		// Now send relay tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// Send USDC
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new(
1
				(
1
					[
1
						xcm::latest::prelude::PalletInstance(
1
							<StatemintAssets as PalletInfoAccess>::index() as u8
1
						),
1
						GeneralIndex(10),
1
					],
1
					125
1
				)
1
					.into()
1
			),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received the DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
		// Alice has received 125 USDC
1
		assert_eq!(
1
			Assets::balance(source_statemint_asset_id, &PARAALICE.into()),
1
			125
1
		);
1
	});
1

            
1
	let dest = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
1
	);
1

            
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(
1
			parachain::CurrencyId::ForeignAsset(source_statemint_asset_id),
1
			100,
1
		);
1
		let asset_fee =
1
			currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(vec![asset_fee, asset].into())),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
1
		));
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that Bob received relay tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 100
1
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
1

            
1
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
1
		let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB);
1

            
1
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 100).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			bob_previous_balance - 100
1
		);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received 100 DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiassets() {
1
	MockNet::reset();
1

            
1
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1

            
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	// Statemint asset
1
	let statemint_asset = Location::new(
1
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
1
	);
1
	let statemint_location_asset = parachain::AssetType::Xcm(
1
		xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"),
1
	);
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
1

            
1
	let asset_metadata_statemint_asset = parachain::AssetMetadata {
1
		name: b"USDC".to_vec(),
1
		symbol: b"USDC".to_vec(),
1
		decimals: 12,
1
	};
1

            
1
	let dest_para = Location::new(1, [Parachain(1)]);
1

            
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			relay_location.clone(),
1
			relay_asset_metadata,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1

            
1
		assert_ok!(AssetManager::register_foreign_asset(
1
			parachain::RuntimeOrigin::root(),
1
			statemint_location_asset.clone(),
1
			asset_metadata_statemint_asset,
1
			1u128,
1
			true
1
		));
1
		XcmWeightTrader::set_asset_price(statemint_asset.clone(), 0u128);
1
	});
1

            
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1

            
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
1

            
1
	// First we send relay chain asset to Alice in AssetHub (via teleport)
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayChainPalletXcm::limited_teleport_assets(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1000).into()),
1
			Box::new(
1
				VersionedLocation::V4(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new(([], 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	// Send DOTs and USDC from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
1
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
1
			INITIAL_BALANCE + 200
1
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
1
			110000000000000
1
		));
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
1
		);
1

            
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			1
1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			10,
1
			RELAYALICE,
1
			300000000000000
1
		));
		// Now send relay tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 200).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// Send USDC
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute.clone())
1
					.clone()
1
					.into()
1
			),
1
			Box::new(
1
				(
1
					[
1
						xcm::latest::prelude::PalletInstance(
1
							<StatemintAssets as PalletInfoAccess>::index() as u8
1
						),
1
						GeneralIndex(10),
1
					],
1
					125
1
				)
1
					.into()
1
			),
1
			0,
1
			WeightLimit::Unlimited
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received the DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
		// Alice has received 125 USDC
1
		assert_eq!(
1
			Assets::balance(source_statemint_asset_id, &PARAALICE.into()),
1
			125
1
		);
1
	});
1

            
1
	let dest = Location::new(
1
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
1
	);
1

            
1
	let statemint_asset_to_send = Asset {
1
		id: AssetId(statemint_asset),
1
		fun: Fungibility::Fungible(100),
1
	};
1

            
1
	let relay_asset_to_send = Asset {
1
		id: AssetId(Location::parent()),
1
		fun: Fungibility::Fungible(100),
1
	};
1

            
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
1
	let assets_to_send: XcmAssets =
1
		XcmAssets::from(vec![statemint_asset_to_send, relay_asset_to_send.clone()]);
1

            
1
	// For some reason the order of the assets is inverted when creating the array above.
1
	// We need to use relay asset for fees, so we pick index 0.
1
	assert_eq!(assets_to_send.get(0).unwrap(), &relay_asset_to_send);
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::V4(chain_part)),
1
			Box::new(VersionedLocation::V4(beneficiary)),
1
			Box::new(VersionedAssets::V4(assets_to_send)),
1
			0,
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
1
		));
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100);
1
	});
1

            
1
	Statemint::execute_with(|| {
1
		// Check that Bob received relay tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			INITIAL_BALANCE + 100
1
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
1

            
1
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
1
		let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB);
1

            
1
		// Now send those tokens to ParaA
1
		assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets(
1
			statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
			Box::new(Location::new(1, [Parachain(1)]).into()),
1
			Box::new(
1
				VersionedLocation::V4(parachain_beneficiary_absolute)
1
					.clone()
1
					.into()
1
			),
1
			Box::new((Location::parent(), 100).into()),
1
			0,
1
			WeightLimit::Unlimited
1
		));
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			bob_previous_balance - 100
1
		);
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		// Alice should have received 100 DOTs
1
		assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			// 4 instructions in transact through signed
1
			Some(4000.into())
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			WEIGHT_REF_TIME_PER_SECOND as u128,
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the relay will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&Location::parent(), &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	Relay::execute_with(|| {
1
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
1
			4000004100u128,
1
		));
		// derived account has all funds
1
		assert!(RelayBalances::free_balance(&derived) == 4000004100);
		// sovereign account has 0 funds
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 0);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		// 100 to sovereign
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 4000 for XCM
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&derived) == 0);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_custom_fee_and_weight() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	ParaA::execute_with(|| {
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the relay will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&Location::parent(), &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	Relay::execute_with(|| {
1
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
1
			4000004100u128,
1
		));
		// derived account has all funds
1
		assert!(RelayBalances::free_balance(&derived) == 4000004100);
		// sovereign account has 0 funds
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 0);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		// 100 to sovereign
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let total_weight = 4000004000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 4000 for XCM
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			},
1
			false
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 100);
1
		assert!(RelayBalances::free_balance(&derived) == 0);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_custom_fee_and_weight_refund() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	ParaA::execute_with(|| {
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the relay will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&Location::parent(), &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	Relay::execute_with(|| {
1
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
1
			4000009100u128,
1
		));
		// derived account has all funds
1
		assert!(RelayBalances::free_balance(&derived) == 4000009100);
		// sovereign account has 0 funds
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 0);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index = <relay_chain::Runtime as frame_system::Config>::PalletInfo::index::<
1
		relay_chain::Balances,
1
	>()
1
	.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<relay_chain::Runtime>::transfer_allow_death {
1
		// 100 to sovereign
1
		dest: para_a_account(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let total_weight = 4000009000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 9000 for XCM
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			},
1
			true
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		// 100 transferred
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 100);
		// 4000005186 refunded
1
		assert_eq!(RelayBalances::free_balance(&derived), 4000005186);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1

            
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			// ParaB
1
			Box::new(xcm::VersionedLocation::V4(para_b_location.clone())),
1
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
1
			// 4 instructions in transact through signed
1
			Some(4.into())
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())),
1
			parachain::ParaTokensPerSecond::get(),
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the paraB will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&para_b_location, &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	ParaB::execute_with(|| {
1
		// free execution, full amount received
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
1
			4000000104u128,
1
		));
		// derived account has all funds
1
		assert!(ParaBalances::free_balance(&derived) == 4000000104);
		// sovereign account has 0 funds
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 0);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index =
1
		<parachain::Runtime as frame_system::Config>::PalletInfo::index::<parachain::Balances>()
1
			.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<parachain::Runtime>::transfer_allow_death {
1
		// 100 to sovereign
1
		dest: para_a_account_20(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 4000 for XCM
1
			// 1-1 to fee
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		assert!(ParaBalances::free_balance(&derived) == 0);
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 100);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para_refund() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1

            
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())),
1
			parachain::ParaTokensPerSecond::get(),
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the paraB will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&para_b_location, &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	ParaB::execute_with(|| {
1
		// free execution, full amount received
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
1
			4000009100u128,
1
		));
		// derived account has all funds
1
		assert!(ParaBalances::free_balance(&derived) == 4000009100);
		// sovereign account has 0 funds
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 0);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index =
1
		<parachain::Runtime as frame_system::Config>::PalletInfo::index::<parachain::Balances>()
1
			.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_balances::Call::<parachain::Runtime>::transfer_allow_death {
1
		// 100 to sovereign
1
		dest: para_a_account_20(),
1
		value: 100u32.into(),
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	let overall_weight = 4000009000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					para_b_balances
1
				))),
1
				fee_amount: Some(overall_weight as u128)
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 9000 for XCM
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: Some(Limited(overall_weight.into()))
1
			},
1
			true
1
		));
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// Check the derived account was refunded
1
		assert_eq!(ParaBalances::free_balance(&derived), 8993);
		// Check the transfer was executed
1
		assert_eq!(ParaBalances::free_balance(&para_a_account_20()), 100);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para_ethereum() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1

            
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			// ParaB
1
			Box::new(xcm::VersionedLocation::V4(para_b_location.clone())),
1
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
1
			// 4 instructions in transact through signed
1
			Some(4.into())
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())),
1
			parachain::ParaTokensPerSecond::get(),
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the paraB will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&para_b_location, &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	let mut parachain_b_alice_balances_before = 0;
1
	ParaB::execute_with(|| {
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
1
			4000000104u128,
1
		));
		// derived account has all funds
1
		assert!(ParaBalances::free_balance(&derived) == 4000000104);
		// sovereign account has 0 funds
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 0);
1
		parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into())
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index =
1
		<parachain::Runtime as frame_system::Config>::PalletInfo::index::<parachain::EthereumXcm>()
1
			.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	use sp_core::U256;
1
	// Let's do a EVM transfer
1
	let eth_tx =
1
		xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 {
1
			gas_limit: U256::from(21000),
1
			fee_payment: xcm_primitives::EthereumXcmFee::Auto,
1
			action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()),
1
			value: U256::from(100),
1
			input: BoundedVec::<
1
				u8,
1
				ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }>
1
			>::try_from(vec![]).unwrap(),
1
			access_list: None,
1
		});
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_ethereum_xcm::Call::<parachain::Runtime>::transact {
1
		xcm_transaction: eth_tx,
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
1
			// 4000000000 for transfer + 4000 for XCM
1
			// 1-1 to fee
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// Make sure the EVM transfer went through
1
		assert!(
1
			ParaBalances::free_balance(&PARAALICE.into())
1
				== parachain_b_alice_balances_before + 100
1
		);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1

            
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			// ParaB
1
			Box::new(xcm::VersionedLocation::V4(para_b_location.clone())),
1
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
1
			// 4 instructions in transact through signed
1
			Some(4.into())
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())),
1
			parachain::ParaTokensPerSecond::get(),
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the paraB will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&para_b_location, &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	let mut parachain_b_alice_balances_before = 0;
1
	ParaB::execute_with(|| {
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
1
			4000000104u128,
1
		));
		// derived account has all funds
1
		assert!(ParaBalances::free_balance(&derived) == 4000000104);
		// sovereign account has 0 funds
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 0);
1
		parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into())
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index =
1
		<parachain::Runtime as frame_system::Config>::PalletInfo::index::<parachain::EthereumXcm>()
1
			.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	use sp_core::U256;
1
	// Let's do a EVM transfer
1
	let eth_tx =
1
		xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 {
1
			gas_limit: U256::from(21000),
1
			fee_payment: xcm_primitives::EthereumXcmFee::Auto,
1
			action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()),
1
			value: U256::from(100),
1
			input: BoundedVec::<
1
				u8,
1
				ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }>
1
			>::try_from(vec![]).unwrap(),
1
			access_list: None,
1
		});
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_ethereum_xcm::Call::<parachain::Runtime>::transact_through_proxy {
1
		transact_as: PARAALICE.into(),
1
		xcm_transaction: eth_tx,
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// Make sure the EVM transfer wasn't executed
1
		assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1

            
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1

            
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1

            
1
	ParaA::execute_with(|| {
1
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			// ParaB
1
			Box::new(xcm::VersionedLocation::V4(para_b_location.clone())),
1
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
1
			// 4 instructions in transact through signed
1
			Some(4.into())
1
		));
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_fee_per_second(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())),
1
			parachain::ParaTokensPerSecond::get(),
1
		));
1
		ancestry = parachain::UniversalLocation::get().into();
1
	});
1

            
1
	// Let's construct the Junction that we will append with DescendOrigin
1
	let signed_origin: Junctions = [AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}]
1
	.into();
1

            
1
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
1

            
1
	// To convert it to what the paraB will see instead of us
1
	descend_origin_multilocation
1
		.reanchor(&para_b_location, &ancestry.interior)
1
		.unwrap();
1

            
1
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1

            
1
	let transfer_recipient = evm_account();
1
	let mut transfer_recipient_balance_before = 0;
1
	ParaB::execute_with(|| {
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
1
			4000000104u128,
1
		));
		// derived account has all funds
1
		assert!(ParaBalances::free_balance(&derived) == 4000000104);
		// sovereign account has 0 funds
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 0);
1
		transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into());
1

            
1
		// Add proxy ALICE  -> derived
1
		let _ = parachain::Proxy::add_proxy_delegate(
1
			&PARAALICE.into(),
1
			derived,
1
			parachain::ProxyType::Any,
1
			0,
1
		);
1
	});
1

            
1
	// Encode the call. Balances transact to para_a_account
1
	// First index
1
	let mut encoded: Vec<u8> = Vec::new();
1
	let index =
1
		<parachain::Runtime as frame_system::Config>::PalletInfo::index::<parachain::EthereumXcm>()
1
			.unwrap() as u8;
1

            
1
	encoded.push(index);
1

            
1
	use sp_core::U256;
1
	// Let's do a EVM transfer
1
	let eth_tx =
1
		xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 {
1
			gas_limit: U256::from(21000),
1
			action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()),
1
			value: U256::from(100),
1
			input: BoundedVec::<
1
				u8,
1
				ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }>
1
			>::try_from(vec![]).unwrap(),
1
			access_list: None,
1
		});
1

            
1
	// Then call bytes
1
	let mut call_bytes = pallet_ethereum_xcm::Call::<parachain::Runtime>::transact_through_proxy {
1
		transact_as: PARAALICE.into(),
1
		xcm_transaction: eth_tx,
1
	}
1
	.encode();
1
	encoded.append(&mut call_bytes);
1

            
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::V4(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
1
			false
1
		));
1
	});
1

            
1
	ParaB::execute_with(|| {
1
		// Make sure the EVM transfer was executed
1
		assert!(
1
			ParaBalances::free_balance(&transfer_recipient.into())
1
				== transfer_recipient_balance_before + 100
1
		);
1
	});
1
}
#[test]
1
fn hrmp_init_accept_through_root() {
1
	MockNet::reset();
1

            
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_a_account(),
1
			1000u128
1
		));
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_b_account(),
1
			1000u128
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		let total_fee = 1_000u128;
1
		let total_weight: u64 = 1_000_000_000;
1
		let tx_weight: u64 = 500_000_000;
1
		// Root can send hrmp init channel
1
		assert_ok!(XcmTransactor::hrmp_manage(
1
			parachain::RuntimeOrigin::root(),
1
			HrmpOperation::InitOpen(HrmpInitParams {
1
				para_id: 2u32.into(),
1
				proposed_max_capacity: 1,
1
				proposed_max_message_size: 1
1
			}),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_fee)
1
			},
1
			TransactWeights {
1
				transact_required_weight_at_most: tx_weight.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			}
1
		));
1
	});
1
	Relay::execute_with(|| {
1
		let expected_event: relay_chain::RuntimeEvent =
1
			polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested {
1
				sender: 1u32.into(),
1
				recipient: 2u32.into(),
1
				proposed_max_capacity: 1u32,
1
				proposed_max_message_size: 1u32,
1
			}
1
			.into();
1
		assert!(relay_chain::relay_events().contains(&expected_event));
1
	});
1
	ParaB::execute_with(|| {
1
		let total_fee = 1_000u128;
1
		let total_weight: u64 = 1_000_000_000;
1
		let tx_weight: u64 = 500_000_000;
1
		// Root can send hrmp accept channel
1
		assert_ok!(XcmTransactor::hrmp_manage(
1
			parachain::RuntimeOrigin::root(),
1
			HrmpOperation::Accept {
1
				para_id: 1u32.into()
1
			},
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_fee)
1
			},
1
			TransactWeights {
1
				transact_required_weight_at_most: tx_weight.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			}
1
		));
1
	});
1

            
1
	Relay::execute_with(|| {
1
		let expected_event: relay_chain::RuntimeEvent =
1
			polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted {
1
				sender: 1u32.into(),
1
				recipient: 2u32.into(),
1
			}
1
			.into();
1
		assert!(relay_chain::relay_events().contains(&expected_event));
1
	});
1
}
#[test]
1
fn hrmp_close_works() {
1
	MockNet::reset();
1

            
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_a_account(),
1
			1000u128
1
		));
1
		assert_ok!(Hrmp::force_open_hrmp_channel(
1
			relay_chain::RuntimeOrigin::root(),
1
			1u32.into(),
1
			2u32.into(),
1
			1u32,
1
			1u32
1
		));
1
		assert_ok!(Hrmp::force_process_hrmp_open(
1
			relay_chain::RuntimeOrigin::root(),
1
			1u32
1
		));
1
	});
1

            
1
	ParaA::execute_with(|| {
1
		let total_fee = 1_000u128;
1
		let total_weight: u64 = 1_000_000_000;
1
		let tx_weight: u64 = 500_000_000;
1
		assert_ok!(XcmTransactor::hrmp_manage(
1
			parachain::RuntimeOrigin::root(),
1
			HrmpOperation::Close(HrmpChannelId {
1
				sender: 1u32.into(),
1
				recipient: 2u32.into()
1
			}),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_fee)
1
			},
1
			TransactWeights {
1
				transact_required_weight_at_most: tx_weight.into(),
1
				overall_weight: Some(Limited(total_weight.into()))
1
			}
1
		));
1
	});
1
	Relay::execute_with(|| {
1
		let expected_event: relay_chain::RuntimeEvent =
1
			polkadot_runtime_parachains::hrmp::Event::ChannelClosed {
1
				by_parachain: 1u32.into(),
1
				channel_id: HrmpChannelId {
1
					sender: 1u32.into(),
1
					recipient: 2u32.into(),
1
				},
1
			}
1
			.into();
1
		assert!(relay_chain::relay_events().contains(&expected_event));
1
	});
1
}
use parity_scale_codec::{Decode, Encode};
use sp_io::hashing::blake2_256;
// Helper to derive accountIds
7
pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 {
7
	let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256);
7
	sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id")
7
}