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
//! Moonriver Runtime Xcm Tests
18

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

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

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

            
92
	// Configure fees for XcmTransactor via the in-memory fee trader only, so that
93
	// the initial funding XCM transfers stay free and only transactor calls pay fees.
94
9
	let precision_factor = 10u128.pow(moonbeam_tests_primitives::RELATIVE_PRICE_DECIMALS);
95
9
	let native_amount_per_second =
96
9
		frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128;
97
9
	let relative_price = native_amount_per_second
98
9
		.saturating_mul(precision_factor)
99
9
		.checked_div(fee_per_second)
100
9
		.ok_or(())?;
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
249
	// We now send back some money to the relay
250
1
	let dest_chain = Location::parent();
251
1
	let beneficiary = Location {
252
1
		parents: 0,
253
1
		interior: [AccountId32 {
254
1
			network: None,
255
1
			id: RELAYALICE.into(),
256
1
		}]
257
1
		.into(),
258
1
	};
259

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

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

            
287
	// Balances in the relay should have been received
288
1
	Relay::execute_with(|| {
289
1
		assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending);
290
1
	});
291
1
}
292

            
293
#[test]
294
1
fn send_relay_asset_to_para_b() {
295
1
	MockNet::reset();
296

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

            
300
1
	let asset_metadata = parachain::AssetMetadata {
301
1
		name: b"RelayToken".to_vec(),
302
1
		symbol: b"Relay".to_vec(),
303
1
		decimals: 12,
304
1
	};
305

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

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

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

            
362
1
	ParaA::execute_with(|| {
363
1
		assert_eq!(
364
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
365
1
			Ok(U256::from(123))
366
		);
367
1
	});
368

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

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

            
402
	// Para A balances should have been substracted
403
1
	ParaA::execute_with(|| {
404
1
		assert_eq!(
405
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
406
1
			Ok(U256::from(23))
407
		);
408
1
	});
409

            
410
	// Para B balances should have been credited
411
1
	ParaB::execute_with(|| {
412
1
		assert_eq!(
413
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
414
1
			Ok(U256::from(100))
415
		);
416
1
	});
417
1
}
418

            
419
#[test]
420
1
fn send_para_a_asset_to_para_b() {
421
1
	MockNet::reset();
422

            
423
	// This represents the asset in paraA
424
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
425
1
	let source_location: AssetType = para_a_balances
426
1
		.try_into()
427
1
		.expect("Location convertion to AssetType should succeed");
428
1
	let source_id: parachain::AssetId = source_location.clone().into();
429

            
430
1
	let asset_metadata = parachain::AssetMetadata {
431
1
		name: b"ParaAToken".to_vec(),
432
1
		symbol: b"ParaA".to_vec(),
433
1
		decimals: 18,
434
1
	};
435

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

            
452
	// Send para A asset from para A to para B
453
1
	let dest = Location {
454
1
		parents: 1,
455
1
		interior: [
456
1
			Parachain(2),
457
1
			AccountKey20 {
458
1
				network: None,
459
1
				key: PARAALICE.into(),
460
1
			},
461
1
		]
462
1
		.into(),
463
1
	};
464
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
465

            
466
1
	ParaA::execute_with(|| {
467
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
468
1
		assert_ok!(PolkadotXcm::transfer_assets(
469
1
			parachain::RuntimeOrigin::signed(PARAALICE.into()),
470
1
			Box::new(VersionedLocation::from(chain_part)),
471
1
			Box::new(VersionedLocation::from(beneficiary)),
472
1
			Box::new(VersionedAssets::from(vec![asset])),
473
			0,
474
1
			WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE))
475
		));
476
1
	});
477

            
478
	// Native token is substracted in paraA
479
1
	ParaA::execute_with(|| {
480
		// free execution, full amount received
481
1
		assert_eq!(
482
1
			ParaBalances::free_balance(&PARAALICE.into()),
483
			INITIAL_BALANCE - 100
484
		);
485
1
	});
486

            
487
	// Asset is minted in paraB
488
1
	ParaB::execute_with(|| {
489
		// free execution, full amount received
490
1
		assert_eq!(
491
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
492
1
			Ok(U256::from(100))
493
		);
494
1
	});
