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

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

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

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

            
17
//! Moonbase Runtime Integration Tests
18

            
19
mod common;
20
use common::*;
21

            
22
use precompile_utils::{
23
	precompile_set::{is_precompile_or_fail, IsActivePrecompile},
24
	prelude::*,
25
	testing::*,
26
};
27

            
28
use fp_evm::{Context, IsPrecompileResult};
29
use frame_support::{
30
	assert_noop, assert_ok,
31
	dispatch::DispatchClass,
32
	traits::{
33
		Contains, Currency as CurrencyT, EnsureOrigin, OnInitialize, PalletInfo, StorageInfo,
34
		StorageInfoTrait,
35
	},
36
	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
37
	StorageHasher, Twox128,
38
};
39
use moonbase_runtime::xcm_config::{AssetHubLocation, XcmExecutor};
40
use moonbase_runtime::{
41
	moonbase_xcm_weights, xcm_config::SelfReserve, AccountId, AssetId, Balances, EvmForeignAssets,
42
	Executive, NormalFilter, OpenTechCommitteeCollective, ParachainStaking, PolkadotXcm,
43
	Precompiles, ProxyType, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent, System,
44
	TransactionPayment, TransactionPaymentAsGasPrice, Treasury, TreasuryCouncilCollective,
45
	XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, WEIGHT_PER_GAS,
46
};
47
use polkadot_parachain::primitives::Sibling;
48
use precompile_utils::testing::MockHandle;
49
use sp_runtime::{
50
	traits::{Convert as XcmConvert, Dispatchable},
51
	BuildStorage, Percent,
52
};
53
use std::str::from_utf8;
54
use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia};
55
use xcm_executor::traits::ConvertLocation;
56

            
57
use moonbase_runtime::currency::{GIGAWEI, WEI};
58
use moonbase_runtime::runtime_params::dynamic_params;
59
use moonbase_runtime::xcm_config::LocationToAccountId;
60
use moonbase_xcm_weights::XcmWeight;
61
use moonkit_xcm_primitives::AccountIdAssetIdConversion;
62
use nimbus_primitives::NimbusId;
63
use pallet_evm::PrecompileSet;
64
use pallet_moonbeam_foreign_assets::AssetStatus;
65
use pallet_parachain_staking::InflationDistributionAccount;
66
use pallet_transaction_payment::Multiplier;
67
use pallet_xcm_transactor::{Currency, CurrencyPayment, HrmpOperation, TransactWeights};
68
use parity_scale_codec::Encode;
69
use sp_core::{crypto::UncheckedFrom, ByteArray, Get, H160, H256, U256};
70
use sp_runtime::{bounded_vec, DispatchError, ModuleError};
71
use std::cell::Cell;
72
use std::rc::Rc;
73
use xcm::{latest::prelude::*, VersionedAssets, VersionedLocation};
74

            
75
type AuthorMappingPCall =
76
	pallet_evm_precompile_author_mapping::AuthorMappingPrecompileCall<Runtime>;
77
type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall<Runtime>;
78
type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall<
79
	Runtime,
80
	moonbase_runtime::xcm_config::XcmExecutorConfig,
81
>;
82
type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall<Runtime>;
83
/*type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall<
84
	Runtime,
85
	ForeignAssetInstance,
86
>;*/
87
type XcmTransactorV1PCall =
88
	pallet_evm_precompile_xcm_transactor::v1::XcmTransactorPrecompileV1Call<Runtime>;
89
type XcmTransactorV2PCall =
90
	pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call<Runtime>;
91

            
92
// TODO: can we construct a const U256...?
93
const BASE_FEE_GENISIS: u128 = 10 * GIGAWEI / 4;
94

            
95
#[test]
96
1
fn xcmp_queue_controller_origin_is_root() {
97
1
	// important for the XcmExecutionManager impl of PauseExecution which uses root origin
98
1
	// to suspend/resume XCM execution in xcmp_queue::on_idle
99
1
	assert_ok!(
100
1
		<moonbase_runtime::Runtime as cumulus_pallet_xcmp_queue::Config
101
1
		>::ControllerOrigin::ensure_origin(root_origin())
102
1
	);
103
1
}
104

            
105
#[test]
106
1
fn verify_pallet_prefixes() {
107
29
	fn is_pallet_prefix<P: 'static>(name: &str) {
108
29
		// Compares the unhashed pallet prefix in the `StorageInstance` implementation by every
109
29
		// storage item in the pallet P. This pallet prefix is used in conjunction with the
110
29
		// item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName)
111
29
		// https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/
112
29
		// expand/storage.rs#L389-L401
113
29
		assert_eq!(
114
29
			<moonbase_runtime::Runtime as frame_system::Config>::PalletInfo::name::<P>(),
115
29
			Some(name)
116
29
		);
117
29
	}
118
	// TODO: use StorageInfoTrait from https://github.com/paritytech/substrate/pull/9246
119
	// This is now available with polkadot-v0.9.9 dependencies
120
1
	is_pallet_prefix::<moonbase_runtime::System>("System");
121
1
	is_pallet_prefix::<moonbase_runtime::Utility>("Utility");
122
1
	is_pallet_prefix::<moonbase_runtime::ParachainSystem>("ParachainSystem");
123
1
	is_pallet_prefix::<moonbase_runtime::TransactionPayment>("TransactionPayment");
124
1
	is_pallet_prefix::<moonbase_runtime::ParachainInfo>("ParachainInfo");
125
1
	is_pallet_prefix::<moonbase_runtime::EthereumChainId>("EthereumChainId");
126
1
	is_pallet_prefix::<moonbase_runtime::EVM>("EVM");
127
1
	is_pallet_prefix::<moonbase_runtime::Ethereum>("Ethereum");
128
1
	is_pallet_prefix::<moonbase_runtime::ParachainStaking>("ParachainStaking");
129
1
	is_pallet_prefix::<moonbase_runtime::Scheduler>("Scheduler");
130
1
	is_pallet_prefix::<moonbase_runtime::Treasury>("Treasury");
131
1
	is_pallet_prefix::<moonbase_runtime::OpenTechCommitteeCollective>(
132
1
		"OpenTechCommitteeCollective",
133
1
	);
134
1
	is_pallet_prefix::<moonbase_runtime::AuthorInherent>("AuthorInherent");
135
1
	is_pallet_prefix::<moonbase_runtime::AuthorFilter>("AuthorFilter");
136
1
	is_pallet_prefix::<moonbase_runtime::CrowdloanRewards>("CrowdloanRewards");
137
1
	is_pallet_prefix::<moonbase_runtime::AuthorMapping>("AuthorMapping");
138
1
	is_pallet_prefix::<moonbase_runtime::MaintenanceMode>("MaintenanceMode");
139
1
	is_pallet_prefix::<moonbase_runtime::Identity>("Identity");
140
1
	is_pallet_prefix::<moonbase_runtime::XcmpQueue>("XcmpQueue");
141
1
	is_pallet_prefix::<moonbase_runtime::CumulusXcm>("CumulusXcm");
142
1
	is_pallet_prefix::<moonbase_runtime::PolkadotXcm>("PolkadotXcm");
143
1
	is_pallet_prefix::<moonbase_runtime::XcmTransactor>("XcmTransactor");
144
1
	is_pallet_prefix::<moonbase_runtime::ProxyGenesisCompanion>("ProxyGenesisCompanion");
145
1
	is_pallet_prefix::<moonbase_runtime::MoonbeamOrbiters>("MoonbeamOrbiters");
146
1
	is_pallet_prefix::<moonbase_runtime::EthereumXcm>("EthereumXcm");
147
1
	is_pallet_prefix::<moonbase_runtime::Randomness>("Randomness");
148
1
	is_pallet_prefix::<moonbase_runtime::TreasuryCouncilCollective>("TreasuryCouncilCollective");
149
1
	is_pallet_prefix::<moonbase_runtime::MoonbeamLazyMigrations>("MoonbeamLazyMigrations");
150
1
	is_pallet_prefix::<moonbase_runtime::RelayStorageRoots>("RelayStorageRoots");
151
1

            
152
13
	let prefix = |pallet_name, storage_name| {
153
13
		let mut res = [0u8; 32];
154
13
		res[0..16].copy_from_slice(&Twox128::hash(pallet_name));
155
13
		res[16..32].copy_from_slice(&Twox128::hash(storage_name));
156
13
		res.to_vec()
157
13
	};
158
1
	assert_eq!(
159
1
		<moonbase_runtime::Balances as StorageInfoTrait>::storage_info(),
160
1
		vec![
161
1
			StorageInfo {
162
1
				pallet_name: b"Balances".to_vec(),
163
1
				storage_name: b"TotalIssuance".to_vec(),
164
1
				prefix: prefix(b"Balances", b"TotalIssuance"),
165
1
				max_values: Some(1),
166
1
				max_size: Some(16),
167
1
			},
168
1
			StorageInfo {
169
1
				pallet_name: b"Balances".to_vec(),
170
1
				storage_name: b"InactiveIssuance".to_vec(),
171
1
				prefix: prefix(b"Balances", b"InactiveIssuance"),
172
1
				max_values: Some(1),
173
1
				max_size: Some(16),
174
1
			},
175
1
			StorageInfo {
176
1
				pallet_name: b"Balances".to_vec(),
177
1
				storage_name: b"Account".to_vec(),
178
1
				prefix: prefix(b"Balances", b"Account"),
179
1
				max_values: None,
180
1
				max_size: Some(100),
181
1
			},
182
1
			StorageInfo {
183
1
				pallet_name: b"Balances".to_vec(),
184
1
				storage_name: b"Locks".to_vec(),
185
1
				prefix: prefix(b"Balances", b"Locks"),
186
1
				max_values: None,
187
1
				max_size: Some(1287),
188
1
			},
189
1
			StorageInfo {
190
1
				pallet_name: b"Balances".to_vec(),
191
1
				storage_name: b"Reserves".to_vec(),
192
1
				prefix: prefix(b"Balances", b"Reserves"),
193
1
				max_values: None,
194
1
				max_size: Some(1037),
195
1
			},
196
1
			StorageInfo {
197
1
				pallet_name: b"Balances".to_vec(),
198
1
				storage_name: b"Holds".to_vec(),
199
1
				prefix: prefix(b"Balances", b"Holds"),
200
1
				max_values: None,
201
1
				max_size: Some(55),
202
1
			},
203
1
			StorageInfo {
204
1
				pallet_name: b"Balances".to_vec(),
205
1
				storage_name: b"Freezes".to_vec(),
206
1
				prefix: prefix(b"Balances", b"Freezes"),
207
1
				max_values: None,
208
1
				max_size: Some(73),
209
1
			},
210
1
		]
211
1
	);
212
1
	assert_eq!(
213
1
		<moonbase_runtime::Sudo as StorageInfoTrait>::storage_info(),
214
1
		vec![StorageInfo {
215
1
			pallet_name: b"Sudo".to_vec(),
216
1
			storage_name: b"Key".to_vec(),
217
1
			prefix: prefix(b"Sudo", b"Key"),
218
1
			max_values: Some(1),
219
1
			max_size: Some(20),
220
1
		}]
221
1
	);
222
1
	assert_eq!(
223
1
		<moonbase_runtime::Proxy as StorageInfoTrait>::storage_info(),
224
1
		vec![
225
1
			StorageInfo {
226
1
				pallet_name: b"Proxy".to_vec(),
227
1
				storage_name: b"Proxies".to_vec(),
228
1
				prefix: prefix(b"Proxy", b"Proxies"),
229
1
				max_values: None,
230
1
				max_size: Some(845),
231
1
			},
232
1
			StorageInfo {
233
1
				pallet_name: b"Proxy".to_vec(),
234
1
				storage_name: b"Announcements".to_vec(),
235
1
				prefix: prefix(b"Proxy", b"Announcements"),
236
1
				max_values: None,
237
1
				max_size: Some(1837),
238
1
			}
239
1
		]
240
1
	);
241
1
	assert_eq!(
242
1
		<moonbase_runtime::MaintenanceMode as StorageInfoTrait>::storage_info(),
243
1
		vec![StorageInfo {
244
1
			pallet_name: b"MaintenanceMode".to_vec(),
245
1
			storage_name: b"MaintenanceMode".to_vec(),
246
1
			prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"),
247
1
			max_values: Some(1),
248
1
			max_size: None,
249
1
		},]
250
1
	);
251

            
252
1
	assert_eq!(
253
1
		<moonbase_runtime::RelayStorageRoots as StorageInfoTrait>::storage_info(),
254
1
		vec![
255
1
			StorageInfo {
256
1
				pallet_name: b"RelayStorageRoots".to_vec(),
257
1
				storage_name: b"RelayStorageRoot".to_vec(),
258
1
				prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"),
259
1
				max_values: None,
260
1
				max_size: Some(44),
261
1
			},
262
1
			StorageInfo {
263
1
				pallet_name: b"RelayStorageRoots".to_vec(),
264
1
				storage_name: b"RelayStorageRootKeys".to_vec(),
265
1
				prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"),
266
1
				max_values: Some(1),
267
1
				max_size: Some(121),
268
1
			},
269
1
		]
270
1
	);
271
1
}
272

            
273
#[test]
274
1
fn test_collectives_storage_item_prefixes() {
275
7
	for StorageInfo { pallet_name, .. } in
276
8
		<moonbase_runtime::TreasuryCouncilCollective as StorageInfoTrait>::storage_info()
277
	{
278
7
		assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec());
279
	}
280

            
281
7
	for StorageInfo { pallet_name, .. } in
282
8
		<moonbase_runtime::OpenTechCommitteeCollective as StorageInfoTrait>::storage_info()
283
	{
284
7
		assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec());
285
	}
