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
extern crate alloc;
18

            
19
use crate::{
20
	currency::GLMR, currency::SUPPLY_FACTOR, xcm_config::Transactors, AccountId,
21
	AuthorFilterConfig, AuthorMappingConfig, Balance, Balances, BalancesConfig,
22
	BridgeKusamaGrandpaConfig, BridgeKusamaMessagesConfig, BridgeKusamaParachainsConfig,
23
	BridgeXcmOverMoonriverConfig, EVMConfig, EligibilityValue, EthereumChainIdConfig,
24
	EthereumConfig, EvmForeignAssetsConfig, InflationInfo, MaintenanceModeConfig,
25
	OpenTechCommitteeCollectiveConfig, ParachainInfoConfig, ParachainStakingConfig,
26
	PolkadotXcmConfig, Precompiles, Range, RuntimeGenesisConfig, TransactionPaymentConfig,
27
	TreasuryCouncilCollectiveConfig, XcmTransactorConfig, XcmWeightTraderConfig, HOURS,
28
};
29
use alloc::{vec, vec::Vec};
30
use bp_messages::MessagesOperatingMode;
31
use bp_runtime::BasicOperatingMode;
32
use cumulus_primitives_core::ParaId;
33
use fp_evm::GenesisAccount;
34
use frame_support::pallet_prelude::PalletInfoAccess;
35
use nimbus_primitives::NimbusId;
36
use pallet_moonbeam_foreign_assets::EvmForeignAssetInfo;
37
use pallet_transaction_payment::Multiplier;
38
use pallet_xcm_weight_trader::XcmWeightTraderAssetInfo;
39
use sp_genesis_builder::PresetId;
40
use sp_keyring::Sr25519Keyring;
41
use sp_runtime::{Perbill, Percent};
42
use xcm::prelude::{GlobalConsensus, Junctions, Location, NetworkId, PalletInstance, Parachain};
43

            
44
const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(20);
45
const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(30);
46
const BLOCKS_PER_ROUND: u32 = 6 * HOURS;
47
const BLOCKS_PER_YEAR: u32 = 31_557_600 / 12;
48
const NUM_SELECTED_CANDIDATES: u32 = 8;
49

            
50
pub fn moonbeam_inflation_config() -> InflationInfo<Balance> {
51
	fn to_round_inflation(annual: Range<Perbill>) -> Range<Perbill> {
52
		use pallet_parachain_staking::inflation::perbill_annual_to_perbill_round;
53
		perbill_annual_to_perbill_round(
54
			annual,
55
			// rounds per year
56
			BLOCKS_PER_YEAR / BLOCKS_PER_ROUND,
57
		)
58
	}
59
	let annual = Range {
60
		min: Perbill::from_percent(4),
61
		ideal: Perbill::from_percent(5),
62
		max: Perbill::from_percent(5),
63
	};
64
	InflationInfo {
65
		// staking expectations
66
		expect: Range {
67
			min: 100_000 * GLMR * SUPPLY_FACTOR,
68
			ideal: 200_000 * GLMR * SUPPLY_FACTOR,
69
			max: 500_000 * GLMR * SUPPLY_FACTOR,
70
		},
71
		// annual inflation
72
		annual,
73
		round: to_round_inflation(annual),
74
	}
75
}
76

            
77
pub fn testnet_genesis(
78
	treasury_council_members: Vec<AccountId>,
79
	open_tech_committee_members: Vec<AccountId>,
80
	candidates: Vec<(AccountId, NimbusId, Balance)>,
81
	delegations: Vec<(AccountId, AccountId, Balance, Percent)>,
82
	endowed_accounts: Vec<AccountId>,
83
	para_id: ParaId,
84
	chain_id: u64,
85
) -> serde_json::Value {
86
	// This is the simplest bytecode to revert without returning any data.
87
	// We will pre-deploy it under all of our precompiles to ensure they can be called from
88
	// within contracts.
89
	// (PUSH1 0x00 PUSH1 0x00 REVERT)
90
	let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];
