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
use crate::mock::{
17
	AssetAddress, ExtBuilder, PCallV1, PCallV2, PCallV3, Precompiles, PrecompilesValue, Runtime,
18
	RuntimeOrigin, TransactorV1, TransactorV2, TransactorV3, XcmTransactor,
19
};
20

            
21
use frame_support::{assert_ok, weights::Weight};
22
use moonbeam_tests_primitives::MemoryFeeTrader;
23
use precompile_utils::{prelude::*, testing::*};
24
use sp_core::H160;
25
use sp_std::boxed::Box;
26
use xcm::latest::Location;
27
use xcm_primitives::XcmFeeTrader;
28

            
29
26
fn precompiles() -> Precompiles<Runtime> {
30
26
	PrecompilesValue::get()
31
26
}
32

            
33
8
fn relative_price_for_fee_per_second(units_per_second: u128) -> u128 {
34
	// Mirror the conversion used by `pallet-xcm-weight-trader` tests:
35
	// relative_price = native_amount_per_second * 10^decimals / units_per_second
36
	//
37
	// For `MemoryFeeTrader`, the "native amount per second" is derived from `Weight::ref_time()`,
38
	// so for one second it is `WEIGHT_REF_TIME_PER_SECOND`.
39
8
	let native_amount_per_second =
40
8
		frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128;
41
8
	let precision_factor = 10u128.pow(moonbeam_tests_primitives::RELATIVE_PRICE_DECIMALS);
42
8
	native_amount_per_second
43
8
		.saturating_mul(precision_factor)
44
8
		.saturating_div(units_per_second)
45
8
}
46

            
47
#[test]
48
1
fn selectors() {
49
1
	assert!(PCallV1::index_to_account_selectors().contains(&0x3fdc4f36));
50
1
	assert!(PCallV1::transact_info_selectors().contains(&0xd07d87c3));
51
1
	assert!(PCallV1::transact_info_with_signed_selectors().contains(&0xb689e20c));
52
1
	assert!(PCallV1::fee_per_second_selectors().contains(&0x906c9990));
53
1
	assert!(PCallV1::transact_through_derivative_multilocation_selectors().contains(&0x94a63c54));
54
1
	assert!(PCallV1::transact_through_derivative_selectors().contains(&0x02ae072d));
55
1
	assert!(PCallV1::transact_through_signed_multilocation_selectors().contains(&0x71d31587));
56
1
	assert!(PCallV1::transact_through_signed_selectors().contains(&0x42ca339d));
57

            
58
1
	assert!(PCallV2::index_to_account_selectors().contains(&0x3fdc4f36));
59
1
	assert!(PCallV2::transact_info_with_signed_selectors().contains(&0xb689e20c));
60
1
	assert!(PCallV2::fee_per_second_selectors().contains(&0x906c9990));
61
1
	assert!(PCallV2::transact_through_derivative_multilocation_selectors().contains(&0xfe430475));
62
1
	assert!(PCallV2::transact_through_derivative_selectors().contains(&0x185de2ae));
63
1
	assert!(PCallV2::transact_through_signed_multilocation_selectors().contains(&0xd7ab340c));
64
1
	assert!(PCallV2::transact_through_signed_selectors().contains(&0xb648f3fe));
65

            
66
1
	assert!(PCallV3::index_to_account_selectors().contains(&0x3fdc4f36));
67
1
	assert!(PCallV3::transact_info_with_signed_selectors().contains(&0xb689e20c));
68
1
	assert!(PCallV3::fee_per_second_selectors().contains(&0x906c9990));
69
1
	assert!(PCallV3::transact_through_derivative_multilocation_selectors().contains(&0xbdacc26b));
70
1
	assert!(PCallV3::transact_through_derivative_selectors().contains(&0xca8c82d8));
71
1
	assert!(PCallV3::transact_through_signed_multilocation_selectors().contains(&0x27b1d492));
72
1
	assert!(PCallV3::transact_through_signed_selectors().contains(&0xb18270cf));
73
1
}
74

            
75
#[test]
76
1
fn modifiers() {
77
1
	ExtBuilder::default().build().execute_with(|| {
78
1
		let mut tester = PrecompilesModifierTester::new(precompiles(), Alice, TransactorV1);
79

            
80
1
		tester.test_view_modifier(PCallV1::index_to_account_selectors());
81
1
		tester.test_view_modifier(PCallV1::transact_info_selectors());
82
1
		tester.test_view_modifier(PCallV1::transact_info_with_signed_selectors());
83
1
		tester.test_view_modifier(PCallV1::fee_per_second_selectors());
84
1
		tester
85
1
			.test_default_modifier(PCallV1::transact_through_derivative_multilocation_selectors());
86
1
		tester.test_default_modifier(PCallV1::transact_through_derivative_selectors());
87
1
		tester.test_default_modifier(PCallV1::transact_through_signed_multilocation_selectors());
88
1
		tester.test_default_modifier(PCallV1::transact_through_signed_selectors());
89

            
90
1
		let mut tester = PrecompilesModifierTester::new(precompiles(), Alice, TransactorV2);
91

            
92
1
		tester.test_view_modifier(PCallV2::index_to_account_selectors());
93
1
		tester.test_view_modifier(PCallV2::transact_info_with_signed_selectors());
94
1
		tester.test_view_modifier(PCallV2::fee_per_second_selectors());
95
1
		tester
96
1
			.test_default_modifier(PCallV2::transact_through_derivative_multilocation_selectors());
97
1
		tester.test_default_modifier(PCallV2::transact_through_derivative_selectors());
98
1
		tester.test_default_modifier(PCallV2::transact_through_signed_multilocation_selectors());
99
1
		tester.test_default_modifier(PCallV2::transact_through_signed_selectors());
100
1
	});
101
1
}
102

            
103
#[test]
104
1
fn selector_less_than_four_bytes() {
105
1
	ExtBuilder::default().build().execute_with(|| {
106
1
		precompiles()
107
1
			.prepare_test(Alice, TransactorV1, vec![1u8, 2u8, 3u8])
108
1
			.execute_reverts(|output| output == b"Tried to read selector out of bounds");
109
1
	});
110
1
}
111

            
112
#[test]
113
1
fn no_selector_exists_but_length_is_right() {
114
1
	ExtBuilder::default().build().execute_with(|| {
115
1
		precompiles()
116
1
			.prepare_test(Alice, TransactorV1, vec![1u8, 2u8, 3u8, 4u8])
117
1
			.execute_reverts(|output| output == b"Unknown selector");
118
1
	});
119
1
}
120

            
121
#[test]
122
1
fn take_index_for_account() {
123
1
	ExtBuilder::default()
124
1
		.with_balances(vec![(Alice.into(), 1000)])
125
1
		.build()
126
1
		.execute_with(|| {
127
1
			let input: Vec<_> = PCallV1::index_to_account { index: 0 }.into();
128

            
129
			// Assert that errors since no index is assigned
130
1
			precompiles()
131
1
				.prepare_test(Alice, TransactorV1, input.clone())
132
1
				.execute_reverts(|output| output == b"No index assigned");
133

            
134
			// register index
135
1
			assert_ok!(XcmTransactor::register(
136
1
				RuntimeOrigin::root(),
137
1
				Alice.into(),
138
				0
139
			));
140

            
141
			// Expected result is zero
142
1
			precompiles()
143
1
				.prepare_test(Alice, TransactorV1, input)
144
1
				.expect_cost(2)
145
1
				.expect_no_logs()
146
1
				.execute_returns(Address(H160::from(Alice)));
147
1
		});
148
1
}
149

            
150
#[test]
151
1
fn take_transact_info() {
152
1
	ExtBuilder::default()
153
1
		.with_balances(vec![(Alice.into(), 1000)])
154
1
		.build()
155
1
		.execute_with(|| {
156
1
			let input: Vec<_> = PCallV1::transact_info {
157
1
				location: Location::parent().into(),
158
1
			}
159
1
			.into();
160

            
161
			// Assert that errors since no index is assigned
162
1
			precompiles()
163
1
				.prepare_test(Alice, TransactorV1, input.clone())
164
1
				.execute_reverts(|output| output == b"Transact Info not set");
165

            
166
			// Root can set transact info
167
1
			assert_ok!(XcmTransactor::set_transact_info(
168
1
				RuntimeOrigin::root(),
169
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
170
1
				Weight::zero(),
171
1
				10000u64.into(),
172
1
				None
173
			));
174

            
175
			// Set fee per second for test setup
176
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
177
1
				Location::parent(),
178
1
				relative_price_for_fee_per_second(1)
179
			));
180

            
181
1
			precompiles()
182
1
				.prepare_test(Alice, TransactorV1, input)
183
1
				.expect_cost(3)
184
1
				.expect_no_logs()
185
1
				.execute_returns((0u64, 1u128, 10000u64));
186
1
		});