286
1
}
287

            
288
#[test]
289
1
fn collective_set_members_root_origin_works() {
290
1
	ExtBuilder::default().build().execute_with(|| {
291
1
		// TreasuryCouncilCollective
292
1
		assert_ok!(TreasuryCouncilCollective::set_members(
293
1
			<Runtime as frame_system::Config>::RuntimeOrigin::root(),
294
1
			vec![AccountId::from(ALICE), AccountId::from(BOB)],
295
1
			Some(AccountId::from(ALICE)),
296
1
			2
297
1
		));
298
		// OpenTechCommitteeCollective
299
1
		assert_ok!(OpenTechCommitteeCollective::set_members(
300
1
			<Runtime as frame_system::Config>::RuntimeOrigin::root(),
301
1
			vec![AccountId::from(ALICE), AccountId::from(BOB)],
302
1
			Some(AccountId::from(ALICE)),
303
1
			2
304
1
		));
305
1
	});
306
1
}
307

            
308
#[test]
309
1
fn collective_set_members_general_admin_origin_works() {
310
	use moonbase_runtime::{
311
		governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility,
312
	};
313

            
314
1
	ExtBuilder::default().build().execute_with(|| {
315
1
		let root_caller = <Runtime as frame_system::Config>::RuntimeOrigin::root();
316
1
		let alice = AccountId::from(ALICE);
317
1

            
318
1
		// TreasuryCouncilCollective
319
1
		let _ = Utility::dispatch_as(
320
1
			root_caller.clone(),
321
1
			Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)),
322
1
			Box::new(
323
1
				pallet_collective::Call::<Runtime, pallet_collective::Instance3>::set_members {
324
1
					new_members: vec![alice, AccountId::from(BOB)],
325
1
					prime: Some(alice),
326
1
					old_count: 2,
327
1
				}
328
1
				.into(),
329
1
			),
330
1
		);
331
1
		// OpenTechCommitteeCollective
332
1
		let _ = Utility::dispatch_as(
333
1
			root_caller,
334
1
			Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)),
335
1
			Box::new(
336
1
				pallet_collective::Call::<Runtime, pallet_collective::Instance4>::set_members {
337
1
					new_members: vec![alice, AccountId::from(BOB)],
338
1
					prime: Some(alice),
339
1
					old_count: 2,
340
1
				}
341
1
				.into(),
342
1
			),
343
1
		);
344
1

            
345
1
		assert_eq!(
346
1
			System::events()
347
1
				.into_iter()
348
2
				.filter_map(|r| {
349
2
					match r.event {
350
2
						RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result })
351
2
							if result.is_ok() =>
352
2
						{
353
2
							Some(true)
354
						}
355
						_ => None,
356
					}
357
2
				})
358
1
				.collect::<Vec<_>>()
359
1
				.len(),
360
1
			2
361
1
		)
362
1
	});
363
1
}
364

            
365
#[test]
366
1
fn collective_set_members_signed_origin_does_not_work() {
367
1
	let alice = AccountId::from(ALICE);
368
1
	ExtBuilder::default().build().execute_with(|| {
369
1
		// TreasuryCouncilCollective
370
1
		assert!(TreasuryCouncilCollective::set_members(
371
1
			<Runtime as frame_system::Config>::RuntimeOrigin::signed(alice),
372
1
			vec![AccountId::from(ALICE), AccountId::from(BOB)],
373
1
			Some(AccountId::from(ALICE)),
374
1
			2
375
1
		)
376
1
		.is_err());
377
		// OpenTechCommitteeCollective
378
1
		assert!(OpenTechCommitteeCollective::set_members(
379
1
			<Runtime as frame_system::Config>::RuntimeOrigin::signed(alice),
380
1
			vec![AccountId::from(ALICE), AccountId::from(BOB)],
381
1
			Some(AccountId::from(ALICE)),
382
1
			2
383
1
		)
384
1
		.is_err());
385
1
	});
386
1
}
387

            
388
#[test]
389
1
fn verify_pallet_indices() {
390
31
	fn is_pallet_index<P: 'static>(index: usize) {
391
31
		assert_eq!(
392
31
			<moonbase_runtime::Runtime as frame_system::Config>::PalletInfo::index::<P>(),
393
31
			Some(index)
394
31
		);
395
31
	}
396
1
	is_pallet_index::<moonbase_runtime::System>(0);
397
1
	is_pallet_index::<moonbase_runtime::Utility>(1);
398
1
	is_pallet_index::<moonbase_runtime::Balances>(3);
399
1
	is_pallet_index::<moonbase_runtime::Sudo>(4);
400
1
	is_pallet_index::<moonbase_runtime::ParachainSystem>(6);
401
1
	is_pallet_index::<moonbase_runtime::TransactionPayment>(7);
402
1
	is_pallet_index::<moonbase_runtime::ParachainInfo>(8);
403
1
	is_pallet_index::<moonbase_runtime::EthereumChainId>(9);
404
1
	is_pallet_index::<moonbase_runtime::EVM>(10);
405
1
	is_pallet_index::<moonbase_runtime::Ethereum>(11);
406
1
	is_pallet_index::<moonbase_runtime::ParachainStaking>(12);
407
1
	is_pallet_index::<moonbase_runtime::Scheduler>(13);
408
1
	//is_pallet_index::<moonbase_runtime::Democracy>(14); Removed
409
1
	is_pallet_index::<moonbase_runtime::Treasury>(17);
410
1
	is_pallet_index::<moonbase_runtime::AuthorInherent>(18);
411
1
	is_pallet_index::<moonbase_runtime::AuthorFilter>(19);
412
1
	is_pallet_index::<moonbase_runtime::CrowdloanRewards>(20);
413
1
	is_pallet_index::<moonbase_runtime::AuthorMapping>(21);
414
1
	is_pallet_index::<moonbase_runtime::Proxy>(22);
415
1
	is_pallet_index::<moonbase_runtime::MaintenanceMode>(23);
416
1
	is_pallet_index::<moonbase_runtime::Identity>(24);
417
1
	is_pallet_index::<moonbase_runtime::XcmpQueue>(25);
418
1
	is_pallet_index::<moonbase_runtime::CumulusXcm>(26);
419
1
	is_pallet_index::<moonbase_runtime::PolkadotXcm>(28);
420
1
	// is_pallet_index::<moonbase_runtime::Assets>(29); Removed
421
1
	// is_pallet_index::<moonbase_runtime::XTokens>(30); Removed
422
1
	// is_pallet_index::<moonbase_runtime::AssetManager>(31); Removed
423
1
	is_pallet_index::<moonbase_runtime::XcmTransactor>(33);
424
1
	is_pallet_index::<moonbase_runtime::ProxyGenesisCompanion>(34);
425
1
	is_pallet_index::<moonbase_runtime::MoonbeamOrbiters>(37);
426
1
	is_pallet_index::<moonbase_runtime::EthereumXcm>(38);
427
1
	is_pallet_index::<moonbase_runtime::Randomness>(39);
428
1
	is_pallet_index::<moonbase_runtime::TreasuryCouncilCollective>(40);
429
1
	is_pallet_index::<moonbase_runtime::OpenTechCommitteeCollective>(46);
430
1
	is_pallet_index::<moonbase_runtime::MoonbeamLazyMigrations>(51);
431
1
}
432

            
433
#[test]
434
1
fn verify_reserved_indices() {
435
	use frame_metadata::*;
436

            
437
1
	let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
438
1
		.build_storage()
439
1
		.unwrap()
440
1
		.into();
441
1

            
442
1
	t.execute_with(|| {
443
1
		let metadata = moonbase_runtime::Runtime::metadata();
444
1
		let metadata = match metadata.1 {
445
1
			RuntimeMetadata::V14(metadata) => metadata,
446
			_ => panic!("metadata has been bumped, test needs to be updated"),
447
		};
448
		// 35: BaseFee
449
		// 36: pallet_assets::<Instance1>
450
1
		let reserved = vec![35, 36];
451
1
		let existing = metadata
452
1
			.pallets
453
1
			.iter()
454
48
			.map(|p| p.index)
455
1
			.collect::<Vec<u8>>();
456
2
		assert!(reserved.iter().all(|index| !existing.contains(index)));
457
1
	});
458
1
}
459

            
460
#[test]
461
1
fn verify_proxy_type_indices() {
462
1
	assert_eq!(moonbase_runtime::ProxyType::Any as u8, 0);
463
1
	assert_eq!(moonbase_runtime::ProxyType::NonTransfer as u8, 1);
464
1
	assert_eq!(moonbase_runtime::ProxyType::Governance as u8, 2);
465
1
	assert_eq!(moonbase_runtime::ProxyType::Staking as u8, 3);
466
1
	assert_eq!(moonbase_runtime::ProxyType::CancelProxy as u8, 4);
467
1
	assert_eq!(moonbase_runtime::ProxyType::Balances as u8, 5);
468
1
	assert_eq!(moonbase_runtime::ProxyType::AuthorMapping as u8, 6);
469
1
	assert_eq!(moonbase_runtime::ProxyType::IdentityJudgement as u8, 7);
470
1
}
471

            
472
// This test ensure that we not filter out pure proxy calls
473
#[test]
474
1
fn verify_normal_filter_allow_pure_proxy() {
475
1
	ExtBuilder::default().build().execute_with(|| {
476
1
		assert!(NormalFilter::contains(&RuntimeCall::Proxy(
477
1
			pallet_proxy::Call::<Runtime>::create_pure {
478
1
				proxy_type: ProxyType::Any,
479
1
				delay: 0,
480
1
				index: 0,
481
1
			}
482
1
		)));
483
1
		assert!(NormalFilter::contains(&RuntimeCall::Proxy(
484
1
			pallet_proxy::Call::<Runtime>::kill_pure {
485
1
				spawner: AccountId::from(ALICE),
486
1
				proxy_type: ProxyType::Any,
487
1
				index: 0,
488
1
				height: 0,
489
1
				ext_index: 0,
490
1
			}
491
1
		)));
492
1
	});
493
1
}
494

            
495
#[test]
496
1
fn join_collator_candidates() {
497
1
	ExtBuilder::default()
498
1
		.with_balances(vec![
499
1
			(AccountId::from(ALICE), 2_000 * UNIT),
500
1
			(AccountId::from(BOB), 2_000 * UNIT),
501
1
			(AccountId::from(CHARLIE), 1_100 * UNIT),
502
1
			(AccountId::from(DAVE), 1_000 * UNIT),
503
1
		])
504
1
		.with_collators(vec![
505
1
			(AccountId::from(ALICE), 1_000 * UNIT),
506
1
			(AccountId::from(BOB), 1_000 * UNIT),
507
1
		])
508
1
		.with_delegations(vec![
509
1
			(AccountId::from(CHARLIE), AccountId::from(ALICE), 50 * UNIT),
510
1
			(AccountId::from(CHARLIE), AccountId::from(BOB), 50 * UNIT),
511
1
		])
512
1
		.build()
513
1
		.execute_with(|| {
514
1
			assert_noop!(
515
1
				ParachainStaking::join_candidates(
516
1
					origin_of(AccountId::from(ALICE)),
517
1
					1_000 * UNIT,
518
1
					2u32
519
1
				),
520
1
				pallet_parachain_staking::Error::<Runtime>::CandidateExists
521
1
			);
522
1
			assert_noop!(
523
1
				ParachainStaking::join_candidates(
524
1
					origin_of(AccountId::from(CHARLIE)),
525
1
					1_000 * UNIT,
526
1
					2u32
527
1
				),
528
1
				pallet_parachain_staking::Error::<Runtime>::DelegatorExists
529
1
			);
530
1
			assert!(System::events().is_empty());
531
1
			assert_ok!(ParachainStaking::join_candidates(
532
1
				origin_of(AccountId::from(DAVE)),
533
1
				1_000 * UNIT,
534
1
				2u32
535
1
			));
536
1
			assert_eq!(
537
1
				last_event(),
538
1
				RuntimeEvent::ParachainStaking(
539
1
					pallet_parachain_staking::Event::JoinedCollatorCandidates {
540
1
						account: AccountId::from(DAVE),
541
1
						amount_locked: 1_000 * UNIT,
542
1
						new_total_amt_locked: 3_100 * UNIT
543
1
					}
544
1
				)
545
1
			);
546
1
			let candidates = ParachainStaking::candidate_pool();
547
1
			assert_eq!(candidates.0[0].owner, AccountId::from(ALICE));
548
1
			assert_eq!(candidates.0[0].amount, 1_050 * UNIT);
549
1
			assert_eq!(candidates.0[1].owner, AccountId::from(BOB));
550
1
			assert_eq!(candidates.0[1].amount, 1_050 * UNIT);
551
1
			assert_eq!(candidates.0[2].owner, AccountId::from(DAVE));
552
1
			assert_eq!(candidates.0[2].amount, 1_000 * UNIT);
553
1
		});
554
1
}
555

            
556
#[test]
557
1
fn transfer_through_evm_to_stake() {
558
1
	ExtBuilder::default()
559
1
		.with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)])
560
1
		.build()
561
1
		.execute_with(|| {
562
1
			// Charlie has no balance => fails to stake
563
1
			assert_noop!(
564
1
				ParachainStaking::join_candidates(
565
1
					origin_of(AccountId::from(CHARLIE)),
566
1
					1_000 * UNIT,
567
1
					0u32
568
1
				),
569
1
				DispatchError::Module(ModuleError {
570
1
					index: 12,
571
1
					error: [8, 0, 0, 0],
572
1
					message: Some("InsufficientBalance")
573
1
				})
574
1
			);
575

            
576
			// Alice transfer from free balance 2000 UNIT to Bob
577
1
			assert_ok!(Balances::transfer_allow_death(
578
1
				origin_of(AccountId::from(ALICE)),
579
1
				AccountId::from(BOB),
580
1
				2_000 * UNIT,
581
1
			));
582
1
			assert_eq!(Balances::free_balance(AccountId::from(BOB)), 2_000 * UNIT);
583

            
584
1
			let gas_limit = 100000u64;
585
1
			// Bob transfers 1000 UNIT to Charlie via EVM
586
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
587
1
				source: H160::from(BOB),
588
1
				target: H160::from(CHARLIE),
589
1
				input: Vec::new(),
590
1
				value: (1_000 * UNIT).into(),
591
1
				gas_limit,
592
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
593
1
				max_priority_fee_per_gas: None,
594
1
				nonce: None,
595
1
				access_list: Vec::new(),
596
1
				authorization_list: Vec::new(),
597
1
			})
