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
use bip32::{
18
	Error as Bip32Error, ExtendedPrivateKey, PrivateKey as PrivateKeyT, PrivateKeyBytes,
19
	PublicKey as PublicKeyT, PublicKeyBytes,
20
};
21
use bip39::{Language, Mnemonic, MnemonicType, Seed};
22
use clap::{Parser, ValueEnum};
23
use libsecp256k1::{PublicKey, SecretKey};
24
use primitive_types::H256;
25
use sp_runtime::traits::IdentifyAccount;
26

            
27
#[derive(Debug, Clone, ValueEnum)]
28
pub enum Network {
29
	Moonbeam,
30
	Moonriver,
31
	Moonbase,
32
	Ethereum,
33
}
34

            
35
impl Network {
36
	/// Returns the coin type for the derivation path
37
	pub fn coin_type(&self) -> u32 {
38
		match self {
39
			Network::Moonbeam => 1284,
40
			Network::Moonriver => 1285,
41
			Network::Moonbase => 1287,
42
			Network::Ethereum => 60,
43
		}
44
	}
45
}
46

            
47
#[derive(Debug, Clone, Parser)]
48
pub struct GenerateAccountKey {
49
	/// Generate 12 words mnemonic instead of 24
50
	#[clap(long, short = 'w')]
51
	w12: bool,
52

            
53
	/// Specify the mnemonic
54
	#[clap(long, short = 'm')]
55
	mnemonic: Option<String>,
56

            
57
	/// The account index to use in the derivation path
58
	#[clap(long = "account-index", short = 'a')]
59
	account_index: Option<u32>,
60

            
61
	/// The network to use for derivation path
62
	#[clap(long, short = 'n', default_value = "moonbeam")]
63
	pub network: Network,
64
}
65

            
66
impl GenerateAccountKey {
67
	pub fn run(&self) {
68
		// Retrieve the mnemonic from the args or generate random ones
69
		let mnemonic = if let Some(phrase) = &self.mnemonic {
70
			Mnemonic::from_phrase(phrase, Language::English).expect("invalid mnemonic")
71
		} else {
72
			match self.w12 {
73
				true => Mnemonic::new(MnemonicType::Words12, Language::English),
74
				false => Mnemonic::new(MnemonicType::Words24, Language::English),
75
			}
76
		};
77

            
78
		// Retrieves the seed from the mnemonic
79
		let seed = Seed::new(&mnemonic, "");
80
		// Use network parameter to determine chain ID for derivation path
81
		let derivation_path = format!(
82
			"m/44'/{}'/0'/0/{}",
83
			self.network.coin_type(),
84
			self.account_index.unwrap_or(0)
85
		);
86
		let private_key = if let Some(private_key) =
87
			derivation_path.parse().ok().and_then(|derivation_path| {
88
				let extended = ExtendedPrivateKey::<Secp256k1SecretKey>::derive_from_path(
89
					&seed,
90
					&derivation_path,
91
				)
92
				.expect("invalid extended private key");
93
				Some(extended.private_key().0)
94
			}) {
95
			private_key
96
		} else {
97
			panic!("invalid extended private key");
98
		};
99

            
100
		// Retrieves the public key
101
		let public_key = PublicKey::from_secret_key(&private_key);
102

            
103
		// Convert into Ethereum-style address.
104
		let signer: account::EthereumSigner = public_key.into();
105
		let address = signer.into_account();
106

            
107
		println!("Address:      {:?}", address);
108
		println!("Mnemonic:     {}", mnemonic.phrase());
109
		println!("Private Key:  {:?}", H256::from(private_key.serialize()));
110
		println!("Path:         {}", derivation_path);
111
	}
112
}
113

            
114
// `libsecp256k1::PublicKey` wrapped type
115
pub struct Secp256k1PublicKey(pub PublicKey);
116
// `libsecp256k1::Secret`  wrapped type
117
pub struct Secp256k1SecretKey(pub SecretKey);
118

            
119
impl PublicKeyT for Secp256k1PublicKey {
120
	fn from_bytes(bytes: PublicKeyBytes) -> Result<Self, Bip32Error> {
121
		let public = PublicKey::parse_compressed(&bytes).map_err(|_| return Bip32Error::Decode)?;
122
		Ok(Self(public))
123
	}
124

            
125
140
	fn to_bytes(&self) -> PublicKeyBytes {
126
140
		self.0.serialize_compressed()
127
140
	}
128

            
129
	fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Bip32Error> {
130
		let mut child = self.0.clone();
131
		let secret = SecretKey::parse(&other).map_err(|_| return Bip32Error::Decode)?;
132
		let _ = child.tweak_add_assign(&secret);
133
		Ok(Self(child))
134
	}
135
}
136

            
137
impl PrivateKeyT for Secp256k1SecretKey {
138
	type PublicKey = Secp256k1PublicKey;
139

            
140
20
	fn from_bytes(bytes: &PrivateKeyBytes) -> Result<Self, Bip32Error> {
141
20
		let secret = SecretKey::parse(&bytes).map_err(|_| return Bip32Error::Decode)?;
142
20
		Ok(Self(secret))
143
20
	}
144

            
145
60
	fn to_bytes(&self) -> PrivateKeyBytes {
146
60
		self.0.serialize()
147
60
	}
148

            
149
100
	fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Bip32Error> {
150
100
		let mut child = self.0.clone();
151
100
		let secret = SecretKey::parse(&other).map_err(|_| return Bip32Error::Decode)?;
152
100
		let _ = child.tweak_add_assign(&secret);
153
100
		Ok(Self(child))
154
100
	}
155

            
156
140
	fn public_key(&self) -> Self::PublicKey {
157
140
		Secp256k1PublicKey(PublicKey::from_secret_key(&self.0))
158
140
	}
159
}