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

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use crate::mock::*;
18
use crate::*;
19
use cumulus_primitives_core::relay_chain::HrmpChannelId;
20
use frame_support::weights::Weight;
21
use frame_support::{assert_noop, assert_ok, weights::constants::WEIGHT_REF_TIME_PER_SECOND};
22
use sp_runtime::traits::Convert;
23
use sp_runtime::DispatchError;
24
use sp_std::boxed::Box;
25
use xcm::latest::prelude::*;
26
use xcm_primitives::{UtilityAvailableCalls, UtilityEncodeCall};
27
#[test]
28
1
fn test_register_address() {
29
1
	ExtBuilder::default()
30
1
		.with_balances(vec![])
31
1
		.build()
32
1
		.execute_with(|| {
33
1
			// Only root can do this, as specified in runtime
34
1
			assert_noop!(
35
1
				XcmTransactor::register(RuntimeOrigin::signed(1u64), 1u64, 1),
36
1
				DispatchError::BadOrigin
37
1
			);
38

            
39
			// Root can register
40
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
41

            
42
1
			assert_eq!(XcmTransactor::index_to_account(&1).unwrap(), 1u64);
43

            
44
1
			let expected = vec![crate::Event::RegisteredDerivative {
45
1
				account_id: 1u64,
46
1
				index: 1,
47
1
			}];
48
1
			assert_eq!(events(), expected);
49
1
		})
50
1
}
51

            
52
#[test]
53
1
fn test_transact_through_derivative_errors() {
54
1
	ExtBuilder::default()
55
1
		.with_balances(vec![])
56
1
		.build()
57
1
		.execute_with(|| {
58
1
			// Non-claimed index so cannot transfer
59
1
			assert_noop!(
60
1
				XcmTransactor::transact_through_derivative(
61
1
					RuntimeOrigin::signed(1u64),
62
1
					Transactors::Relay,
63
1
					1,
64
1
					CurrencyPayment {
65
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
66
1
							Location::parent()
67
1
						))),
68
1
						fee_amount: None
69
1
					},
70
1
					vec![0u8],
71
1
					TransactWeights {
72
1
						transact_required_weight_at_most: 100u64.into(),
73
1
						overall_weight: None
74
1
					},
75
1
					false
76
1
				),
77
1
				Error::<Test>::UnclaimedIndex
78
1
			);
79

            
80
			// Root can register
81
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
82

            
83
			// TransactInfo not yet set
84
1
			assert_noop!(
85
1
				XcmTransactor::transact_through_derivative(
86
1
					RuntimeOrigin::signed(1u64),
87
1
					Transactors::Relay,
88
1
					1,
89
1
					CurrencyPayment {
90
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
91
1
							Location::parent()
92
1
						))),
93
1
						fee_amount: None
94
1
					},
95
1
					vec![0u8],
96
1
					TransactWeights {
97
1
						transact_required_weight_at_most: 100u64.into(),
98
1
						overall_weight: None
99
1
					},
100
1
					false
101
1
				),
102
1
				Error::<Test>::TransactorInfoNotSet
103
1
			);
104

            
105
			// Root can set transact info
106
1
			assert_ok!(XcmTransactor::set_transact_info(
107
1
				RuntimeOrigin::root(),
108
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
109
1
				0.into(),
110
1
				10000.into(),
111
1
				None
112
1
			));
113

            
114
			// TransactInfo present, but FeePerSecond not set
115
1
			assert_noop!(
116
1
				XcmTransactor::transact_through_derivative(
117
1
					RuntimeOrigin::signed(1u64),
118
1
					Transactors::Relay,
119
1
					1,
120
1
					CurrencyPayment {
121
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
122
1
							Location::parent()
123
1
						))),
124
1
						fee_amount: None
125
1
					},
126
1
					vec![0u8],
127
1
					TransactWeights {
128
1
						transact_required_weight_at_most: 100u64.into(),
129
1
						overall_weight: None
130
1
					},
131
1
					false
132
1
				),
133
1
				Error::<Test>::FeePerSecondNotSet
134
1
			);
135

            
136
			// Set fee per second
137
1
			assert_ok!(XcmTransactor::set_fee_per_second(
138
1
				RuntimeOrigin::root(),
139
1
				Box::new(xcm::VersionedLocation::V4(Location::new(
140
1
					1,
141
1
					[Junction::Parachain(1000)]
142
1
				))),
143
1
				1
144
1
			));
145

            
146
			// TransactInfo present, but the asset is not a reserve of dest
147
1
			assert_noop!(
148
1
				XcmTransactor::transact_through_derivative(
149
1
					RuntimeOrigin::signed(1u64),
150
1
					Transactors::Relay,
151
1
					1,
152
1
					CurrencyPayment {
153
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
154
1
							Location::new(1, [Junction::Parachain(1000)])
155
1
						))),
156
1
						fee_amount: None
157
1
					},
158
1
					vec![0u8],
159
1
					TransactWeights {
160
1
						transact_required_weight_at_most: 100u64.into(),
161
1
						overall_weight: None
162
1
					},
163
1
					false
164
1
				),
165
1
				Error::<Test>::AssetIsNotReserveInDestination
166
1
			);
167

            
168
			// Set fee per second
169
1
			assert_ok!(XcmTransactor::set_fee_per_second(
170
1
				RuntimeOrigin::root(),
171
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
172
1
				1
173
1
			));
174

            
175
			// Cannot exceed the max weight
176
1
			assert_noop!(
177
1
				XcmTransactor::transact_through_derivative(
178
1
					RuntimeOrigin::signed(1u64),
179
1
					Transactors::Relay,
180
1
					1,
181
1
					CurrencyPayment {
182
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
183
1
							Location::parent()
184
1
						))),
185
1
						fee_amount: None
