moonbase_runtime/
genesis_config_preset.rs

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
17extern crate alloc;
18
19use 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};
27use alloc::{vec, vec::Vec};
28use cumulus_primitives_core::ParaId;
29use fp_evm::GenesisAccount;
30use frame_support::PalletId;
31use nimbus_primitives::NimbusId;
32use pallet_transaction_payment::Multiplier;
33use pallet_xcm_transactor::relay_indices::RelayChainIndices;
34use sp_genesis_builder::PresetId;
35use sp_keyring::Sr25519Keyring;
36use sp_runtime::{traits::One, Perbill, Percent};
37
38const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(20);
39const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(30);
40const BLOCKS_PER_ROUND: u32 = 2 * HOURS;
41const BLOCKS_PER_YEAR: u32 = 31_557_600 / 6;
42const NUM_SELECTED_CANDIDATES: u32 = 8;
43
44/// Westend pallet and extrinsic indices
45pub 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
66pub fn moonbase_inflation_config() -> InflationInfo<Balance> {
67	fn to_round_inflation(annual: Range<Perbill>) -> Range<Perbill> {
68		use pallet_parachain_staking::inflation::perbill_annual_to_perbill_round;
69		perbill_annual_to_perbill_round(
70			annual,
71			// rounds per year
72			BLOCKS_PER_YEAR / BLOCKS_PER_ROUND,
73		)
74	}
75	let annual = Range {
76		min: Perbill::from_percent(4),
77		ideal: Perbill::from_percent(5),
78		max: Perbill::from_percent(5),
79	};
80	InflationInfo {
81		// staking expectations
82		expect: Range {
83			min: 100_000 * UNIT,
84			ideal: 200_000 * UNIT,
85			max: 500_000 * UNIT,
86		},
87		// annual inflation
88		annual,
89		round: to_round_inflation(annual),
90	}
91}
92
93pub fn testnet_genesis(
94	root_key: AccountId,
95	treasury_council_members: Vec<AccountId>,
96	open_tech_committee_members: Vec<AccountId>,
97	candidates: Vec<(AccountId, NimbusId, Balance)>,
98	delegations: Vec<(AccountId, AccountId, Balance, Percent)>,
99	endowed_accounts: Vec<AccountId>,
100	para_id: ParaId,
101	chain_id: u64,
102) -> 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	let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD];
108
109	// Fund the crowdloan pallet account with enough balance for rewards
110	let crowdloan_pallet_account: AccountId =
111		sp_runtime::traits::AccountIdConversion::into_account_truncating(&PalletId(*b"Crowdloa"));
112
113	let mut balances: Vec<(AccountId, Balance)> = endowed_accounts
114		.iter()
115		.cloned()
116		.map(|k| (k, 1 << 80))
117		.collect();
118
119	// Add crowdloan pallet account with sufficient funds for all rewards
120	balances.push((crowdloan_pallet_account, 100_000_000 * UNIT));
121
122	let config = RuntimeGenesisConfig {
123		system: Default::default(),
124		balances: BalancesConfig {
125			balances,
126			dev_accounts: Default::default(),
127		},
128		sudo: SudoConfig {
129			key: Some(root_key),
130		},
131		parachain_info: ParachainInfoConfig {
132			parachain_id: para_id,
133			..Default::default()
134		},
135		ethereum_chain_id: EthereumChainIdConfig {
136			chain_id,
137			..Default::default()
138		},
139		evm: EVMConfig {
140			// We need _some_ code inserted at the precompile address so that
141			// the evm will actually call the address.
142			accounts: Precompiles::used_addresses()
143				.map(|addr| {
144					(
145						addr.into(),
146						GenesisAccount {
147							nonce: Default::default(),
148							balance: Default::default(),
149							storage: Default::default(),
150							code: revert_bytecode.clone(),
151						},
152					)
153				})
154				.collect(),
155			..Default::default()
156		},
157		ethereum: EthereumConfig {
158			..Default::default()
159		},
160		parachain_staking: ParachainStakingConfig {
161			candidates: candidates
162				.iter()
163				.cloned()
164				.map(|(account, _, bond)| (account, bond))
165				.collect(),
166			delegations,
167			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		treasury_council_collective: TreasuryCouncilCollectiveConfig {
174			phantom: Default::default(),
175			members: treasury_council_members,
176		},
177		open_tech_committee_collective: OpenTechCommitteeCollectiveConfig {
178			phantom: Default::default(),
179			members: open_tech_committee_members,
180		},
181		author_filter: AuthorFilterConfig {
182			eligible_count: EligibilityValue::new_unchecked(50),
183			..Default::default()
184		},
185		author_mapping: AuthorMappingConfig {
186			mappings: candidates
187				.iter()
188				.cloned()
189				.map(|(account_id, author_id, _)| (author_id, account_id))
190				.collect(),
191		},
192		proxy_genesis_companion: Default::default(),
193		treasury: Default::default(),
194		maintenance_mode: MaintenanceModeConfig {
195			start_in_maintenance_mode: false,
196			..Default::default()
197		},
198		// This should initialize it to whatever we have set in the pallet
199		polkadot_xcm: PolkadotXcmConfig::default(),
200		transaction_payment: TransactionPaymentConfig {
201			multiplier: Multiplier::from(8u128),
202			..Default::default()
203		},
204		moonbeam_orbiters: MoonbeamOrbitersConfig {
205			min_orbiter_deposit: One::one(),
206		},
207		xcm_transactor: XcmTransactorConfig {
208			relay_indices: WESTEND_RELAY_INDICES,
209			..Default::default()
210		},
211		crowdloan_rewards: CrowdloanRewardsConfig {
212			funded_accounts: vec![
213				// Dorothy account with test rewards
214				(
215					[
216						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
217						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
218						0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
219					],
220					Some(AccountId::from(sp_core::hex2array!(
221						"773539d4Ac0e786233D90A233654ccEE26a613D9"
222					))),
223					3_000_000 * UNIT,
224				),
225			],
226			init_vesting_block: 0u32,
227			end_vesting_block: 201600u32,
228		},
229	};
230
231	serde_json::to_value(&config).expect("Could not build genesis config.")
232}
233
234pub 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`.
293pub 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.
306pub fn preset_names() -> Vec<PresetId> {
307	vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
308}