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

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

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

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

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

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

            
231
2
	serde_json::to_value(&config).expect("Could not build genesis config.")
232
2
}
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
}