187
1
}
188
#[test]
189
1
fn take_transact_info_with_signed() {
190
1
	ExtBuilder::default()
191
1
		.with_balances(vec![(Alice.into(), 1000)])
192
1
		.build()
193
1
		.execute_with(|| {
194
1
			let input: Vec<_> = PCallV1::transact_info_with_signed {
195
1
				location: Location::parent().into(),
196
1
			}
197
1
			.into();
198

            
199
			// Assert that errors since no index is assigned
200
1
			precompiles()
201
1
				.prepare_test(Alice, TransactorV1, input.clone())
202
1
				.execute_reverts(|output| output == b"Transact Info not set");
203

            
204
			// Root can set transact info
205
1
			assert_ok!(XcmTransactor::set_transact_info(
206
1
				RuntimeOrigin::root(),
207
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
208
1
				Weight::zero(),
209
1
				10000u64.into(),
210
1
				Some(1.into())
211
			));
212

            
213
			// Set fee per second for test setup
214
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
215
1
				Location::parent(),
216
1
				relative_price_for_fee_per_second(1)
217
			));
218

            
219
1
			precompiles()
220
1
				.prepare_test(Alice, TransactorV1, input)
221
1
				.expect_cost(2)
222
1
				.expect_no_logs()
223
1
				.execute_returns((0u64, 1u128, 10_000u64));
224
1
		});
