Skip to main content

soil_cli/commands/
generate.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Implementation of the `generate` subcommand
8use crate::{
9	utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams,
10	NetworkSchemeFlag, OutputTypeFlag,
11};
12use bip39::Mnemonic;
13use clap::Parser;
14use itertools::Itertools;
15
16/// The `generate` command
17#[derive(Debug, Clone, Parser)]
18#[command(name = "generate", about = "Generate a random account")]
19pub struct GenerateCmd {
20	/// The number of words in the phrase to generate. One of 12 (default), 15, 18, 21 and 24.
21	#[arg(short = 'w', long, value_name = "WORDS")]
22	words: Option<usize>,
23
24	#[allow(missing_docs)]
25	#[clap(flatten)]
26	pub keystore_params: KeystoreParams,
27
28	#[allow(missing_docs)]
29	#[clap(flatten)]
30	pub network_scheme: NetworkSchemeFlag,
31
32	#[allow(missing_docs)]
33	#[clap(flatten)]
34	pub output_scheme: OutputTypeFlag,
35
36	#[allow(missing_docs)]
37	#[clap(flatten)]
38	pub crypto_scheme: CryptoSchemeFlag,
39}
40
41impl GenerateCmd {
42	/// Run the command
43	pub fn run(&self) -> Result<(), Error> {
44		let words = match self.words {
45			Some(words_count) if [12, 15, 18, 21, 24].contains(&words_count) => Ok(words_count),
46			Some(_) => Err(Error::Input(
47				"Invalid number of words given for phrase: must be 12/15/18/21/24".into(),
48			)),
49			None => Ok(12),
50		}?;
51		let mnemonic = Mnemonic::generate(words)
52			.map_err(|e| Error::Input(format!("Mnemonic generation failed: {e}").into()))?;
53		let password = self.keystore_params.read_password()?;
54		let output = self.output_scheme.output_type;
55
56		let phrase = mnemonic.words().join(" ");
57
58		with_crypto_scheme!(
59			self.crypto_scheme.scheme,
60			print_from_uri(&phrase, password, self.network_scheme.network, output)
61		);
62		Ok(())
63	}
64}
65
66#[cfg(test)]
67mod tests {
68	use super::*;
69
70	#[test]
71	fn generate() {
72		let generate = GenerateCmd::parse_from(&["generate", "--password", "12345"]);
73		assert!(generate.run().is_ok())
74	}
75}