1
// Copyright 2019-2025 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 moonbase_runtime::xcm_config::AssetType;
28
use pallet_xcm_transactor::{
29
	Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights,
30
};
31
use sp_runtime::traits::Convert;
32
use sp_std::boxed::Box;
33
use xcm::{
34
	latest::prelude::{
35
		AccountId32, AccountKey20, All, Asset, AssetId, Assets as XcmAssets, BuyExecution,
36
		ClearOrigin, DepositAsset, Fungibility, GeneralIndex, Junction, Junctions, Limited,
37
		Location, OriginKind, PalletInstance, Parachain, QueryResponse, Reanchorable, Response,
38
		WeightLimit, Wild, WithdrawAsset, Xcm,
39
	},
40
	VersionedAssetId, VersionedAssets, VersionedXcm,
41
};
42
use xcm::{IntoVersion, VersionedLocation, WrapVersion};
43
use xcm_executor::traits::ConvertLocation;
44
use xcm_executor::traits::TransferType;
45
use xcm_mock::*;
46
use xcm_primitives::{
47
	split_location_into_chain_part_and_beneficiary, UtilityEncodeCall, DEFAULT_PROOF_SIZE,
48
};
49
use xcm_simulator::TestExt;
50
mod common;
51
use cumulus_primitives_core::relay_chain::HrmpChannelId;
52
use parachain::PolkadotXcm;
53

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

            
87
/// Helper function to set fee per second for an asset location (for compatibility with old tests).
88
/// Converts fee_per_second to relative_price and adds/edits the asset in the weight-trader.
89
9
fn set_fee_per_second_for_location(location: Location, fee_per_second: u128) -> Result<(), ()> {
90
	use moonbeam_tests_primitives::MemoryFeeTrader;
91
	use xcm_primitives::XcmFeeTrader;
92

            
93
	// In tests, we configure fees for XcmTransactor via the in-memory fee trader
94
	// instead of pallet-xcm-weight-trader, so that generic XCM funding transfers
95
	// remain free (as on master) and only the transactor calls are charged.
96
9
	let precision_factor = 10u128.pow(moonbeam_tests_primitives::RELATIVE_PRICE_DECIMALS);
97
9
	let native_amount_per_second =
98
9
		frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128;
99
9
	let relative_price = native_amount_per_second
100
9
		.saturating_mul(precision_factor)
101
9
		.checked_div(fee_per_second)
102
9
		.ok_or(())?;
103

            
104
9
	<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(location, relative_price).map_err(|_| ())
105
9
}
106

            
107
25
fn currency_to_asset(currency_id: parachain::CurrencyId, amount: u128) -> Asset {
108
25
	Asset {
109
25
		id: AssetId(
110
25
			<parachain::Runtime as pallet_xcm_transactor::Config>::CurrencyIdToLocation::convert(
111
25
				currency_id,
112
25
			)
113
25
			.unwrap(),
114
25
		),
115
25
		fun: Fungibility::Fungible(amount),
116
25
	}
117
25
}
118

            
119
// Send a relay asset (like DOT) to a parachain A
120
#[test]
121
1
fn receive_relay_asset_from_relay() {
122
1
	MockNet::reset();
123

            
124
1
	let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
125
1
	let source_id: parachain::AssetId = source_location.clone().into();
126
1
	let asset_metadata = parachain::AssetMetadata {
127
1
		name: b"RelayToken".to_vec(),
128
1
		symbol: b"Relay".to_vec(),
129
1
		decimals: 12,
130
1
	};
131
	// register relay asset in parachain A
132
1
	ParaA::execute_with(|| {
133
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
134
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
135
1
			.try_into()
136
1
			.expect("v3 to latest location conversion failed");
137
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
138
1
			source_id,
139
1
			source_location_latest,
140
1
			asset_metadata.decimals,
141
1
			asset_metadata.symbol.try_into().expect("too long"),
142
1
			asset_metadata.name.try_into().expect("too long"),
143
		));
144
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
145
1
	});
146

            
147
	// Actually send relay asset to parachain
148
1
	let dest: Location = AccountKey20 {
149
1
		network: None,
150
1
		key: PARAALICE,
151
1
	}
152
1
	.into();
153
1
	Relay::execute_with(|| {
154
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
155
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
156
1
			assets: Wild(All),
157
1
			beneficiary: dest.clone(),
158
1
		}]);
159
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
160
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
161
1
			Box::new(Parachain(1).into()),
162
1
			Box::new(([], 123).into()),
163
1
			Box::new(TransferType::LocalReserve),
164
1
			Box::new(fees_id),
165
1
			Box::new(TransferType::LocalReserve),
166
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
167
1
			WeightLimit::Unlimited
168
		));
169
1
	});
170

            
171
	// Verify that parachain received the asset
172
1
	ParaA::execute_with(|| {
173
		// free execution, full amount received
174
1
		assert_eq!(
175
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
176
1
			Ok(U256::from(123))
177
		);
178
1
	});
179
1
}
180

            
181
// Send relay asset (like DOT) back from Parachain A to relaychain
182
#[test]
183
1
fn send_relay_asset_to_relay() {
184
1
	MockNet::reset();
185

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

            
189
1
	let asset_metadata = parachain::AssetMetadata {
190
1
		name: b"RelayToken".to_vec(),
191
1
		symbol: b"Relay".to_vec(),
192
1
		decimals: 12,
193
1
	};
194

            
195
	// Register relay asset in paraA
196
1
	ParaA::execute_with(|| {
197
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
198
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
199
1
			.try_into()
200
1
			.expect("v3 to latest location conversion failed");
201
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
202
1
			source_id,
203
1
			source_location_latest,
204
1
			asset_metadata.decimals,
205
1
			asset_metadata.symbol.try_into().expect("too long"),
206
1
			asset_metadata.name.try_into().expect("too long"),
207
		));
208
		// Free execution
209
1
		assert_ok!(add_supported_asset(source_location, 0));
210
1
	});
211

            
212
1
	let dest: Location = Junction::AccountKey20 {
213
1
		network: None,
214
1
		key: PARAALICE,
215
1
	}
216
1
	.into();
217

            
218
	// First send relay chain asset to Parachain like in previous test
219
1
	Relay::execute_with(|| {
220
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
221
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
222
1
			assets: Wild(All),
223
1
			beneficiary: dest.clone(),
224
1
		}]);
225
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
226
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
227
1
			Box::new(Parachain(1).into()),
228
1
			Box::new(([], 123).into()),
229
1
			Box::new(TransferType::LocalReserve),
230
1
			Box::new(fees_id),
231
1
			Box::new(TransferType::LocalReserve),
232
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
233
1
			WeightLimit::Unlimited
234
		));
235
1
	});
236

            
237
1
	ParaA::execute_with(|| {
238
		// Free execution, full amount received
239
1
		assert_eq!(
240
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
241
1
			Ok(U256::from(123))
242
		);
243
1
	});
244

            
245
	// Lets gather the balance before sending back money
246
1
	let mut balance_before_sending = 0;
247
1
	Relay::execute_with(|| {
248
1
		balance_before_sending = RelayBalances::free_balance(&RELAYALICE);
249
1
	});
250

            
251
	// We now send back some money to the relay
252
1
	let dest = Location {
253
1
		parents: 1,
254
1
		interior: [AccountId32 {
255
1
			network: None,
256
1
			id: RELAYALICE.into(),
257
1
		}]
258
1
		.into(),
259
1
	};
260
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
261

            
262
1
	ParaA::execute_with(|| {
263
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 123);
264
		// free execution, full amount received
265
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
266
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
267
1
			assets: Wild(All),
268
1
			beneficiary,
269
1
		}]);