598
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
599
1
			assert_eq!(
600
1
				Balances::free_balance(AccountId::from(CHARLIE)),
601
1
				1_000 * UNIT,
602
1
			);
603

            
604
			// Charlie can stake now
605
1
			assert_ok!(ParachainStaking::join_candidates(
606
1
				origin_of(AccountId::from(CHARLIE)),
607
1
				1_000 * UNIT,
608
1
				0u32,
609
1
			),);
610
1
			let candidates = ParachainStaking::candidate_pool();
611
1
			assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE));
612
1
			assert_eq!(candidates.0[0].amount, 1_000 * UNIT);
613
1
		});
614
1
}
615

            
616
#[test]
617
1
fn reward_block_authors() {
618
1
	ExtBuilder::default()
619
1
		.with_balances(vec![
620
1
			// Alice gets 100 extra tokens for her mapping deposit
621
1
			(AccountId::from(ALICE), 2_100 * UNIT),
622
1
			(AccountId::from(BOB), 1_000 * UNIT),
623
1
		])
624
1
		.with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
625
1
		.with_delegations(vec![(
626
1
			AccountId::from(BOB),
627
1
			AccountId::from(ALICE),
628
1
			500 * UNIT,
629
1
		)])
630
1
		.with_mappings(vec![(
631
1
			NimbusId::from_slice(&ALICE_NIMBUS).unwrap(),
632
1
			AccountId::from(ALICE),
633
1
		)])
634
1
		.build()
635
1
		.execute_with(|| {
636
1
			increase_last_relay_slot_number(1);
637
1
			// Just before round 3
638
1
			run_to_block(2399, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap()));
639
1
			// no rewards doled out yet
640
1
			assert_eq!(
641
1
				Balances::usable_balance(AccountId::from(ALICE)),
642
1
				1_100 * UNIT,
643
1
			);
644
1
			assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,);
645
1
			run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap()));
646
1
			// rewards minted and distributed
647
1
			assert_eq!(
648
1
				Balances::usable_balance(AccountId::from(ALICE)),
649
1
				1213666666584000000000,
650
1
			);
651
1
			assert_eq!(
652
1
				Balances::usable_balance(AccountId::from(BOB)),
653
1
				541333333292000000000,
654
1
			);
655
1
		});
656
1
}
657

            
658
#[test]
659
1
fn reward_block_authors_with_parachain_bond_reserved() {
660
1
	ExtBuilder::default()
661
1
		.with_balances(vec![
662
1
			// Alice gets 100 extra tokens for her mapping deposit
663
1
			(AccountId::from(ALICE), 2_100 * UNIT),
664
1
			(AccountId::from(BOB), 1_000 * UNIT),
665
1
			(AccountId::from(CHARLIE), UNIT),
666
1
		])
667
1
		.with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
668
1
		.with_delegations(vec![(
669
1
			AccountId::from(BOB),
670
1
			AccountId::from(ALICE),
671
1
			500 * UNIT,
672
1
		)])
673
1
		.with_mappings(vec![(
674
1
			NimbusId::from_slice(&ALICE_NIMBUS).unwrap(),
675
1
			AccountId::from(ALICE),
676
1
		)])
677
1
		.build()
678
1
		.execute_with(|| {
679
1
			increase_last_relay_slot_number(1);
680
1
			assert_ok!(ParachainStaking::set_inflation_distribution_config(
681
1
				root_origin(),
682
1
				[
683
1
					InflationDistributionAccount {
684
1
						account: AccountId::from(CHARLIE),
685
1
						percent: Percent::from_percent(30),
686
1
					},
687
1
					InflationDistributionAccount::default(),
688
1
				]
689
1
				.into()
690
1
			));
691

            
692
			// Stop just before round 2
693
1
			run_to_block(1199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap()));
694
1

            
695
1
			// no rewards doled out yet
696
1
			assert_eq!(
697
1
				Balances::usable_balance(AccountId::from(ALICE)),
698
1
				1_100 * UNIT,
699
1
			);
700
1
			assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,);
701
1
			assert_eq!(Balances::usable_balance(AccountId::from(CHARLIE)), UNIT,);
702

            
703
			// Go to round 2
704
1
			run_to_block(1201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap()));
705
1

            
706
1
			// 30% reserved for parachain bond
707
1
			assert_eq!(
708
1
				Balances::usable_balance(AccountId::from(CHARLIE)),
709
1
				47515000000000000000,
710
1
			);
711

            
712
			// Go to round 3
713
1
			run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap()));
714
1
			// rewards minted and distributed
715
1
			assert_eq!(
716
1
				Balances::usable_balance(AccountId::from(ALICE)),
717
1
				1182693333281650000000,
718
1
			);
719
1
			assert_eq!(
720
1
				Balances::usable_balance(AccountId::from(BOB)),
721
1
				525841666640825000000,
722
1
			);
723
			// 30% again reserved for parachain bond
724
1
			assert_eq!(
725
1
				Balances::usable_balance(AccountId::from(CHARLIE)),
726
1
				94727725000000000000,
727
1
			);
728
1
		});
729
1
}
730

            
731
#[test]
732
1
fn create_and_manipulate_foreign_asset_using_root() {
733
1
	ExtBuilder::default().build().execute_with(|| {
734
1
		let source_location = xcm::v5::Location::parent();
735
1

            
736
1
		// Create foreign asset
737
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
738
1
			moonbase_runtime::RuntimeOrigin::root(),
739
1
			1,
740
1
			source_location.clone(),
741
1
			12,
742
1
			bounded_vec![b'M', b'T'],
743
1
			bounded_vec![b'M', b'y', b'T', b'o', b'k'],
744
1
		));
745
1
		assert_eq!(
746
1
			EvmForeignAssets::assets_by_id(1),
747
1
			Some(source_location.clone())
748
1
		);
749
1
		assert_eq!(
750
1
			EvmForeignAssets::assets_by_location(&source_location),
751
1
			Some((1, AssetStatus::Active))
752
1
		);
753

            
754
		// Freeze foreign asset
755
1
		assert_ok!(EvmForeignAssets::freeze_foreign_asset(
756
1
			moonbase_runtime::RuntimeOrigin::root(),
757
1
			1,
758
1
			true
759
1
		));
760
1
		assert_eq!(
761
1
			EvmForeignAssets::assets_by_location(&source_location),
762
1
			Some((1, AssetStatus::FrozenXcmDepositAllowed))
763
1
		);
764

            
765
		// Unfreeze foreign asset
766
1
		assert_ok!(EvmForeignAssets::unfreeze_foreign_asset(
767
1
			moonbase_runtime::RuntimeOrigin::root(),
768
1
			1,
769
1
		));
770
1
		assert_eq!(
771
1
			EvmForeignAssets::assets_by_location(&source_location),
772
1
			Some((1, AssetStatus::Active))
773
1
		);
774
1
	});
775
1
}
776

            
777
#[test]
778
1
fn create_and_manipulate_foreign_asset_using_sibling() {
779
1
	ExtBuilder::default().build().execute_with(|| {
780
1
		let asset_location: Location = (Parent, Parachain(1), PalletInstance(3)).into();
781
1
		let para_location = asset_location.chain_location();
782
1
		let para_account =
783
1
			LocationToAccountId::convert_location(&para_location).expect("Cannot convert location");
784
1

            
785
1
		let deposit = dynamic_params::xcm_config::ForeignAssetCreationDeposit::get();
786
1
		Balances::make_free_balance_be(&para_account, deposit * 2);
787
1

            
788
1
		// Create foreign asset
789
1
		assert_ok!(EvmForeignAssets::create_foreign_asset(
790
1
			pallet_xcm::Origin::Xcm(para_location.clone()).into(),
791
1
			1,
792
1
			asset_location.clone(),
793
1
			12,
794
1
			bounded_vec![b'M', b'T'],
795
1
			bounded_vec![b'M', b'y', b'T', b'o', b'k'],
796
1
		));
797

            
798
		// deposit is taken from the account
799
1
		assert_eq!(Balances::free_balance(&para_account), deposit);
800

            
801
1
		assert_eq!(
802
1
			EvmForeignAssets::assets_by_id(1),
803
1
			Some(asset_location.clone())
804
1
		);
805
1
		assert_eq!(
806
1
			EvmForeignAssets::assets_by_location(&asset_location),
807
1
			Some((1, AssetStatus::Active))
808
1
		);
809

            
810
		// Freeze foreign asset
811
1
		assert_ok!(EvmForeignAssets::freeze_foreign_asset(
812
1
			pallet_xcm::Origin::Xcm(para_location.clone()).into(),
813
1
			1,
814
1
			true
815
1
		));
816
1
		assert_eq!(
817
1
			EvmForeignAssets::assets_by_location(&asset_location),
818
1
			Some((1, AssetStatus::FrozenXcmDepositAllowed))
819
1
		);
820

            
821
		// Unfreeze foreign asset
822
1
		assert_ok!(EvmForeignAssets::unfreeze_foreign_asset(
823
1
			pallet_xcm::Origin::Xcm(para_location.clone()).into(),
824
1
			1,
825
1
		));
826
1
		assert_eq!(
827
1
			EvmForeignAssets::assets_by_location(&asset_location),
828
1
			Some((1, AssetStatus::Active))
829
1
		);
830
1
	});
831
1
}
832

            
833
// The precoompile asset-erc20 is deprecated and not used anymore for new evm foreign assets
834
// We don't have testing tools in rust test to call real evm smart contract, so we rely on ts tests.
835
/*
836
#[test]
837
fn xcm_asset_erc20_precompiles_supply_and_balance() {
838
	ExtBuilder::default()
839
		.with_xcm_assets(vec![XcmAssetInitialization {
840
			asset_id: 1,
841
			xcm_location: xcm::v5::Location::parent(),
842
			name: "RelayToken",
843
			symbol: "Relay",
844
			decimals: 12,
845
			balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)],
846
		}])
847
		.with_balances(vec![
848
			(AccountId::from(ALICE), 2_000 * UNIT),
849
			(AccountId::from(BOB), 1_000 * UNIT),
850
		])
851
		.build()
852
		.execute_with(|| {
853
			// We have the assetId that corresponds to the relay chain registered
854
			let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into();
855

            
856
			// Its address is
857
			let asset_precompile_address = Runtime::asset_id_to_account(
858
				FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
859
				relay_asset_id,
860
			);
861

            
862
			// Assert the asset has been created with the correct supply
863
			assert_eq!(Assets::total_supply(relay_asset_id), 1_000 * UNIT);
864

            
865
			// Access totalSupply through precompile. Important that the context is correct
866
			Precompiles::new()
867
				.prepare_test(
868
					ALICE,
869
					asset_precompile_address,
870
					ForeignAssetsPCall::total_supply {},
871
				)
872
				.expect_cost(3338)
873
				.expect_no_logs()
874
				.execute_returns(U256::from(1000 * UNIT));
875

            
876
			// Access balanceOf through precompile
877
			Precompiles::new()
878
				.prepare_test(
879
					ALICE,
880
					asset_precompile_address,
881
					ForeignAssetsPCall::balance_of {
882
						who: Address(ALICE.into()),
883
					},
884
				)
885
				.expect_cost(3338)
886
				.expect_no_logs()
887
				.execute_returns(U256::from(1000 * UNIT));
888
		});
889
}
890

            
891
#[test]
892
fn xcm_asset_erc20_precompiles_transfer() {
893
	ExtBuilder::default()
894
		.with_xcm_assets(vec![XcmAssetInitialization {
895
			asset_id: 1,
896
			xcm_location: xcm::v5::Location::parent(),
897
			name: "RelayToken",
898
			symbol: "Relay",
899
			decimals: 12,
900
			balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)],
901
		}])
902
		.with_balances(vec![
903
			(AccountId::from(ALICE), 2_000 * UNIT),
904
			(AccountId::from(BOB), 1_000 * UNIT),
905
		])
906
		.build()
907
		.execute_with(|| {
908
			// We have the assetId that corresponds to the relay chain registered
909
			let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into();
910

            
911
			// Its address is
912
			let asset_precompile_address = Runtime::asset_id_to_account(
913
				FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
914
				relay_asset_id,
915
			);
916

            
917
			// Transfer tokens from Alice to Bob, 400 UNIT.
918
			Precompiles::new()
919
				.prepare_test(
920
					ALICE,
921
					asset_precompile_address,
922
					ForeignAssetsPCall::transfer {
923
						to: Address(BOB.into()),
924
						value: { 400 * UNIT }.into(),
925
					},
926
				)
927
				.expect_cost(24695)
928
				.expect_log(log3(
929
					asset_precompile_address,
930
					SELECTOR_LOG_TRANSFER,
931
					H160::from(ALICE),
932
					H160::from(BOB),
933
					solidity::encode_event_data(U256::from(400 * UNIT)),
934
				))
935
				.execute_returns(true);
936

            
937
			// Make sure BOB has 400 UNIT
938
			Precompiles::new()
939
				.prepare_test(
940
					BOB,
941
					asset_precompile_address,
942
					ForeignAssetsPCall::balance_of {
943
						who: Address(BOB.into()),
944
					},
945
				)
946
				.expect_cost(3338)
947
				.expect_no_logs()
948
				.execute_returns(U256::from(400 * UNIT));
949
		});
950
}
951

            
952
#[test]
953
fn xcm_asset_erc20_precompiles_approve() {
954
	ExtBuilder::default()
955
		.with_xcm_assets(vec![XcmAssetInitialization {
956
			asset_id: 1,
957
			xcm_location: xcm::v5::Location::parent(),
958
			name: "RelayToken",
959
			symbol: "Relay",
960
			decimals: 12,
961
			balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)],
962
		}])
963
		.with_balances(vec![
964
			(AccountId::from(ALICE), 2_000 * UNIT),
965
			(AccountId::from(BOB), 1_000 * UNIT),
966
		])
967
		.build()
968
		.execute_with(|| {
969
			// We have the assetId that corresponds to the relay chain registered
970
			let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into();
971

            
972
			// Its address is
973
			let asset_precompile_address = Runtime::asset_id_to_account(
974
				FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
975
				relay_asset_id,
976
			);
977

            
978
			// Aprove Bob for spending 400 UNIT from Alice
979
			Precompiles::new()
980
				.prepare_test(
981
					ALICE,
982
					asset_precompile_address,
983
					ForeignAssetsPCall::approve {
984
						spender: Address(BOB.into()),
985
						value: { 400 * UNIT }.into(),
986
					},
987
				)
988
				.expect_cost(15604)
989
				.expect_log(log3(
990
					asset_precompile_address,
991
					SELECTOR_LOG_APPROVAL,
992
					H160::from(ALICE),
993
					H160::from(BOB),
994
					solidity::encode_event_data(U256::from(400 * UNIT)),
995
				))
996
				.execute_returns(true);
997

            
998
			// Transfer tokens from Alice to Charlie by using BOB as origin
999
			Precompiles::new()
				.prepare_test(
					BOB,
					asset_precompile_address,
					ForeignAssetsPCall::transfer_from {
						from: Address(ALICE.into()),
						to: Address(CHARLIE.into()),
						value: { 400 * UNIT }.into(),
					},
				)
				.expect_cost(29960)
				.expect_log(log3(
					asset_precompile_address,
					SELECTOR_LOG_TRANSFER,
					H160::from(ALICE),
					H160::from(CHARLIE),
					solidity::encode_event_data(U256::from(400 * UNIT)),
				))
				.execute_returns(true);
			// Make sure CHARLIE has 400 UNIT
			Precompiles::new()
				.prepare_test(
					CHARLIE,
					asset_precompile_address,
					ForeignAssetsPCall::balance_of {
						who: Address(CHARLIE.into()),
					},
				)
				.expect_cost(3338)
				.expect_no_logs()
				.execute_returns(U256::from(400 * UNIT));
		});
}*/
#[test]
1
fn xtokens_precompiles_transfer() {
1
	ExtBuilder::default()
1
		.with_xcm_assets(vec![XcmAssetInitialization {
1
			asset_id: 1,
1
			xcm_location: AssetHubLocation::get(),
1
			name: "RelayToken",
1
			symbol: "Relay",
1
			decimals: 12,
1
			balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)],
1
		}])
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			let xtokens_precompile_address = H160::from_low_u64_be(2052);
1

            
1
			// We have the assetId that corresponds to the relay chain registered
