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
//! Moonriver Chain Specifications and utilities for building them.
18
//!
19
//! Learn more about Substrate chain specifications at
20
//! https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec
21
extern crate alloc;
22

            
23
use crate::{
24
	currency::MOVR, AccountId, AuthorFilterConfig, AuthorMappingConfig, Balance, BalancesConfig,
25
	CrowdloanRewardsConfig, EVMConfig, EligibilityValue, EthereumChainIdConfig, EthereumConfig,
26
	InflationInfo, MaintenanceModeConfig, OpenTechCommitteeCollectiveConfig, ParachainInfoConfig,
27
	ParachainStakingConfig, PolkadotXcmConfig, Precompiles, Range, RuntimeGenesisConfig,
28
	TransactionPaymentConfig, TreasuryCouncilCollectiveConfig, HOURS,
29
};
30
use alloc::{vec, vec::Vec};
31
use cumulus_primitives_core::ParaId;
32
use fp_evm::GenesisAccount;
33
use nimbus_primitives::NimbusId;
34
use pallet_transaction_payment::Multiplier;
35
use sp_genesis_builder::PresetId;
36
use sp_keyring::Sr25519Keyring;
37
use sp_runtime::{Perbill, Percent};
38

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

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

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

            
88
	let config = RuntimeGenesisConfig {
89
		system: Default::default(),
90
		balances: BalancesConfig {
91
			balances: endowed_accounts
92
				.iter()
93
				.cloned()
94
				.map(|k| (k, 1 << 80))
95
				.collect(),
96
		},
97
		crowdloan_rewards: CrowdloanRewardsConfig {
98
			funded_amount: crowdloan_fund_pot,
99
		},
100
		parachain_info: ParachainInfoConfig {
101
			parachain_id: para_id,
102
			..Default::default()
103
		},
104
		ethereum_chain_id: EthereumChainIdConfig {
105
			chain_id,
106
			..Default::default()
107
		},
108
		evm: EVMConfig {
109
			// We need _some_ code inserted at the precompile address so that
110
			// the evm will actually call the address.
111
			accounts: Precompiles::used_addresses()
112
				.map(|addr| {
113
					(
114
						addr.into(),
115
						GenesisAccount {
116
							nonce: Default::default(),
117
							balance: Default::default(),
118
							storage: Default::default(),
119
							code: revert_bytecode.clone(),
120
						},
121
					)
122
				})
123
				.collect(),
124
			..Default::default()
125
		},
126
		ethereum: EthereumConfig {
127
			..Default::default()
128
		},
129
		parachain_staking: ParachainStakingConfig {
130
			candidates: candidates
131
				.iter()
132
				.cloned()
133
				.map(|(account, _, bond)| (account, bond))
134
				.collect(),
135
			delegations,
136
			inflation_config: moonriver_inflation_config(),
137
			collator_commission: COLLATOR_COMMISSION,
138
			parachain_bond_reserve_percent: PARACHAIN_BOND_RESERVE_PERCENT,
139
			blocks_per_round: BLOCKS_PER_ROUND,
140
			num_selected_candidates: NUM_SELECTED_CANDIDATES,
141
		},
142
		treasury_council_collective: TreasuryCouncilCollectiveConfig {
143
			phantom: Default::default(),
144
			members: treasury_council_members,
145
		},
146
		open_tech_committee_collective: OpenTechCommitteeCollectiveConfig {
147
			phantom: Default::default(),
148
			members: open_tech_committee_members,
149
		},
150
		author_filter: AuthorFilterConfig {
151
			eligible_count: EligibilityValue::new_unchecked(50),
152
			..Default::default()
153
		},
154
		author_mapping: AuthorMappingConfig {
155
			mappings: candidates
156
				.iter()
157
				.cloned()
158
				.map(|(account_id, author_id, _)| (author_id, account_id))
159
				.collect(),
160
		},
161
		proxy_genesis_companion: Default::default(),
162
		treasury: Default::default(),
163
		migrations: Default::default(),
164
		maintenance_mode: MaintenanceModeConfig {
165
			start_in_maintenance_mode: false,
166
			..Default::default()
167
		},
168
		// This should initialize it to whatever we have set in the pallet
169
		polkadot_xcm: PolkadotXcmConfig::default(),
170
		transaction_payment: TransactionPaymentConfig {
171
			multiplier: Multiplier::from(10u128),
172
			..Default::default()
173
		},
174
	};
175

            
176
	serde_json::to_value(&config).expect("Could not build genesis config.")
177
}
178

            
179
/// Generate a chain spec for use with the development service.
180
pub fn development() -> serde_json::Value {
181
	testnet_genesis(
182
		// Treasury Council members: Baltathar, Charleth and Dorothy
183
		vec![
184
			AccountId::from(sp_core::hex2array!(
185
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
186
			)),
187
			AccountId::from(sp_core::hex2array!(
188
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
189
			)),
190
			AccountId::from(sp_core::hex2array!(
191
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
192
			)),
193
		],
194
		// Open Tech committee members: Alith and Baltathar
195
		vec![
196
			AccountId::from(sp_core::hex2array!(
197
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
198
			)),
199
			AccountId::from(sp_core::hex2array!(
200
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
201
			)),
202
		],
203
		// Collator Candidate: Alice -> Alith
204
		vec![(
205
			AccountId::from(sp_core::hex2array!(
206
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
207
			)),
208
			NimbusId::from(Sr25519Keyring::Alice.public()),
209
			100_000 * MOVR,
210
		)],
211
		// Delegations
212
		vec![],
213
		vec![
214
			AccountId::from(sp_core::hex2array!(
215
				"f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"
216
			)),
217
			AccountId::from(sp_core::hex2array!(
218
				"3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0"
219
			)),
220
			AccountId::from(sp_core::hex2array!(
221
				"798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc"
222
			)),
223
			AccountId::from(sp_core::hex2array!(
224
				"773539d4Ac0e786233D90A233654ccEE26a613D9"
225
			)),
226
		],
227
		3_000_000 * MOVR,
228
		Default::default(), // para_id
229
		1281,               //ChainId
230
	)
231
}
232

            
233
/// Provides the JSON representation of predefined genesis config for given `id`.
234
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
235
	let patch = match id.as_str() {
236
		sp_genesis_builder::DEV_RUNTIME_PRESET => development(),
237
		_ => return None,
238
	};
239
	Some(
240
		serde_json::to_string(&patch)
241
			.expect("serialization to json is expected to work. qed.")
242
			.into_bytes(),
243
	)
244
}
245

            
246
/// List of supported presets.
247
pub fn preset_names() -> Vec<PresetId> {
248
	vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
249
}