495
1
}
496

            
497
#[test]
498
1
fn send_para_a_asset_from_para_b_to_para_c() {
499
1
	MockNet::reset();
500

            
501
	// Represents para A asset
502
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
503
1
	let source_location: AssetType = para_a_balances
504
1
		.try_into()
505
1
		.expect("Location convertion to AssetType should succeed");
506
1
	let source_id: parachain::AssetId = source_location.clone().into();
507

            
508
1
	let asset_metadata = parachain::AssetMetadata {
509
1
		name: b"ParaAToken".to_vec(),
510
1
		symbol: b"ParaA".to_vec(),
511
1
		decimals: 18,
512
1
	};
513

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

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

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

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

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

            
580
	// Para B balances have been credited
581
1
	ParaB::execute_with(|| {
582
1
		assert_eq!(
583
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
584
1
			Ok(U256::from(100))
585
		);
586
1
	});
587

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

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

            
614
	// The message passed through parachainA so we needed to pay since its the native token
615
1
	ParaC::execute_with(|| {
616
		// free execution, full amount received
617
1
		assert_eq!(
618
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
619
1
			Ok(U256::from(95))
620
		);
621
1
	});
622
1
}
623

            
624
#[test]
625
1
fn send_para_a_asset_to_para_b_and_back_to_para_a() {
626
1
	MockNet::reset();
627

            
628
	// Para A asset
629
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
630
1
	let source_location: AssetType = para_a_balances
631
1
		.try_into()
632
1
		.expect("Location convertion to AssetType should succeed");
633
1
	let source_id: parachain::AssetId = source_location.clone().into();
634

            
635
1
	let asset_metadata = parachain::AssetMetadata {
636
1
		name: b"ParaAToken".to_vec(),
637
1
		symbol: b"ParaA".to_vec(),
638
1
		decimals: 18,
639
1
	};
640

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

            
657
	// Send para A asset to para B
658
1
	let dest = Location {
659
1
		parents: 1,
660
1
		interior: [
661
1
			Parachain(2),
662
1
			AccountKey20 {
663
1
				network: None,
664
1
				key: PARAALICE.into(),
665
1
			},
666
1
		]
667
1
		.into(),
668
1
	};
669
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
670

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

            
683
	// Balances have been subtracted
684
1
	ParaA::execute_with(|| {
685
1
		assert_eq!(
686
1
			ParaBalances::free_balance(&PARAALICE.into()),
687
			INITIAL_BALANCE - 100
688
		);
689
1
	});
690

            
691
	// Para B balances have been credited
692
1
	ParaB::execute_with(|| {
693
1
		assert_eq!(
694
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
695
1
			Ok(U256::from(100))
696
		);
697
1
	});
698

            
699
	// Send back para A asset to para A
700
1
	let dest = Location {
701
1
		parents: 1,
702
1
		interior: [
703
1
			Parachain(1),
704
1
			AccountKey20 {
705
1
				network: None,
706
1
				key: PARAALICE.into(),
707
1
			},
708
1
		]
709
1
		.into(),
710
1
	};
711
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
712

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

            
725
	// Para A asset has been credited
726
1
	ParaA::execute_with(|| {
727
		// Weight used is 4
728
1
		assert_eq!(
729
1
			ParaBalances::free_balance(&PARAALICE.into()),
730
			INITIAL_BALANCE - 4
731
		);
732
1
	});
733
1
}
734

            
735
#[test]
736
1
fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() {
737
1
	MockNet::reset();
738

            
739
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
740
1
	let source_location: AssetType = para_a_balances
741
1
		.try_into()
742
1
		.expect("Location conversion to AssetType should succeed");
743
1
	let source_id: parachain::AssetId = source_location.clone().into();
744

            
745
1
	let asset_metadata = parachain::AssetMetadata {
746
1
		name: b"ParaAToken".to_vec(),
747
1
		symbol: b"ParaA".to_vec(),
748
1
		decimals: 18,
749
1
	};
750

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

            
766
1
	let dest = Location {
767
1
		parents: 1,
768
1
		interior: [
769
1
			Parachain(2),
770
1
			AccountKey20 {
771
1
				network: None,
772
1
				key: PARAALICE.into(),
773
1
			},
774
1
		]
775
1
		.into(),
776
1
	};
777
1
	let (chain_part, beneficiary) = split_location_into_chain_part_and_beneficiary(dest).unwrap();
778

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

            
791
1
	ParaA::execute_with(|| {
792
		// Free execution, full amount received
793
1
		assert_eq!(
794
1
			ParaBalances::free_balance(&PARAALICE.into()),
795
			INITIAL_BALANCE - 100
796
		);
797
1
	});
798

            
799
1
	ParaB::execute_with(|| {
800
		// Free execution, full amount received
801
1
		assert_eq!(
802
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
803
1
			Ok(U256::from(100))
804
		);
805
1
	});
806

            
807
	// This time we will force the new reanchoring by manually sending the
808
	// Message through polkadotXCM pallet
809

            
810
1
	let dest = Location {
811
1
		parents: 1,
812
1
		interior: [Parachain(1)].into(),
813
1
	};
814

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

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

            
845
1
	ParaB::execute_with(|| {
846
		// free execution, full amount received
847
1
		assert_eq!(
848
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
849
1
			Ok(U256::from(100))
850
		);
851
1
	});
852

            
853
	// This time we will force the new reanchoring by manually sending the
854
	// Message through polkadotXCM pallet
855

            
856
1
	let dest = Location {
857
1
		parents: 1,
858
1
		interior: [Parachain(1)].into(),
859
1
	};
860

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

            
863
1
	let message = xcm::VersionedXcm::<()>::V5(Xcm(vec![
864
1
		WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()),
865
1
		ClearOrigin,
866
1
		BuyExecution {
867
1
			fees: (reanchored_para_a_balances, 100).into(),
868
1
			weight_limit: Limited(80.into()),
869
1
		},
870
1
		DepositAsset {
871
1
			assets: All.into(),
872
1
			beneficiary: Location::new(
873
1
				0,
874
1
				[AccountKey20 {
875
1
					network: None,
876
1
					key: PARAALICE,
877
1
				}],
878
1
			),
879
1
		},
880
1
	]));