186
1
					},
187
1
					vec![0u8],
188
1
					TransactWeights {
189
1
						transact_required_weight_at_most: 10001u64.into(),
190
1
						overall_weight: None
191
1
					},
192
1
					false
193
1
				),
194
1
				Error::<Test>::MaxWeightTransactReached
195
1
			);
196
1
		})
197
1
}
198

            
199
#[test]
200
1
fn test_transact_through_signed_errors() {
201
1
	ExtBuilder::default()
202
1
		.with_balances(vec![])
203
1
		.build()
204
1
		.execute_with(|| {
205
1
			// TransactInfo not yet set
206
1
			assert_noop!(
207
1
				XcmTransactor::transact_through_signed(
208
1
					RuntimeOrigin::signed(1u64),
209
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
210
1
					CurrencyPayment {
211
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
212
1
							Location::parent()
213
1
						))),
214
1
						fee_amount: None
215
1
					},
216
1
					vec![0u8],
217
1
					TransactWeights {
218
1
						transact_required_weight_at_most: 100u64.into(),
219
1
						overall_weight: None
220
1
					},
221
1
					false
222
1
				),
223
1
				Error::<Test>::TransactorInfoNotSet
224
1
			);
225

            
226
			// Root can set transact info without extra_signed being None
227
1
			assert_ok!(XcmTransactor::set_transact_info(
228
1
				RuntimeOrigin::root(),
229
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
230
1
				0.into(),
231
1
				10000.into(),
232
1
				None
233
1
			));
234

            
235
			// TransactInfo present, but FeePerSecond not set
236
1
			assert_noop!(
237
1
				XcmTransactor::transact_through_signed(
238
1
					RuntimeOrigin::signed(1u64),
239
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
240
1
					CurrencyPayment {
241
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
242
1
							Location::parent()
243
1
						))),
244
1
						fee_amount: None
245
1
					},
246
1
					vec![0u8],
247
1
					TransactWeights {
248
1
						transact_required_weight_at_most: 100u64.into(),
249
1
						overall_weight: None
250
1
					},
251
1
					false
252
1
				),
253
1
				Error::<Test>::SignedTransactNotAllowedForDestination
254
1
			);
255

            
256
			// Root can set transact info, with extra signed
257
1
			assert_ok!(XcmTransactor::set_transact_info(
258
1
				RuntimeOrigin::root(),
259
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
260
1
				0.into(),
261
1
				15000.into(),
262
1
				Some(12000.into())
263
1
			));
264

            
265
			// TransactInfo present, but FeePerSecond not set
266
1
			assert_noop!(
267
1
				XcmTransactor::transact_through_signed(
268
1
					RuntimeOrigin::signed(1u64),
269
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
270
1
					CurrencyPayment {
271
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
272
1
							Location::parent()
273
1
						))),
274
1
						fee_amount: None
275
1
					},
276
1
					vec![0u8],
277
1
					TransactWeights {
278
1
						transact_required_weight_at_most: 100u64.into(),
279
1
						overall_weight: None
280
1
					},
281
1
					false
282
1
				),
283
1
				Error::<Test>::FeePerSecondNotSet
284
1
			);
285

            
286
			// Set fee per second
287
1
			assert_ok!(XcmTransactor::set_fee_per_second(
288
1
				RuntimeOrigin::root(),
289
1
				Box::new(xcm::VersionedLocation::V4(Location::new(
290
1
					1,
291
1
					[Junction::Parachain(1000)]
292
1
				))),
293
1
				1
294
1
			));
295

            
296
			// TransactInfo present, but the asset is not a reserve of dest
297
1
			assert_noop!(
298
1
				XcmTransactor::transact_through_signed(
299
1
					RuntimeOrigin::signed(1u64),
300
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
301
1
					CurrencyPayment {
302
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
303
1
							Location::new(1, [Junction::Parachain(1000)])
304
1
						))),
305
1
						fee_amount: None
306
1
					},
307
1
					vec![0u8],
308
1
					TransactWeights {
309
1
						transact_required_weight_at_most: 100u64.into(),
310
1
						overall_weight: None
311
1
					},
312
1
					false
313
1
				),
314
1
				Error::<Test>::AssetIsNotReserveInDestination
315
1
			);
316
1
		})
317
1
}
318

            
319
#[test]
320
1
fn test_transact_through_derivative_multilocation_success() {
321
1
	ExtBuilder::default()
322
1
		.with_balances(vec![])
323
1
		.build()
324
1
		.execute_with(|| {
325
1
			// Root can register
326
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
327

            
328
			// Root can set transact info
329
1
			assert_ok!(XcmTransactor::set_transact_info(
330
1
				RuntimeOrigin::root(),
331
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
332
1
				0.into(),
333
1
				10000.into(),
334
1
				None
335
1
			));
336

            
337
			// Set fee per second
338
1
			assert_ok!(XcmTransactor::set_fee_per_second(
339
1
				RuntimeOrigin::root(),
340
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
341
1
				1
342
1
			));
343

            
344
			// fee as destination are the same, this time it should work
345
1
			assert_ok!(XcmTransactor::transact_through_derivative(
346
1
				RuntimeOrigin::signed(1u64),
347
1
				Transactors::Relay,
348
1
				1,
349
1
				CurrencyPayment {
350
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
351
1
						Location::parent()
352
1
					))),
353
1
					fee_amount: None
354
1
				},
355
1
				vec![1u8],
356
1
				TransactWeights {
357
1
					transact_required_weight_at_most: 100u64.into(),
358
1
					overall_weight: None
359
1
				},
360
1
				false
361
1
			));
