From 2eb9d7a1a0f09d955641cd965d1f2a9c3bb693be Mon Sep 17 00:00:00 2001 From: leovct Date: Fri, 18 Oct 2024 14:10:50 +0200 Subject: [PATCH 1/8] feat(cast): add `json` flag in `cast wallet new-mnemonic` --- crates/cast/bin/cmd/wallet/mod.rs | 45 +++++++++++++++++++++++++------ crates/cast/tests/cli/main.rs | 36 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index 893a0f0ecdb4..495396dec116 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 as JSON. + #[arg(long, short, default_value = "false")] + json: bool, }, /// Generate a vanity address. @@ -290,16 +294,21 @@ impl WalletSubcommands { } } } - Self::NewMnemonic { words, accounts, entropy } => { + Self::NewMnemonic { words, accounts, entropy, json } => { + let mut json_values = if json { Some(vec![]) } else { None }; + 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 +317,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": wallet.address(), + "private_key": format!("0x{}", hex::encode(wallet.credential().to_bytes())), + })); + } else { + println!("- Account {i}:"); + println!("Address: {}", wallet.address()); + println!("Private key: 0x{private_key}\n"); + } + } + + if let Some(json) = json_values.as_mut() { + json.push(json!({ + "mnemonic": phrase, + "accounts": accounts, + })); + println!("{}", serde_json::to_string_pretty(json)?); } } Self::Vanity(cmd) => { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index be9ccc168c11..98fc9825e3be 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -299,6 +299,42 @@ Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +"#]]); +}); + +// tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic +casttest!(wallet_mnemonic_json, |_prj, cmd| { + cmd.args([ + "wallet", + "new-mnemonic", + "--json", + "--accounts", + "3", + "--entropy", + "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + ]) + .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" + } + ] + } +] + "#]]); }); From a803c11f119bf0d5d80cc71a8c113be5e14d52cd 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 11:41:54 +0200 Subject: [PATCH 2/8] Update crates/cast/bin/cmd/wallet/mod.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/bin/cmd/wallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index 495396dec116..4a91f7d2cb9f 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -329,7 +329,7 @@ impl WalletSubcommands { if json { accounts.as_array_mut().unwrap().push(json!({ "address": wallet.address(), - "private_key": format!("0x{}", hex::encode(wallet.credential().to_bytes())), + "private_key": format!("0x{}", private_key), })); } else { println!("- Account {i}:"); From e3c0d9e08523a7200d633030e032366ae0e73efb 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 11:42:35 +0200 Subject: [PATCH 3/8] Update crates/cast/tests/cli/main.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/tests/cli/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 98fc9825e3be..c193c59d7e48 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -303,7 +303,7 @@ Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 }); // tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic -casttest!(wallet_mnemonic_json, |_prj, cmd| { +casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { cmd.args([ "wallet", "new-mnemonic", From 97c0226008c69872c5112f543b9e032cdfd1fe4e Mon Sep 17 00:00:00 2001 From: leovct Date: Mon, 21 Oct 2024 11:50:33 +0200 Subject: [PATCH 4/8] chore: adjust `wallet_mnemonic_from_entropy` to generate three accounts instead of one --- crates/cast/tests/cli/main.rs | 72 ++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index c193c59d7e48..a67919cc5728 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,14 @@ Accounts: Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +- Account 1: +Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +Private key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + +- Account 2: +Address: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC +Private key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a + "#]]); }); @@ -307,11 +322,11 @@ casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { cmd.args([ "wallet", "new-mnemonic", - "--json", "--accounts", "3", "--entropy", "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + "--json", ]) .assert_success() .stdout_eq(str![[r#" @@ -1324,32 +1339,37 @@ casttest!(block_number_hash, |_prj, cmd| { assert_eq!(s.trim().parse::().unwrap(), 1, "{s}") }); -casttest!(send_eip7702, async |_prj, cmd| { - let (_api, handle) = - anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into()))) - .await; - let endpoint = handle.http_endpoint(); - - cmd.args([ - "send", - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "--auth", - "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - "--private-key", - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - "--rpc-url", - &endpoint, - ]) - .assert_success(); +casttest!( + send_eip7702, + async | _prj, + cmd | { + let (_api, handle) = anvil::spawn( + NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into())), + ) + .await; + let endpoint = handle.http_endpoint(); + + cmd.args([ + "send", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "--auth", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &endpoint, + ]) + .assert_success(); - cmd.cast_fuse() - .args(["code", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "--rpc-url", &endpoint]) - .assert_success() - .stdout_eq(str![[r#" + cmd.cast_fuse() + .args(["code", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "--rpc-url", &endpoint]) + .assert_success() + .stdout_eq(str![[r#" 0xef010070997970c51812dc3a010c7d01b50e0d17dc79c8 "#]]); -}); + } +); casttest!(hash_message, |_prj, cmd| { cmd.args(["hash-message", "hello"]).assert_success().stdout_eq(str![[r#" From 3ca20ae9b49832216e06676dfed7245cee5562c1 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 11:51:06 +0200 Subject: [PATCH 5/8] Update crates/cast/bin/cmd/wallet/mod.rs Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- crates/cast/bin/cmd/wallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index 4a91f7d2cb9f..bce9b2c71aab 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -70,7 +70,7 @@ pub enum WalletSubcommands { #[arg(long, short, conflicts_with = "words")] entropy: Option, - /// Output generated mnemonic phrase as JSON. + /// Output generated mnemonic phrase and accounts as JSON. #[arg(long, short, default_value = "false")] json: bool, }, From 6179e125b17c7ab748a0c53806c71ac1b2e99222 Mon Sep 17 00:00:00 2001 From: leovct Date: Mon, 21 Oct 2024 11:54:15 +0200 Subject: [PATCH 6/8] fix: preserve check-summed format for addresses --- crates/cast/bin/cmd/wallet/mod.rs | 2 +- crates/cast/tests/cli/main.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index bce9b2c71aab..e123626e862d 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -328,7 +328,7 @@ impl WalletSubcommands { let private_key = hex::encode(wallet.credential().to_bytes()); if json { accounts.as_array_mut().unwrap().push(json!({ - "address": wallet.address(), + "address": format!("{}", wallet.address()), "private_key": format!("0x{}", private_key), })); } else { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a67919cc5728..dc039f437a37 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -335,15 +335,15 @@ casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { "mnemonic": "test test test test test test test test test test test junk", "accounts": [ { - "address": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "private_key": "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" }, { - "address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "address": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "private_key": "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" }, { - "address": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "address": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", "private_key": "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" } ] From 298346d1c9150fed581d1b73e04a658349b149e3 Mon Sep 17 00:00:00 2001 From: leovct Date: Mon, 21 Oct 2024 11:59:58 +0200 Subject: [PATCH 7/8] chore: simplify code --- crates/cast/bin/cmd/wallet/mod.rs | 10 ++++----- crates/cast/tests/cli/main.rs | 36 +++++++++++++++---------------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index e123626e862d..4664e6611687 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -295,8 +295,6 @@ impl WalletSubcommands { } } Self::NewMnemonic { words, accounts, entropy, json } => { - let mut json_values = if json { Some(vec![]) } else { None }; - let phrase = if let Some(entropy) = entropy { let entropy = Entropy::from_slice(hex::decode(entropy)?)?; Mnemonic::::new_from_entropy(entropy).to_phrase() @@ -338,12 +336,12 @@ impl WalletSubcommands { } } - if let Some(json) = json_values.as_mut() { - json.push(json!({ + if json { + let obj = json!({ "mnemonic": phrase, "accounts": accounts, - })); - println!("{}", serde_json::to_string_pretty(json)?); + }); + 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 dc039f437a37..08d8bc2c2c14 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -330,25 +330,23 @@ casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { ]) .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" - } - ] - } -] +{ + "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" + } + ] +} "#]]); }); From bfa77d7511ebb407e9173fe106f52eaeb710b130 Mon Sep 17 00:00:00 2001 From: leovct Date: Mon, 21 Oct 2024 12:09:48 +0200 Subject: [PATCH 8/8] fix: rustfmt --- crates/cast/tests/cli/main.rs | 49 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 08d8bc2c2c14..5487dc9f374b 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1337,37 +1337,32 @@ casttest!(block_number_hash, |_prj, cmd| { assert_eq!(s.trim().parse::().unwrap(), 1, "{s}") }); -casttest!( - send_eip7702, - async | _prj, - cmd | { - let (_api, handle) = anvil::spawn( - NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into())), - ) - .await; - let endpoint = handle.http_endpoint(); - - cmd.args([ - "send", - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "--auth", - "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - "--private-key", - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - "--rpc-url", - &endpoint, - ]) - .assert_success(); +casttest!(send_eip7702, async |_prj, cmd| { + let (_api, handle) = + anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::PragueEOF.into()))) + .await; + let endpoint = handle.http_endpoint(); + + cmd.args([ + "send", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "--auth", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &endpoint, + ]) + .assert_success(); - cmd.cast_fuse() - .args(["code", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "--rpc-url", &endpoint]) - .assert_success() - .stdout_eq(str![[r#" + cmd.cast_fuse() + .args(["code", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "--rpc-url", &endpoint]) + .assert_success() + .stdout_eq(str![[r#" 0xef010070997970c51812dc3a010c7d01b50e0d17dc79c8 "#]]); - } -); +}); casttest!(hash_message, |_prj, cmd| { cmd.args(["hash-message", "hello"]).assert_success().stdout_eq(str![[r#"