225
1
}
226

            
227
#[test]
228
1
fn take_fee_per_second() {
229
1
	ExtBuilder::default()
230
1
		.with_balances(vec![(Alice.into(), 1000)])
231
1
		.build()
232
1
		.execute_with(|| {
233
1
			let input: Vec<_> = PCallV1::fee_per_second {
234
1
				location: Location::parent().into(),
235
1
			}
236
1
			.into();
237

            
238
			// Assert that errors
239
1
			precompiles()
240
1
				.prepare_test(Alice, TransactorV1, input.clone())
241
1
				.execute_reverts(|output| output == b"Fee Per Second not set");
242

            
243
			// Set fee per second for test setup
244
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
245
1
				Location::parent(),
246
1
				relative_price_for_fee_per_second(1)
247
			));
248
1
			precompiles()
249
1
				.prepare_test(Alice, TransactorV1, input)
250
1
				.expect_cost(2)
251
1
				.expect_no_logs()
252
1
				.execute_returns(1u64);
253
1
		});
254
1
}
255

            
256
#[test]
257
1
fn test_transact_derivative_multilocation_v2() {
258
1
	ExtBuilder::default()
259
1
		.with_balances(vec![(Alice.into(), 1000)])
260
1
		.build()
261
1
		.execute_with(|| {
262
			// register index
263
1
			assert_ok!(XcmTransactor::register(
264
1
				RuntimeOrigin::root(),
265
1
				Alice.into(),
266
				0
267
			));
268

            
269
			// we pay with our current self reserve.
270
1
			let fee_payer_asset = Location::parent().into();
271

            
272
1
			let bytes = vec![1u8, 2u8, 3u8];
273

            
274
1
			let total_weight = 1_000_000_000u64;
275
			// We are transferring asset 0, which we have instructed to be the relay asset
276
1
			precompiles()
277
1
				.prepare_test(
278
1
					Alice,
279
1
					TransactorV2,
280
1
					PCallV2::transact_through_derivative_multilocation {
281
1
						transactor: 0,
282
1
						index: 0,
283
1
						fee_asset: fee_payer_asset,
284
1
						weight: 4000000,
285
1
						inner_call: bytes.into(),
286
1
						fee_amount: u128::from(total_weight).into(),
287
1
						overall_weight: total_weight,
288
1
					},
289
				)
290
1
				.expect_cost(188253001)
291
1
				.expect_no_logs()
292
1
				.execute_returns(());
293
1
		});
294
1
}
295

            
296
#[test]
297
1
fn test_transact_derivative_multilocation_v3() {
298
1
	ExtBuilder::default()
299
1
		.with_balances(vec![(Alice.into(), 1000)])
300
1
		.build()
301
1
		.execute_with(|| {
302
			// register index
303
1
			assert_ok!(XcmTransactor::register(
304
1
				RuntimeOrigin::root(),
305
1
				Alice.into(),
306
				0
307
			));
308

            
309
			// we pay with our current self reserve.
310
1
			let fee_payer_asset = Location::parent();
311

            
312
1
			let bytes = vec![1u8, 2u8, 3u8];
313

            
314
			//let total_weight = 1_000_000_000u64;
315
1
			let total_weight = Weight::from_parts(1_000_000_000u64, 82_000u64);
316
1
			let require_weight_at_most = Weight::from_parts(4_000_000u64, 82_000u64);
317
			// We are transferring asset 0, which we have instructed to be the relay asset
318
1
			precompiles()
319
1
				.prepare_test(
320
1
					Alice,
321
1
					TransactorV3,
322
1
					PCallV3::transact_through_derivative_multilocation {
323
1
						transactor: 0,
324
1
						index: 0,
325
1
						fee_asset: fee_payer_asset,
326
1
						weight: require_weight_at_most,
327
1
						inner_call: bytes.into(),
328
1
						fee_amount: u128::from(total_weight.ref_time()).into(),
329
1
						overall_weight: total_weight,
330
1
						refund: false,
331
1
					},
332
				)
333
1
				.expect_cost(188253001)
334
1
				.expect_no_logs()
335
1
				.execute_returns(());
336
1
		});
337
1
}
338

            
339
#[test]
340
1
fn take_transact_info_with_signed_v3() {
341
1
	ExtBuilder::default()
342
1
		.with_balances(vec![(Alice.into(), 1000)])
343
1
		.build()
344
1
		.execute_with(|| {
345
1
			let input: Vec<_> = PCallV3::transact_info_with_signed {
346
1
				location: Location::parent(),
347
1
			}
348
1
			.into();
349

            
350
			// Assert that errors since no index is assigned
351
1
			precompiles()
352
1
				.prepare_test(Alice, TransactorV3, input.clone())
353
1
				.execute_reverts(|output| output == b"Transact Info not set");
354

            
355
			// Root can set transact info
356
1
			assert_ok!(XcmTransactor::set_transact_info(
357
1
				RuntimeOrigin::root(),
358
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
359
1
				Weight::zero(),
360
1
				10000u64.into(),
361
1
				Some(1.into())
362
			));
363

            
364
			// Set fee per second for test setup
365
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
366
1
				Location::parent(),
367
1
				relative_price_for_fee_per_second(1)
368
			));
369

            
370
1
			let expected_max_weight: Weight = 10_000u64.into();
371
1
			let expected_transact_extra_weight_signed: Weight = 1u64.into();
372
1
			let expected_transact_extra_weight: Weight = 0u64.into();
373

            
374
1
			precompiles()
375
1
				.prepare_test(Alice, TransactorV3, input)
376
1
				.expect_cost(2)
377
1
				.expect_no_logs()
378
1
				.execute_returns((
379
1
					expected_transact_extra_weight,
380
1
					expected_transact_extra_weight_signed,
381
1
					expected_max_weight,
382
1
				));
383
1
		});