362
1
			let expected = vec![
363
1
				crate::Event::RegisteredDerivative {
364
1
					account_id: 1u64,
365
1
					index: 1,
366
1
				},
367
1
				crate::Event::TransactInfoChanged {
368
1
					location: Location::parent(),
369
1
					remote_info: RemoteTransactInfoWithMaxWeight {
370
1
						transact_extra_weight: 0.into(),
371
1
						max_weight: 10000.into(),
372
1
						transact_extra_weight_signed: None,
373
1
					},
374
1
				},
375
1
				crate::Event::DestFeePerSecondChanged {
376
1
					location: Location::parent(),
377
1
					fee_per_second: 1,
378
1
				},
379
1
				crate::Event::TransactedDerivative {
380
1
					account_id: 1u64,
381
1
					dest: Location::parent(),
382
1
					call: Transactors::Relay
383
1
						.encode_call(UtilityAvailableCalls::AsDerivative(1, vec![1u8])),
384
1
					index: 1,
385
1
				},
386
1
			];
387
1
			assert_eq!(events(), expected);
388
1
		})
389
1
}
390

            
391
#[test]
392
1
fn test_transact_through_derivative_success() {
393
1
	ExtBuilder::default()
394
1
		.with_balances(vec![])
395
1
		.build()
396
1
		.execute_with(|| {
397
1
			// Root can register
398
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
399

            
400
			// Root can set transact info
401
1
			assert_ok!(XcmTransactor::set_transact_info(
402
1
				RuntimeOrigin::root(),
403
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
404
1
				0.into(),
405
1
				10000.into(),
406
1
				None
407
1
			));
408

            
409
			// Set fee per second
410
1
			assert_ok!(XcmTransactor::set_fee_per_second(
411
1
				RuntimeOrigin::root(),
412
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
413
1
				1
414
1
			));
415

            
416
			// fee as destination are the same, this time it should work
417
1
			assert_ok!(XcmTransactor::transact_through_derivative(
418
1
				RuntimeOrigin::signed(1u64),
419
1
				Transactors::Relay,
420
1
				1,
421
1
				CurrencyPayment {
422
1
					currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
423
1
					fee_amount: None
424
1
				},
425
1
				vec![1u8],
426
1
				TransactWeights {
427
1
					transact_required_weight_at_most: 100u64.into(),
428
1
					overall_weight: None
429
1
				},
430
1
				false
431
1
			));
432
1
			let expected = vec![
433
1
				crate::Event::RegisteredDerivative {
434
1
					account_id: 1u64,
435
1
					index: 1,
436
1
				},
437
1
				crate::Event::TransactInfoChanged {
438
1
					location: Location::parent(),
439
1
					remote_info: RemoteTransactInfoWithMaxWeight {
440
1
						transact_extra_weight: 0.into(),
441
1
						max_weight: 10000.into(),
442
1
						transact_extra_weight_signed: None,
443
1
					},
444
1
				},
445
1
				crate::Event::DestFeePerSecondChanged {
446
1
					location: Location::parent(),
447
1
					fee_per_second: 1,
448
1
				},
449
1
				crate::Event::TransactedDerivative {
450
1
					account_id: 1u64,
451
1
					dest: Location::parent(),
452
1
					call: Transactors::Relay
453
1
						.encode_call(UtilityAvailableCalls::AsDerivative(1, vec![1u8])),
454
1
					index: 1,
455
1
				},
456
1
			];
457
1
			assert_eq!(events(), expected);
458
1
			let sent_messages = mock::sent_xcm();
459
1
			let (_, sent_message) = sent_messages.first().unwrap();
460
1

            
461
1
			// Check message doesn't contain the appendix
462
1
			assert!(!sent_message.0.contains(&SetAppendix(Xcm(vec![
463
1
				RefundSurplus,
464
1
				DepositAsset {
465
1
					assets: Wild(AllCounted(1u32)),
466
1
					beneficiary: Location {
467
1
						parents: 0,
468
1
						interior: [Junction::Parachain(100)].into()
469
1
					}
470
1
				}
471
1
			]))));
472
1
		})
473
1
}
474

            
475
#[test]
476
1
fn test_root_can_transact_through_sovereign() {
477
1
	ExtBuilder::default()
478
1
		.with_balances(vec![])
479
1
		.build()
480
1
		.execute_with(|| {
481
1
			// Only root can do this
482
1
			assert_noop!(
483
1
				XcmTransactor::transact_through_sovereign(
484
1
					RuntimeOrigin::signed(1),
485
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
486
1
					Some(1u64),
487
1
					CurrencyPayment {
488
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
489
1
							Location::parent()
490
1
						))),
491
1
						fee_amount: None
492
1
					},
493
1
					vec![1u8],
494
1
					OriginKind::SovereignAccount,
495
1
					TransactWeights {
496
1
						transact_required_weight_at_most: 100u64.into(),
497
1
						overall_weight: None
498
1
					},
499
1
					false
500
1
				),
501
1
				DispatchError::BadOrigin
502
1
			);
503

            
504
			// Root can set transact info
505
1
			assert_ok!(XcmTransactor::set_transact_info(
506
1
				RuntimeOrigin::root(),
507
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
508
1
				0.into(),
509
1
				10000.into(),
510
1
				None
511
1
			));
512

            
513
			// Set fee per second
514
1
			assert_ok!(XcmTransactor::set_fee_per_second(
515
1
				RuntimeOrigin::root(),
516
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
517
1
				1
518
1
			));
519

            
520
			// fee as destination are the same, this time it should work
521
1
			assert_ok!(XcmTransactor::transact_through_sovereign(
522
1
				RuntimeOrigin::root(),
523
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
524
1
				Some(1u64),
525
1
				CurrencyPayment {
526
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
527
1
						Location::parent()
528
1
					))),
529
1
					fee_amount: None
530
1
				},
531
1
				vec![1u8],
532
1
				OriginKind::SovereignAccount,