1
			let asset_id: AssetId = 1;
1

            
1
			// Its address is
1
			let asset_precompile_address =
1
				Runtime::asset_id_to_account(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, asset_id);
1

            
1
			// Alice has 1000 tokens. She should be able to send through precompile
1
			let destination = Location::new(
1
				1,
1
				[Junction::AccountId32 {
1
					network: None,
1
					id: [1u8; 32],
1
				}],
1
			);
1

            
1
			let inside = Rc::new(Cell::new(false));
1
			let inside2 = inside.clone();
1

            
1
			// We use the address of the asset as an identifier of the asset we want to transfer
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xtokens_precompile_address,
1
					XtokensPCall::transfer {
1
						currency_address: Address(asset_precompile_address.into()),
1
						amount: 500_000_000_000_000u128.into(),
1
						destination,
1
						weight: 4_000_000,
1
					},
1
				)
1
				.expect_cost(260283)
1
				.expect_no_logs()
1
				// We expect an evm subcall ERC20.burnFrom
1
				.with_subcall_handle(move |subcall| {
1
					let Subcall {
1
						address,
1
						transfer,
1
						input,
1
						target_gas: _,
1
						is_static,
1
						context,
1
					} = subcall;
1

            
1
					assert_eq!(context.caller, EvmForeignAssets::account_id().into());
1
					assert_eq!(
1
						address,
1
						[255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into()
1
					);
1
					assert_eq!(is_static, false);
1
					assert!(transfer.is_none());
1
					assert_eq!(
1
						context.address,
1
						[255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into()
1
					);
1
					assert_eq!(context.apparent_value, 0u8.into());
1
					assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]);
1
					assert_eq!(&input[4..16], &[0u8; 12]);
1
					assert_eq!(&input[16..36], ALICE);
1
					inside2.set(true);
1

            
1
					SubcallOutput {
1
						output: Default::default(),
1
						cost: 149_000,
1
						logs: vec![],
1
						..SubcallOutput::succeed()
1
					}
1
				})
1
				.execute_returns(())
1
		})
1
}
#[test]
1
fn xtokens_precompiles_transfer_multiasset() {
1
	ExtBuilder::default()
1
		.with_xcm_assets(vec![XcmAssetInitialization {
1
			asset_id: 1,
1
			xcm_location: AssetHubLocation::get(),
1
			name: "DOT",
1
			symbol: "DOT",
1
			decimals: 12,
1
			balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)],
1
		}])
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			let xtokens_precompile_address = H160::from_low_u64_be(2052);
1

            
1
			// Alice has 1000 tokens. She should be able to send through precompile
1
			let destination = Location::new(
1
				1,
1
				[Junction::AccountId32 {
1
					network: None,
1
					id: [1u8; 32],
1
				}],
1
			);
1

            
1
			let inside = Rc::new(Cell::new(false));
1
			let inside2 = inside.clone();
1

            
1
			// This time we transfer it through TransferMultiAsset
1
			// Instead of the address, we encode directly the multilocation referencing the asset
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xtokens_precompile_address,
1
					XtokensPCall::transfer_multiasset {
1
						// We want to transfer DOT
1
						asset: AssetHubLocation::get(),
1
						amount: 500_000_000_000_000u128.into(),
1
						destination,
1
						weight: 4_000_000,
1
					},
1
				)
1
				.expect_cost(260283)
1
				.expect_no_logs()
1
				// We expect an evm subcall ERC20.burnFrom
1
				.with_subcall_handle(move |subcall| {
1
					let Subcall {
1
						address,
1
						transfer,
1
						input,
1
						target_gas: _,
1
						is_static,
1
						context,
1
					} = subcall;
1

            
1
					assert_eq!(context.caller, EvmForeignAssets::account_id().into());
1
					assert_eq!(
1
						address,
1
						[255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into()
1
					);
1
					assert_eq!(is_static, false);
1
					assert!(transfer.is_none());
1
					assert_eq!(
1
						context.address,
1
						[255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into()
1
					);
1
					assert_eq!(context.apparent_value, 0u8.into());
1
					assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]);
1
					assert_eq!(&input[4..16], &[0u8; 12]);
1
					assert_eq!(&input[16..36], ALICE);
1
					inside2.set(true);
1

            
1
					SubcallOutput {
1
						output: Default::default(),
1
						cost: 149_000,
1
						logs: vec![],
1
						..SubcallOutput::succeed()
1
					}
1
				})
1
				.execute_returns(());
1

            
1
			// Ensure that the subcall was actually called.
1
			assert!(inside.get(), "subcall not called");
1
		})
1
}
#[test]
1
fn xtokens_precompiles_transfer_native() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			let xtokens_precompile_address = H160::from_low_u64_be(2052);
1

            
1
			// Its address is
1
			let asset_precompile_address = H160::from_low_u64_be(2050);
1

            
1
			// Alice has 1000 tokens. She should be able to send through precompile
1
			let destination = Location::new(
1
				1,
1
				[Junction::AccountId32 {
1
					network: None,
1
					id: [1u8; 32],
1
				}],
1
			);
1

            
1
			// We use the address of the asset as an identifier of the asset we want to transfer
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xtokens_precompile_address,
1
					XtokensPCall::transfer {
1
						currency_address: Address(asset_precompile_address),
1
						amount: { 500 * UNIT }.into(),
1
						destination,
1
						weight: 4_000_000,
1
					},
1
				)
1
				.expect_cost(108683)
1
				.expect_no_logs()
1
				.execute_returns(());
1
		})
1
}
1
fn run_with_system_weight<F>(w: Weight, mut assertions: F)
1
where
1
	F: FnMut() -> (),
1
{
1
	let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
		.build_storage()
1
		.unwrap()
1
		.into();
1
	t.execute_with(|| {
1
		System::set_block_consumed_resources(w, 0);
1
		assertions()
1
	});
1
}
#[test]
#[rustfmt::skip]
1
fn length_fee_is_sensible() {
	use sp_runtime::testing::TestXt;
	// tests that length fee is sensible for a few hypothetical transactions
1
	ExtBuilder::default().build().execute_with(|| {
1
		let call = frame_system::Call::remark::<Runtime> { remark: vec![] };
1
		let uxt: TestXt<_, ()> = TestXt::new_signed(RuntimeCall::System(call), 1u64, (), ());
1

            
9
		let calc_fee = |len: u32| -> Balance {
9
			moonbase_runtime::TransactionPayment::query_fee_details(uxt.clone(), len)
9
				.inclusion_fee
9
				.expect("fee should be calculated")
9
				.len_fee
9
		};
		//                  left: cost of length fee, right: size in bytes
		//                             /------------- proportional component: O(N * 1B)
		//                             |           /- exponential component: O(N ** 3)
		//                             |           |
1
		assert_eq!(                    1_000_000_001, calc_fee(1));
1
		assert_eq!(                   10_000_001_000, calc_fee(10));
1
		assert_eq!(                  100_001_000_000, calc_fee(100));
1
		assert_eq!(                1_001_000_000_000, calc_fee(1_000));
1
		assert_eq!(               11_000_000_000_000, calc_fee(10_000)); // inflection point
1
		assert_eq!(            1_100_000_000_000_000, calc_fee(100_000));
1
		assert_eq!(        1_001_000_000_000_000_000, calc_fee(1_000_000)); // one UNIT, ~ 1MB
1
		assert_eq!(    1_000_010_000_000_000_000_000, calc_fee(10_000_000));
1
		assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000));
1
	});
1
}
#[test]
1
fn multiplier_can_grow_from_zero() {
	use frame_support::traits::Get;
1
	let minimum_multiplier = moonbase_runtime::MinimumMultiplier::get();
1
	let target = moonbase_runtime::TargetBlockFullness::get()
1
		* RuntimeBlockWeights::get()
1
			.get(DispatchClass::Normal)
1
			.max_total
1
			.unwrap();
1
	// if the min is too small, then this will not change, and we are doomed forever.
1
	// the weight is 1/100th bigger than target.
1
	run_with_system_weight(target * 101 / 100, || {
1
		let next = moonbase_runtime::FastAdjustingFeeUpdate::<Runtime>::convert(minimum_multiplier);
1
		assert!(
1
			next > minimum_multiplier,
			"{:?} !>= {:?}",
			next,
			minimum_multiplier
		);
1
	})
1
}
#[test]
1
fn ethereum_invalid_transaction() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		set_parachain_inherent_data();
1
		// Ensure an extrinsic not containing enough gas limit to store the transaction
1
		// on chain is rejected.
1
		assert_eq!(
1
			Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)),
1
			Err(
1
				sp_runtime::transaction_validity::TransactionValidityError::Invalid(
1
					sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8)
1
				)
1
			)
1
		);
1
	});
1
}
#[test]
1
fn transfer_ed_0_substrate() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), (1 * UNIT) + (1 * WEI)),
1
			(AccountId::from(BOB), existential_deposit()),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			// Substrate transfer
1
			assert_ok!(Balances::transfer_allow_death(
1
				origin_of(AccountId::from(ALICE)),
1
				AccountId::from(BOB),
1
				1 * UNIT,
1
			));
			// 1 WEI is left in the account
1
			assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI);
1
		});
1
}
#[test]
1
fn initial_gas_fee_is_correct() {
	use fp_evm::FeeCalculator;
1
	ExtBuilder::default().build().execute_with(|| {
1
		let multiplier = TransactionPayment::next_fee_multiplier();
1
		assert_eq!(multiplier, Multiplier::from(8u128));
1
		assert_eq!(
1
			TransactionPaymentAsGasPrice::min_gas_price(),
1
			(
1
				2_500_000_000u128.into(),
1
				Weight::from_parts(<Runtime as frame_system::Config>::DbWeight::get().read, 0)
1
			)
1
		);
1
	});
1
}
#[test]
1
fn transfer_ed_0_evm() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(
1
				AccountId::from(ALICE),
1
				((1 * UNIT) + (21_000 * BASE_FEE_GENISIS)) + (1 * WEI),
1
			),
1
			(AccountId::from(BOB), existential_deposit()),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			set_parachain_inherent_data();
1
			// EVM transfer
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
1
				source: H160::from(ALICE),
1
				target: H160::from(BOB),
1
				input: Vec::new(),
1
				value: (1 * UNIT).into(),
1
				gas_limit: 21_000u64,
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: None,
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
			// 1 WEI is left in the account
1
			assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,);
1
		});
1
}
#[test]
1
fn refund_ed_0_evm() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(
1
				AccountId::from(ALICE),
1
				((1 * UNIT) + (21_777 * BASE_FEE_GENISIS) + existential_deposit()),
1
			),
1
			(AccountId::from(BOB), existential_deposit()),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			// EVM transfer that zeroes ALICE
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
1
				source: H160::from(ALICE),
1
				target: H160::from(BOB),
1
				input: Vec::new(),
1
				value: (1 * UNIT).into(),
1
				gas_limit: 21_777u64,
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: None,
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
			// ALICE is refunded
1
			assert_eq!(
1
				Balances::free_balance(AccountId::from(ALICE)),
1
				777 * BASE_FEE_GENISIS + existential_deposit(),
1
			);
1
		});