384
1
}
385

            
386
#[test]
387
1
fn test_transact_derivative_multilocation() {
388
1
	ExtBuilder::default()
389
1
		.with_balances(vec![(Alice.into(), 1000)])
390
1
		.build()
391
1
		.execute_with(|| {
392
			// register index
393
1
			assert_ok!(XcmTransactor::register(
394
1
				RuntimeOrigin::root(),
395
1
				Alice.into(),
396
				0
397
			));
398

            
399
			// Root can set transact info
400
1
			assert_ok!(XcmTransactor::set_transact_info(
401
1
				RuntimeOrigin::root(),
402
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
403
1
				Weight::zero(),
404
1
				10000000.into(),
405
1
				None
406
			));
407

            
408
			// Set fee per second for test setup
409
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
410
1
				Location::parent(),
411
1
				relative_price_for_fee_per_second(1)
412
			));
413

            
414
			// we pay with our current self reserve.
415
1
			let fee_payer_asset = Location::parent().into();
416

            
417
1
			let bytes = vec![1u8, 2u8, 3u8];
418

            
419
			// We are transferring asset 0, which we have instructed to be the relay asset
420
1
			precompiles()
421
1
				.prepare_test(
422
1
					Alice,
423
1
					TransactorV1,
424
1
					PCallV1::transact_through_derivative_multilocation {
425
1
						transactor: 0,
426
1
						index: 0,
427
1
						fee_asset: fee_payer_asset,
428
1
						weight: 4_000_000,
429
1
						inner_call: bytes.into(),
430
1
					},
431
				)
432
1
				.expect_cost(188253001)
433
1
				.expect_no_logs()
434
1
				.execute_returns(());
435
1
		});