533
1
				TransactWeights {
534
1
					transact_required_weight_at_most: 100u64.into(),
535
1
					overall_weight: None
536
1
				},
537
1
				false
538
1
			));
539

            
540
1
			let expected = vec![
541
1
				crate::Event::TransactInfoChanged {
542
1
					location: Location::parent(),
543
1
					remote_info: RemoteTransactInfoWithMaxWeight {
544
1
						transact_extra_weight: 0.into(),
545
1
						max_weight: 10000.into(),
546
1
						transact_extra_weight_signed: None,
547
1
					},
548
1
				},
549
1
				crate::Event::DestFeePerSecondChanged {
550
1
					location: Location::parent(),
551
1
					fee_per_second: 1,
552
1
				},
553
1
				crate::Event::TransactedSovereign {
554
1
					fee_payer: Some(1u64),
555
1
					dest: Location::parent(),
556
1
					call: vec![1u8],
557
1
				},
558
1
			];
559
1
			assert_eq!(events(), expected);
560
1
		})
561
1
}
562

            
563
#[test]
564
1
fn test_fee_calculation_works() {
565
1
	ExtBuilder::default()
566
1
		.with_balances(vec![])
567
1
		.build()
568
1
		.execute_with(|| {
569
1
			assert_eq!(
570
1
				XcmTransactor::calculate_fee_per_second(
571
1
					1000000000.into(),
572
1
					8 * WEIGHT_REF_TIME_PER_SECOND as u128
573
1
				),
574
1
				8000000000
575
1
			);
576
1
		})
577
1
}
578

            
579
// Kusama case
580
#[test]
581
1
fn test_fee_calculation_works_kusama_0_9_20_case() {
582
1
	ExtBuilder::default()
583
1
		.with_balances(vec![])
584
1
		.build()
585
1
		.execute_with(|| {
586
1
			// 38620923000 * 319324000/1e12 = 12332587.6161
587
1
			// integer arithmetic would round this to 12332587
588
1
			// we test here that it rounds up to 12332588 instead
589
1
			assert_eq!(
590
1
				XcmTransactor::calculate_fee_per_second(319324000.into(), 38620923000),
591
1
				12332588
592
1
			);
593
1
		})
594
1
}
595

            
596
#[test]
597
1
fn de_registering_works() {
598
1
	ExtBuilder::default()
599
1
		.with_balances(vec![])
600
1
		.build()
601
1
		.execute_with(|| {
602
1
			// Root can register
603
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
604

            
605
1
			assert_eq!(XcmTransactor::index_to_account(&1).unwrap(), 1u64);
606

            
607
1
			assert_ok!(XcmTransactor::deregister(RuntimeOrigin::root(), 1));
608

            
609
1
			assert!(XcmTransactor::index_to_account(&1).is_none());
610

            
611
1
			let expected = vec![
612
1
				crate::Event::RegisteredDerivative {
613
1
					account_id: 1u64,
614
1
					index: 1,
615
1
				},
616
1
				crate::Event::DeRegisteredDerivative { index: 1 },
617
1
			];
618
1
			assert_eq!(events(), expected);
619
1
		})
620
1
}
621

            
622
#[test]
623
1
fn removing_transact_info_works() {
624
1
	ExtBuilder::default()
625
1
		.with_balances(vec![])
626
1
		.build()
627
1
		.execute_with(|| {
628
1
			// Root can set transact info
629
1
			assert_ok!(XcmTransactor::set_transact_info(
630
1
				RuntimeOrigin::root(),
631
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
632
1
				0.into(),
633
1
				10000.into(),
634
1
				None
635
1
			));
636

            
637
			// Root can remove transact info
638
1
			assert_ok!(XcmTransactor::remove_transact_info(
639
1
				RuntimeOrigin::root(),
640
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
641
1
			));
642

            
643
1
			assert!(XcmTransactor::transact_info(Location::parent()).is_none());
644

            
645
1
			let expected = vec![
646
1
				crate::Event::TransactInfoChanged {
647
1
					location: Location::parent(),
648
1
					remote_info: RemoteTransactInfoWithMaxWeight {
649
1
						transact_extra_weight: 0.into(),
650
1
						max_weight: 10000.into(),
651
1
						transact_extra_weight_signed: None,
652
1
					},
653
1
				},
654
1
				crate::Event::TransactInfoRemoved {
655
1
					location: Location::parent(),
656
1
				},
657
1
			];
658
1
			assert_eq!(events(), expected);
659
1
		})
660
1
}
661

            
662
#[test]
663
1
fn test_transact_through_signed_fails_if_transact_info_not_set_at_all() {
664
1
	ExtBuilder::default()
665
1
		.with_balances(vec![])
666
1
		.build()
667
1
		.execute_with(|| {
668
1
			// fee as destination are the same, this time it should work
669
1
			assert_noop!(
670
1
				XcmTransactor::transact_through_signed(
671
1
					RuntimeOrigin::signed(1u64),
672
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
673
1
					CurrencyPayment {
674
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
675
1
						fee_amount: None
676
1
					},
677
1
					vec![1u8],
678
1
					TransactWeights {
679
1
						transact_required_weight_at_most: 100u64.into(),
680
1
						overall_weight: None
681
1
					},
682
1
					false
683
1
				),
684
1
				Error::<Test>::TransactorInfoNotSet
685
1
			);
686
1
		})
687
1
}
688

            
689
#[test]
690
1
fn test_transact_through_signed_fails_if_weight_is_not_set() {
691
1
	ExtBuilder::default()
692
1
		.with_balances(vec![])
693
1
		.build()
694
1
		.execute_with(|| {
695
1
			// Root can set transact info
696
1
			assert_ok!(XcmTransactor::set_transact_info(
697
1
				RuntimeOrigin::root(),
698
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
699
1
				0.into(),
700
1
				10000.into(),
701
1
				None
702
1
			));
703

            
704
			// weight value not set for signed transact, fails
705
1
			assert_noop!(
706
1
				XcmTransactor::transact_through_signed(
707
1
					RuntimeOrigin::signed(1u64),
708
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
709
1
					CurrencyPayment {
710
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
711
1
						fee_amount: None
712
1
					},
713
1
					vec![1u8],
714
1
					TransactWeights {
715
1
						transact_required_weight_at_most: 100u64.into(),
716
1
						overall_weight: None
717
1
					},
718
1
					false
719
1
				),
720
1
				Error::<Test>::SignedTransactNotAllowedForDestination
721
1
			);
722
1
		})
723
1
}
724

            
725
#[test]
726
1
fn test_transact_through_signed_fails_if_weight_overflows() {
727
1
	ExtBuilder::default()
728
1
		.with_balances(vec![])
729
1
		.build()
730
1
		.execute_with(|| {
731
1
			// Root can set transact info
732
1
			assert_ok!(XcmTransactor::set_transact_info(
733
1
				RuntimeOrigin::root(),
734
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
735
1
				0.into(),
736
1
				10000.into(),
737
1
				Some(Weight::MAX)
738
1
			));
739

            
740
			// weight should overflow
741
1
			assert_noop!(
742
1
				XcmTransactor::transact_through_signed(
743
1
					RuntimeOrigin::signed(1u64),
744
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
745
1
					CurrencyPayment {
746
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
747
1
						fee_amount: None
748
1
					},
749
1
					vec![1u8],
750
1
					TransactWeights {
751
1
						transact_required_weight_at_most: 10064u64.into(),
752
1
						overall_weight: None
753
1
					},
754
1
					false
755
1
				),
756
1
				Error::<Test>::WeightOverflow
757
1
			);
758
1
		})
759
1
}
760

            
761
#[test]
762
1
fn test_transact_through_signed_fails_if_weight_is_bigger_than_max_weight() {
763
1
	ExtBuilder::default()
764
1
		.with_balances(vec![])
765
1
		.build()
766
1
		.execute_with(|| {
767
1
			// Root can set transact info
768
1
			assert_ok!(XcmTransactor::set_transact_info(
769
1
				RuntimeOrigin::root(),
770
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
771
1
				0.into(),
772
1
				10000.into(),
773
1
				Some(1.into())
774
1
			));
775

            
776
			// 10000 + 1 > 10000 (max weight permitted by dest chain)
777
1
			assert_noop!(
778
1
				XcmTransactor::transact_through_signed(
779
1
					RuntimeOrigin::signed(1u64),
780
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
781
1
					CurrencyPayment {
782
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
783
1
						fee_amount: None
784
1
					},
785
1
					vec![1u8],
786
1
					TransactWeights {
787
1
						transact_required_weight_at_most: 100000u64.into(),
788
1
						overall_weight: None
789
1
					},
790
1
					false
791
1
				),
792
1
				Error::<Test>::MaxWeightTransactReached
793
1
			);
794
1
		})
795
1
}
796

            
797
#[test]
798
1
fn test_transact_through_signed_fails_if_fee_per_second_not_set() {
799
1
	ExtBuilder::default()
800
1
		.with_balances(vec![])
801
1
		.build()
802
1
		.execute_with(|| {
803
1
			// Root can set transact info
804
1
			assert_ok!(XcmTransactor::set_transact_info(
805
1
				RuntimeOrigin::root(),
806
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
807
1
				0.into(),
808
1
				10000.into(),
809
1
				Some(1.into())
810
1
			));
811

            
812
			// fee per second not set, fails
813
1
			assert_noop!(
814
1
				XcmTransactor::transact_through_signed(
815
1
					RuntimeOrigin::signed(1u64),
816
1
					Box::new(xcm::VersionedLocation::V4(Location::parent())),
817
1
					CurrencyPayment {
818
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
819
1
						fee_amount: None
820
1
					},
821
1
					vec![1u8],
822
1
					TransactWeights {
823
1
						transact_required_weight_at_most: 100u64.into(),
824
1
						overall_weight: None
825
1
					},
826
1
					false
827
1
				),
828
1
				Error::<Test>::FeePerSecondNotSet
829
1
			);
830
1
		})
831
1
}
832

            
833
#[test]
834
1
fn test_transact_through_signed_works() {
835
1
	ExtBuilder::default()
836
1
		.with_balances(vec![])
837
1
		.build()
838
1
		.execute_with(|| {
839
1
			// Root can set transact info
840
1
			assert_ok!(XcmTransactor::set_transact_info(
841
1
				RuntimeOrigin::root(),
842
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
843
1
				0.into(),
844
1
				10000.into(),
845
1
				Some(1.into())
846
1
			));
847

            
848
			// Set fee per second
849
1
			assert_ok!(XcmTransactor::set_fee_per_second(
850
1
				RuntimeOrigin::root(),
851
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
852
1
				1
853
1
			));
854

            
855
			// transact info and fee per second set
856
			// this time it should work
857
1
			assert_ok!(XcmTransactor::transact_through_signed(
858
1
				RuntimeOrigin::signed(1u64),
859
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
860
1
				CurrencyPayment {
861
1
					currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
862
1
					fee_amount: None
863
1
				},
864
1
				vec![1u8],
865
1
				TransactWeights {
866
1
					transact_required_weight_at_most: 100u64.into(),
867
1
					overall_weight: None
868
1
				},
869
1
				false
870
1
			));
871

            
872
1
			let expected = vec![
873
1
				crate::Event::TransactInfoChanged {
874
1
					location: Location::parent(),
875
1
					remote_info: RemoteTransactInfoWithMaxWeight {
876
1
						transact_extra_weight: 0.into(),
877
1
						max_weight: 10000.into(),
878
1
						transact_extra_weight_signed: Some(1.into()),
879
1
					},
880
1
				},
881
1
				crate::Event::DestFeePerSecondChanged {
882
1
					location: Location::parent(),
883
1
					fee_per_second: 1,
884
1
				},
885
1
				crate::Event::TransactedSigned {
886
1
					fee_payer: 1u64,
887
1
					dest: Location::parent(),
888
1
					call: vec![1u8],
889
1
				},
890
1
			];
891
1
			assert_eq!(events(), expected);
892
1
		})
893
1
}
894

            
895
#[test]
896
1
fn test_send_through_derivative_with_custom_weight_and_fee() {
897
1
	ExtBuilder::default()
898
1
		.with_balances(vec![])
899
1
		.build()
900
1
		.execute_with(|| {
901
1
			// Root can register
902
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
903

            
904
			// We are gonna use a total weight of 10_100, a tx weight of 100,
905
			// and a total fee of 100
906
1
			let total_weight: Weight = 10_100u64.into();
907
1
			let tx_weight: Weight = 100_u64.into();
908
1
			let total_fee = 100u128;
909
1

            
910
1
			// By specifying total fee and total weight, we ensure
911
1
			// that even if the transact_info is not populated,
912
1
			// the message is forged with our parameters
913
1
			assert_ok!(XcmTransactor::transact_through_derivative(
914
1
				RuntimeOrigin::signed(1u64),
915
1
				Transactors::Relay,
916
1
				1,
917
1
				CurrencyPayment {
918
1
					currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
919
1
					fee_amount: Some(total_fee)
920
1
				},
921
1
				vec![1u8],
922
1
				TransactWeights {
923
1
					transact_required_weight_at_most: tx_weight,
924
1
					overall_weight: Some(Limited(total_weight))
925
1
				},
926
1
				false
927
1
			));
928
1
			let expected = vec![
929
1
				crate::Event::RegisteredDerivative {
930
1
					account_id: 1u64,
931
1
					index: 1,
932
1
				},
933
1
				crate::Event::TransactedDerivative {
934
1
					account_id: 1u64,
935
1
					dest: Location::parent(),
936
1
					call: Transactors::Relay
937
1
						.encode_call(UtilityAvailableCalls::AsDerivative(1, vec![1u8])),
938
1
					index: 1,
939
1
				},
940
1
			];
941
1
			assert_eq!(events(), expected);
942
1
			let sent_messages = mock::sent_xcm();
943
1
			let (_, sent_message) = sent_messages.first().unwrap();
944
1
			// Lets make sure the message is as expected
945
1
			assert!(sent_message
946
1
				.0
947
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
948
1
			assert!(sent_message.0.contains(&BuyExecution {
949
1
				fees: (Location::here(), total_fee).into(),
950
1
				weight_limit: Limited(total_weight),
951
1
			}));
952
1
			assert!(sent_message.0.contains(&Transact {
953
1
				origin_kind: OriginKind::SovereignAccount,
954
1
				require_weight_at_most: tx_weight,
955
1
				call: Transactors::Relay
956
1
					.encode_call(UtilityAvailableCalls::AsDerivative(1, vec![1u8]))
957
1
					.into(),
958
1
			}));
959
1
		})
960
1
}
961

            
962
#[test]
963
1
fn test_send_through_sovereign_with_custom_weight_and_fee() {
964
1
	ExtBuilder::default()
965
1
		.with_balances(vec![])
966
1
		.build()
967
1
		.execute_with(|| {
968
1
			// Root can register
969
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
970

            
971
			// We are gonna use a total weight of 10_100, a tx weight of 100,
972
			// and a total fee of 100
973
1
			let total_weight: Weight = 10_100u64.into();
974
1
			let tx_weight: Weight = 100_u64.into();
975
1
			let total_fee = 100u128;
976
1

            
977
1
			// By specifying total fee and total weight, we ensure
978
1
			// that even if the transact_info is not populated,
979
1
			// the message is forged with our parameters
980
1

            
981
1
			// fee as destination are the same, this time it should work
982
1
			assert_ok!(XcmTransactor::transact_through_sovereign(
983
1
				RuntimeOrigin::root(),
984
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
985
1
				Some(1u64),
986
1
				CurrencyPayment {
987
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
988
1
						Location::parent()
989
1
					))),
990
1
					fee_amount: Some(total_fee)
991
1
				},
992
1
				vec![1u8],
993
1
				OriginKind::SovereignAccount,
994
1
				TransactWeights {
995
1
					transact_required_weight_at_most: tx_weight,
996
1
					overall_weight: Some(Limited(total_weight))
997
1
				},
998
1
				false
999
1
			));
1
			let expected = vec![
1
				crate::Event::RegisteredDerivative {
1
					account_id: 1u64,
1
					index: 1,
1
				},
1
				crate::Event::TransactedSovereign {
1
					fee_payer: Some(1u64),
1
					dest: Location::parent(),
1
					call: vec![1u8],
1
				},
1
			];
1
			assert_eq!(events(), expected);
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::SovereignAccount,
1
				require_weight_at_most: tx_weight,
1
				call: vec![1u8].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_transact_through_sovereign_with_fee_payer_none() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// Root can register
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			assert_ok!(XcmTransactor::transact_through_sovereign(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				// We don't specify any fee_payer, instead we pay fees with the
1
				// sovereign account funds directly on the destination.
1
				None,
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				vec![1u8],
1
				OriginKind::SovereignAccount,
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				},
1
				false
1
			));