91

            
92
	let config = RuntimeGenesisConfig {
93
		system: Default::default(),
94
		balances: BalancesConfig {
95
			balances: endowed_accounts
96
				.iter()
97
				.cloned()
98
				.map(|k| (k, 1 << 110))
99
				.collect(),
100
			dev_accounts: Default::default(),
101
		},
102
		parachain_info: ParachainInfoConfig {
103
			parachain_id: para_id,
104
			..Default::default()
105
		},
106
		ethereum_chain_id: EthereumChainIdConfig {
107
			chain_id,
108
			..Default::default()
109
		},
110
		evm: EVMConfig {
111
			// We need _some_ code inserted at the precompile address so that
112
			// the evm will actually call the address.
113
			accounts: Precompiles::used_addresses()
114
				.map(|addr| {
115
					(
116
						addr.into(),
117
						GenesisAccount {
118
							nonce: Default::default(),
119
							balance: Default::default(),
120
							storage: Default::default(),
121
							code: revert_bytecode.clone(),
122
						},
123
					)
124
				})
125
				.collect(),
126
			..Default::default()
127
		},
128
		ethereum: EthereumConfig {
129
			..Default::default()
130
		},
131
		parachain_staking: ParachainStakingConfig {
132
			candidates: candidates
133
				.iter()
134
				.cloned()
135
				.map(|(account, _, bond)| (account, bond))
136
				.collect(),
137
			delegations,
138
			inflation_config: moonbeam_inflation_config(),
139
			collator_commission: COLLATOR_COMMISSION,
140
			parachain_bond_reserve_percent: PARACHAIN_BOND_RESERVE_PERCENT,
141
			blocks_per_round: BLOCKS_PER_ROUND,
142
			num_selected_candidates: NUM_SELECTED_CANDIDATES,
143
		},
144
		treasury_council_collective: TreasuryCouncilCollectiveConfig {
145
			phantom: Default::default(),
146
			members: treasury_council_members,
147
		},
148
		open_tech_committee_collective: OpenTechCommitteeCollectiveConfig {
149
			phantom: Default::default(),
150
			members: open_tech_committee_members,
151
		},
152
		author_filter: AuthorFilterConfig {
153
			eligible_count: EligibilityValue::new_unchecked(50),
154
			..Default::default()
155
		},
156
		author_mapping: AuthorMappingConfig {
157
			mappings: candidates
158
				.iter()
159
				.cloned()
160
				.map(|(account_id, author_id, _)| (author_id, account_id))
161
				.collect(),
162
		},
163
		proxy_genesis_companion: Default::default(),
164
		treasury: Default::default(),
165
		maintenance_mode: MaintenanceModeConfig {
166
			start_in_maintenance_mode: false,
167
			..Default::default()
168
		},
169
		polkadot_xcm: PolkadotXcmConfig {
170
			supported_version: vec![
171
				// Required for bridging Moonbeam with Moonriver
172
				(
173
					bp_moonriver::GlobalConsensusLocation::get(),
174
					xcm::latest::VERSION,
175
				),
176
			],
177
			..Default::default()
178
		},
179
		transaction_payment: TransactionPaymentConfig {
180
			multiplier: Multiplier::from(8u128),
181
			..Default::default()
182
		},
183
		evm_foreign_assets: EvmForeignAssetsConfig {
184
			assets: vec![EvmForeignAssetInfo {
185
				asset_id: 1001,
186
				name: b"xcMOVR".to_vec().try_into().expect("Invalid asset name"),
187
				symbol: b"xcMOVR".to_vec().try_into().expect("Invalid asset symbol"),
188
				decimals: 18,
189
				xcm_location: Location::new(
190
					2,
191
					[
192
						GlobalConsensus(crate::bridge_config::KusamaGlobalConsensusNetwork::get()),
193
						Parachain(<bp_moonriver::Moonriver as bp_runtime::Parachain>::PARACHAIN_ID),
194
						PalletInstance(<Balances as PalletInfoAccess>::index() as u8),
195
					],
196
				),
197
			}],
198
			_phantom: Default::default(),
199
		},
200
		xcm_weight_trader: XcmWeightTraderConfig {
201
			assets: vec![XcmWeightTraderAssetInfo {
202
				location: Location::new(
203
					2,
204
					[
205
						GlobalConsensus(crate::bridge_config::KusamaGlobalConsensusNetwork::get()),
206
						Parachain(<bp_moonriver::Moonriver as bp_runtime::Parachain>::PARACHAIN_ID),
207
						PalletInstance(<Balances as PalletInfoAccess>::index() as u8),
208
					],
209
				),
210
				relative_price: GLMR,
211
			}],
212
			_phantom: Default::default(),
213
		},
214
		bridge_kusama_grandpa: BridgeKusamaGrandpaConfig {
215
			owner: Some(endowed_accounts[0]),
216
			init_data: None,
217
		},
218
		bridge_kusama_parachains: BridgeKusamaParachainsConfig {
219
			owner: Some(endowed_accounts[0]),
220
			operating_mode: BasicOperatingMode::Normal,
221
			..Default::default()
222
		},
223
		bridge_kusama_messages: BridgeKusamaMessagesConfig {
224
			owner: Some(endowed_accounts[0]),
225
			opened_lanes: vec![],
226
			operating_mode: MessagesOperatingMode::Basic(BasicOperatingMode::Normal),
227
			_phantom: Default::default(),
228
		},
229
		bridge_xcm_over_moonriver: BridgeXcmOverMoonriverConfig {
230
			opened_bridges: vec![(
231
				Location::new(
232
					1,
233
					[Parachain(
234
						<bp_moonbeam::Moonbeam as bp_runtime::Parachain>::PARACHAIN_ID,
235
					)],
236
				),
237
				Junctions::from([
238
					NetworkId::Kusama.into(),
239
					Parachain(<bp_moonriver::Moonriver as bp_runtime::Parachain>::PARACHAIN_ID),
240
				]),
241
				Some(Default::default()),
242
			)],
243
			_phantom: Default::default(),
244
		},
245
		xcm_transactor: XcmTransactorConfig {
246
			chain_indices_map: vec![
247
				(
248
					Transactors::Relay,
249
					pallet_xcm_transactor::chain_indices::ChainIndices::Relay(
250
						moonbeam_relay_encoder::polkadot::POLKADOT_RELAY_INDICES,
251
					),
252
				),
253
				(
254
					Transactors::AssetHub,
255
					pallet_xcm_transactor::chain_indices::ChainIndices::AssetHub(
256
						moonbeam_assethub_encoder::polkadot::POLKADOT_ASSETHUB_INDICES,
257
					),
258
				),
259
			],
260
			..Default::default()
261
		},
262
	};