1
}
#[test]
1
fn author_does_receive_priority_fee() {
1
	ExtBuilder::default()
1
		.with_balances(vec![(
1
			AccountId::from(BOB),
1
			(1 * UNIT) + (21_000 * (500 * GIGAWEI)),
1
		)])
1
		.build()
1
		.execute_with(|| {
1
			// Some block author as seen by pallet-evm.
1
			let author = AccountId::from(<pallet_evm::Pallet<Runtime>>::find_author());
1
			pallet_author_inherent::Author::<Runtime>::put(author);
1
			// Currently the default impl of the evm uses `deposit_into_existing`.
1
			// If we were to use this implementation, and for an author to receive eventual tips,
1
			// the account needs to be somehow initialized, otherwise the deposit would fail.
1
			Balances::make_free_balance_be(&author, 100 * UNIT);
1

            
1
			// EVM transfer.
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
1
				source: H160::from(BOB),
1
				target: H160::from(ALICE),
1
				input: Vec::new(),
1
				value: (1 * UNIT).into(),
1
				gas_limit: 21_000u64,
1
				max_fee_per_gas: U256::from(300 * GIGAWEI),
1
				max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)),
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
1
			let priority_fee = 200 * GIGAWEI * 21_000;
1
			// Author free balance increased by priority fee.
1
			assert_eq!(Balances::free_balance(author), 100 * UNIT + priority_fee,);
1
		});
1
}
#[test]
1
fn total_issuance_after_evm_transaction_with_priority_fee() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(
1
				AccountId::from(BOB),
1
				(1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS) + existential_deposit()),
1
			),
1
			(AccountId::from(ALICE), existential_deposit()),
1
			(
1
				<pallet_treasury::TreasuryAccountId<Runtime> as sp_core::TypedGet>::get(),
1
				existential_deposit(),
1
			),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			let issuance_before = <Runtime as pallet_evm::Config>::Currency::total_issuance();
1
			let author = AccountId::from(<pallet_evm::Pallet<Runtime>>::find_author());
1
			pallet_author_inherent::Author::<Runtime>::put(author);
1
			// EVM transfer.
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
1
				source: H160::from(BOB),
1
				target: H160::from(ALICE),
1
				input: Vec::new(),
1
				value: (1 * UNIT).into(),
1
				gas_limit: 21_000u64,
1
				max_fee_per_gas: U256::from(2 * BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENISIS)),
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
1
			let issuance_after = <Runtime as pallet_evm::Config>::Currency::total_issuance();
1

            
1
			let base_fee: Balance = BASE_FEE_GENISIS * 21_000;
1

            
1
			let treasury_proportion = dynamic_params::runtime_config::FeesTreasuryProportion::get();
1

            
1
			// only base fee is split between being burned and sent to treasury
1
			let treasury_base_fee_part: Balance = treasury_proportion.mul_floor(base_fee);
1
			let burnt_base_fee_part: Balance = base_fee - treasury_base_fee_part;
1

            
1
			assert_eq!(issuance_after, issuance_before - burnt_base_fee_part);
1
			assert_eq!(moonbase_runtime::Treasury::pot(), treasury_base_fee_part);
1
		});
1
}
#[test]
1
fn total_issuance_after_evm_transaction_without_priority_fee() {
	use fp_evm::FeeCalculator;
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(
1
				AccountId::from(BOB),
1
				(1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS)),
1
			),
1
			(AccountId::from(ALICE), existential_deposit()),
1
			(
1
				<pallet_treasury::TreasuryAccountId<Runtime> as sp_core::TypedGet>::get(),
1
				existential_deposit(),
1
			),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			set_parachain_inherent_data();
1
			let issuance_before = <Runtime as pallet_evm::Config>::Currency::total_issuance();
1
			// EVM transfer.
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
1
				source: H160::from(BOB),
1
				target: H160::from(ALICE),
1
				input: Vec::new(),
1
				value: (1 * UNIT).into(),
1
				gas_limit: 21_000u64,
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: None,
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
1
			let issuance_after = <Runtime as pallet_evm::Config>::Currency::total_issuance();
1
			// Fee is 1 GWEI base fee.
1
			let base_fee = TransactionPaymentAsGasPrice::min_gas_price().0;
1
			assert_eq!(base_fee.as_u128(), BASE_FEE_GENISIS); // hint in case following asserts fail
1
			let base_fee: Balance = BASE_FEE_GENISIS * 21_000;
1

            
1
			let treasury_proportion = dynamic_params::runtime_config::FeesTreasuryProportion::get();
1

            
1
			// only base fee is split between being burned and sent to treasury
1
			let treasury_base_fee_part: Balance = treasury_proportion.mul_floor(base_fee);
1
			let burnt_base_fee_part: Balance = base_fee - treasury_base_fee_part;
1

            
1
			assert_eq!(issuance_after, issuance_before - burnt_base_fee_part);
1
			assert_eq!(moonbase_runtime::Treasury::pot(), treasury_base_fee_part);
1
		});
1
}
#[test]
1
fn root_can_change_default_xcm_vers() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_xcm_assets(vec![XcmAssetInitialization {
1
			asset_id: 1,
1
			xcm_location: AssetHubLocation::get(),
1
			name: "Dot",
1
			symbol: "Dot",
1
			decimals: 12,
1
			balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)],
1
		}])
1
		.build()
1
		.execute_with(|| {
1
			let source_id: moonbase_runtime::AssetId = 1;
1
			let currency_id = moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id);
1
			let asset = Asset {
1
				id: AssetId(
1
					<Runtime as pallet_xcm_transactor::Config>::CurrencyIdToLocation::convert(
1
						currency_id,
1
					)
1
					.unwrap(),
1
				),
1
				fun: Fungibility::Fungible(100_000_000_000_000),
1
			};
1
			// Default XCM version is not set yet, so xtokens should fail because it does not
1
			// know with which version to send
1
			assert_noop!(
1
				PolkadotXcm::transfer_assets(
1
					origin_of(AccountId::from(ALICE)),
1
					Box::new(VersionedLocation::from(Location::parent())),
1
					Box::new(VersionedLocation::from(Location {
1
						parents: 0,
1
						interior: [AccountId32 {
1
							network: None,
1
							id: [1u8; 32],
1
						}]
1
						.into(),
1
					})),
1
					Box::new(VersionedAssets::from(asset.clone())),
1
					0,
1
					WeightLimit::Unlimited
1
				),
1
				pallet_xcm::Error::<Runtime>::LocalExecutionIncomplete
1
			);
			// Root sets the defaultXcm
1
			assert_ok!(PolkadotXcm::force_default_xcm_version(
1
				root_origin(),
1
				Some(5)
1
			));
			// Now transferring does not fail
1
			assert_ok!(PolkadotXcm::transfer_assets(
1
				origin_of(AccountId::from(ALICE)),
1
				Box::new(VersionedLocation::from(Location::parent())),
1
				Box::new(VersionedLocation::from(Location {
1
					parents: 0,
1
					interior: [AccountId32 {
1
						network: None,
1
						id: [1u8; 32],
1
					}]
1
					.into(),
1
				})),
1
				Box::new(VersionedAssets::from(asset)),
1
				0,
1
				WeightLimit::Unlimited
1
			));
1
		})
1
}
#[test]
1
fn transactor_cannot_use_more_than_max_weight() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_xcm_assets(vec![XcmAssetInitialization {
1
			asset_id: 1,
1
			xcm_location: xcm::v5::Location::parent(),
1
			name: "RelayToken",
1
			symbol: "Relay",
1
			decimals: 12,
1
			balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)],
1
		}])
1
		.build()
1
		.execute_with(|| {
1
			let source_id: moonbase_runtime::AssetId = 1;
1
			assert_ok!(XcmTransactor::register(
1
				root_origin(),
1
				AccountId::from(ALICE),
1
				0,
1
			));
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_transact_info(
1
				root_origin(),
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
1
				// Relay charges 1000 for every instruction, and we have 3, so 3000
1
				3000.into(),
1
				20000.into(),
1
				None
1
			));
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_fee_per_second(
1
				root_origin(),
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
1
				1,
1
			));
1
			assert_noop!(
1
				XcmTransactor::transact_through_derivative(
1
					origin_of(AccountId::from(ALICE)),
1
					moonbase_runtime::xcm_config::Transactors::Relay,
1
					0,
1
					CurrencyPayment {
1
						currency: Currency::AsMultiLocation(Box::new(
1
							xcm::VersionedLocation::from(Location::parent())
1
						)),
1
						fee_amount: None
1
					},
1
					vec![],
1
					// 20000 is the max
1
					TransactWeights {
1
						transact_required_weight_at_most: 17001.into(),
1
						overall_weight: None
1
					},
1
					false
1
				),
1
				pallet_xcm_transactor::Error::<Runtime>::MaxWeightTransactReached
1
			);
1
			assert_noop!(
1
				XcmTransactor::transact_through_derivative(
1
					origin_of(AccountId::from(ALICE)),
1
					moonbase_runtime::xcm_config::Transactors::Relay,
1
					0,
1
					CurrencyPayment {
1
						currency: Currency::AsCurrencyId(
1
							moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id)
1
						),
1
						fee_amount: None
1
					},
1
					vec![],
1
					// 20000 is the max
1
					TransactWeights {
1
						transact_required_weight_at_most: 17001.into(),
1
						overall_weight: None
1
					},
1
					false
1
				),
1
				pallet_xcm_transactor::Error::<Runtime>::MaxWeightTransactReached
1
			);
1
		})
1
}
#[test]
1
fn root_can_use_hrmp_manage() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.build()
1
		.execute_with(|| {
1
			// It fails sending, because the router does not work in test mode
1
			// But all rest checks pass
1
			assert_noop!(
1
				XcmTransactor::hrmp_manage(
1
					root_origin(),
1
					HrmpOperation::Accept {
1
						para_id: 2000u32.into()
1
					},
1
					CurrencyPayment {
1
						currency: Currency::AsMultiLocation(Box::new(
1
							xcm::VersionedLocation::from(Location::parent())
1
						)),
1
						fee_amount: Some(10000)
1
					},
1
					// 20000 is the max
1
					TransactWeights {
1
						transact_required_weight_at_most: 17001.into(),
1
						overall_weight: Some(Limited(20000.into()))
1
					}
1
				),
1
				pallet_xcm_transactor::Error::<Runtime>::ErrorValidating
1
			);
1
		})
1
}
#[test]
1
fn transact_through_signed_precompile_works_v1() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			// Destination
1
			let dest = Location::parent();
1

            
1
			let fee_payer_asset = Location::parent();
1

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

            
1
			let xcm_transactor_v1_precompile_address = H160::from_low_u64_be(2054);
1

            
1
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_transact_info(
1
				root_origin(),
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
1
				// Relay charges 1000 for every instruction, and we have 3, so 3000
1
				3000.into(),
1
				Weight::from_parts(200_000, (xcm_primitives::DEFAULT_PROOF_SIZE) + 4000),
1
				Some(4000.into())
1
			));
			// Root can set transact info
1
			assert_ok!(XcmTransactor::set_fee_per_second(
1
				root_origin(),
1
				Box::new(xcm::VersionedLocation::from(Location::parent())),
1
				1,
1
			));
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xcm_transactor_v1_precompile_address,
1
					XcmTransactorV1PCall::transact_through_signed_multilocation {
1
						dest,
1
						fee_asset: fee_payer_asset,
1
						weight: 15000,
1
						call: bytes.into(),
1
					},
1
				)
1
				.expect_cost(30883)
1
				.expect_no_logs()
1
				.execute_returns(());
1
		});
1
}
#[test]
1
fn transact_through_signed_precompile_works_v2() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			// Destination
1
			let dest = Location::parent();
1

            
1
			let fee_payer_asset = Location::parent();
1

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

            
1
			let total_weight = 1_000_000_000u64;
1

            
1
			let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061);
1

            
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xcm_transactor_v2_precompile_address,
1
					XcmTransactorV2PCall::transact_through_signed_multilocation {
1
						dest,
1
						fee_asset: fee_payer_asset,
1
						weight: 4_000_000,
1
						call: bytes.into(),
1
						fee_amount: u128::from(total_weight).into(),
1
						overall_weight: total_weight,
1
					},
1
				)
1
				.expect_cost(30883)
1
				.expect_no_logs()
1
				.execute_returns(());
1
		});
1
}
#[test]
1
fn transact_through_signed_cannot_send_to_local_chain() {
1
	ExtBuilder::default()
1
		.with_balances(vec![
1
			(AccountId::from(ALICE), 2_000 * UNIT),
1
			(AccountId::from(BOB), 1_000 * UNIT),
1
		])
1
		.with_safe_xcm_version(3)
1
		.build()
1
		.execute_with(|| {
1
			// Destination
1
			let dest = Location::here();
1

            
1
			let fee_payer_asset = Location::parent();
1

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

            
1
			let total_weight = 1_000_000_000u64;
1

            
1
			let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061);
1

            
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					xcm_transactor_v2_precompile_address,
1
					XcmTransactorV2PCall::transact_through_signed_multilocation {
1
						dest,
1
						fee_asset: fee_payer_asset,
1
						weight: 4_000_000,
1
						call: bytes.into(),
1
						fee_amount: u128::from(total_weight).into(),
1
						overall_weight: total_weight,
1
					},
1
				)
1
				.execute_reverts(|output| {
1
					from_utf8(&output)
1
						.unwrap()
1
						.contains("Dispatched call failed with error:")
1
						&& from_utf8(&output).unwrap().contains("ErrorValidating")
1
				});
1
		});