1
			let expected = vec![
1
				crate::Event::RegisteredDerivative {
1
					account_id: 1u64,
1
					index: 1,
1
				},
1
				crate::Event::TransactedSovereign {
1
					fee_payer: None,
1
					dest: Location::parent(),
1
					call: vec![1u8],
1
				},
1
			];
1
			assert_eq!(events(), expected);
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected even if we haven't indicated a
1
			// fee_payer.
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::SovereignAccount,
1
				require_weight_at_most: tx_weight,
1
				call: vec![1u8].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_send_through_signed_with_custom_weight_and_fee() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			// By specifying total fee and total weight, we ensure
1
			// that even if the transact_info is not populated,
1
			// the message is forged with our parameters
1

            
1
			// fee as destination are the same, this time it should work
1
			assert_ok!(XcmTransactor::transact_through_signed(
1
				RuntimeOrigin::signed(1u64),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				vec![1u8],
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				},
1
				false
1
			));
1
			let expected = vec![crate::Event::TransactedSigned {
1
				fee_payer: 1u64,
1
				dest: Location::parent(),
1
				call: vec![1u8],
1
			}];
1
			assert_eq!(events(), expected);
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::SovereignAccount,
1
				require_weight_at_most: tx_weight,
1
				call: vec![1u8].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_init() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::InitOpen(HrmpInitParams {
1
					para_id: 1u32.into(),
1
					proposed_max_capacity: 1,
1
					proposed_max_message_size: 1
1
				}),
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_init_v2_convert_works() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			// Change xcm version
1
			CustomVersionWrapper::set_version(2);
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::InitOpen(HrmpInitParams {
1
					para_id: 1u32.into(),
1
					proposed_max_capacity: 1,
1
					proposed_max_message_size: 1
1
				}),
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0].into(),
1
			}));
			// Check message contains the new appendix