270
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
271
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
272
1
			Box::new(VersionedLocation::from(chain_part)),
273
1
			Box::new(VersionedAssets::from(asset)),
274
1
			Box::new(TransferType::DestinationReserve),
275
1
			Box::new(fees_id),
276
1
			Box::new(TransferType::DestinationReserve),
277
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
278
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
279
		));
280
1
	});
281

            
282
	// The balances in paraAlice should have been substracted
283
1
	ParaA::execute_with(|| {
284
1
		assert_eq!(
285
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
286
1
			Ok(U256::from(0))
287
		);
288
1
	});
289

            
290
	// Balances in the relay should have been received
291
1
	Relay::execute_with(|| {
292
		// Free execution,x	 full amount received
293
1
		assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending);
294
1
	});
295
1
}
296

            
297
#[test]
298
1
fn send_relay_asset_to_para_b() {
299
1
	MockNet::reset();
300

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

            
304
1
	let asset_metadata = parachain::AssetMetadata {
305
1
		name: b"RelayToken".to_vec(),
306
1
		symbol: b"Relay".to_vec(),
307
1
		decimals: 12,
308
1
	};
309

            
310
	// Register asset in paraA. Free execution
311
1
	ParaA::execute_with(|| {
312
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
313
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
314
1
			.try_into()
315
1
			.expect("v3 to latest location conversion failed");
316
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
317
1
			source_id,
318
1
			source_location_latest,
319
1
			asset_metadata.decimals,
320
1
			asset_metadata.symbol.clone().try_into().expect("too long"),
321
1
			asset_metadata.name.clone().try_into().expect("too long"),
322
		));
323
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
324
1
	});
325

            
326
	// Register asset in paraB. Free execution
327
1
	ParaB::execute_with(|| {
328
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
329
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
330
1
			.try_into()
331
1
			.expect("v3 to latest location conversion failed");
332
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
333
1
			source_id,
334
1
			source_location_latest,
335
1
			asset_metadata.decimals,
336
1
			asset_metadata.symbol.clone().try_into().expect("too long"),
337
1
			asset_metadata.name.clone().try_into().expect("too long"),
338
		));
339
1
		assert_ok!(add_supported_asset(source_location, 0));
340
1
	});
341

            
342
	// First send relay chain asset to Parachain A like in previous test
343
1
	let dest: Location = Junction::AccountKey20 {
344
1
		network: None,
345
1
		key: PARAALICE,
346
1
	}
347
1
	.into();
348
1
	Relay::execute_with(|| {
349
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
350
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
351
1
			assets: Wild(All),
352
1
			beneficiary: dest.clone(),
353
1
		}]);
354
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
355
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
356
1
			Box::new(Parachain(1).into()),
357
1
			Box::new(([], 123).into()),
358
1
			Box::new(TransferType::LocalReserve),
359
1
			Box::new(fees_id),
360
1
			Box::new(TransferType::LocalReserve),
361
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
362
1
			WeightLimit::Unlimited
363
		));
364
1
	});
365

            
366
1
	ParaA::execute_with(|| {
367
		// Free execution, full amount received
368
1
		assert_eq!(
369
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
370
1
			Ok(U256::from(123))
371
		);
372
1
	});
373

            
374
	// Now send relay asset from para A to para B
375
1
	let dest = Location {
376
1
		parents: 1,
377
1
		interior: [
378
1
			Parachain(2),
379
1
			AccountKey20 {
380
1
				network: None,
381
1
				key: PARAALICE.into(),
382
1
			},
383
1
		]
384
1
		.into(),
385
1
	};
386
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
387

            
388
1
	ParaA::execute_with(|| {
389
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
390
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
391
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
392
1
			assets: Wild(All),
393
1
			beneficiary,
394
1
		}]);
395
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
396
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
397
1
			Box::new(VersionedLocation::from(chain_part)),
398
1
			Box::new(VersionedAssets::from(vec![asset])),
399
1
			Box::new(TransferType::RemoteReserve(Location::parent().into())),
400
1
			Box::new(fees_id),
401
1
			Box::new(TransferType::RemoteReserve(Location::parent().into())),
402
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
403
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
404
		));
405
1
	});
406

            
407
	// Para A balances should have been subtracted
408
1
	ParaA::execute_with(|| {
409
1
		assert_eq!(
410
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
411
1
			Ok(U256::from(23))
412
		);
413
1
	});
414

            
415
	// Para B balances should have been credited
416
1
	ParaB::execute_with(|| {
417
1
		assert_eq!(
418
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
419
1
			Ok(U256::from(100))
420
		);
421
1
	});
422
1
}
423

            
424
#[test]
425
1
fn send_para_a_asset_to_para_b() {
426
1
	MockNet::reset();
427

            
428
	// this represents the asset in paraA
429
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
430
1
	let source_location: AssetType = para_a_balances
431
1
		.try_into()
432
1
		.expect("Location convertion to AssetType should succeed");
433
1
	let source_id: parachain::AssetId = source_location.clone().into();
434

            
435
1
	let asset_metadata = parachain::AssetMetadata {
436
1
		name: b"ParaAToken".to_vec(),
437
1
		symbol: b"ParaA".to_vec(),
438
1
		decimals: 18,
439
1
	};
440

            
441
	// Register asset in paraB. Free execution
442
1
	ParaB::execute_with(|| {
443
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
444
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
445
1
			.try_into()
446
1
			.expect("v3 to latest location conversion failed");
447
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
448
1
			source_id,
449
1
			source_location_latest,
450
1
			asset_metadata.decimals,
451
1
			asset_metadata.symbol.try_into().expect("too long"),
452
1
			asset_metadata.name.try_into().expect("too long"),
453
		));
454
1
		assert_ok!(add_supported_asset(source_location, 0));
455
1
	});
456

            
457
	// Send para A asset from para A to para B
458
1
	let dest = Location {
459
1
		parents: 1,
460
1
		interior: [
461
1
			Parachain(2),
462
1
			AccountKey20 {
463
1
				network: None,
464
1
				key: PARAALICE.into(),
465
1
			},
466
1
		]
467
1
		.into(),
468
1
	};
469

            
470
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
471

            
472
1
	ParaA::execute_with(|| {
473
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
474
		// Free execution, full amount received
475
1
		assert_ok!(PolkadotXcm::transfer_assets(
476
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
477
1
			Box::new(VersionedLocation::from(chain_part)),
478
1
			Box::new(VersionedLocation::from(beneficiary)),
479
1
			Box::new(VersionedAssets::from(vec![asset])),
480
			0,
481
1
			WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE))
482
		));
483
1
	});
484

            
485
	// Native token is substracted in paraA
486
1
	ParaA::execute_with(|| {
487
1
		assert_eq!(
488
1
			ParaBalances::free_balance(&PARAALICE.into()),
489
			INITIAL_BALANCE - 100
490
		);
491
1
	});
492

            
493
	// Asset is minted in paraB
494
1
	ParaB::execute_with(|| {
495
1
		assert_eq!(
496
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
497
1
			Ok(U256::from(100))
498
		);
499
1
	});
500
1
}
501

            
502
#[test]
503
1
fn send_para_a_asset_from_para_b_to_para_c() {
504
1
	MockNet::reset();
505

            
506
	// Represents para A asset
507
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
508
1
	let source_location: AssetType = para_a_balances
509
1
		.try_into()
510
1
		.expect("Location convertion to AssetType should succeed");
511
1
	let source_id: parachain::AssetId = source_location.clone().into();
512

            
513
1
	let asset_metadata = parachain::AssetMetadata {
514
1
		name: b"ParaAToken".to_vec(),
515
1
		symbol: b"ParaA".to_vec(),
516
1
		decimals: 18,
517
1
	};
518

            
519
	// Register para A asset in parachain B. Free execution
520
1
	ParaB::execute_with(|| {
521
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
522
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
523
1
			.try_into()
524
1
			.expect("v3 to latest location conversion failed");
525
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
526
1
			source_id,
527
1
			source_location_latest,
528
1
			asset_metadata.decimals,
529
1
			asset_metadata.symbol.clone().try_into().expect("too long"),
530
1
			asset_metadata.name.clone().try_into().expect("too long"),
531
		));
532
1
		assert_ok!(add_supported_asset(source_location.clone(), 0));
533
1
	});