1
}
// Test to ensure we can use either in crowdloan rewards without worrying for migrations
#[test]
1
fn account_id_32_encodes_like_32_byte_u8_slice() {
1
	let account_as_account_id_32: sp_runtime::AccountId32 = [1u8; 32].into();
1
	let account_as_slice = [1u8; 32];
1
	assert_eq!(account_as_account_id_32.encode(), account_as_slice.encode());
1
}
#[test]
1
fn author_mapping_precompile_associate_update_and_clear() {
1
	ExtBuilder::default()
1
		.with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
1
		.build()
1
		.execute_with(|| {
1
			let author_mapping_precompile_address = H160::from_low_u64_be(2055);
1
			let first_nimbus_id: NimbusId =
1
				sp_core::sr25519::Public::unchecked_from([1u8; 32]).into();
1
			let first_vrf_id: session_keys_primitives::VrfId =
1
				sp_core::sr25519::Public::unchecked_from([1u8; 32]).into();
1
			let second_nimbus_id: NimbusId =
1
				sp_core::sr25519::Public::unchecked_from([2u8; 32]).into();
1
			let second_vrf_id: session_keys_primitives::VrfId =
1
				sp_core::sr25519::Public::unchecked_from([2u8; 32]).into();
1

            
1
			// Associate it
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					author_mapping_precompile_address,
1
					AuthorMappingPCall::add_association {
1
						nimbus_id: [1u8; 32].into(),
1
					},
1
				)
1
				.expect_cost(19935)
1
				.expect_no_logs()
1
				.execute_returns(());
1

            
1
			let expected_associate_event =
1
				RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered {
1
					nimbus_id: first_nimbus_id.clone(),
1
					account_id: AccountId::from(ALICE),
1
					keys: first_vrf_id.clone(),
1
				});
1
			assert_eq!(last_event(), expected_associate_event);
			// Update it
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					author_mapping_precompile_address,
1
					AuthorMappingPCall::update_association {
1
						old_nimbus_id: [1u8; 32].into(),
1
						new_nimbus_id: [2u8; 32].into(),
1
					},
1
				)
1
				.expect_cost(19452)
1
				.expect_no_logs()
1
				.execute_returns(());
1

            
1
			let expected_update_event =
1
				RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated {
1
					new_nimbus_id: second_nimbus_id.clone(),
1
					account_id: AccountId::from(ALICE),
1
					new_keys: second_vrf_id.clone(),
1
				});
1
			assert_eq!(last_event(), expected_update_event);
			// Clear it
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					author_mapping_precompile_address,
1
					AuthorMappingPCall::clear_association {
1
						nimbus_id: [2u8; 32].into(),
1
					},
1
				)
1
				.expect_cost(19960)
1
				.expect_no_logs()
1
				.execute_returns(());
1

            
1
			let expected_clear_event =
1
				RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRemoved {
1
					nimbus_id: second_nimbus_id,
1
					account_id: AccountId::from(ALICE),
1
					keys: second_vrf_id,
1
				});
1
			assert_eq!(last_event(), expected_clear_event);
1
		});
1
}
#[test]
1
fn author_mapping_register_and_set_keys() {
1
	ExtBuilder::default()
1
		.with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
1
		.build()
1
		.execute_with(|| {
1
			let author_mapping_precompile_address = H160::from_low_u64_be(2055);
1
			let first_nimbus_id: NimbusId =
1
				sp_core::sr25519::Public::unchecked_from([1u8; 32]).into();
1
			let first_vrf_key: session_keys_primitives::VrfId =
1
				sp_core::sr25519::Public::unchecked_from([3u8; 32]).into();
1
			let second_nimbus_id: NimbusId =
1
				sp_core::sr25519::Public::unchecked_from([2u8; 32]).into();
1
			let second_vrf_key: session_keys_primitives::VrfId =
1
				sp_core::sr25519::Public::unchecked_from([4u8; 32]).into();
1

            
1
			// Associate it
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					author_mapping_precompile_address,
1
					AuthorMappingPCall::set_keys {
1
						keys: solidity::encode_arguments((
1
							H256::from([1u8; 32]),
1
							H256::from([3u8; 32]),
1
						))
1
						.into(),
1
					},
1
				)
1
				.expect_cost(22435)
1
				.expect_no_logs()
1
				.execute_returns(());
1

            
1
			let expected_associate_event =
1
				RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered {
1
					nimbus_id: first_nimbus_id.clone(),
1
					account_id: AccountId::from(ALICE),
1
					keys: first_vrf_key.clone(),
1
				});
1
			assert_eq!(last_event(), expected_associate_event);
			// Update it
1
			Precompiles::new()
1
				.prepare_test(
1
					ALICE,
1
					author_mapping_precompile_address,
1
					AuthorMappingPCall::set_keys {
1
						keys: solidity::encode_arguments((
1
							H256::from([2u8; 32]),
1
							H256::from([4u8; 32]),
1
						))
1
						.into(),
1
					},
1
				)
1
				.expect_cost(22435)
1
				.expect_no_logs()
1
				.execute_returns(());
1

            
1
			let expected_update_event =
1
				RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated {
1
					new_nimbus_id: second_nimbus_id.clone(),
1
					account_id: AccountId::from(ALICE),
1
					new_keys: second_vrf_key.clone(),
1
				});
1
			assert_eq!(last_event(), expected_update_event);
1
		});
1
}
#[test]
1
fn test_xcm_utils_ml_tp_account() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		let xcm_utils_precompile_address = H160::from_low_u64_be(2060);
1
		let expected_address_parent: H160 =
1
			ParentIsPreset::<AccountId>::convert_location(&Location::parent())
1
				.unwrap()
1
				.into();
1

            
1
		Precompiles::new()
1
			.prepare_test(
1
				ALICE,
1
				xcm_utils_precompile_address,
1
				XcmUtilsPCall::multilocation_to_address {
1
					location: Location::parent(),
1
				},
1
			)
1
			.expect_cost(
1
				<Runtime as frame_system::Config>::DbWeight::get()
1
					.read
1
					.saturating_div(WEIGHT_PER_GAS)
1
					.saturating_mul(2),
1
			)
1
			.expect_no_logs()
1
			.execute_returns(Address(expected_address_parent));
1

            
1
		let parachain_2000_multilocation = Location::new(1, [Parachain(2000)]);
1
		let expected_address_parachain: H160 =
1
			SiblingParachainConvertsVia::<Sibling, AccountId>::convert_location(
1
				&parachain_2000_multilocation,
1
			)
1
			.unwrap()
1
			.into();
1

            
1
		Precompiles::new()
1
			.prepare_test(
1
				ALICE,
1
				xcm_utils_precompile_address,
1
				XcmUtilsPCall::multilocation_to_address {
1
					location: parachain_2000_multilocation,
1
				},
1
			)
1
			.expect_cost(
1
				<Runtime as frame_system::Config>::DbWeight::get()
1
					.read
1
					.saturating_div(WEIGHT_PER_GAS)
1
					.saturating_mul(2),
1
			)
1
			.expect_no_logs()
1
			.execute_returns(Address(expected_address_parachain));
1

            
1
		let alice_in_parachain_2000_multilocation = Location::new(
1
			1,
1
			[
1
				Parachain(2000),
1
				AccountKey20 {
1
					network: None,
1
					key: ALICE,
1
				},
1
			],
1
		);
1
		let expected_address_alice_in_parachain_2000 =
1
			xcm_builder::HashedDescription::<
1
				AccountId,
1
				xcm_builder::DescribeFamily<xcm_builder::DescribeAllTerminal>,
1
			>::convert_location(&alice_in_parachain_2000_multilocation)
1
			.unwrap()
1
			.into();
1

            
1
		Precompiles::new()
1
			.prepare_test(
1
				ALICE,
1
				xcm_utils_precompile_address,
1
				XcmUtilsPCall::multilocation_to_address {
1
					location: alice_in_parachain_2000_multilocation,
1
				},
1
			)
1
			.expect_cost(
1
				<Runtime as frame_system::Config>::DbWeight::get()
1
					.read
1
					.saturating_div(WEIGHT_PER_GAS)
1
					.saturating_mul(2),
1
			)
1
			.expect_no_logs()
1
			.execute_returns(Address(expected_address_alice_in_parachain_2000));
1
	});
1
}
#[test]
1
fn test_nested_batch_calls_from_xcm_transact() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		// This ensures we notice if MAX_XCM_DECODE_DEPTH changes
1
		// in a future polkadot-sdk version
1
		assert_eq!(xcm::MAX_XCM_DECODE_DEPTH, 8);
1
		let mut valid_nested_calls =
1
			RuntimeCall::System(frame_system::Call::remark { remark: vec![] });
9
		for _ in 0..xcm::MAX_XCM_DECODE_DEPTH {
8
			valid_nested_calls = RuntimeCall::Utility(pallet_utility::Call::batch {
8
				calls: vec![valid_nested_calls],
8
			});
8
		}
1
		let valid_message = Xcm(vec![Transact {
1
			origin_kind: OriginKind::SovereignAccount,
1
			fallback_max_weight: None,
1
			call: valid_nested_calls.encode().into(),
1
		}]);
1

            
1
		assert!(XcmExecutor::prepare(valid_message).is_ok());
1
		let excessive_nested_calls = RuntimeCall::Utility(pallet_utility::Call::batch {
1
			calls: vec![valid_nested_calls],
1
		});
1

            
1
		let invalid_message = Xcm(vec![Transact {
1
			origin_kind: OriginKind::SovereignAccount,
1
			fallback_max_weight: None,
1
			call: excessive_nested_calls.encode().into(),
1
		}]);
1
		// Expect to fail because we have too many nested calls
1
		assert!(XcmExecutor::prepare(invalid_message).is_err());
1
	});
1
}
#[test]
1
fn test_xcm_utils_weight_message() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		let xcm_utils_precompile_address = H160::from_low_u64_be(2060);
1
		let expected_weight =
1
			XcmWeight::<moonbase_runtime::Runtime, RuntimeCall>::clear_origin().ref_time();
1

            
1
		let message: Vec<u8> = xcm::VersionedXcm::<()>::V5(Xcm(vec![ClearOrigin])).encode();
1

            
1
		let input = XcmUtilsPCall::weight_message {
1
			message: message.into(),
1
		};
1

            
1
		Precompiles::new()
1
			.prepare_test(ALICE, xcm_utils_precompile_address, input)
1
			.expect_cost(
1
				<Runtime as frame_system::Config>::DbWeight::get()
1
					.read
1
					.saturating_div(WEIGHT_PER_GAS),
1
			)
1
			.expect_no_logs()
1
			.execute_returns(expected_weight);
1
	});
1
}
#[test]
1
fn test_xcm_utils_get_units_per_second() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		let xcm_utils_precompile_address = H160::from_low_u64_be(2060);
1
		let location = SelfReserve::get();
1

            
1
		let input = XcmUtilsPCall::get_units_per_second { location };
1

            
1
		let expected_units =
1
			WEIGHT_REF_TIME_PER_SECOND as u128 * moonbase_runtime::currency::WEIGHT_FEE;
1

            
1
		Precompiles::new()
1
			.prepare_test(ALICE, xcm_utils_precompile_address, input)
1
			.expect_cost(
1
				<Runtime as frame_system::Config>::DbWeight::get()
1
					.read
1
					.saturating_div(WEIGHT_PER_GAS)
1
					.saturating_mul(2),
1
			)
1
			.expect_no_logs()
1
			.execute_returns(expected_units);
1
	});
1
}
#[test]
1
fn precompile_existence() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		let precompiles = Precompiles::new();
1
		let precompile_addresses: std::collections::BTreeSet<_> = vec![
1
			1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 256, 1024, 1025, 1026, 1027,
1
			2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061,
1
			2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074,
1
		]
1
		.into_iter()
1
		.map(H160::from_low_u64_be)
1
		.collect();
3001
		for i in 0..3000 {
3000
			let address = H160::from_low_u64_be(i);
3000

            
3000
			if precompile_addresses.contains(&address) {
48
				assert!(
48
					is_precompile_or_fail::<Runtime>(address, 100_000u64).expect("to be ok"),
					"is_precompile({}) should return true",
					i
				);
48
				assert!(
48
					precompiles
48
						.execute(&mut MockHandle::new(
48
							address,
48
							Context {
48
								address,
48
								caller: H160::zero(),
48
								apparent_value: U256::zero()
48
							}
48
						),)
48
						.is_some(),
					"execute({},..) should return Some(_)",
					i
				);
			} else {
2952
				assert!(
2952
					!is_precompile_or_fail::<Runtime>(address, 100_000u64).expect("to be ok"),
					"is_precompile({}) should return false",
					i
				);
2952
				assert!(
2952
					precompiles
2952
						.execute(&mut MockHandle::new(
2952
							address,
2952
							Context {
2952
								address,
2952
								caller: H160::zero(),
2952
								apparent_value: U256::zero()
2952
							}
2952
						),)
2952
						.is_none(),
					"execute({},..) should return None",
					i
				);
			}
		}
1
	});