1
			assert!(sent_message.0.contains(&SetAppendix(Xcm(vec![
1
				RefundSurplus,
1
				DepositAsset {
1
					assets: Wild(AllCounted(1)),
1
					beneficiary: Location {
1
						parents: 0,
1
						interior: [Junction::Parachain(100)].into()
1
					}
1
				}
1
			]))));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_init_v3_convert_works() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			// Change xcm version
1
			CustomVersionWrapper::set_version(3);
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::InitOpen(HrmpInitParams {
1
					para_id: 1u32.into(),
1
					proposed_max_capacity: 1,
1
					proposed_max_message_size: 1
1
				}),
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0].into(),
1
			}));
			// Check message contains the new appendix
1
			assert!(sent_message.0.contains(&SetAppendix(Xcm(vec![
1
				RefundSurplus,
1
				DepositAsset {
1
					assets: Wild(AllCounted(1)),
1
					beneficiary: Location {
1
						parents: 0,
1
						interior: [Junction::Parachain(100)].into()
1
					}
1
				}
1
			]))));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_init_v5_convert_fails() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			// Change xcm version
1
			CustomVersionWrapper::set_version(5);
1

            
1
			assert_noop!(
1
				XcmTransactor::hrmp_manage(
1
					RuntimeOrigin::root(),
1
					HrmpOperation::InitOpen(HrmpInitParams {
1
						para_id: 1u32.into(),
1
						proposed_max_capacity: 1,
1
						proposed_max_message_size: 1
1
					}),
1
					CurrencyPayment {
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
							Location::parent()
1
						))),