534

            
535
	// Register para A asset in parachain C. Free execution
536
1
	ParaC::execute_with(|| {
537
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
538
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
539
1
			.try_into()
540
1
			.expect("v3 to latest location conversion failed");
541
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
542
1
			source_id,
543
1
			source_location_latest,
544
1
			asset_metadata.decimals,
545
1
			asset_metadata.symbol.clone().try_into().expect("too long"),
546
1
			asset_metadata.name.clone().try_into().expect("too long"),
547
		));
548
1
		assert_ok!(add_supported_asset(source_location, 0));
549
1
	});
550

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

            
565
1
	ParaA::execute_with(|| {
566
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
567
		// free execution, full amount received
568
1
		assert_ok!(PolkadotXcm::transfer_assets(
569
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
570
1
			Box::new(VersionedLocation::from(chain_part)),
571
1
			Box::new(VersionedLocation::from(beneficiary)),
572
1
			Box::new(VersionedAssets::from(vec![asset])),
573
			0,
574
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
575
		));
576
1
	});
577

            
578
	// Para A balances have been substracted
579
1
	ParaA::execute_with(|| {
580
1
		assert_eq!(
581
1
			ParaBalances::free_balance(&PARAALICE.into()),
582
			INITIAL_BALANCE - 100
583
		);
584
1
	});
585

            
586
	// Para B balances have been credited
587
1
	ParaB::execute_with(|| {
588
1
		assert_eq!(
589
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
590
1
			Ok(U256::from(100))
591
		);
592
1
	});
593

            
594
	// Send para A asset from para B to para C
595
1
	let dest = Location {
596
1
		parents: 1,
597
1
		interior: [
598
1
			Parachain(3),
599
1
			AccountKey20 {
600
1
				network: None,
601
1
				key: PARAALICE.into(),
602
1
			},
603
1
		]
604
1
		.into(),
605
1
	};
606
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
607

            
608
1
	ParaB::execute_with(|| {
609
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
610
1
		assert_ok!(PolkadotXcm::transfer_assets(
611
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
612
1
			Box::new(VersionedLocation::from(chain_part)),
613
1
			Box::new(VersionedLocation::from(beneficiary)),
614
1
			Box::new(VersionedAssets::from(vec![asset])),
615
			0,
616
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
617
		));
618
1
	});
619

            
620
	// The message passed through parachainA so we needed to pay since its the native token
621
	// The message passed through parachainA so we needed to pay since its the native token
622
1
	ParaC::execute_with(|| {
623
1
		assert_eq!(
624
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
625
1
			Ok(U256::from(95))
626
		);
627
1
	});
628
1
}
629

            
630
#[test]
631
1
fn send_para_a_asset_to_para_b_and_back_to_para_a() {
632
1
	MockNet::reset();
633

            
634
	// Para A asset
635
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
636
1
	let source_location: AssetType = para_a_balances
637
1
		.try_into()
638
1
		.expect("Location convertion to AssetType should succeed");
639
1
	let source_id: parachain::AssetId = source_location.clone().into();
640

            
641
1
	let asset_metadata = parachain::AssetMetadata {
642
1
		name: b"ParaAToken".to_vec(),
643
1
		symbol: b"ParaA".to_vec(),
644
1
		decimals: 18,
645
1
	};
646

            
647
	// Register para A asset in para B
648
1
	ParaB::execute_with(|| {
649
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
650
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
651
1
			.try_into()
652
1
			.expect("v3 to latest location conversion failed");
653
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
654
1
			source_id,
655
1
			source_location_latest,
656
1
			asset_metadata.decimals,
657
1
			asset_metadata.symbol.try_into().expect("too long"),
658
1
			asset_metadata.name.try_into().expect("too long"),
659
		));
660
1
		assert_ok!(add_supported_asset(source_location, 0));
661
1
	});
662

            
663
	// Send para A asset to para B
664
1
	let dest = Location {
665
1
		parents: 1,
666
1
		interior: [
667
1
			Parachain(2),
668
1
			AccountKey20 {
669
1
				network: None,
670
1
				key: PARAALICE.into(),
671
1
			},
672
1
		]
673
1
		.into(),
674
1
	};
675
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
676

            
677
1
	ParaA::execute_with(|| {
678
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
679
1
		assert_ok!(PolkadotXcm::transfer_assets(
680
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
681
1
			Box::new(VersionedLocation::from(chain_part)),
682
1
			Box::new(VersionedLocation::from(beneficiary)),
683
1
			Box::new(VersionedAssets::from(vec![asset])),
684
			0,
685
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
686
		));
687
1
	});
688

            
689
	// Balances have been subtracted
690
1
	ParaA::execute_with(|| {
691
1
		assert_eq!(
692
1
			ParaBalances::free_balance(&PARAALICE.into()),
693
			INITIAL_BALANCE - 100
694
		);
695
1
	});
696

            
697
	// Para B balances have been credited
698
1
	ParaB::execute_with(|| {
699
1
		assert_eq!(
700
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
701
1
			Ok(U256::from(100))
702
		);
703
1
	});
704

            
705
	// Send back para A asset to para A
706
1
	let dest = Location {
707
1
		parents: 1,
708
1
		interior: [
709
1
			Parachain(1),
710
1
			AccountKey20 {
711
1
				network: None,
712
1
				key: PARAALICE.into(),
713
1
			},
714
1
		]
715
1
		.into(),
716
1
	};
717
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
718

            
719
1
	ParaB::execute_with(|| {
720
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
721
1
		assert_ok!(PolkadotXcm::transfer_assets(
722
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
723
1
			Box::new(VersionedLocation::from(chain_part)),
724
1
			Box::new(VersionedLocation::from(beneficiary)),
725
1
			Box::new(VersionedAssets::from(vec![asset])),
726
			0,
727
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
728
		));
729
1
	});
730

            
731
1
	ParaA::execute_with(|| {
732
		// Weight used is 4
733
1
		assert_eq!(
734
1
			ParaBalances::free_balance(&PARAALICE.into()),
735
			INITIAL_BALANCE - 4
736
		);
737
1
	});
738
1
}
739

            
740
#[test]
741
1
fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() {
742
1
	MockNet::reset();
743

            
744
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
745
1
	let source_location: AssetType = para_a_balances
746
1
		.try_into()
747
1
		.expect("Location convertion to AssetType should succeed");
748
1
	let source_id: parachain::AssetId = source_location.clone().into();
749

            
750
1
	let asset_metadata = parachain::AssetMetadata {
751
1
		name: b"ParaAToken".to_vec(),
752
1
		symbol: b"ParaA".to_vec(),
753
1
		decimals: 18,
754
1
	};
755

            
756
1
	ParaB::execute_with(|| {
757
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
758
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
759
1
			.try_into()
760
1
			.expect("v3 to latest location conversion failed");
761
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
762
1
			source_id,
763
1
			source_location_latest,
764
1
			asset_metadata.decimals,
765
1
			asset_metadata.symbol.try_into().expect("too long"),
766
1
			asset_metadata.name.try_into().expect("too long"),
767
		));
768
1
		assert_ok!(add_supported_asset(source_location, 0));
769
1
	});