436
1
}
437

            
438
#[test]
439
1
fn test_transact_derivative() {
440
1
	ExtBuilder::default()
441
1
		.with_balances(vec![(Alice.into(), 1000)])
442
1
		.build()
443
1
		.execute_with(|| {
444
			// register index
445
1
			assert_ok!(XcmTransactor::register(
446
1
				RuntimeOrigin::root(),
447
1
				Alice.into(),
448
				0
449
			));
450

            
451
			// Root can set transact info
452
1
			assert_ok!(XcmTransactor::set_transact_info(
453
1
				RuntimeOrigin::root(),
454
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
455
1
				Weight::zero(),
456
1
				10000000.into(),
457
1
				None
458
			));
459

            
460
			// Set fee per second for test setup
461
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
462
1
				Location::parent(),
463
1
				relative_price_for_fee_per_second(1)
464
			));
465

            
466
1
			let bytes = vec![1u8, 2u8, 3u8];
467

            
468
			// We are transferring asset 0, which we have instructed to be the relay asset
469
1
			precompiles()
470
1
				.prepare_test(
471
1
					Alice,
472
1
					TransactorV1,
473
1
					PCallV1::transact_through_derivative {
474
1
						transactor: 0,
475
1
						index: 0,
476
1
						currency_id: Address(AssetAddress(0).into()),
477
1
						weight: 4_000_000,
478
1
						inner_call: bytes.into(),
479
1
					},
480
				)
481
1
				.expect_cost(188254001)
482
1
				.expect_no_logs()
483
1
				.execute_returns(());
484
1
		});