1
						fee_amount: Some(total_fee)
1
					},
1
					TransactWeights {
1
						transact_required_weight_at_most: tx_weight,
1
						overall_weight: Some(Limited(total_weight))
1
					}
1
				),
1
				Error::<Test>::ErrorValidating
1
			);
1
		})
1
}
#[test]
1
fn test_hrmp_max_fee_errors() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 10_000_000_000_000u128;
1

            
1
			assert_noop!(
1
				XcmTransactor::hrmp_manage(
1
					RuntimeOrigin::root(),
1
					HrmpOperation::InitOpen(HrmpInitParams {
1
						para_id: 1u32.into(),
1
						proposed_max_capacity: 1,
1
						proposed_max_message_size: 1
1
					}),
1
					CurrencyPayment {
1
						currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
							Location::parent()
1
						))),
1
						fee_amount: Some(total_fee)
1
					},
1
					TransactWeights {
1
						transact_required_weight_at_most: tx_weight,
1
						overall_weight: Some(Limited(total_weight))
1
					}
1
				),
1
				Error::<Test>::TooMuchFeeUsed
1
			);
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_accept() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::Accept {
1
					para_id: 1u32.into()
1
				},
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_cancel() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1
			let channel_id = HrmpChannelId {
1
				sender: 1u32.into(),
1
				recipient: 1u32.into(),
1
			};
1
			let open_requests: u32 = 1;
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::Cancel {
1
					channel_id,
1
					open_requests
1
				},
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_hrmp_manipulator_close() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// We are gonna use a total weight of 10_100, a tx weight of 100,
1
			// and a total fee of 100
1
			let total_weight: Weight = 10_100u64.into();
1
			let tx_weight: Weight = 100_u64.into();
1
			let total_fee = 100u128;
1

            
1
			assert_ok!(XcmTransactor::hrmp_manage(
1
				RuntimeOrigin::root(),
1
				HrmpOperation::Close(HrmpChannelId {
1
					sender: 1u32.into(),
1
					recipient: 1u32.into()
1
				}),
1
				CurrencyPayment {
1
					currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4(
1
						Location::parent()
1
					))),
1
					fee_amount: Some(total_fee)
1
				},
1
				TransactWeights {
1
					transact_required_weight_at_most: tx_weight,
1
					overall_weight: Some(Limited(total_weight))
1
				}
1
			));
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1
			// Lets make sure the message is as expected
1
			assert!(sent_message
1
				.0
1
				.contains(&WithdrawAsset((Location::here(), total_fee).into())));