881
1
	ParaB::execute_with(|| {
882
		// Send a message to the sovereign account in ParaA to withdraw
883
		// and deposit asset
884
1
		assert_ok!(ParachainPalletXcm::send(
885
1
			parachain::RuntimeOrigin::root(),
886
1
			Box::new(dest.into()),
887
1
			Box::new(message),
888
		));
889
1
	});
890

            
891
1
	ParaA::execute_with(|| {
892
		// Weight used is 4
893
1
		assert_eq!(
894
1
			ParaBalances::free_balance(&PARAALICE.into()),
895
			INITIAL_BALANCE - 4
896
		);
897
1
	});
898
1
}
899

            
900
#[test]
901
1
fn receive_relay_asset_with_trader() {
902
1
	MockNet::reset();
903

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

            
907
1
	let asset_metadata = parachain::AssetMetadata {
908
1
		name: b"RelayToken".to_vec(),
909
1
		symbol: b"Relay".to_vec(),
910
1
		decimals: 12,
911
1
	};
912

            
913
	// This time we are gonna put a rather high number of units per second
914
	// we know later we will divide by 1e12
915
	// Lets put 1e6 as units per second
916
1
	ParaA::execute_with(|| {
917
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
918
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
919
1
			.try_into()
920
1
			.expect("v3 to latest location conversion failed");
921
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
922
1
			source_id,
923
1
			source_location_latest,
924
1
			asset_metadata.decimals,
925
1
			asset_metadata.symbol.try_into().expect("too long"),
926
1
			asset_metadata.name.try_into().expect("too long"),
927
		));
928
1
		assert_ok!(add_supported_asset(
929
1
			source_location.clone(),
930
			2500000000000u128
931
		));
932
1
	});
933

            
934
1
	let dest: Location = Junction::AccountKey20 {
935
1
		network: None,
936
1
		key: PARAALICE,
937
1
	}
938
1
	.into();
939
	// We are sending 100 tokens from relay.
940
	// Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second)
941
	// weight is 4 since we are executing 4 instructions with a unitweightcost of 1.
942
	// Units per second should be 2_500_000_000_000_000
943
	// Therefore with no refund, we should receive 10 tokens less
944
	// Native trader fails for this, and we use the asset trader
945
1
	Relay::execute_with(|| {
946
1
		let fees_id: VersionedAssetId = AssetId(Location::here()).into();
947
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
948
1
			assets: Wild(All),
949
1
			beneficiary: dest.clone(),
950
1
		}]);
