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::UNIT, AccountId, AuthorFilterConfig, AuthorMappingConfig, Balance, BalancesConfig,
21
	CrowdloanRewardsConfig, EVMConfig, EligibilityValue, EthereumChainIdConfig, EthereumConfig,
22
	InflationInfo, MaintenanceModeConfig, MoonbeamOrbitersConfig,
23
	OpenTechCommitteeCollectiveConfig, ParachainInfoConfig, ParachainStakingConfig,
24
	PolkadotXcmConfig, Precompiles, Range, RuntimeGenesisConfig, SudoConfig,
25
	TransactionPaymentConfig, TreasuryCouncilCollectiveConfig, XcmTransactorConfig, HOURS,
26
};
27
use alloc::{vec, vec::Vec};
28
use cumulus_primitives_core::ParaId;
29
use fp_evm::GenesisAccount;
30
use frame_support::PalletId;
31
use nimbus_primitives::NimbusId;
32
use pallet_transaction_payment::Multiplier;
33
use pallet_xcm_transactor::relay_indices::RelayChainIndices;
34
use sp_genesis_builder::PresetId;
35
use sp_keyring::Sr25519Keyring;
36
use sp_runtime::{traits::One, Perbill, Percent};
37

            
38
const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(20);
39
const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(30);
40
const BLOCKS_PER_ROUND: u32 = 2 * HOURS;
41
const BLOCKS_PER_YEAR: u32 = 31_557_600 / 6;
42
const NUM_SELECTED_CANDIDATES: u32 = 8;
43

            
44
/// Westend pallet and extrinsic indices
45
pub const WESTEND_RELAY_INDICES: RelayChainIndices = RelayChainIndices {
46
	staking: 6u8,
47
	utility: 16u8,
48
	hrmp: 51u8,
49
	bond: 0u8,
50
	bond_extra: 1u8,
51
	unbond: 2u8,
52
	withdraw_unbonded: 3u8,
53
	validate: 4u8,
54
	nominate: 5u8,
55
	chill: 6u8,
56
	set_payee: 7u8,
57
	set_controller: 8u8,
58
	rebond: 19u8,
59
	as_derivative: 1u8,
60
	init_open_channel: 0u8,
61
	accept_open_channel: 1u8,
62
	close_channel: 2u8,
63
	cancel_open_request: 6u8,
64
};
65

            
66
23
pub fn moonbase_inflation_config() -> InflationInfo<Balance> {
67
23
	fn to_round_inflation(annual: Range<Perbill>) -> Range<Perbill> {
68
		use pallet_parachain_staking::inflation::perbill_annual_to_perbill_round;
69
23
		perbill_annual_to_perbill_round(
70
23
			annual,
71
			// rounds per year
72
23
			BLOCKS_PER_YEAR / BLOCKS_PER_ROUND,
73
		)
74
23
	}
75
23
	let annual = Range {
76
23
		min: Perbill::from_percent(4),
77
23
		ideal: Perbill::from_percent(5),
78
23
		max: Perbill::from_percent(5),
79
23
	};
80
23
	InflationInfo {
81
23
		// staking expectations
82
23
		expect: Range {
83
23
			min: 100_000 * UNIT,
84
23
			ideal: 200_000 * UNIT,
85
23
			max: 500_000 * UNIT,
86
23
		},
87
23
		// annual inflation
88
23
		annual,
89
23
		round: to_round_inflation(annual),
90
23
	}
91
23
}
92

            
93
23
pub fn testnet_genesis(
94
23
	root_key: AccountId,
95
23
	treasury_council_members: Vec<AccountId>,
96
23
	open_tech_committee_members: Vec<AccountId>,
97
23
	candidates: Vec<(AccountId, NimbusId, Balance)>,
98
23
	delegations: Vec<(AccountId, AccountId, Balance, Percent)>,
99
23
	endowed_accounts: Vec<AccountId>,
100
23
	para_id: ParaId,
101
23
	chain_id: u64,
102
23
) -> serde_json::Value {
103
	// This is the simplest bytecode to revert without returning any data.
104
	// We will pre-deploy it under all of our precompiles to ensure they can be called from
105
	// within contracts.
106
	// (PUSH1 0x00 PUSH1 0x00 REVERT)
107
23
	let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];
108

            
109
	// Fund the crowdloan pallet account with enough balance for rewards
110
23
	let crowdloan_pallet_account: AccountId =
111
23
		sp_runtime::traits::AccountIdConversion::into_account_truncating(&PalletId(*b"Crowdloa"));
112

            
113
23
	let mut balances: Vec<(AccountId, Balance)> = endowed_accounts
114
23
		.iter()
115
23
		.cloned()
116
43
		.map(|k| (k, 1 << 80))
117
23
		.collect();
118

            
119
	// Add crowdloan pallet account with sufficient funds for all rewards
120
23
	balances.push((crowdloan_pallet_account, 100_000_000 * UNIT));