770

            
771
1
	let dest = Location {
772
1
		parents: 1,
773
1
		interior: [
774
1
			Parachain(2),
775
1
			AccountKey20 {
776
1
				network: None,
777
1
				key: PARAALICE.into(),
778
1
			},
779
1
		]
780
1
		.into(),
781
1
	};
782
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
783

            
784
1
	ParaA::execute_with(|| {
785
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
786
1
		assert_ok!(PolkadotXcm::transfer_assets(
787
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
788
1
			Box::new(VersionedLocation::from(chain_part)),
789
1
			Box::new(VersionedLocation::from(beneficiary)),
790
1
			Box::new(VersionedAssets::from(vec![asset])),
791
			0,
792
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
793
		));
794
1
	});
795

            
796
	// Para A asset has been credited
797
1
	ParaA::execute_with(|| {
798
1
		assert_eq!(
799
1
			ParaBalances::free_balance(&PARAALICE.into()),
800
			INITIAL_BALANCE - 100
801
		);
802
1
	});
803

            
804
1
	ParaB::execute_with(|| {
805
		// free execution, full amount received
806
1
		assert_eq!(
807
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
808
1
			Ok(U256::from(100))
809
		);
810
1
	});
811

            
812
	// This time we will force the new reanchoring by manually sending the
813
	// Message through polkadotXCM pallet
814

            
815
1
	let dest = Location {
816
1
		parents: 1,
817
1
		interior: [Parachain(1)].into(),
818
1
	};
819

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

            
822
1
	let message = xcm::VersionedXcm::<()>::V5(Xcm(vec![
823
1
		WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()),
824
1
		ClearOrigin,
825
1
		BuyExecution {
826
1
			fees: (reanchored_para_a_balances, 100).into(),
827
1
			weight_limit: Limited(80.into()),
828
1
		},
829
1
		DepositAsset {
830
1
			assets: All.into(),
831
1
			beneficiary: Location::new(
832
1
				0,
833
1
				[AccountKey20 {
834
1
					network: None,
835
1
					key: PARAALICE,
836
1
				}],
837
1
			),
838
1
		},
839
1
	]));
840
1
	ParaB::execute_with(|| {
841
		// Send a message to the sovereign account in ParaA to withdraw
842
		// and deposit asset
843
1
		assert_ok!(ParachainPalletXcm::send(
844
1
			parachain::RuntimeOrigin::root(),
845
1
			Box::new(dest.into()),
846
1
			Box::new(message),
847
		));
848
1
	});
849

            
850
1
	ParaA::execute_with(|| {
851
		// Weight used is 4
852
1
		assert_eq!(
853
1
			ParaBalances::free_balance(&PARAALICE.into()),
854
			INITIAL_BALANCE - 4
855
		);
856
1
	});
857
1
}
858

            
859
#[test]
860
1
fn receive_relay_asset_with_trader() {
861
1
	MockNet::reset();
862

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

            
866
1
	let asset_metadata = parachain::AssetMetadata {
867
1
		name: b"RelayToken".to_vec(),
868
1
		symbol: b"Relay".to_vec(),
869
1
		decimals: 12,
870
1
	};
871

            
872
	// This time we are gonna put a rather high number of units per second
873
	// we know later we will divide by 1e12
874
	// Lets put 1e6 as units per second
875
1
	ParaA::execute_with(|| {
876
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
877
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
878
1
			.try_into()
879
1
			.expect("v3 to latest location conversion failed");
880
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
881
1
			source_id,
882
1
			source_location_latest,
883
1
			asset_metadata.decimals,
884
1
			asset_metadata.symbol.try_into().expect("too long"),
885
1
			asset_metadata.name.try_into().expect("too long"),
886
		));
887
1
		assert_ok!(add_supported_asset(source_location, 2_500_000_000_000));
888
1
	});
889

            
890
1
	let dest: Location = Junction::AccountKey20 {
891
1
		network: None,
892
1
		key: PARAALICE,
893
1
	}
894
1
	.into();
895
	// We are sending 100 tokens from relay.
896
	// Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second)
897
	// weight is 4 since we are executing 4 instructions with a unitweightcost of 1.
898
	// Units per second should be 2_500_000_000_000_000
899
	// Therefore with no refund, we should receive 10 tokens less
900
	// Native trader fails for this, and we use the asset trader
901
1
	Relay::execute_with(|| {
902
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
903
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
904
1
			assets: Wild(All),
905
1
			beneficiary: dest.clone(),
906
1
		}]);
907
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
908
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
909
1
			Box::new(Parachain(1).into()),
910
1
			Box::new(([], 100).into()),
911
1
			Box::new(TransferType::LocalReserve),
912
1
			Box::new(fees_id),
913
1
			Box::new(TransferType::LocalReserve),
914
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
915
1
			WeightLimit::Unlimited
916
		));
917
1
	});
918

            
919
1
	ParaA::execute_with(|| {
920
		// non-free execution, not full amount received
921
1
		assert_eq!(
922
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
923
1
			Ok(U256::from(90))
924
		);
925
		// Fee should have been received by treasury
926
1
		assert_eq!(
927
1
			EvmForeignAssets::balance(source_id, Treasury::account_id()),
928
1
			Ok(U256::from(10))
929
		);
930
1
	});
931
1
}
932

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

            
937
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
938
1
	let source_location: AssetType = para_a_balances
939
1
		.try_into()
940
1
		.expect("Location convertion to AssetType should succeed");
941
1
	let source_id: parachain::AssetId = source_location.clone().into();
942

            
943
1
	let asset_metadata = parachain::AssetMetadata {
944
1
		name: b"ParaAToken".to_vec(),
945
1
		symbol: b"ParaA".to_vec(),
946
1
		decimals: 18,
947
1
	};
948

            
949
1
	ParaB::execute_with(|| {
950
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
951
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
952
1
			.try_into()
953
1
			.expect("v3 to latest location conversion failed");
954
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
955
1
			source_id,
956
1
			source_location_latest,
957
1
			asset_metadata.decimals,
958
1
			asset_metadata.symbol.try_into().expect("too long"),
959
1
			asset_metadata.name.try_into().expect("too long"),
960
		));
961
1
		assert_ok!(add_supported_asset(source_location, 2500000000000));
962
1
	});
963

            
964
1
	let dest = Location {
965
1
		parents: 1,
966
1
		interior: [
967
1
			Parachain(2),
968
1
			AccountKey20 {
969
1
				network: None,
970
1
				key: PARAALICE.into(),
971
1
			},
972
1
		]
973
1
		.into(),
974
1
	};
975
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
976

            
977
	// In destination chain, we only need 4 weight
978
	// We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury
979
1
	ParaA::execute_with(|| {
980
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
981
1
		assert_ok!(PolkadotXcm::transfer_assets(
982
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
983
1
			Box::new(VersionedLocation::from(chain_part)),
984
1
			Box::new(VersionedLocation::from(beneficiary)),
985
1
			Box::new(VersionedAssets::from(vec![asset])),
986
			0,
987
1
			WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE))
988
		));
989
1
	});
990
1
	ParaA::execute_with(|| {
991
		// free execution, full amount received
992
1
		assert_eq!(
993
1
			ParaBalances::free_balance(&PARAALICE.into()),
994
			INITIAL_BALANCE - 100
995
		);
996
1
	});
997

            
998
	// We are sending 100 tokens from para A.
999
	// Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second)
	// weight is 4 since we are executing 4 instructions with a unitweightcost of 1.
	// Units per second should be 2_500_000_000_000_000
	// Since we set 10 weight in destination chain, 25 will be charged upfront
	// 15 of those will be refunded, while 10 will go to treasury as the true weight used
	// will be 4