951
1
		assert_ok!(RelayChainPalletXcm::transfer_assets_using_type_and_then(
952
1
			relay_chain::RuntimeOrigin::signed(RELAYALICE),
953
1
			Box::new(Parachain(1).into()),
954
1
			Box::new(([] /* Here */, 100).into()),
955
1
			Box::new(TransferType::LocalReserve),
956
1
			Box::new(fees_id),
957
1
			Box::new(TransferType::LocalReserve),
958
1
			Box::new(VersionedXcm::V5(xcm_on_dest)),
959
1
			WeightLimit::Unlimited
960
		));
961
1
	});
962

            
963
1
	ParaA::execute_with(|| {
964
		// non-free execution, not full amount received
965
1
		assert_eq!(
966
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
967
1
			Ok(U256::from(90))
968
		);
969
		// Fee should have been received by treasury
970
1
		assert_eq!(
971
1
			EvmForeignAssets::balance(source_id, Treasury::account_id()),
972
1
			Ok(U256::from(10))
973
		);
974
1
	});
975
1
}
976

            
977
#[test]
978
1
fn send_para_a_asset_to_para_b_with_trader() {
979
1
	MockNet::reset();
980

            
981
1
	let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]);
982
1
	let source_location: AssetType = para_a_balances
983
1
		.try_into()
984
1
		.expect("Location convertion to AssetType should succeed");
985
1
	let source_id: parachain::AssetId = source_location.clone().into();
986

            
987
1
	let asset_metadata = parachain::AssetMetadata {
988
1
		name: b"ParaAToken".to_vec(),
989
1
		symbol: b"ParaA".to_vec(),
990
1
		decimals: 18,
991
1
	};
992

            
993
1
	ParaB::execute_with(|| {
994
1
		let parachain::AssetType::Xcm(source_location_v3) = source_location.clone();
995
1
		let source_location_latest: Location = xcm::VersionedLocation::V3(source_location_v3)
996
1
			.try_into()
997
1
			.expect("v3 to latest location conversion failed");
998
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
999
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(
1
			source_location.clone(),
			2500000000000u128
		));
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();
	// In destination chain, we only need 4 weight
	// We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury
1
	ParaA::execute_with(|| {
1
		let asset = currency_to_asset(parachain::CurrencyId::SelfReserve, 100);
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(10u64, DEFAULT_PROOF_SIZE))
		));
1
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			ParaBalances::free_balance(&PARAALICE.into()),
			INITIAL_BALANCE - 100
		);
1
	});
	// We are sending 100 tokens from para A.
	// 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.clone(), 12500000u128));
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 trully 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(
1
			source_location.clone(),
			2500000000000u128
		));
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(([] /* Here */, 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.clone(), 1u128));
		// 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
		));
		// 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(([] /* Here */, 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(4000003100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u64))
		);
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
			moonriver_runtime::xcm_config::Transactors::Relay,
			0,
1
			CurrencyPayment {
1
				currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
1
					Location::parent()
1
				))),
1
				fee_amount: None
1
			},
1
			encoded,
			// 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller
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_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.clone(), 1u128));
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(([] /* Here */, 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(4000003100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u64))
		);
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
			moonriver_runtime::xcm_config::Transactors::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.clone(), 1u128));
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(([] /* Here */, 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(4000009100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009000u64))
		);
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
			moonriver_runtime::xcm_config::Transactors::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,x	 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.clone(), 1u128));
		// 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
		));
		// 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(([] /* Here */, 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(4000003100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u64))
		);
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: /* Here */ [].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
			moonriver_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
		));
		// 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
			moonriver_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.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.clone(), 1u128));
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(([] /* Here */, 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(4000003100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000003000u64))
		);
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: /* Here */ [].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
			moonriver_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.clone(), 1u128));
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(([] /* Here */, 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(4000009100u64))
		);
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);
		// free execution, full amount received
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
	});
1
	ParaA::execute_with(|| {
		// free execution, full amount received
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(4000009000u64))
		);
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: /* Here */ [].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
			moonriver_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 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 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(
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.clone(), 0u128));
1
	});
1
	let response = Response::Version(2);