1
}
#[test]
1
fn removed_precompiles() {
1
	ExtBuilder::default().build().execute_with(|| {
1
		let precompiles = Precompiles::new();
1
		let removed_precompiles = [1025, 1027, 2051, 2062, 2063];
3000
		for i in 1..3000 {
2999
			let address = H160::from_low_u64_be(i);
2999

            
2999
			if !is_precompile_or_fail::<Runtime>(address, 100_000u64).expect("to be ok") {
2951
				continue;
48
			}
48

            
48
			if !removed_precompiles.contains(&i) {
43
				assert!(
43
					match precompiles.is_active_precompile(address, 100_000u64) {
43
						IsPrecompileResult::Answer { is_precompile, .. } => is_precompile,
						_ => false,
					},
					"{i} should be an active precompile"
				);
43
				continue;
5
			}
5

            
5
			assert!(
5
				!match precompiles.is_active_precompile(address, 100_000u64) {
5
					IsPrecompileResult::Answer { is_precompile, .. } => is_precompile,
					_ => false,
				},
				"{i} shouldn't be an active precompile"
			);
5
			precompiles
5
				.prepare_test(Alice, address, [])
5
				.execute_reverts(|out| out == b"Removed precompile");
5
		}
1
	})
1
}
#[test]
1
fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() {
	use frame_support::dispatch::{DispatchInfo, Pays};
	use moonbase_runtime::{currency, EXTRINSIC_BASE_WEIGHT};
1
	ExtBuilder::default().build().execute_with(|| {
1
		let size_bytes = 0;
1
		let tip = 0;
1
		let dispatch_info = DispatchInfo {
1
			class: DispatchClass::Normal,
1
			pays_fee: Pays::Yes,
1
			call_weight: Weight::zero(),
1
			extension_weight: Weight::zero(),
1
		};
1

            
1
		assert_eq!(
1
			TransactionPayment::compute_fee(size_bytes, &dispatch_info, tip),
1
			EXTRINSIC_BASE_WEIGHT.ref_time() as u128 * currency::WEIGHT_FEE,
1
		);
1
	});
1
}
#[test]
1
fn deal_with_fees_handles_tip() {
	use frame_support::traits::OnUnbalanced;
	use moonbase_runtime::Treasury;
	use moonbeam_runtime_common::deal_with_fees::DealWithSubstrateFeesAndTip;
1
	ExtBuilder::default().build().execute_with(|| {
1
		set_parachain_inherent_data();
1
		// This test validates the functionality of the `DealWithSubstrateFeesAndTip` trait implementation
1
		// in the Moonbeam runtime. It verifies that:
1
		// - The correct proportion of the fee is sent to the treasury.
1
		// - The remaining fee is burned (removed from the total supply).
1
		// - The entire tip is sent to the block author.
1

            
1
		// The test details:
1
		// 1. Simulate issuing a `fee` of 100 and a `tip` of 1000.
1
		// 2. Confirm the initial total supply is 1,100 (equal to the sum of the issued fee and tip).
1
		// 3. Confirm the treasury's balance is initially 0.
1
		// 4. Execute the `DealWithSubstrateFeesAndTip::on_unbalanceds` function with the `fee` and `tip`.
1
		// 5. Validate that the treasury's balance has increased by 20% of the fee (based on FeesTreasuryProportion).
1
		// 6. Validate that 80% of the fee is burned, and the total supply decreases accordingly.
1
		// 7. Validate that the entire tip (100%) is sent to the block author (collator).
1

            
1
		// Step 1: Issue the fee and tip amounts.
1
		let fee = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
1
			AccountId,
1
		>>::issue(100);
1
		let tip = <pallet_balances::Pallet<Runtime> as frame_support::traits::fungible::Balanced<
1
			AccountId,
1
		>>::issue(1000);
1

            
1
		// Step 2: Validate the initial supply and balances.
1
		let total_supply_before = Balances::total_issuance();
1
		let block_author = pallet_author_inherent::Pallet::<Runtime>::get();
1
		let block_author_balance_before = Balances::free_balance(&block_author);
1
		assert_eq!(total_supply_before, 1_100);
1
		assert_eq!(Balances::free_balance(&Treasury::account_id()), 0);
		// Step 3: Execute the fees handling logic.
1
		DealWithSubstrateFeesAndTip::<
1
			Runtime,
1
			dynamic_params::runtime_config::FeesTreasuryProportion,
1
		>::on_unbalanceds(vec![fee, tip].into_iter());
1

            
1
		// Step 4: Compute the split between treasury and burned fees based on FeesTreasuryProportion (20%).
1
		let treasury_proportion = dynamic_params::runtime_config::FeesTreasuryProportion::get();
1

            
1
		let treasury_fee_part: Balance = treasury_proportion.mul_floor(100);
1
		let burnt_fee_part: Balance = 100 - treasury_fee_part;
1

            
1
		// Step 5: Validate the treasury received 20% of the fee.
1
		assert_eq!(
1
			Balances::free_balance(&Treasury::account_id()),
1
			treasury_fee_part,
1
		);
		// Step 6: Verify that 80% of the fee was burned (removed from the total supply).
1
		let total_supply_after = Balances::total_issuance();
1
		assert_eq!(total_supply_before - total_supply_after, burnt_fee_part,);
		// Step 7: Validate that the block author (collator) received 100% of the tip.
1
		let block_author_balance_after = Balances::free_balance(&block_author);
1
		assert_eq!(
1
			block_author_balance_after - block_author_balance_before,
1
			1000,
1
		);
1
	});
1
}
#[test]
1
fn evm_revert_substrate_events() {
1
	ExtBuilder::default()
1
		.with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
1
		.build()
1
		.execute_with(|| {
1
			let batch_precompile_address = H160::from_low_u64_be(2056);
1

            
1
			// Batch a transfer followed by an invalid call to batch.
1
			// Thus BatchAll will revert the transfer.
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call {
1
				source: ALICE.into(),
1
				target: batch_precompile_address,
1
				input: BatchPCall::batch_all {
1
					to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(),
1
					value: vec![U256::from(1 * UNIT), U256::zero()].into(),
1
					call_data: vec![].into(),
1
					gas_limit: vec![].into()
1
				}
1
				.into(),
1
				value: U256::zero(), // No value sent in EVM
1
				gas_limit: 500_000,
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: None,
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
1
			let transfer_count = System::events()
1
				.iter()
4
				.filter(|r| match r.event {
					RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true,
6
					_ => false,
6
				})
1
				.count();
1

            
1
			assert_eq!(transfer_count, 0, "there should be no transfer event");
1
		});
1
}
#[test]
1
fn evm_success_keeps_substrate_events() {
1
	ExtBuilder::default()
1
		.with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)])
1
		.build()
1
		.execute_with(|| {
1
			let batch_precompile_address = H160::from_low_u64_be(2056);
1

            
1
			assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call {
1
				source: ALICE.into(),
1
				target: batch_precompile_address,
1
				input: BatchPCall::batch_all {
1
					to: vec![Address(BOB.into())].into(),
1
					value: vec![U256::from(1 * UNIT)].into(),
1
					call_data: vec![].into(),
1
					gas_limit: vec![].into()
1
				}
1
				.into(),
1
				value: U256::zero(), // No value sent in EVM
1
				gas_limit: 500_000,
1
				max_fee_per_gas: U256::from(BASE_FEE_GENISIS),
1
				max_priority_fee_per_gas: None,
1
				nonce: Some(U256::from(0)),
1
				access_list: Vec::new(),
1
				authorization_list: Vec::new(),
1
			})
1
			.dispatch(<Runtime as frame_system::Config>::RuntimeOrigin::root()));
1
			let transfer_count = System::events()
1
				.iter()
6
				.filter(|r| match r.event {
1
					RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true,
9
					_ => false,
10
				})
1
				.count();
1

            
1
			assert_eq!(transfer_count, 1, "there should be 1 transfer event");
1
		});
1
}
#[test]
1
fn validate_transaction_fails_on_filtered_call() {
	use sp_runtime::transaction_validity::{
		InvalidTransaction, TransactionSource, TransactionValidityError,
	};
	use sp_transaction_pool::runtime_api::runtime_decl_for_tagged_transaction_queue::TaggedTransactionQueueV3; // editorconfig-checker-disable-line
1
	ExtBuilder::default().build().execute_with(|| {
1
		let xt = UncheckedExtrinsic::new_bare(
1
			pallet_evm::Call::<Runtime>::call {
1
				source: Default::default(),
1
				target: H160::default(),
1
				input: Vec::new(),
1
				value: Default::default(),
1
				gas_limit: Default::default(),
1
				max_fee_per_gas: Default::default(),
1
				max_priority_fee_per_gas: Default::default(),
1
				nonce: Default::default(),
1
				access_list: Default::default(),
1
				authorization_list: Default::default(),
1
			}
1
			.into(),
1
		);
1

            
1
		assert_eq!(
1
			Runtime::validate_transaction(TransactionSource::External, xt, Default::default(),),
1
			Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1
		);
1
	});
1
}
#[cfg(test)]
mod treasury_tests {
	use super::*;
	use frame_support::traits::fungible::NativeOrWithId;
	use moonbase_runtime::XcmWeightTrader;
	use sp_runtime::traits::Hash;
8
	fn expect_events(events: Vec<RuntimeEvent>) {
8
		let block_events: Vec<RuntimeEvent> =
59
			System::events().into_iter().map(|r| r.event).collect();
8

            
8
		dbg!(events.clone());
8
		dbg!(block_events.clone());
8

            
12
		assert!(events.iter().all(|evt| block_events.contains(evt)))
8
	}
13
	fn next_block() {
13
		System::reset_events();
13
		System::set_block_number(System::block_number() + 1u32);
13
		System::on_initialize(System::block_number());
13
		Treasury::on_initialize(System::block_number());
13
	}
6
	fn get_asset_balance(id: &u128, account: &AccountId) -> U256 {
6
		pallet_moonbeam_foreign_assets::Pallet::<Runtime>::balance(id.clone(), account.clone())
6
			.expect("failed to get account balance")
6
	}
	#[test]
1
	fn test_treasury_spend_local_with_root_origin() {
1
		let initial_treasury_balance = 1_000 * UNIT;
1
		ExtBuilder::default()
1
			.with_balances(vec![
1
				(AccountId::from(ALICE), 2_000 * UNIT),
1
				(Treasury::account_id(), initial_treasury_balance),
1
			])
1
			.build()
1
			.execute_with(|| {
1
				let spend_amount = 100u128 * UNIT;
1
				let spend_beneficiary = AccountId::from(BOB);
1

            
1
				next_block();
1

            
1
				// Perform treasury spending
1
				let valid_from = System::block_number() + 5u32;
1
				assert_ok!(moonbase_runtime::Sudo::sudo(
1
					root_origin(),
1
					Box::new(RuntimeCall::Treasury(pallet_treasury::Call::spend {
1
						amount: spend_amount,
1
						asset_kind: Box::new(NativeOrWithId::Native),
1
						beneficiary: Box::new(AccountId::from(BOB)),
1
						valid_from: Some(valid_from),
1
					}))
1
				));
1
				let payout_period =
1
					<<Runtime as pallet_treasury::Config>::PayoutPeriod as Get<u32>>::get();
1
				let expected_events = [RuntimeEvent::Treasury(
1
					pallet_treasury::Event::AssetSpendApproved {
1
						index: 0,
1
						asset_kind: NativeOrWithId::Native,
1
						amount: spend_amount,
1
						beneficiary: spend_beneficiary,
1
						valid_from,
1
						expire_at: payout_period + valid_from,
1
					},
1
				)]
1
				.to_vec();
1
				expect_events(expected_events);
6
				while System::block_number() < valid_from {
5
					next_block();
5
				}
1
				assert_ok!(Treasury::payout(origin_of(spend_beneficiary), 0));
1
				let expected_events = [
1
					RuntimeEvent::Treasury(pallet_treasury::Event::Paid {
1
						index: 0,
1
						payment_id: (),
1
					}),
1
					RuntimeEvent::Balances(pallet_balances::Event::Transfer {
1
						from: Treasury::account_id(),
1
						to: spend_beneficiary,
1
						amount: spend_amount,
1
					}),
1
				]
1
				.to_vec();
1
				expect_events(expected_events);
1
			});
1
	}
	#[test]
1
	fn test_treasury_spend_local_with_council_origin() {
1
		let initial_treasury_balance = 1_000 * UNIT;
1
		ExtBuilder::default()
1
			.with_balances(vec![
1
				(AccountId::from(ALICE), 2_000 * UNIT),
1
				(Treasury::account_id(), initial_treasury_balance),
1
			])
1
			.build()
1
			.execute_with(|| {
1
				let spend_amount = 100u128 * UNIT;
1
				let spend_beneficiary = AccountId::from(BOB);
1

            
1
				next_block();
1

            
1
				// TreasuryCouncilCollective
1
				assert_ok!(TreasuryCouncilCollective::set_members(
1
					root_origin(),
1
					vec![AccountId::from(ALICE)],
1
					Some(AccountId::from(ALICE)),
1
					1
1
				));
1
				next_block();
1

            
1
				// Perform treasury spending
1
				let valid_from = System::block_number() + 5u32;
1
				let proposal = RuntimeCall::Treasury(pallet_treasury::Call::spend {
1
					amount: spend_amount,
1
					asset_kind: Box::new(NativeOrWithId::Native),
1
					beneficiary: Box::new(AccountId::from(BOB)),
1
					valid_from: Some(valid_from),
1
				});
1
				assert_ok!(TreasuryCouncilCollective::propose(
1
					origin_of(AccountId::from(ALICE)),
1
					1,
1
					Box::new(proposal.clone()),
1
					1_000
1
				));
1
				let payout_period =
1
					<<Runtime as pallet_treasury::Config>::PayoutPeriod as Get<u32>>::get();
1
				let expected_events = [
1
					RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved {
1
						index: 0,
1
						asset_kind: NativeOrWithId::Native,
1
						amount: spend_amount,
1
						beneficiary: spend_beneficiary,
1
						valid_from,
1
						expire_at: payout_period + valid_from,
1
					}),
1
					RuntimeEvent::TreasuryCouncilCollective(pallet_collective::Event::Executed {
1
						proposal_hash: sp_runtime::traits::BlakeTwo256::hash_of(&proposal),
1
						result: Ok(()),
1
					}),
1
				]
1
				.to_vec();
1
				expect_events(expected_events);
6
				while System::block_number() < valid_from {
5
					next_block();
5
				}
1
				assert_ok!(Treasury::payout(origin_of(spend_beneficiary), 0));
1
				let expected_events = [
1
					RuntimeEvent::Treasury(pallet_treasury::Event::Paid {
1
						index: 0,
1
						payment_id: (),
1
					}),
1
					RuntimeEvent::Balances(pallet_balances::Event::Transfer {
1
						from: Treasury::account_id(),
1
						to: spend_beneficiary,
1
						amount: spend_amount,
1
					}),
1
				]
1
				.to_vec();
1
				expect_events(expected_events);
1
			});
1
	}
	#[test]
1
	fn test_treasury_spend_foreign_asset_with_root_origin() {
1
		let initial_treasury_balance = 1_000 * UNIT;
1
		let asset_id = 1000100010001000u128;
1
		ExtBuilder::default()
1
			.with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)])
1
			.build()
1
			.execute_with(|| {
1
				let spend_amount = 100u128 * UNIT;
1
				let spend_beneficiary = AccountId::from(BOB);
1

            
1
				let asset_location: Location = Location {
1
					parents: 1,
1
					interior: Junctions::Here,
1
				};
1

            
1
				assert_ok!(EvmForeignAssets::create_foreign_asset(
1
					root_origin(),
1
					asset_id,
1
					asset_location.clone(),
1
					12,
1
					bounded_vec![b'M', b'T'],
1
					bounded_vec![b'M', b'y', b'T', b'o', b'k'],
1
				));
1
				assert_ok!(XcmWeightTrader::add_asset(
1
					root_origin(),
1
					asset_location,
1
					1u128
1
				));
1
				assert_ok!(EvmForeignAssets::mint_into(
1
					asset_id,
1
					Treasury::account_id(),
1
					initial_treasury_balance.into()
1
				));
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &Treasury::account_id()),
1
					initial_treasury_balance.into(),
					"Treasury balance not updated"
				);