1
	ParaB::execute_with(|| {
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(90))
		);
		// Fee should have been received by treasury
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, Treasury::account_id()),
1
			Ok(U256::from(10))
		);
1
	});
1
}
#[test]
1
fn send_para_a_asset_to_para_b_with_trader_and_fee() {
1
	MockNet::reset();
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
1
	let source_location: AssetType = para_a_balances
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_id: parachain::AssetId = source_location.clone().into();
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"ParaAToken".to_vec(),
1
		symbol: b"ParaA".to_vec(),
1
		decimals: 18,
1
	};
1
	ParaB::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
		// With these units per second, 80K weight convrets to 1 asset unit
1
		assert_ok!(add_supported_asset(source_location, 12500000));
1
	});
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
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
	// we use transfer_with_fee
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
1
		let asset_fee = currency_to_asset(parachain::CurrencyId::SelfReserve, 1);
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedLocation::from(beneficiary)),
1
			Box::new(VersionedAssets::from(vec![asset_fee, asset])),
			0,
1
			WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// 100 tokens transferred plus 1 taken from fees
1
		assert_eq!(
1
			ParaBalances::free_balance(&PARAALICE.into()),
			INITIAL_BALANCE - 100 - 1
		);
1
	});
1
	ParaB::execute_with(|| {
		// free execution, full amount received because the xcm instruction does not cost
		// what it is specified
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(101))
		);
1
	});
1
}
#[test]
1
fn error_when_not_paying_enough() {
1
	MockNet::reset();
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
	let dest: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
	// This time we are gonna put a rather high number of units per second
	// we know later we will divide by 1e12
	// Lets put 1e6 as units per second
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 2500000000000));
1
	});
1
	ParaA::execute_with(|| {
		// amount not received as it is not paying enough
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(0))
		);
1
	});
	// We are sending 100 tokens from relay.
	// If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10
	// Therefore with no refund, we should receive 10 tokens less
1
	Relay::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 5).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// amount not received as it is not paying enough
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(0))
		);
1
	});
1
}
#[test]
1
fn transact_through_derivative_multilocation() {
1
	MockNet::reset();
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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
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::from(Location::parent())),
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(Location::parent(), WEIGHT_REF_TIME_PER_SECOND as u128)
1
			.expect("must succeed");
1
	});
	// Let's construct the call to know how much weight it is going to require
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
		// 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000003100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			MockTransactors::Relay,
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				fee_amount: None
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
			},
			false
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
19
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
19
				_ => None,
19
			});
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1
	Relay::execute_with(|| {
		// 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
	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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
	// Let's construct the call to know how much weight it is going to require
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
		// 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000003100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	let overall_weight = 4000003000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			MockTransactors::Relay,
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				// 1-1 fee weight mapping
1
				fee_amount: Some(overall_weight as u128)
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
			},
			false
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
18
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
18
				_ => None,
18
			});
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1
	Relay::execute_with(|| {
		// 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
	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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
	// Let's construct the call to know how much weight it is going to require
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
		// 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000009100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000009000);
1
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	let overall_weight = 4000009000u64;
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_derivative(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			MockTransactors::Relay,
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			true
		));
1
		let event_found: Option<parachain::RuntimeEvent> = parachain::para_events()
1
			.iter()
18
			.find_map(|event| match event.clone() {
				parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped {
					..
				}) => Some(event.clone()),
18
				_ => None,
18
			});
		// Assert that the events do not contain the assets being trapped
1
		assert!(event_found.is_none());
1
	});
1
	Relay::execute_with(|| {
		// free execution, full amount received
		// 4000009000 refunded + 100 transferred = 4000009100
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 4000009100);
1
		assert_eq!(RelayBalances::free_balance(&registered_address), 0);
1
	});
1
}
#[test]
1
fn transact_through_sovereign() {
1
	MockNet::reset();
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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
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::from(Location::parent())),
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(Location::parent(), WEIGHT_REF_TIME_PER_SECOND as u128)
1
			.expect("must succeed");
1
	});
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000003100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
		0
1
	});
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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);
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		let utility_bytes = <XcmTransactor as UtilityEncodeCall>::encode_call(
1
			moonbase_runtime::xcm_config::Transactors::Relay,
1
			xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
		);
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			false
		));
1
	});
1
	Relay::execute_with(|| {
		// 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
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(Location::parent())),
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
1
			None
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(Location::parent(), WEIGHT_REF_TIME_PER_SECOND as u128)
1
			.expect("must succeed");
1
	});
1
	let derivative_address = derivative_account_id(para_a_account(), 0);
1
	Relay::execute_with(|| {
		// 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(),
			100u128
		));
		// 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(),
			4000003000u128
		));
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
	});
	// 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
	encoded.push(index);
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);
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: /* Here */ [].into(),
1
	};
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
		// The final call will be an AsDerivative using index 0
1
		let utility_bytes = <XcmTransactor as UtilityEncodeCall>::encode_call(
1
			moonbase_runtime::xcm_config::Transactors::Relay,
1
			xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
		);
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(dest)),
			// 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::from(
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
			},
			false
		));
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
	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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location;
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000003100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000003000);
1
		0
1
	});
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	let total_weight = 4000003000u64;
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		let utility_bytes = <XcmTransactor as UtilityEncodeCall>::encode_call(
1
			moonbase_runtime::xcm_config::Transactors::Relay,
1
			xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
		);
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			false
		));
1
	});
1
	Relay::execute_with(|| {
		// 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
	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
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 1));
1
	});
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 4000009100u128).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009100u128))
		);
1
	});
	// Register address
1
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::register(
1
			parachain::RuntimeOrigin::root(),
1
			PARAALICE.into(),
			0,
		));
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
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009000u128))
		);
1
	});
	// What we will do now is transfer this relay tokens from the derived account to the sovereign
	// again
1
	Relay::execute_with(|| {
		// free execution,x	 full amount received
1
		assert!(RelayBalances::free_balance(&para_a_account()) == 4000009000);
1
		0
1
	});
	// We send the xcm transact operation to parent
1
	let dest = Location {
1
		parents: 1,
1
		interior: [].into(),
1
	};
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	let total_weight = 4000009000u64;
	// Root can directly pass the execution byes to the sovereign
1
	ParaA::execute_with(|| {
1
		let utility_bytes = <XcmTransactor as UtilityEncodeCall>::encode_call(
1
			moonbase_runtime::xcm_config::Transactors::Relay,
1
			xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded),
		);
1
		assert_ok!(XcmTransactor::transact_through_sovereign(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(dest)),
1
			Some(PARAALICE.into()),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			true
		));
1
	});
1
	Relay::execute_with(|| {
		// free execution, full amount received
		// 4000009000 refunded + 100 transferred = 4000009100
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 4000009100);
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
	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
	};
	// register relay asset in parachain A and set XCM version to 1
1
	ParaA::execute_with(|| {
1
		parachain::XcmVersioner::set_version(1);
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
			3,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1
	let response = Response::Version(2);
1
	let querier: Location = [].into();
	// This is irrelevant, nothing will be done with this message,
	// 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
	}]);
	// The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force
	// it directly here
	// Actually send relay asset to parachain
1
	let dest: Location = AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	Relay::execute_with(|| {
		// This sets the default version, for not known destinations
1
		assert_ok!(RelayChainPalletXcm::force_default_xcm_version(
1
			relay_chain::RuntimeOrigin::root(),
1
			Some(3)
		));
		// 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
		));
		// Transfer assets. Since it is an unknown destination, it will query for version
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 123).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
		// Let's advance the relay. This should trigger the subscription message
1
		relay_chain::relay_roll_to(2);
		// queries should have been updated