1
	let querier: Location = ([]/* Here */).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(([] /* Here */, 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 = [] /* Here */
1
		.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.clone(), 0u128));
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
	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.clone(), 0u128));
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(([] /* Here */, 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 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.clone(), 0u128));
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(([] /* Here */, 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 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.clone(), 0u128));
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(([] /* Here */, 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 an smart contract account
		// is not deleted completely until it's data is deleted. Data deletion
		// will be implemented in a future release
		// 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 an smart contract account
		// is not deleted completely until it's data is deleted. Data deletion
		// will be implemented in a future release
		// 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 on genesis.
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.clone(), 0u128));
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(([] /* Here */, 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.
		// Transfer the assets from evm_account to PARAALICE
1
		assert_ok!(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_statemine_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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	let statemine_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 = statemine_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"StatemineToken".to_vec(),
1
		symbol: b"StatemineToken".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.clone(), 0u128));
1
	});
1
	Statemine::execute_with(|| {
		// Set new prefix
1
		statemine_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemineAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemineAssets::create(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			0,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemineAssets::mint(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			0,
			RELAYALICE,
			300000000000000
		));
		// This is needed, since the asset is created as non-sufficient
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_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 with new prefix
1
		let asset_location = Location::new(
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemineAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				xcm::latest::prelude::GeneralIndex(0),
1
			],
		);
1
		let fees_id: VersionedAssetId = AssetId(asset_location.clone()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: dest.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((asset_location, 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(|| {
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_id, PARAALICE.into()),
1
			Ok(U256::from(123))
		);
1
	});
1
}
#[test]
1
fn send_statemine_asset_from_para_a_to_statemine_with_relay_fee() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemine asset
1
	let statemine_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemine_location_asset: AssetType = statemine_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into();
1
	let asset_metadata_statemine_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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(relay_location_v3) = relay_location.clone();
1
		let relay_location_latest: Location = xcm::VersionedLocation::V3(relay_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		let relay_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			relay_id,
1
			relay_location_latest,
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_location.clone(), 0u128));
1
		let parachain::AssetType::Xcm(statemine_location_v3) = statemine_location_asset.clone();