263

            
264
	serde_json::to_value(&config).expect("Could not build genesis config.")
265
}
266

            
267
/// Generate a chain spec for use with the development service.
268
pub fn development() -> serde_json::Value {
269
	testnet_genesis(
270
		// Treasury Council members: Baltathar, Charleth and Dorothy
271
		vec![
272
			AccountId::from(sp_core::hex2array!(
273
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
274
			)),
275
			AccountId::from(sp_core::hex2array!(
276
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
277
			)),
278
			AccountId::from(sp_core::hex2array!(
279
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
280
			)),
281
		],
282
		// Open Tech committee members: Alith and Baltathar
283
		vec![
284
			AccountId::from(sp_core::hex2array!(
285
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
286
			)),
287
			AccountId::from(sp_core::hex2array!(
288
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
289
			)),
290
		],
291
		// Collator Candidate: Alice -> Alith
292
		vec![(
293
			AccountId::from(sp_core::hex2array!(
294
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
295
			)),
296
			NimbusId::from(Sr25519Keyring::Alice.public()),
297
			20_000 * GLMR * SUPPLY_FACTOR,
298
		)],
299
		// Delegations
300
		vec![],
301
		vec![
302
			AccountId::from(sp_core::hex2array!(
303
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
304
			)),
305
			AccountId::from(sp_core::hex2array!(
306
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
307
			)),
308
			AccountId::from(sp_core::hex2array!(
309
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
310
			)),
311
			AccountId::from(sp_core::hex2array!(
312
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
313
			)),
314
		],
315
		Default::default(), // para_id
316
		1281,               //ChainId
317
	)
318
}
319

            
320
/// Provides the JSON representation of predefined genesis config for given `id`.
321
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
322
	let patch = match id.as_str() {
323
		sp_genesis_builder::DEV_RUNTIME_PRESET => development(),
324
		_ => return None,
325
	};
326
	Some(
327
		serde_json::to_string(&patch)
328
			.expect("serialization to json is expected to work. qed.")
329
			.into_bytes(),
330
	)
331
}
332

            
333
/// List of supported presets.
334
pub fn preset_names() -> Vec<PresetId> {
335
	vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
336
}