1
		assert!(RelayChainPalletXcm::query(&0).is_some());
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
	Relay::execute_with(|| {
		// Assert that the events vector contains the version change
1
		assert!(relay_chain::relay_events().contains(&expected_supported_version));
1
	});
	// ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets
	// of the new version change
1
	ParaA::execute_with(|| {
		// Set version
1
		parachain::XcmVersioner::set_version(2);
		// Do runtime upgrade
1
		parachain::on_runtime_upgrade();
		// Initialize block, to call on_initialize and notify targets
1
		parachain::para_roll_to(2);
		// Expect the event in the parachain
1
		assert!(parachain::para_events().iter().any(|e| matches!(
2
			e,
			parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified {
				result: 2,
				..
			})
		)));
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
	Relay::execute_with(|| {
		// 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
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
1
	let source_location: AssetType = para_a_balances
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_id: parachain::AssetId = source_location.clone().into();
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();
	// This is irrelevant, nothing will be done with this message,
	// 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
	ParaA::execute_with(|| {
		// advertised version
1
		parachain::XcmVersioner::set_version(2);
1
	});
1
	ParaB::execute_with(|| {
		// Let's try with v0
1
		parachain::XcmVersioner::set_version(0);
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1
	ParaA::execute_with(|| {
		// This sets the default version, for not known destinations
1
		assert_ok!(ParachainPalletXcm::force_default_xcm_version(
1
			parachain::RuntimeOrigin::root(),
1
			Some(3)
		));
		// Wrap version, which sets VersionedStorage
1
		assert_ok!(<ParachainPalletXcm as WrapVersion>::wrap_version(
1
			&Location::new(1, [Parachain(2)]).into(),
1
			mock_message
		));
1
		parachain::para_roll_to(2);
		// queries should have been updated
1
		assert!(ParachainPalletXcm::query(&0).is_some());
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
	ParaA::execute_with(|| {
		// Assert that the events vector contains the version change
1
		assert!(parachain::para_events().contains(&expected_supported_version));
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);
		// free execution, full amount received
1
		assert_ok!(PolkadotXcm::transfer_assets(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedLocation::from(beneficiary)),
1
			Box::new(VersionedAssets::from(vec![asset])),
			0,
1
			WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE))
		));
		// free execution, full amount received
1
		assert_eq!(
1
			ParaBalances::free_balance(&PARAALICE.into()),
			INITIAL_BALANCE - 100
		);
1
	});
1
	ParaB::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
	// ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets
	// of the new version change
1
	ParaB::execute_with(|| {
		// Set version
1
		parachain::XcmVersioner::set_version(2);
		// Do runtime upgrade
1
		parachain::on_runtime_upgrade();
		// Initialize block, to call on_initialize and notify targets
1
		parachain::para_roll_to(2);
		// Expect the event in the parachain
1
		assert!(parachain::para_events().iter().any(|e| matches!(
2
			e,
			parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified {
				result: 2,
				..
			})
		)));
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();
	// Para A should have received the version change
1
	ParaA::execute_with(|| {
		// 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_is_possible_for_non_existent_account() {
1
	MockNet::reset();
1
	let fresh_account = PARABOB;
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
	};
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
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
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 123).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
	// parachain should not have received assets
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, fresh_account.into()),
1
			Ok(U256::from(123))
		);
1
	});
1
}
#[test]
1
fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() {
1
	MockNet::reset();
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
	};
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
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
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 123).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
	// parachain should have received assets
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, fresh_account.into()),
1
			Ok(U256::from(123))
		);
1
	});
1
}
#[test]
1
fn evm_account_receiving_assets_should_handle_sufficients_ref_count() {
1
	MockNet::reset();
1
	let mut sufficient_account = [0u8; 20];
1
	sufficient_account[0..20].copy_from_slice(&evm_account()[..]);
1
	let evm_account_id = parachain::AccountId::from(sufficient_account);
	// Evm account is self sufficient
1
	ParaA::execute_with(|| {
1
		assert_eq!(parachain::System::account(evm_account_id).sufficients, 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
	};
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
			1,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
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
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 123).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
	// Evm account sufficient ref count increased by 1.
1
	ParaA::execute_with(|| {
		// TODO: since the suicided logic was introduced the data of the smart contract is not
		// removed, it will have to be updated in a future release when there is the ability to
		// remove contract data
		// assert_eq!(parachain::System::account(evm_account_id).sufficients, 2);
1
	});
1
	ParaA::execute_with(|| {
		// Remove the account from the evm context.
1
		parachain::EVM::remove_account(&evm_account());
		// Evm account sufficient ref count decreased by 1.
		// TODO: since the suicided logic was introduced the data of the smart contract is not
		// removed, it will have to be updated in a future release when there is the ability to
		// remove contract data
		// assert_eq!(parachain::System::account(evm_account_id).sufficients, 1);
1
	});
1
}
#[test]
1
fn empty_account_should_not_be_reset() {
1
	MockNet::reset();
	// Test account has nonce 1 when used for the first time.
1
	let sufficient_account = PARABOB;
1
	let evm_account_id = parachain::AccountId::from(sufficient_account);
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
	};
	// register relay asset in parachain A
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
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,
			100
		));
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
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 123).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	ParaA::execute_with(|| {
		// Empty the assets from the account.
		// As this makes the account go below the `min_balance`, the account is considered dead
		// at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero.
1
		assert_ok!(parachain::EvmForeignAssets::transfer(
1
			source_id,
1
			evm_account_id,
1
			PARAALICE.into(),
1
			U256::from(123)
		));
		// Verify account asset balance is Zero.
1
		assert_eq!(
1
			parachain::EvmForeignAssets::balance(source_id, evm_account_id.into()),
1
			Ok(U256::from(0))
		);
		// 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,
			0,
		));
		// 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());
		// 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
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	let statemint_asset_a_balances = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			PalletInstance(5),
1
			xcm::latest::prelude::GeneralIndex(0u128),
1
		],
	);
1
	let source_location: AssetType = statemint_asset_a_balances
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_id: parachain::AssetId = source_location.clone().into();
1
	let asset_metadata = parachain::AssetMetadata {
1
		name: b"StatemintToken".to_vec(),
1
		symbol: b"StatemintToken".to_vec(),
1
		decimals: 12,
1
	};
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
1
			asset_metadata.decimals,
1
			asset_metadata.symbol.try_into().expect("too long"),
1
			asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(source_location, 0));
1
	});
1
	Statemint::execute_with(|| {
		// Set new prefix
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			0,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			0,
			RELAYALICE,
			300000000000000
		));
		// 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,
			100000000000000
		));
		// Actually send relay asset to parachain
1
		let dest: Location = AccountKey20 {
1
			network: None,
1
			key: PARAALICE,
1
		}
1
		.into();
		// Send asset with previous prefix
1
		let fees_id: VersionedAssetId = AssetId(Location::new(
1
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemintAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				xcm::latest::prelude::GeneralIndex(0),
1
			],
1
		))
1
		.into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).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
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(123))
		);
1
	});
1
}
#[test]
1
fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = Location::parent();
1
	let relay_location_v3 =
1
		match xcm::VersionedLocation::V5(relay_location.clone()).into_version(xcm::v3::VERSION) {
1
			Ok(xcm::VersionedLocation::V3(loc)) => loc.into(),
			_ => panic!("Failed to convert relay location to v3"),
		};
1
	let relay_asset_type = parachain::AssetType::Xcm(relay_location_v3);
1
	let source_relay_id: parachain::AssetId = relay_asset_type.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemint asset
1
	let statemint_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemint_location_asset: AssetType = statemint_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
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
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		assert_ok!(add_supported_asset(relay_asset_type.clone(), 0));
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_statemint_asset_id,
1
			statemint_asset.clone(),
1
			asset_metadata_statemint_asset.decimals,