1
				assert_ok!(moonbase_runtime::Sudo::sudo(
1
					root_origin(),
1
					Box::new(RuntimeCall::Treasury(pallet_treasury::Call::spend {
1
						amount: spend_amount,
1
						asset_kind: Box::new(NativeOrWithId::WithId(asset_id)),
1
						beneficiary: Box::new(spend_beneficiary),
1
						valid_from: None,
1
					}))
1
				));
1
				let payout_period =
1
					<<Runtime as pallet_treasury::Config>::PayoutPeriod as Get<u32>>::get();
1

            
1
				let current_block = System::block_number();
1
				expect_events(vec![RuntimeEvent::Treasury(
1
					pallet_treasury::Event::AssetSpendApproved {
1
						index: 0,
1
						asset_kind: NativeOrWithId::WithId(asset_id),
1
						amount: spend_amount,
1
						beneficiary: spend_beneficiary,
1
						valid_from: current_block,
1
						expire_at: current_block + payout_period,
1
					},
1
				)]);
1

            
1
				assert_ok!(Treasury::payout(origin_of(spend_beneficiary), 0));
1
				expect_events(vec![RuntimeEvent::Treasury(pallet_treasury::Event::Paid {
1
					index: 0,
1
					payment_id: (),
1
				})]);
1

            
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &Treasury::account_id()),
1
					(initial_treasury_balance - spend_amount).into(),
					"Treasury balance not updated"
				);
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &spend_beneficiary),
1
					spend_amount.into(),
					"Treasury payout failed"
				);
1
			});
1
	}
	#[test]
1
	fn test_treasury_spend_foreign_asset_with_council_origin() {
1
		let initial_treasury_balance = 1_000 * UNIT;
1
		let asset_id = 1000100010001000u128;
1
		ExtBuilder::default()
1
			.with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)])
1
			.build()
1
			.execute_with(|| {
1
				let spend_amount = 100u128 * UNIT;
1
				let spend_beneficiary = AccountId::from(BOB);
1

            
1
				let asset_location: Location = Location {
1
					parents: 1,
1
					interior: Junctions::Here,
1
				};
1

            
1
				assert_ok!(EvmForeignAssets::create_foreign_asset(
1
					root_origin(),
1
					asset_id,
1
					asset_location.clone(),
1
					12,
1
					bounded_vec![b'M', b'T'],
1
					bounded_vec![b'M', b'y', b'T', b'o', b'k'],
1
				));
1
				assert_ok!(XcmWeightTrader::add_asset(
1
					root_origin(),
1
					asset_location,
1
					1u128
1
				));
1
				assert_ok!(EvmForeignAssets::mint_into(
1
					asset_id,
1
					Treasury::account_id(),
1
					initial_treasury_balance.into()
1
				));
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &Treasury::account_id()),
1
					initial_treasury_balance.into(),
					"Treasury balance not updated"
				);
				// TreasuryCouncilCollective
1
				assert_ok!(TreasuryCouncilCollective::set_members(
1
					root_origin(),
1
					vec![AccountId::from(ALICE)],
1
					Some(AccountId::from(ALICE)),
1
					1
1
				));
				// Perform treasury spending
1
				let proposal = RuntimeCall::Treasury(pallet_treasury::Call::spend {
1
					amount: spend_amount,
1
					asset_kind: Box::new(NativeOrWithId::WithId(asset_id)),
1
					beneficiary: Box::new(spend_beneficiary),
1
					valid_from: None,
1
				});
1
				assert_ok!(TreasuryCouncilCollective::propose(
1
					origin_of(AccountId::from(ALICE)),
1
					1,
1
					Box::new(proposal.clone()),
1
					1_000
1
				));
1
				let payout_period =
1
					<<Runtime as pallet_treasury::Config>::PayoutPeriod as Get<u32>>::get();
1

            
1
				let current_block = System::block_number();
1
				let expected_events = [
1
					RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved {
1
						index: 0,
1
						asset_kind: NativeOrWithId::WithId(asset_id),
1
						amount: spend_amount,
1
						beneficiary: spend_beneficiary,
1
						valid_from: current_block,
1
						expire_at: current_block + payout_period,
1
					}),
1
					RuntimeEvent::TreasuryCouncilCollective(pallet_collective::Event::Executed {
1
						proposal_hash: sp_runtime::traits::BlakeTwo256::hash_of(&proposal),
1
						result: Ok(()),
1
					}),
1
				]
1
				.to_vec();
1
				expect_events(expected_events);
1

            
1
				assert_ok!(Treasury::payout(origin_of(spend_beneficiary), 0));
1
				expect_events(vec![RuntimeEvent::Treasury(pallet_treasury::Event::Paid {
1
					index: 0,
1
					payment_id: (),
1
				})]);
1

            
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &Treasury::account_id()),
1
					(initial_treasury_balance - spend_amount).into(),
					"Treasury balance not updated"
				);
1
				assert_eq!(
1
					get_asset_balance(&asset_id, &spend_beneficiary),
1
					spend_amount.into(),
					"Treasury payout failed"
				);
1
			});
1
	}
}
#[cfg(test)]
mod fee_tests {
	use super::*;
	use fp_evm::FeeCalculator;
	use frame_support::{
		traits::{ConstU128, OnFinalize},
		weights::{ConstantMultiplier, WeightToFee},
	};
	use moonbase_runtime::{
		currency, BlockWeights, FastAdjustingFeeUpdate, LengthToFee, MinimumMultiplier,
		TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS,
	};
	use sp_runtime::{BuildStorage, FixedPointNumber, Perbill};
1
	fn run_with_system_weight<F>(w: Weight, mut assertions: F)
1
	where
1
		F: FnMut() -> (),
1
	{
1
		let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
			.build_storage()
1
			.unwrap()
1
			.into();
1
		t.execute_with(|| {
1
			System::set_block_consumed_resources(w, 0);
1
			assertions()
1
		});
1
	}
	#[test]
1
	fn test_multiplier_can_grow_from_zero() {
1
		let minimum_multiplier = MinimumMultiplier::get();
1
		let target = TargetBlockFullness::get()
1
			* BlockWeights::get()
1
				.get(DispatchClass::Normal)
1
				.max_total
1
				.unwrap();
1
		// if the min is too small, then this will not change, and we are doomed forever.
1
		// the weight is 1/100th bigger than target.
1
		run_with_system_weight(target * 101 / 100, || {
1
			let next = FastAdjustingFeeUpdate::<Runtime>::convert(minimum_multiplier);
1
			assert!(
1
				next > minimum_multiplier,
				"{:?} !>= {:?}",
				next,
				minimum_multiplier
			);
1
		})
1
	}
	#[test]
1
	fn test_fee_calculation() {
1
		let base_extrinsic = BlockWeights::get()
1
			.get(DispatchClass::Normal)
1
			.base_extrinsic;
1
		let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000);
1
		let extrinsic_len = 100u32;
1
		let extrinsic_weight = 5_000u64;
1
		let tip = 42u128;
		type WeightToFeeImpl =
			ConstantMultiplier<u128, ConstU128<{ moonbase_runtime::currency::WEIGHT_FEE }>>;
		type LengthToFeeImpl = LengthToFee;
		// base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip
1
		let expected_fee =
1
			WeightToFeeImpl::weight_to_fee(&base_extrinsic)
1
				+ multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee(
1
					&Weight::from_parts(extrinsic_weight, 1),
1
				)) + LengthToFeeImpl::weight_to_fee(&Weight::from_parts(extrinsic_len as u64, 1))
1
				+ tip;
1

            
1
		let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
			.build_storage()
1
			.unwrap()
1
			.into();
1
		t.execute_with(|| {
1
			pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier);
1
			let actual_fee = TransactionPayment::compute_fee(
1
				extrinsic_len,
1
				&frame_support::dispatch::DispatchInfo {
1
					class: DispatchClass::Normal,
1
					pays_fee: frame_support::dispatch::Pays::Yes,
1
					call_weight: Weight::from_parts(extrinsic_weight, 1),
1
					extension_weight: Weight::zero(),
1
				},
1
				tip,
1
			);
1

            
1
			assert_eq!(
				expected_fee,
				actual_fee,
				"The actual fee did not match the expected fee, diff {}",
				actual_fee - expected_fee
			);
1
		});
1
	}
	#[test]
1
	fn test_min_gas_price_is_deterministic() {
1
		let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
			.build_storage()
1
			.unwrap()
1
			.into();
1
		t.execute_with(|| {
1
			let multiplier = sp_runtime::FixedU128::from_u32(1);
1
			pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier);
1
			let actual = TransactionPaymentAsGasPrice::min_gas_price().0;
1
			let expected: U256 = multiplier
1
				.saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128))
1
				.into();
1

            
1
			assert_eq!(expected, actual);
1
		});
1
	}
	#[test]
1
	fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() {
1
		let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
			.build_storage()
1
			.unwrap()
1
			.into();
1
		t.execute_with(|| {
1
			let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000);
1
			let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000);
1

            
1
			pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier_1);
1
			let a = TransactionPaymentAsGasPrice::min_gas_price();
1
			pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier_2);
1
			let b = TransactionPaymentAsGasPrice::min_gas_price();
1

            
1
			assert_ne!(
				a, b,
				"both gas prices were equal, unexpected precision loss incurred"
			);
1
		});
1
	}
	#[test]
1
	fn test_fee_scenarios() {
		use sp_runtime::FixedU128;
1
		let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
1
			.build_storage()
1
			.unwrap()
1
			.into();
1
		t.execute_with(|| {
1
			let weight_fee_per_gas = (currency::WEIGHT_FEE).saturating_mul(WEIGHT_PER_GAS as u128);
12
			let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 {
12
				let start_multiplier =
12
					FixedU128::from_rational(start_gas_price, weight_fee_per_gas);
12
				pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(start_multiplier);
12

            
12
				let block_weight = NORMAL_WEIGHT * fullness;
60004
				for i in 0..num_blocks {
60004
					System::set_block_number(i as u32);
60004
					System::set_block_consumed_resources(block_weight, 0);
60004
					TransactionPayment::on_finalize(i as u32);
60004
				}
12
				TransactionPaymentAsGasPrice::min_gas_price().0
12
			};
			// The expected values are the ones observed during test execution,
			// they are expected to change when parameters that influence
			// the fee calculation are changed, and should be updated accordingly.
			// If a test fails when nothing specific to fees has changed,
			// it may indicate an unexpected collateral effect and should be investigated
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(0), 1),
1
				U256::from(998_600_980),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(25), 1),
1
				U256::from(999_600_080),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(50), 1),
1
				U256::from(1_000_600_180),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(100), 1),
1
				U256::from(1_002_603_380),
1
			);
			// 1 "real" hour (at 6-second blocks)
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(0), 600),
1
				U256::from(431_710_642),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(25), 600),
1
				U256::from(786_627_866),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(50), 600),
1
				U256::from(1_433_329_383u128),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(100), 600),
1
				U256::from(4_758_812_897u128),
1
			);
			// 1 "real" day (at 6-second blocks)
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(0), 14400),
1
				U256::from(31_250_000), // lower bound enforced
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(25), 14400),
1
				U256::from(31_250_000), // lower bound enforced if threshold not reached
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(50), 14400),
1
				U256::from(5_653_326_895_069u128),
1
			);
1
			assert_eq!(
1
				sim(1_000_000_000, Perbill::from_percent(100), 14400),
1
				U256::from(31_250_000_000_000u128),
1
				// upper bound enforced (min_gas_price * MaximumMultiplier)
1
			);
1
		});
1
	}
}
#[cfg(test)]
mod balance_tests {
	use crate::common::{ExtBuilder, ALICE};
	use frame_support::assert_ok;
	use frame_support::traits::LockableCurrency;
	use frame_support::traits::{LockIdentifier, ReservableCurrency, WithdrawReasons};
	use moonbase_runtime::{Balances, Runtime, System};
	use moonbeam_core_primitives::AccountId;
	#[test]
1
	fn reserve_should_work_for_frozen_balance() {
1
		let alice = AccountId::from(ALICE);
		const ID_1: LockIdentifier = *b"1       ";
1
		ExtBuilder::default()
1
			.with_balances(vec![(alice, 10)])
1
			.build()
1
			.execute_with(|| {
1
				// Check balances
1
				let account = System::account(&alice).data;
1
				assert_eq!(account.free, 10);
1
				assert_eq!(account.frozen, 0);
1
				assert_eq!(account.reserved, 0);
1
				Balances::set_lock(ID_1, &alice, 9, WithdrawReasons::RESERVE);
1

            
1
				let account = System::account(&alice).data;
1
				assert_eq!(account.free, 10);
1
				assert_eq!(account.frozen, 9);
1
				assert_eq!(account.reserved, 0);
1
				assert_ok!(Balances::reserve(&alice, 5));
1
				let account = System::account(&alice).data;
1
				assert_eq!(account.free, 5);
1
				assert_eq!(account.frozen, 9);
1
				assert_eq!(account.reserved, 5);
1
				let previous_reserved_amount = account.reserved;
1
				let ed: u128 = <Runtime as pallet_balances::Config>::ExistentialDeposit::get();
1
				let next_reserve = account.free.saturating_sub(ed);
1
				assert_ok!(Balances::reserve(&alice, next_reserve));
1
				let account = System::account(&alice).data;
1
				assert_eq!(account.free, ed);
1
				assert_eq!(account.frozen, 9);
1
				assert_eq!(
1
					account.reserved,
1
					previous_reserved_amount.saturating_add(next_reserve)
1
				);
1
			});
1
	}
}
moonbeam_runtime_common::generate_common_xcm_tests!(moonbase_runtime);