121

            
122
23
	let config = RuntimeGenesisConfig {
123
23
		system: Default::default(),
124
23
		balances: BalancesConfig {
125
23
			balances,
126
23
			dev_accounts: Default::default(),
127
23
		},
128
23
		sudo: SudoConfig {
129
23
			key: Some(root_key),
130
23
		},
131
23
		parachain_info: ParachainInfoConfig {
132
23
			parachain_id: para_id,
133
23
			..Default::default()
134
23
		},
135
23
		ethereum_chain_id: EthereumChainIdConfig {
136
23
			chain_id,
137
23
			..Default::default()
138
23
		},
139
		evm: EVMConfig {
140
			// We need _some_ code inserted at the precompile address so that
141
			// the evm will actually call the address.
142
23
			accounts: Precompiles::used_addresses()
143
1104
				.map(|addr| {
144
1104
					(
145
1104
						addr.into(),
146
1104
						GenesisAccount {
147
1104
							nonce: Default::default(),
148
1104
							balance: Default::default(),
149
1104
							storage: Default::default(),
150
1104
							code: revert_bytecode.clone(),
151
1104
						},
152
1104
					)
153
1104
				})
154
23
				.collect(),
155
23
			..Default::default()
156
		},
157
23
		ethereum: EthereumConfig {
158
23
			..Default::default()
159
23
		},
160
		parachain_staking: ParachainStakingConfig {
161
23
			candidates: candidates
162
23
				.iter()
163
23
				.cloned()
164
23
				.map(|(account, _, bond)| (account, bond))
165
23
				.collect(),
166
23
			delegations,
167
23
			inflation_config: moonbase_inflation_config(),
168
			collator_commission: COLLATOR_COMMISSION,
169
			parachain_bond_reserve_percent: PARACHAIN_BOND_RESERVE_PERCENT,
170
			blocks_per_round: BLOCKS_PER_ROUND,
171
			num_selected_candidates: NUM_SELECTED_CANDIDATES,
172
		},
173
23
		treasury_council_collective: TreasuryCouncilCollectiveConfig {
174
23
			phantom: Default::default(),
175
23
			members: treasury_council_members,
176
23
		},
177
23
		open_tech_committee_collective: OpenTechCommitteeCollectiveConfig {
178
23
			phantom: Default::default(),
179
23
			members: open_tech_committee_members,
180
23
		},
181
23
		author_filter: AuthorFilterConfig {
182
23
			eligible_count: EligibilityValue::new_unchecked(50),
183
23
			..Default::default()
184
23
		},
185
		author_mapping: AuthorMappingConfig {
186
23
			mappings: candidates
187
23
				.iter()
188
23
				.cloned()
189
23
				.map(|(account_id, author_id, _)| (author_id, account_id))
190
23
				.collect(),
191
		},
192
23
		proxy_genesis_companion: Default::default(),
193
23
		treasury: Default::default(),
194
23
		maintenance_mode: MaintenanceModeConfig {
195
23
			start_in_maintenance_mode: false,
196
23
			..Default::default()
197
23
		},
198
		// This should initialize it to whatever we have set in the pallet
199
23
		polkadot_xcm: PolkadotXcmConfig::default(),
200
23
		transaction_payment: TransactionPaymentConfig {
201
23
			multiplier: Multiplier::from(8u128),
202
23
			..Default::default()
203
23
		},
204
23
		moonbeam_orbiters: MoonbeamOrbitersConfig {
205
23
			min_orbiter_deposit: One::one(),
206
23
		},
207
23
		xcm_transactor: XcmTransactorConfig {
208
23
			relay_indices: WESTEND_RELAY_INDICES,
209
23
			..Default::default()
210
23
		},
211
23
		crowdloan_rewards: CrowdloanRewardsConfig {
212
23
			funded_accounts: vec![
213
23
				// Dorothy account with test rewards
214
23
				(
215
23
					[
216
23
						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
217
23
						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
218
23
						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
219
23
					],
220
23
					Some(AccountId::from(sp_core::hex2array!(
221
23
						"773539d4Ac0e786233D90A233654ccEE26a613D9"
222
23
					))),
223
23
					3_000_000 * UNIT,
224
23
				),
225
23
			],
226
23
			init_vesting_block: 0u32,
227
23
			end_vesting_block: 201600u32,
228
23
		},
229
	};
230

            
231
23
	serde_json::to_value(&config).expect("Could not build genesis config.")
232
23
}
233

            
234
pub fn development() -> serde_json::Value {
235
	testnet_genesis(
236
		// Alith is Sudo
237
		AccountId::from(sp_core::hex2array!(
238
			"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
239
		)),
240
		// Treasury Council members: Baltathar, Charleth and Dorothy
241
		vec![
242
			AccountId::from(sp_core::hex2array!(
243
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
244
			)),
245
			AccountId::from(sp_core::hex2array!(
246
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
247
			)),
248
			AccountId::from(sp_core::hex2array!(
249
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
250
			)),
251
		],
252
		// Open Tech committee members: Alith and Baltathar
253
		vec![
254
			AccountId::from(sp_core::hex2array!(
255
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
256
			)),
257
			AccountId::from(sp_core::hex2array!(
258
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
259
			)),
260
		],
261
		// Collator Candidates
262
		vec![(
263
			// Alice -> Alith
264
			AccountId::from(sp_core::hex2array!(
265
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
266
			)),
267
			NimbusId::from(Sr25519Keyring::Alice.public()),
268
			1_000 * UNIT,
269
		)],
270
		// Delegations
271
		vec![],
272
		// Endowed: Alith, Baltathar, Charleth and Dorothy
273
		vec![
274
			AccountId::from(sp_core::hex2array!(
275
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
276
			)),
277
			AccountId::from(sp_core::hex2array!(
278
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
279
			)),
280
			AccountId::from(sp_core::hex2array!(
281
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
282
			)),
283
			AccountId::from(sp_core::hex2array!(
284
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
285
			)),
286
		],
287
		Default::default(), // para_id
288
		1280,               //ChainId
289
	)
290
}
291

            
292
/// Provides the JSON representation of predefined genesis config for given `id`.
293
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
294
	let patch = match id.as_str() {
295
		sp_genesis_builder::DEV_RUNTIME_PRESET => development(),
296
		_ => return None,
297
	};
298
	Some(
299
		serde_json::to_string(&patch)
300
			.expect("serialization to json is expected to work. qed.")
301
			.into_bytes(),
302
	)
303
}
304

            
305
/// List of supported presets.
306
pub fn preset_names() -> Vec<PresetId> {
307
	vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
308
}