1
			asset_metadata_statemint_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemint_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		assert_ok!(add_supported_asset(statemint_location_asset, 0));
1
	});
1
	let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
	// Send relay chain asset to Alice in Parachain A
1
	Relay::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_from_relay.clone(),
1
		}]);
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			Box::new(Parachain(1).into()),
1
			Box::new(([], 200).into()),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::LocalReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Unlimited
		));
1
	});
1
	Statemint::execute_with(|| {
		// Set new prefix
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			300000000000000
		));
		// 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,
			100000000000000
		));
		// 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();
		// Send with new prefix
1
		let fees_id: VersionedAssetId = AssetId(Location::new(
1
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemintAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
1
		))
1
		.into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_from_statemint.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
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
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
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
	ParaA::execute_with(|| {
		// Alice has received 125 USDC
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_statemint_asset_id, PARAALICE.into()),
1
			Ok(U256::from(125))
		);
		// Alice has received 200 Relay assets
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Check that BOB's balance is empty before the transfer
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]);
1
	});
1
	let (chain_part, beneficiary) =
1
		split_location_into_chain_part_and_beneficiary(statemint_beneficiary).unwrap();
	// 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),
			100,
		);
1
		let asset_fee =
1
			currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset_fee, asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
		));
1
	});
1
	ParaA::execute_with(|| {
		// Alice has 100 USDC less
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_statemint_asset_id, PARAALICE.into()),
1
			Ok(U256::from(25))
		);
		// Alice has 100 relay asset less
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
1
	Statemint::execute_with(|| {
		// 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();
	// Relay asset
1
	let relay_location_v3 = xcm::v3::Location::parent();
1
	let relay_location = parachain::AssetType::Xcm(relay_location_v3.clone());
1
	let relay_location_v5 = Location::parent();
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location_v5.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(relay_location_v5.clone(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
	// 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::from(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 200).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received the DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
	let dest = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
	);
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
	// 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 fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 100).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received 100 DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_with_fee() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location_v3 = xcm::v3::Location::parent();
1
	let relay_location = parachain::AssetType::Xcm(relay_location_v3.clone());
1
	let relay_location_v5 = Location::parent();
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location_v5.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
	// 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::from(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 200).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received the DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
	let dest = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
	);
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
	// 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
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset_fee, asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(90))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Free execution: check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 110
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 100).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 10
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received 100 DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(190))
		);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiasset() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location_v3 = xcm::v3::Location::parent();
1
	let relay_location = parachain::AssetType::Xcm(relay_location_v3.clone());
1
	let relay_location_v5 = Location::parent();
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
1
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location_v5.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
	// 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::from(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 200).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received the DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
	let dest = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
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
	};
	// Finally we test that we are able to send back the DOTs to AssetHub from the ParaA
1
	ParaA::execute_with(|| {
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary,
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(asset)),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE))
		));
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemint::execute_with(|| {
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 100).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received 100 DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multicurrencies() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location_v3 = xcm::v3::Location::parent();
1
	let relay_location = parachain::AssetType::Xcm(relay_location_v3.clone());
1
	let relay_location_v5 = Location::parent();
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemint asset
1
	let statemint_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemint_location_asset: AssetType = statemint_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
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
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location_v5.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_statemint_asset_id,
1
			statemint_asset.clone(),
1
			asset_metadata_statemint_asset.decimals,
1
			asset_metadata_statemint_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemint_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(statemint_asset, 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
	// 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::from(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs and USDC from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			300000000000000
		));
		// Now send relay tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 200).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// Send USDC
1
		let fees_id: VersionedAssetId = AssetId(Location::new(
1
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemintAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
1
		))
1
		.into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
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
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received the DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
		// Alice has received 125 USDC
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_statemint_asset_id, PARAALICE.into()),
1
			Ok(U256::from(125))
		);
1
	});
1
	let dest = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
	);
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
	// 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),
			100,
		);
1
		let asset_fee =
1
			currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: beneficiary.clone(),
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(vec![asset_fee, asset])),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
		));
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Check that Bob received relay tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]);
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);
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 100).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			bob_previous_balance - 100
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received 100 DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiassets() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location_v3 = xcm::v3::Location::parent();
1
	let relay_location = parachain::AssetType::Xcm(relay_location_v3.clone());
1
	let relay_location_v5 = Location::parent();
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemint asset
1
	let statemint_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemint_location_asset: AssetType = statemint_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into();
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
	let dest_para = Location::new(1, [Parachain(1)]);
1
	let sov = xcm_builder::SiblingParachainConvertsVia::<
1
		polkadot_parachain::primitives::Sibling,
1
		statemint_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_relay_id,
1
			relay_location_v5.clone(),
1
			relay_asset_metadata.decimals,
1
			relay_asset_metadata.symbol.try_into().expect("too long"),
1
			relay_asset_metadata.name.try_into().expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(Location::parent(), 0u128);
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_statemint_asset_id,
1
			statemint_asset.clone(),
1
			asset_metadata_statemint_asset.decimals,
1
			asset_metadata_statemint_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemint_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(statemint_asset.clone(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemint_beneficiary_absolute: Location = Junction::AccountId32 {
1
		network: None,
1
		id: RELAYALICE.into(),
1
	}
1
	.into();
	// 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::from(statemint_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs and USDC from AssetHub to ParaA (Moonbeam)
1
	Statemint::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemintBalances::transfer_allow_death(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
1
		statemint_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemintAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemintAssets::create(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemintAssets::mint(
1
			statemint_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			300000000000000
		));
		// Now send relay tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 200).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// Send USDC
1
		let fees_id: VersionedAssetId = AssetId(Location::new(
1
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemintAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
1
		))
1
		.into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
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
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received the DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
		// Alice has received 125 USDC
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_statemint_asset_id, PARAALICE.into()),
1
			Ok(U256::from(125))
		);
1
	});
1
	let dest = Location::new(
		1,
1
		[
1
			Parachain(1000),
1
			AccountId32 {
1
				network: None,
1
				id: RELAYBOB.into(),
1
			},
1
		],
	);
1
	let statemint_asset_to_send = Asset {
1
		id: AssetId(statemint_asset),
1
		fun: Fungibility::Fungible(100),
1
	};
1
	let relay_asset_to_send = Asset {
1
		id: AssetId(Location::parent()),
1
		fun: Fungibility::Fungible(100),
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()]);
	// For some reason the order of the assets is inverted when creating the array above.
	// 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
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary,
1
		}]);
1
		assert_ok!(PolkadotXcm::transfer_assets_using_type_and_then(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(VersionedLocation::from(chain_part)),
1
			Box::new(VersionedAssets::from(assets_to_send)),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(fees_id),
1
			Box::new(TransferType::DestinationReserve),
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
1
			WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64))
		));
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(100))
		);
1
	});
1
	Statemint::execute_with(|| {
		// Check that Bob received relay tokens back in AssetHub
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]);
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);
		// Now send those tokens to ParaA
1
		let fees_id: VersionedAssetId = AssetId(Location::parent()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemintChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemint_like::RuntimeOrigin::signed(RELAYBOB),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((Location::parent(), 100).into()),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(fees_id),
1
				Box::new(TransferType::LocalReserve),
1
				Box::new(VersionedXcm::V5(xcm_on_dest)),
1
				WeightLimit::Unlimited
			)
		);
		// 100 DOTs were deducted from Bob's account
1
		assert_eq!(
1
			StatemintBalances::free_balance(RELAYBOB),
1
			bob_previous_balance - 100
		);
1
	});
1
	ParaA::execute_with(|| {
		// Alice should have received 100 DOTs
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_relay_id, PARAALICE.into()),
1
			Ok(U256::from(200))
		);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
