From a7f608c7f71f1a61949998ca58c117edaa842f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Vincent?= <28714795+leovct@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:12:18 +0200 Subject: [PATCH] feat(cast): add `json` flag in `cast wallet new-mnemonic` (#9139) * feat(cast): add `json` flag in `cast wallet new-mnemonic` * Update crates/cast/bin/cmd/wallet/mod.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * Update crates/cast/tests/cli/main.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * chore: adjust `wallet_mnemonic_from_entropy` to generate three accounts instead of one * Update crates/cast/bin/cmd/wallet/mod.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * fix: preserve check-summed format for addresses * chore: simplify code * fix: rustfmt --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/bin/cmd/wallet/mod.rs | 43 +++++++++++++++++++----- crates/cast/tests/cli/main.rs | 55 +++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index 893a0f0ecdb4d..4664e66116878 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -69,6 +69,10 @@ pub enum WalletSubcommands { /// Entropy to use for the mnemonic #[arg(long, short, conflicts_with = "words")] entropy: Option, + + /// Output generated mnemonic phrase and accounts as JSON. + #[arg(long, short, default_value = "false")] + json: bool, }, /// Generate a vanity address. @@ -290,16 +294,19 @@ impl WalletSubcommands { } } } - Self::NewMnemonic { words, accounts, entropy } => { + Self::NewMnemonic { words, accounts, entropy, json } => { let phrase = if let Some(entropy) = entropy { let entropy = Entropy::from_slice(hex::decode(entropy)?)?; - println!("{}", "Generating mnemonic from provided entropy...".yellow()); Mnemonic::::new_from_entropy(entropy).to_phrase() } else { let mut rng = thread_rng(); Mnemonic::::new_with_count(&mut rng, words)?.to_phrase() }; + if !json { + println!("{}", "Generating mnemonic from provided entropy...".yellow()); + } + let builder = MnemonicBuilder::::default().phrase(phrase.as_str()); let derivation_path = "m/44'/60'/0'/0/"; let wallets = (0..accounts) @@ -308,13 +315,33 @@ impl WalletSubcommands { let wallets = wallets.into_iter().map(|b| b.build()).collect::, _>>()?; - println!("{}", "Successfully generated a new mnemonic.".green()); - println!("Phrase:\n{phrase}"); - println!("\nAccounts:"); + if !json { + println!("{}", "Successfully generated a new mnemonic.".green()); + println!("Phrase:\n{phrase}"); + println!("\nAccounts:"); + } + + let mut accounts = json!([]); for (i, wallet) in wallets.iter().enumerate() { - println!("- Account {i}:"); - println!("Address: {}", wallet.address()); - println!("Private key: 0x{}\n", hex::encode(wallet.credential().to_bytes())); + let private_key = hex::encode(wallet.credential().to_bytes()); + if json { + accounts.as_array_mut().unwrap().push(json!({ + "address": format!("{}", wallet.address()), + "private_key": format!("0x{}", private_key), + })); + } else { + println!("- Account {i}:"); + println!("Address: {}", wallet.address()); + println!("Private key: 0x{private_key}\n"); + } + } + + if json { + let obj = json!({ + "mnemonic": phrase, + "accounts": accounts, + }); + println!("{}", serde_json::to_string_pretty(&obj)?); } } Self::Vanity(cmd) => { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index b0a0f42a242b0..55575985cfd25 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -285,9 +285,16 @@ Created new encrypted keystore file: [..] // tests that `cast wallet new-mnemonic --entropy` outputs the expected mnemonic casttest!(wallet_mnemonic_from_entropy, |_prj, cmd| { - cmd.args(["wallet", "new-mnemonic", "--entropy", "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c"]) - .assert_success() - .stdout_eq(str![[r#" + cmd.args([ + "wallet", + "new-mnemonic", + "--accounts", + "3", + "--entropy", + "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + ]) + .assert_success() + .stdout_eq(str![[r#" Generating mnemonic from provided entropy... Successfully generated a new mnemonic. Phrase: @@ -298,6 +305,48 @@ Accounts: Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +- Account 1: +Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +Private key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + +- Account 2: +Address: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC +Private key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a + + +"#]]); +}); + +// tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic +casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { + cmd.args([ + "wallet", + "new-mnemonic", + "--accounts", + "3", + "--entropy", + "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + "--json", + ]) + .assert_success() + .stdout_eq(str![[r#" +{ + "mnemonic": "test test test test test test test test test test test junk", + "accounts": [ + { + "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "private_key": "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + }, + { + "address": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "private_key": "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + }, + { + "address": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "private_key": "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + } + ] +} "#]]); });