1
		let statemine_location_latest: Location = xcm::VersionedLocation::V3(statemine_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		let statemine_id: parachain::AssetId = statemine_location_asset.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			statemine_id,
1
			statemine_location_latest,
1
			asset_metadata_statemine_asset.decimals,
1
			asset_metadata_statemine_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemine_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		assert_ok!(add_supported_asset(statemine_location_asset.clone(), 0u128));
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(([] /* Here */, 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
	Statemine::execute_with(|| {
		// Set new prefix
1
		statemine_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemineAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemineAssets::create(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemineAssets::mint(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			300000000000000
		));
		// Send some native statemine tokens to sovereign for fees.
		// We can't pay fees with USDC as the asset is minted as non-sufficient.
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			100000000000000
		));
		// Send statemine USDC asset to Alice in Parachain A
1
		let parachain_beneficiary_from_statemine: Location = AccountKey20 {
1
			network: None,
1
			key: PARAALICE,
1
		}
1
		.into();
		// Send with new prefix
1
		let asset_location = Location::new(
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemineAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
		);
1
		let fees_id: VersionedAssetId = AssetId(asset_location.clone()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_from_statemine.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((asset_location, 125).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 statemine_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_statemine_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
	Statemine::execute_with(|| {
		// Check that BOB's balance is empty before the transfer
1
		assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![]);
1
	});
1
	let (chain_part, beneficiary) =
1
		split_location_into_chain_part_and_beneficiary(statemine_beneficiary).unwrap();
	// Transfer USDC from Parachain A to Statemine using Relay asset as fee
1
	ParaA::execute_with(|| {
1
		let asset_1 = currency_to_asset(
1
			parachain::CurrencyId::ForeignAsset(source_statemine_asset_id),
			100,
		);
1
		let asset_2 = currency_to_asset(parachain::CurrencyId::ForeignAsset(source_relay_id), 100);
1
		let fees_id: VersionedAssetId = asset_2.id.clone().into();
1
		let assets_to_send = vec![asset_1, asset_2];
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(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
	});
1
	ParaA::execute_with(|| {
		// Alice has 100 USDC less
1
		assert_eq!(
1
			EvmForeignAssets::balance(source_statemine_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
	Statemine::execute_with(|| {
		// Check that BOB received 100 USDC on statemine
1
		assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
1
}
#[test]
1
fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = relay_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
		let source_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
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 statemine_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(statemine_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemine::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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
	Statemine::execute_with(|| {
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemine::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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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!(StatemineBalances::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_statemine_via_xtokens_transfer_with_fee() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = relay_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
		let source_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
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 statemine_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(statemine_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemine::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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
	Statemine::execute_with(|| {
		// Free execution: check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 110
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemine::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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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
			StatemineBalances::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_statemine_via_xtokens_transfer_multiasset() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = relay_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
		let source_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
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 statemine_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(statemine_beneficiary_absolute)
1
					.clone()
1
					.into()
			),
1
			Box::new(([], 200).into()),
			0,
1
			WeightLimit::Unlimited
		));
1
	});
	// Send DOTs from AssetHub to ParaA (Moonbeam)
1
	Statemine::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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 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(
1
				vec![(Location::parent(), 100).into()]
			)),
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
	Statemine::execute_with(|| {
		// Check that Bob received the tokens back in AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemine::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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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!(StatemineBalances::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_statemine_via_xtokens_transfer_multicurrencies() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemine asset
1
	let statemine_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemine_location_asset: AssetType = statemine_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into();
1
	let asset_metadata_statemine_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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = relay_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
		let source_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
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
		let parachain::AssetType::Xcm(statemine_location_v3) = statemine_location_asset.clone();
1
		let statemine_location_latest: Location = xcm::VersionedLocation::V3(statemine_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		let statemine_id: parachain::AssetId = statemine_location_asset.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			statemine_id,
1
			statemine_location_latest,
1
			asset_metadata_statemine_asset.decimals,
1
			asset_metadata_statemine_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemine_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(statemine_asset.clone(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemine_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(statemine_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
	Statemine::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
1
		statemine_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemineAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemineAssets::create(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemineAssets::mint(
1
			statemine_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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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 asset_location = Location::new(
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemineAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
		);
1
		let fees_id: VersionedAssetId = AssetId(asset_location.clone()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((asset_location, 125).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_statemine_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_1 = currency_to_asset(
1
			parachain::CurrencyId::ForeignAsset(source_statemine_asset_id),
			100,
		);
1
		let asset_2 = 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, asset_2])),
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
	Statemine::execute_with(|| {
		// Check that Bob received relay tokens back in AssetHub
		// (100 - MinXcmFee)
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemine::execute_with(|| {
1
		let bob_previous_balance = StatemineBalances::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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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
			StatemineBalances::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_statemine_via_xtokens_transfer_multiassets() {
1
	MockNet::reset();
	// Relay asset
1
	let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent());
1
	let source_relay_id: parachain::AssetId = relay_location.clone().into();
1
	let relay_asset_metadata = parachain::AssetMetadata {
1
		name: b"RelayToken".to_vec(),
1
		symbol: b"Relay".to_vec(),
1
		decimals: 12,
1
	};
	// Statemine asset
1
	let statemine_asset = Location::new(
		1,
1
		[
1
			Parachain(1000u32),
1
			PalletInstance(5u8),
1
			GeneralIndex(10u128),
1
		],
	);
1
	let statemine_location_asset: AssetType = statemine_asset
1
		.clone()
1
		.try_into()
1
		.expect("Location convertion to AssetType should succeed");
1
	let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into();
1
	let asset_metadata_statemine_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
		statemine_like::AccountId,
1
	>::convert_location(&dest_para)
1
	.unwrap();
1
	ParaA::execute_with(|| {
1
		let parachain::AssetType::Xcm(source_location_v3) = relay_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
		let source_id: parachain::AssetId = relay_location.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			source_id,
1
			source_location_latest,
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
		let parachain::AssetType::Xcm(statemine_location_v3) = statemine_location_asset.clone();
1
		let statemine_location_latest: Location = xcm::VersionedLocation::V3(statemine_location_v3)
1
			.try_into()
1
			.expect("v3 to latest location conversion failed");
1
		let statemine_id: parachain::AssetId = statemine_location_asset.clone().into();
1
		assert_ok!(EvmForeignAssets::register_foreign_asset(
1
			statemine_id,
1
			statemine_location_latest,
1
			asset_metadata_statemine_asset.decimals,
1
			asset_metadata_statemine_asset
1
				.symbol
1
				.try_into()
1
				.expect("too long"),
1
			asset_metadata_statemine_asset
1
				.name
1
				.try_into()
1
				.expect("too long"),
		));
1
		XcmWeightTrader::set_asset_price(statemine_asset.clone(), 0u128);
1
	});
1
	let parachain_beneficiary_absolute: Location = Junction::AccountKey20 {
1
		network: None,
1
		key: PARAALICE,
1
	}
1
	.into();
1
	let statemine_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(statemine_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
	Statemine::execute_with(|| {
		// Check Alice received 200 tokens on AssetHub
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYALICE),
			INITIAL_BALANCE + 200
		);
1
		assert_ok!(StatemineBalances::transfer_allow_death(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
			sov,
			110000000000000
		));
1
		statemine_like::PrefixChanger::set_prefix(
1
			PalletInstance(<StatemineAssets as PalletInfoAccess>::index() as u8).into(),
		);
1
		assert_ok!(StatemineAssets::create(
1
			statemine_like::RuntimeOrigin::signed(RELAYALICE),
			10,
			RELAYALICE,
			1
		));
1
		assert_ok!(StatemineAssets::mint(
1
			statemine_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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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 asset_location = Location::new(
			0,
1
			[
1
				xcm::latest::prelude::PalletInstance(
1
					<StatemineAssets as PalletInfoAccess>::index() as u8,
1
				),
1
				GeneralIndex(10),
1
			],
		);
1
		let fees_id: VersionedAssetId = AssetId(asset_location.clone()).into();
1
		let xcm_on_dest = Xcm::<()>(vec![DepositAsset {
1
			assets: Wild(All),
1
			beneficiary: parachain_beneficiary_absolute.clone(),
1
		}]);
1
		assert_ok!(
1
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_like::RuntimeOrigin::signed(RELAYALICE),
1
				Box::new(Location::new(1, [Parachain(1)]).into()),
1
				Box::new((asset_location, 125).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_statemine_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 statemine_asset_to_send = Asset {
1
		id: AssetId(statemine_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![statemine_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: 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(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
	Statemine::execute_with(|| {
		// Check that Bob received relay tokens back in AssetHub
		// (100 - MinXcmFee)
1
		assert_eq!(
1
			StatemineBalances::free_balance(RELAYBOB),
			INITIAL_BALANCE + 100
		);
		// Check that BOB received 100 USDC on AssetHub
1
		assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]);
1
	});
	// Send back tokens from AH to ParaA from Bob's account
1
	Statemine::execute_with(|| {
1
		let bob_previous_balance = StatemineBalances::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
			StatemineChainPalletXcm::transfer_assets_using_type_and_then(
1
				statemine_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
			StatemineBalances::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())
		));
		// 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-1 to fee
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
	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_location = parachain::SelfLocation::get();
1
	descend_origin_location.append_with(signed_origin).unwrap();
	// To convert it to what the paraB will see instead of us
1
	descend_origin_location
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_location)
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!(ParaBalances::free_balance(&derived) == 0);
1
		assert!(ParaBalances::free_balance(&para_a_account_20()) == 100);
1
	});
1
}
#[test]
1
fn transact_through_signed_multilocation_para_to_para_refund() {
1
	MockNet::reset();
1
	let mut ancestry = Location::parent();
1
	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_location = parachain::SelfLocation::get();
1
	descend_origin_location.append_with(signed_origin).unwrap();
	// To convert it to what the paraB will see instead of us
1
	descend_origin_location
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_location)
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_location = parachain::SelfLocation::get();
1
	descend_origin_location.append_with(signed_origin).unwrap();
	// To convert it to what the paraB will see instead of us
1
	descend_origin_location
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_location)
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_location = parachain::SelfLocation::get();
1
	descend_origin_location.append_with(signed_origin).unwrap();
	// To convert it to what the paraB will see instead of us
1
	descend_origin_location
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_location)
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_location = parachain::SelfLocation::get();
1
	descend_origin_location.append_with(signed_origin).unwrap();
	// To convert it to what the paraB will see instead of us
1
	descend_origin_location
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_location)
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;
		// Root can send hrmp close
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::XcmWeightTrader;
use parity_scale_codec::{Decode, Encode};
use sp_io::hashing::blake2_256;
// Helper to derive accountIds
7
pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 {
7
	let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256);
7
	sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id")
7
}