1
			Box::new(xcm::VersionedLocation::from(Location::parent())),
			// Relay charges 1000 for every instruction, and we have 3, so 3000
1
			3000.into(),
1
			20000000000.into(),
			// 4 instructions in transact through signed
1
			Some(4000.into())
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(Location::parent(), WEIGHT_REF_TIME_PER_SECOND as u128)
1
			.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1
	Relay::execute_with(|| {
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
			4000004100u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::from(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
			// 4000000000 for transfer + 4000 for XCM
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
			false
		));
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
	ParaA::execute_with(|| {
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1
	Relay::execute_with(|| {
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
			4000004100u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	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::from(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			encoded,
			// 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
			},
			false
		));
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
	ParaA::execute_with(|| {
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::Account32Hash::<
1
		relay_chain::KusamaNetwork,
1
		relay_chain::AccountId,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1
	Relay::execute_with(|| {
		// free execution, full amount received
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			derived.clone(),
			4000009100u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	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::from(Location::parent())),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				fee_amount: Some(total_weight as u128)
1
			},
1
			encoded,
			// 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
			},
			true
		));
1
	});
1
	Relay::execute_with(|| {
		// 100 transferred
1
		assert_eq!(RelayBalances::free_balance(&para_a_account()), 100);
		// 4000009000 refunded
1
		assert_eq!(RelayBalances::free_balance(&derived), 4000009000);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para() {
1
	frame_support::__private::sp_tracing::init_for_tests();
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1
	let para_b_location = Location::new(1, [Parachain(2)]);
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
			// ParaB
1
			Box::new(xcm::VersionedLocation::from(para_b_location.clone())),
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
			// 4 instructions in transact through signed
1
			Some(4.into())
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(
1
			para_b_balances.clone(),
1
			parachain::ParaTokensPerSecond::get(),
		)
1
		.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1
	ParaB::execute_with(|| {
		// free execution, full amount received
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
			4000000104u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::from(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
			// 4000000000 for transfer + 4000 for XCM
			// 1-1 to fee
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
			false
		));
1
	});
1
	ParaB::execute_with(|| {
1
		assert_eq!(ParaBalances::free_balance(&derived), 0);
1
		assert_eq!(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
	let para_b_location = Location::new(1, [Parachain(2)]);
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1
	ParaA::execute_with(|| {
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(
1
			para_b_balances.clone(),
1
			parachain::ParaTokensPerSecond::get(),
		)
1
		.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
1
	ParaB::execute_with(|| {
		// free execution, full amount received
1
		assert_ok!(ParaBalances::transfer_allow_death(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			derived.clone(),
			4000009100u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	// 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
	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::from(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					para_b_balances
1
				))),
1
				fee_amount: Some(overall_weight as u128)
1
			},
1
			encoded,
			// 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
			},
			true
		));
1
	});
1
	ParaB::execute_with(|| {
		// Check the derived account was refunded
1
		assert_eq!(ParaBalances::free_balance(&derived), 3826174993);
		// 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
	let para_b_location = Location::new(1, [Parachain(2)]);
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
			// ParaB
1
			Box::new(xcm::VersionedLocation::from(para_b_location.clone())),
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
			// 4 instructions in transact through signed
1
			Some(4.into())
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(
1
			para_b_balances.clone(),
1
			parachain::ParaTokensPerSecond::get(),
		)
1
		.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
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(),
			4000000104u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	use sp_core::U256;
	// 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
		});
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::from(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					para_b_balances
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
			// 4000000000 for transfer + 4000 for XCM
			// 1-1 to fee
1
			TransactWeights {
1
				transact_required_weight_at_most: 4000000000.into(),
1
				overall_weight: None
1
			},
			false
		));
1
	});
1
	ParaB::execute_with(|| {
		// Make sure the EVM transfer went through
1
		assert!(
1
			ParaBalances::free_balance(&PARAALICE.into())
1
				== parachain_b_alice_balances_before + 100
		);
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
	let para_b_location = Location::new(1, [Parachain(2)]);
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
			// ParaB
1
			Box::new(xcm::VersionedLocation::from(para_b_location.clone())),
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
			// 4 instructions in transact through signed
1
			Some(4.into())
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(
1
			para_b_balances.clone(),
1
			parachain::ParaTokensPerSecond::get(),
		)
1
		.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
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(),
			4000000104u128,
		));
		// 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
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	use sp_core::U256;
	// 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
		});
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::from(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			false
		));
1
	});
1
	ParaB::execute_with(|| {
		// 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
	let para_b_location = Location::new(1, [Parachain(2)]);
1
	let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]);
1
	ParaA::execute_with(|| {
		// Root can set transact info
1
		assert_ok!(XcmTransactor::set_transact_info(
1
			parachain::RuntimeOrigin::root(),
			// ParaB
1
			Box::new(xcm::VersionedLocation::from(para_b_location.clone())),
			// Para charges 1000 for every instruction, and we have 3, so 3
1
			3.into(),
1
			20000000000.into(),
			// 4 instructions in transact through signed
1
			Some(4.into())
		));
		// Root can set transact info
		// Set fee per second using weight-trader (replaces old set_fee_per_second)
1
		set_fee_per_second_for_location(
1
			para_b_balances.clone(),
1
			parachain::ParaTokensPerSecond::get(),
		)
1
		.expect("must succeed");
1
		ancestry = parachain::UniversalLocation::get().into();
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
	let mut descend_origin_multilocation = parachain::SelfLocation::get();
1
	descend_origin_multilocation
1
		.append_with(signed_origin)
1
		.unwrap();
	// 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
	let derived = xcm_builder::HashedDescription::<
1
		parachain::AccountId,
1
		xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
	>::convert_location(&descend_origin_multilocation)
1
	.unwrap();
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(),
			4000000104u128,
		));
		// 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());
		// Add proxy ALICE  -> derived
1
		let _ = parachain::Proxy::add_proxy_delegate(
1
			&PARAALICE.into(),
1
			derived,
1
			parachain::ProxyType::Any,
1
			0,
1
		);
1
	});
	// Encode the call. Balances transact to para_a_account
	// 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
	encoded.push(index);
	use sp_core::U256;
	// 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
		});
	// 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
	ParaA::execute_with(|| {
1
		assert_ok!(XcmTransactor::transact_through_signed(
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
1
			Box::new(xcm::VersionedLocation::from(para_b_location)),
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
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
			},
			false
		));
1
	});
1
	ParaB::execute_with(|| {
		// Make sure the EVM transfer was executed
1
		assert!(
1
			ParaBalances::free_balance(&transfer_recipient.into())
1
				== transfer_recipient_balance_before + 100
		);
1
	});
1
}
#[test]
1
fn hrmp_init_accept_through_root() {
1
	MockNet::reset();
1
	Relay::execute_with(|| {
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_a_account(),
			1000u128
		));
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_b_account(),
			1000u128
		));
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;
		// 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::from(
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
	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;
		// 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::from(
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
	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
	Relay::execute_with(|| {
1
		assert_ok!(RelayBalances::transfer_allow_death(
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
1
			para_a_account(),
			1000u128
		));
1
		assert_ok!(Hrmp::force_open_hrmp_channel(
1
			relay_chain::RuntimeOrigin::root(),
1
			1u32.into(),
1
			2u32.into(),
			1u32,
			1u32
		));
1
		assert_ok!(Hrmp::force_process_hrmp_open(
1
			relay_chain::RuntimeOrigin::root(),
			1u32
		));
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::from(
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
	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 crate::xcm_mock::parachain::{EvmForeignAssets, MockTransactors, Treasury, XcmWeightTrader};
use parity_scale_codec::{Decode, Encode};
use sp_core::U256;
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
}