485
1
}
486

            
487
#[test]
488
1
fn test_transact_derivative_v2() {
489
1
	ExtBuilder::default()
490
1
		.with_balances(vec![(Alice.into(), 1000)])
491
1
		.build()
492
1
		.execute_with(|| {
493
			// register index
494
1
			assert_ok!(XcmTransactor::register(
495
1
				RuntimeOrigin::root(),
496
1
				Alice.into(),
497
				0
498
			));
499

            
500
1
			let bytes = vec![1u8, 2u8, 3u8];
501

            
502
1
			let total_weight = 1_000_000_000u64;
503

            
504
			// We are transferring asset 0, which we have instructed to be the relay asset
505
1
			precompiles()
506
1
				.prepare_test(
507
1
					Alice,
508
1
					TransactorV2,
509
1
					PCallV2::transact_through_derivative {
510
1
						transactor: 0,
511
1
						index: 0,
512
1
						fee_asset: Address(AssetAddress(0).into()),
513
1
						weight: 4_000_000,
514
1
						inner_call: bytes.into(),
515
1
						fee_amount: u128::from(total_weight).into(),
516
1
						overall_weight: total_weight,
517
1
					},
518
				)
519
1
				.expect_cost(188254001)
520
1
				.expect_no_logs()
521
1
				.execute_returns(());
522
1
		});
523
1
}
524

            
525
#[test]
526
1
fn test_transact_derivative_v3() {
527
1
	ExtBuilder::default()
528
1
		.with_balances(vec![(Alice.into(), 1000)])
529
1
		.build()
530
1
		.execute_with(|| {
531
			// register index
532
1
			assert_ok!(XcmTransactor::register(
533
1
				RuntimeOrigin::root(),
534
1
				Alice.into(),
535
				0
536
			));
537

            
538
1
			let bytes = vec![1u8, 2u8, 3u8];
539

            
540
			//let total_weight = 1_000_000_000u64;
541
1
			let total_weight = Weight::from_parts(1_000_000_000u64, 82_000u64);
542
1
			let require_weight_at_most = Weight::from_parts(4_000_000u64, 82_000u64);
543

            
544
			// We are transferring asset 0, which we have instructed to be the relay asset
545
1
			precompiles()
546
1
				.prepare_test(
547
1
					Alice,
548
1
					TransactorV3,
549
1
					PCallV3::transact_through_derivative {
550
1
						transactor: 0,
551
1
						index: 0,
552
1
						fee_asset: Address(AssetAddress(0).into()),
553
1
						weight: require_weight_at_most,
554
1
						inner_call: bytes.into(),
555
1
						fee_amount: u128::from(total_weight.ref_time()).into(),
556
1
						overall_weight: total_weight,
557
1
						refund: false,
558
1
					},
559
				)
560
1
				.expect_cost(188254001)
561
1
				.expect_no_logs()
562
1
				.execute_returns(());
563
1
		});
564
1
}
565

            
566
#[test]
567
1
fn test_transact_signed() {
568
1
	ExtBuilder::default()
569
1
		.with_balances(vec![(Alice.into(), 1000)])
570
1
		.build()
571
1
		.execute_with(|| {
572
			// Root can set transact info
573
1
			assert_ok!(XcmTransactor::set_transact_info(
574
1
				RuntimeOrigin::root(),
575
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
576
1
				Weight::zero(),
577
1
				10000000.into(),
578
1
				Some(1.into())
579
			));
580

            
581
			// Set fee per second for test setup
582
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
583
1
				Location::parent(),
584
1
				relative_price_for_fee_per_second(1)
585
			));
586

            
587
			// Destination
588
1
			let dest = Location::parent().into();
589

            
590
1
			let bytes = vec![1u8, 2u8, 3u8];
591

            
592
			// We are transferring asset 0, which we have instructed to be the relay asset
593
1
			precompiles()
594
1
				.prepare_test(
595
1
					Alice,
596
1
					TransactorV1,
597
1
					PCallV1::transact_through_signed {
598
1
						dest,
599
1
						fee_asset: Address(AssetAddress(0).into()),
600
1
						weight: 4_000_000,
601
1
						call: bytes.into(),
602
1
					},
603
				)
604
1
				.expect_cost(468449001)
605
1
				.expect_no_logs()
606
1
				.execute_returns(());
607
1
		});