1
			assert!(sent_message.0.contains(&BuyExecution {
1
				fees: (Location::here(), total_fee).into(),
1
				weight_limit: Limited(total_weight),
1
			}));
1
			assert!(sent_message.0.contains(&Transact {
1
				origin_kind: OriginKind::Native,
1
				require_weight_at_most: tx_weight,
1
				call: vec![0, 0, 1, 0, 0, 0, 1, 0, 0, 0].into(),
1
			}));
1
		})
1
}
#[test]
1
fn test_transact_through_derivative_with_refund_works() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// Root can register
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_transact_info(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				0.into(),
1
				10000.into(),
1
				None
1
			));
			// Set fee per second
1
			assert_ok!(XcmTransactor::set_fee_per_second(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				1
1
			));
			// fee as destination are the same, this time it should work
1
			assert_ok!(XcmTransactor::transact_through_derivative(
1
				RuntimeOrigin::signed(1u64),
1
				Transactors::Relay,
1
				1,
1
				CurrencyPayment {
1
					currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
1
					fee_amount: None
1
				},
1
				vec![1u8],
1
				TransactWeights {
1
					transact_required_weight_at_most: 100u64.into(),
1
					overall_weight: Some(Limited(1000.into()))
1
				},
1
				true
1
			));
1
			let expected = vec![
1
				crate::Event::RegisteredDerivative {
1
					account_id: 1u64,
1
					index: 1,
1
				},
1
				crate::Event::TransactInfoChanged {
1
					location: Location::parent(),
1
					remote_info: RemoteTransactInfoWithMaxWeight {
1
						transact_extra_weight: 0.into(),
1
						max_weight: 10000.into(),
1
						transact_extra_weight_signed: None,
1
					},
1
				},
1
				crate::Event::DestFeePerSecondChanged {
1
					location: Location::parent(),
1
					fee_per_second: 1,
1
				},
1
				crate::Event::TransactedDerivative {
1
					account_id: 1u64,
1
					dest: Location::parent(),
1
					call: Transactors::Relay
1
						.encode_call(UtilityAvailableCalls::AsDerivative(1, vec![1u8])),
1
					index: 1,
1
				},
1
			];
1
			assert_eq!(events(), expected);
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1

            
1
			// Check message contains the new appendix
1
			assert!(sent_message.0.contains(&SetAppendix(Xcm(vec![
1
				RefundSurplus,
1
				DepositAsset {
1
					assets: Wild(AllCounted(1u32)),
1
					beneficiary: Location {
1
						parents: 0,
1
						interior: [Junction::Parachain(100)].into()
1
					}
1
				}
1
			]))));
1
		})
1
}
#[test]
1
fn test_transact_through_derivative_with_refund_fails_overall_weight_not_set() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// Root can register
1
			assert_ok!(XcmTransactor::register(RuntimeOrigin::root(), 1u64, 1));
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_transact_info(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				0.into(),
1
				10000.into(),
1
				None
1
			));
			// Set fee per second
1
			assert_ok!(XcmTransactor::set_fee_per_second(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				1
1
			));
			// fee as destination are the same, this time it should work
1
			assert_noop!(
1
				XcmTransactor::transact_through_derivative(
1
					RuntimeOrigin::signed(1u64),
1
					Transactors::Relay,
1
					1,
1
					CurrencyPayment {
1
						currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
1
						fee_amount: None
1
					},
1
					vec![1u8],
1
					TransactWeights {
1
						transact_required_weight_at_most: 100u64.into(),
1
						overall_weight: None
1
					},
1
					true
1
				),
1
				Error::<Test>::RefundNotSupportedWithTransactInfo
1
			);
1
		})
1
}
#[test]
1
fn test_transact_through_signed_with_refund_works() {
1
	ExtBuilder::default()
1
		.with_balances(vec![])
1
		.build()
1
		.execute_with(|| {
1
			// Set fee per second
1
			assert_ok!(XcmTransactor::set_fee_per_second(
1
				RuntimeOrigin::root(),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				1
1
			));
			// Overall weight to use
1
			let total_weight: Weight = 10_100u64.into();
1
			assert_ok!(XcmTransactor::transact_through_signed(
1
				RuntimeOrigin::signed(1u64),
1
				Box::new(xcm::VersionedLocation::V4(Location::parent())),
1
				CurrencyPayment {
1
					currency: Currency::AsCurrencyId(CurrencyId::OtherReserve(0)),
1
					fee_amount: None
1
				},
1
				vec![1u8],
1
				TransactWeights {
1
					transact_required_weight_at_most: 100u64.into(),
1
					overall_weight: Some(Limited(total_weight))
1
				},
1
				true
1
			));
1
			let expected = vec![
1
				crate::Event::DestFeePerSecondChanged {
1
					location: Location::parent(),
1
					fee_per_second: 1,
1
				},
1
				crate::Event::TransactedSigned {
1
					fee_payer: 1u64,
1
					dest: Location::parent(),
1
					call: vec![1u8],
1
				},
1
			];
1
			assert_eq!(events(), expected);
1
			let sent_messages = mock::sent_xcm();
1
			let (_, sent_message) = sent_messages.first().unwrap();
1

            
1
			// Check message contains the new appendix
1
			assert!(sent_message.0.contains(&SetAppendix(Xcm(vec![
1
				RefundSurplus,
1
				DepositAsset {
1
					assets: Wild(AllCounted(1u32)),
1
					beneficiary: Location {
1
						parents: 0,
1
						interior: [
1
							Junction::Parachain(100),
1
							AccountIdToLocation::convert(1)
1
								.interior
1
								.take_first()
1
								.unwrap()
1
						]
1
						.into()
1
					}
1
				}
1
			]))));
1
		})
1
}