608
1
}
609

            
610
#[test]
611
1
fn test_transact_signed_v2() {
612
1
	ExtBuilder::default()
613
1
		.with_balances(vec![(Alice.into(), 1000)])
614
1
		.build()
615
1
		.execute_with(|| {
616
			// Destination
617
1
			let dest = Location::parent().into();
618

            
619
1
			let bytes = vec![1u8, 2u8, 3u8];
620

            
621
1
			let total_weight = 1_000_000_000u64;
622

            
623
			// We are transferring asset 0, which we have instructed to be the relay asset
624
1
			precompiles()
625
1
				.prepare_test(
626
1
					Alice,
627
1
					TransactorV2,
628
1
					PCallV2::transact_through_signed {
629
1
						dest,
630
1
						fee_asset: Address(AssetAddress(0).into()),
631
1
						weight: 4_000_000,
632
1
						call: bytes.into(),
633
1
						fee_amount: u128::from(total_weight).into(),
634
1
						overall_weight: total_weight,
635
1
					},
636
				)
637
1
				.expect_cost(468449001)
638
1
				.expect_no_logs()
639
1
				.execute_returns(());
640
1
		});
641
1
}
642

            
643
#[test]
644
1
fn test_transact_signed_v3() {
645
1
	ExtBuilder::default()
646
1
		.with_balances(vec![(Alice.into(), 1000)])
647
1
		.build()
648
1
		.execute_with(|| {
649
			// register index
650
1
			assert_ok!(XcmTransactor::register(
651
1
				RuntimeOrigin::root(),
652
1
				Alice.into(),
653
				0
654
			));
655

            
656
1
			let bytes = vec![1u8, 2u8, 3u8];
657

            
658
1
			let total_weight = Weight::from_parts(1_000_000_000u64, 82_000u64);
659
1
			let require_weight_at_most = Weight::from_parts(4_000_000u64, 82_000u64);
660
			// We are transferring asset 0, which we have instructed to be the relay asset
661
1
			precompiles()
662
1
				.prepare_test(
663
1
					Alice,
664
1
					TransactorV3,
665
1
					PCallV3::transact_through_signed {
666
1
						dest: Location::parent(),
667
1
						fee_asset: Address(AssetAddress(0).into()),
668
1
						weight: require_weight_at_most,
669
1
						call: bytes.into(),
670
1
						fee_amount: u128::from(total_weight.ref_time()).into(),
671
1
						overall_weight: total_weight,
672
1
						refund: false,
673
1
					},
674
				)
675
1
				.expect_cost(468449001)
676
1
				.expect_no_logs()
677
1
				.execute_returns(());
678
1
		});
679
1
}
680

            
681
#[test]
682
1
fn test_transact_signed_multilocation() {
683
1
	ExtBuilder::default()
684
1
		.with_balances(vec![(Alice.into(), 1000)])
685
1
		.build()
686
1
		.execute_with(|| {
687
			// Root can set transact info
688
1
			assert_ok!(XcmTransactor::set_transact_info(
689
1
				RuntimeOrigin::root(),
690
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
691
1
				Weight::zero(),
692
1
				10000000.into(),
693
1
				Some(1.into())
694
			));
695

            
696
			// Set fee per second for test setup
697
1
			assert_ok!(<MemoryFeeTrader as XcmFeeTrader>::set_asset_price(
698
1
				Location::parent(),
699
1
				relative_price_for_fee_per_second(1)
700
			));
701

            
702
			// Destination
703
1
			let dest = Location::parent().into();
704

            
705
1
			let fee_payer_asset = Location::parent().into();
706

            
707
1
			let bytes = vec![1u8, 2u8, 3u8];
708

            
709
			// We are transferring asset 0, which we have instructed to be the relay asset
710
1
			precompiles()
711
1
				.prepare_test(
712
1
					Alice,
713
1
					TransactorV1,
714
1
					PCallV1::transact_through_signed_multilocation {
715
1
						dest,
716
1
						fee_asset: fee_payer_asset,
717
1
						weight: 4_000_000,
718
1
						call: bytes.into(),
719
1
					},
720
				)
721
1
				.expect_cost(468448001)
722
1
				.expect_no_logs()
723
1
				.execute_returns(());
724
1
		});
725
1
}
726

            
727
#[test]
728
1
fn test_transact_signed_multilocation_v2() {
729
1
	ExtBuilder::default()
730
1
		.with_balances(vec![(Alice.into(), 1000)])
731
1
		.build()
732
1
		.execute_with(|| {
733
			// Destination
734
1
			let dest = Location::parent().into();
735

            
736
1
			let fee_payer_asset = Location::parent().into();
737

            
738
1
			let bytes = vec![1u8, 2u8, 3u8];
739

            
740
1
			let total_weight = 1_000_000_000u64;
741

            
742
			// We are transferring asset 0, which we have instructed to be the relay asset
743
1
			precompiles()
744
1
				.prepare_test(
745
1
					Alice,
746
1
					TransactorV2,
747
1
					PCallV2::transact_through_signed_multilocation {
748
1
						dest,
749
1
						fee_asset: fee_payer_asset,
750
1
						weight: 4_000_000,
751
1
						call: bytes.into(),
752
1
						fee_amount: u128::from(total_weight).into(),
753
1
						overall_weight: total_weight,
754
1
					},
755
				)
756
1
				.expect_cost(468448001)
757
1
				.expect_no_logs()
758
1
				.execute_returns(());
759
1
		});
760
1
}
761

            
762
#[test]
763
1
fn test_transact_through_signed_multilocation_v3() {
764
1
	ExtBuilder::default()
765
1
		.with_balances(vec![(Alice.into(), 1000)])
766
1
		.build()
767
1
		.execute_with(|| {
768
			// register index
769
1
			assert_ok!(XcmTransactor::register(
770
1
				RuntimeOrigin::root(),
771
1
				Alice.into(),
772
				0
773
			));
774

            
775
			// we pay with our current self reserve.
776
1
			let fee_payer_asset = Location::parent();
777

            
778
1
			let bytes = vec![1u8, 2u8, 3u8];
779

            
780
1
			let total_weight = Weight::from_parts(1_000_000_000u64, 82_000u64);
781
1
			let require_weight_at_most = Weight::from_parts(4_000_000u64, 82_000u64);
782
			// We are transferring asset 0, which we have instructed to be the relay asset
783
1
			precompiles()
784
1
				.prepare_test(
785
1
					Alice,
786
1
					TransactorV3,
787
1
					PCallV3::transact_through_signed_multilocation {
788
1
						dest: Location::parent(),
789
1
						fee_asset: fee_payer_asset,
790
1
						weight: require_weight_at_most,
791
1
						call: bytes.into(),
792
1
						fee_amount: u128::from(total_weight.ref_time()).into(),
793
1
						overall_weight: total_weight,
794
1
						refund: false,
795
1
					},
796
				)
797
1
				.expect_cost(468448001)
798
1
				.expect_no_logs()
799
1
				.execute_returns(());
800
1
		});
801
1
}
802

            
803
#[test]
804
1
fn test_solidity_interface_has_all_function_selectors_documented_and_implemented_v1() {
805
1
	check_precompile_implements_solidity_interfaces(
806
1
		&["src/v1/XcmTransactorV1.sol"],
807
		PCallV1::supports_selector,
808
	)
809
1
}
810

            
811
#[test]
812
1
fn test_solidity_interface_has_all_function_selectors_documented_and_implemented_v2() {
813
1
	check_precompile_implements_solidity_interfaces(
814
1
		&["src/v2/XcmTransactorV2.sol"],
815
		PCallV2::supports_selector,
816
	)
817
1
}
818

            
819
#[test]
820
1
fn test_solidity_interface_has_all_function_selectors_documented_and_implemented_v3() {
821
1
	check_precompile_implements_solidity_interfaces(
822
1
		&["src/v3/XcmTransactorV3.sol"],
823
		PCallV3::supports_selector,
824
	)
825
1
}
826

            
827
#[test]
828
1
fn test_deprecated_solidity_selectors_are_supported() {
829
8
	for deprecated_function in [
830
		"index_to_account(uint16)",
831
1
		"transact_info((uint8,bytes[]))",
832
1
		"transact_through_derivative_multilocation(uint8,uint16,(uint8,bytes[]),uint64,bytes)",
833
1
		"transact_through_derivative(uint8,uint16,address,uint64,bytes)",
834
1
		"transact_info_with_signed((uint8,bytes[]))",
835
1
		"fee_per_second((uint8,bytes[]))",
836
1
		"transact_through_signed_multilocation((uint8,bytes[]),(uint8,bytes[]),uint64,bytes)",
837
1
		"transact_through_signed((uint8,bytes[]),address,uint64,bytes)",
838
	] {
839
8
		let selector = compute_selector(deprecated_function);
840
8
		if !PCallV1::supports_selector(selector) {
841
			panic!(
842
				"failed decoding selector 0x{:x} => '{}' as Action",
843
				selector, deprecated_function,
844
			)
845
8
		}
846
	}
847
1
}