Repository: alpenlabs/strata
Pull request #756: Reorder address validation for faucet (strata-cli)
Author: login: pranjalpokharel7
Created: 2025-03-30T05:12:03Z | Merged: 2025-04-02T09:13:58Z

## Description

Validate address before solving PoW challenge in faucet command (strata-cli). 

**Issue**
<img width="600" alt="Screenshot 2025-03-28 at 18 08 04" src="https://github.com/user-attachments/assets/7973ea22-8890-407a-bcc9-81c324d2765f" />

\
**Fixed** 
<img width="935" alt="Screenshot 2025-03-30 at 10 54 46" src="https://github.com/user-attachments/assets/e5ecaefc-9746-436e-971c-f462c3e70f41" />

**Updated Fixed Screenshot**
<img width="1155" alt="Screenshot 2025-03-31 at 08 44 02" src="https://github.com/user-attachments/assets/09a31f11-11b1-4eee-ad76-6b1aa01d87cf" />

### Type of Change

<!--
Select the type of change your PR introduces (put an `x` in all that apply):
-->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature/Enhancement (non-breaking change which adds functionality or enhances an existing one)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactor
- [ ] New or updated tests
- [ ] Dependency Update

## Notes to Reviewers

<!--
Anything in particular you want to note that will help reviewers fulfill their role
in reviewing this PR?
-->

## Checklist

<!--
Ensure all the following are checked:
-->

- [x] I have performed a self-review of my code.
- [x] I have commented my code where necessary.
- [x] I have updated the documentation if needed.
- [x] My changes do not introduce new warnings.
- [x] I have added (where necessary) tests that prove my changes are effective or that my feature works.
- [x] New and existing tests pass with my changes.

## Related Issues

<!--
Link any related issues (e.g., `closes #123`, `fixes #456`).
-->


Linked issue #123: Sync manager cannot start because l1_reader starts after sync tasks are spawned and sync tasks don't get any genesis L1 block
This is kind of a deadlock situation.

l1_reader starts after sync manager completes starting and sync manager is expecting genesis block inserted by l1_reader.

Related: #141 
#141 should close this

Diff:
diff --git a/bin/strata-cli/Cargo.toml b/bin/strata-cli/Cargo.toml
index 2afabe3be7..11f642d52d 100644
--- a/bin/strata-cli/Cargo.toml
+++ b/bin/strata-cli/Cargo.toml
@@ -3,9 +3,6 @@ edition = "2021"
 name = "strata-cli"
 version = "0.3.0"
 
-[features]
-strata_faucet = []
-
 [[bin]]
 name = "strata"
 path = "src/main.rs"
diff --git a/bin/strata-cli/src/cmd/faucet.rs b/bin/strata-cli/src/cmd/faucet.rs
index d4e2df9bdf..423f164f18 100644
--- a/bin/strata-cli/src/cmd/faucet.rs
+++ b/bin/strata-cli/src/cmd/faucet.rs
@@ -1,8 +1,5 @@
-#[cfg(feature = "strata_faucet")]
-use std::fmt;
-use std::str::FromStr;
+use std::{fmt, str::FromStr};
 
-#[cfg(feature = "strata_faucet")]
 use alloy::{primitives::Address as StrataAddress, providers::WalletProvider};
 use argh::FromArgs;
 use bdk_wallet::{bitcoin::Address, KeychainKind};
@@ -12,19 +9,19 @@ use serde::{Deserialize, Serialize};
 use sha2::{Digest, Sha256};
 use shrex::{encode, Hex};
 
-#[cfg(feature = "strata_faucet")]
 use crate::{
     net_type::{net_type_or_exit, NetworkType},
+    seed::Seed,
+    settings::Settings,
+    signet::SignetWallet,
     strata::StrataWallet,
 };
-use crate::{seed::Seed, settings::Settings, signet::SignetWallet};
 
 /// Request some bitcoin from the faucet
 #[derive(FromArgs, PartialEq, Debug)]
 #[argh(subcommand, name = "faucet")]
 pub struct FaucetArgs {
     /// either "signet" or "strata"
-    #[cfg(feature = "strata_faucet")]
     #[argh(positional)]
     network_type: String,
     /// address that funds will be sent to. defaults to internal wallet
@@ -41,14 +38,12 @@ pub struct PowChallenge {
     difficulty: u8,
 }
 
-#[cfg(feature = "strata_faucet")]
 /// Which chain the faucet is reasoning about.
 enum Chain {
     L1,
     L2,
 }
 
-#[cfg(feature = "strata_faucet")]
 impl Chain {
     fn from_network_type(network_type: NetworkType) -> Result<Self, String> {
         match network_type {
@@ -58,7 +53,6 @@ impl Chain {
     }
 }
 
-#[cfg(feature = "strata_faucet")]
 impl fmt::Display for Chain {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let chain_str = match self {
@@ -70,22 +64,28 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    let network_type = net_type_or_exit(&args.network_type);
+
+    let (address, claim) = match network_type {
+        NetworkType::Signet => (
+            resolve_signet_address(&args, &seed, &settings).to_string(),
+            "claim_l1",
+        ),
+        NetworkType::Strata => (
+            resolve_strata_address(&args, &seed, &settings).to_string(),
+            "claim_l2",
+        ),
+    };
+
     println!("Fetching challenge from faucet");
+
     let client = reqwest::Client::new();
     let base = Url::from_str(&settings.faucet_endpoint).expect("valid url");
-
-    #[cfg(feature = "strata_faucet")]
-    let network_type = net_type_or_exit(&args.network_type);
-
-    #[cfg(feature = "strata_faucet")]
     let endpoint = {
         let chain = Chain::from_network_type(network_type.clone()).expect("conversion to succeed");
         base.join(&format!("/pow_challenge/{}", chain)).unwrap()
     };
 
-    #[cfg(not(feature = "strata_faucet"))]
-    let endpoint = base.join("/pow_challenge").unwrap();
-
     let challenge = client
         .get(endpoint)
         .send()
@@ -123,85 +123,20 @@ pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
         "✔ Solved challenge after {solution} attempts. Claiming now."
     ));
 
-    #[cfg(feature = "strata_faucet")]
-    let url = match network_type {
-        NetworkType::Signet => {
-            let mut l1w =
-                SignetWallet::new(&seed, settings.network, settings.signet_backend.clone())
-                    .unwrap();
-            let address = match args.address {
-                None => {
-                    let address_info = l1w.reveal_next_address(KeychainKind::External);
-                    l1w.persist().unwrap();
-                    address_info.address
-                }
-                Some(address) => {
-                    let address = Address::from_str(&address).expect("bad address");
-                    address
-                        .require_network(settings.network)
-                        .expect("wrong bitcoin network")
-                }
-            };
-
-            println!("Claiming to signet address {}", address);
-
-            format!(
-                "{base}claim_l1/{}/{}",
-                encode(&solution.to_le_bytes()),
-                address
-            )
-        }
-        NetworkType::Strata => {
-            let l2w = StrataWallet::new(&seed, &settings.strata_endpoint).unwrap();
-            // they said EVMs were advanced 👁️👁️
-            let address = match args.address {
-                Some(address) => StrataAddress::from_str(&address).expect("bad address"),
-                None => l2w.default_signer_address(),
-            };
-            println!("Claiming to Strata address {}", address);
-            format!(
-                "{base}claim_l2/{}/{}",
-                encode(&solution.to_le_bytes()),
-                address
-            )
-        }
-    };
-
-    #[cfg(not(feature = "strata_faucet"))]
-    let url = {
-        let mut l1w =
-            SignetWallet::new(&seed, settings.network, settings.signet_backend.clone()).unwrap();
-        let address = match args.address {
-            None => {
-                let address_info = l1w.reveal_next_address(KeychainKind::External);
-                l1w.persist().unwrap();
-                address_info.address
-            }
-            Some(address) => {
-                let address = Address::from_str(&address).expect("bad address");
-                address
-                    .require_network(settings.network)
-                    .expect("wrong bitcoin network")
-            }
-        };
-
-        println!("Claiming to signet address {}", address);
-
-        format!(
-            "{base}claim_l1/{}/{}",
-            encode(&solution.to_le_bytes()),
-            address
-        )
-    };
+    println!("Claiming to {} address {}", network_type, address);
 
+    let url = format!(
+        "{base}{}/{}/{}",
+        claim,
+        encode(&solution.to_le_bytes()),
+        address
+    );
     let res = client.get(url).send().await.unwrap();
 
     let status = res.status();
     let body = res.text().await.expect("invalid response");
     if status == StatusCode::OK {
-        println!(
-            "Successful queued request for signet bitcoin. It should arrive in your wallet soon.",
-        );
+        println!("Faucet claim successfully queued. The funds should appear in your wallet soon.",);
     } else {
         println!("Failed: faucet responded with {status}: {body}");
     }
@@ -218,3 +153,47 @@ fn pow_valid(mut hasher: Sha256, difficulty: u8, solution: Solution) -> bool {
     hasher.update(solution);
     count_leading_zeros(&hasher.finalize()) >= difficulty
 }
+
+fn resolve_signet_address(
+    args: &FaucetArgs,
+    seed: &Seed,
+    settings: &Settings,
+) -> bdk_wallet::bitcoin::Address {
+    let mut l1w =
+        SignetWallet::new(seed, settings.network, settings.signet_backend.clone()).unwrap();
+
+    match &args.address {
+        None => {
+            let address_info = l1w.reveal_next_address(KeychainKind::External);
+            l1w.persist().unwrap();
+            address_info.address
+        }
+        Some(address) => {
+            let address = Address::from_str(address).unwrap_or_else(|_| {
+                eprintln!("Invalid signet address provided as argument.");
+                std::process::exit(1);
+            });
+            address
+                .require_network(settings.network)
+                .expect("wrong bitcoin network")
+        }
+    }
+}
+
+fn resolve_strata_address(
+    args: &FaucetArgs,
+    seed: &Seed,
+    settings: &Settings,
+) -> alloy::primitives::Address {
+    let l2w = StrataWallet::new(seed, &settings.strata_endpoint).unwrap();
+
+    match &args.address {
+        Some(address) => StrataAddress::from_str(address).unwrap_or_else(|_| {
+            eprintln!(
+                "Invalid strata address provided as argument - must be an EVM-compatible address."
+            );
+            std::process::exit(1);
+        }),
+        None => l2w.default_signer_address(),
+    }
+}
diff --git a/bin/strata-cli/src/cmd/send.rs b/bin/strata-cli/src/cmd/send.rs
index a9731b8759..e1237bcc62 100644
--- a/bin/strata-cli/src/cmd/send.rs
+++ b/bin/strata-cli/src/cmd/send.rs
@@ -47,7 +47,10 @@ pub async fn send(args: SendArgs, seed: Seed, settings: Settings) {
         NetworkType::Signet => {
             let amount = Amount::from_sat(args.amount);
             let address = Address::from_str(&args.address)
-                .expect("valid address")
+                .unwrap_or_else(|_| {
+                    eprintln!("Invalid signet address provided as argument.");
+                    std::process::exit(1);
+                })
                 .require_network(settings.network)
                 .expect("correct network");
             let mut l1w =
@@ -80,7 +83,12 @@ pub async fn send(args: SendArgs, seed: Seed, settings: Settings) {
         }
         NetworkType::Strata => {
             let l2w = StrataWallet::new(&seed, &settings.strata_endpoint).expect("valid wallet");
-            let address = StrataAddress::from_str(&args.address).expect("valid address");
+            let address = StrataAddress::from_str(&args.address).unwrap_or_else(|_| {
+                eprintln!(
+                    "Invalid strata address provided as argument - must be an EVM-compatible address."
+                );
+                std::process::exit(1);
+            });
             let tx = TransactionRequest::default()
                 .with_to(address)
                 .with_value(U256::from(args.amount as u128 * SATS_TO_WEI));
diff --git a/bin/strata-cli/src/cmd/withdraw.rs b/bin/strata-cli/src/cmd/withdraw.rs
index b4ab22b642..a4d1cfe8e4 100644
--- a/bin/strata-cli/src/cmd/withdraw.rs
+++ b/bin/strata-cli/src/cmd/withdraw.rs
@@ -30,7 +30,10 @@ pub struct WithdrawArgs {
 pub async fn withdraw(args: WithdrawArgs, seed: Seed, settings: Settings) {
     let address = args.address.map(|a| {
         Address::from_str(&a)
-            .expect("valid address")
+            .unwrap_or_else(|_| {
+                eprintln!("Invalid signet address provided as argument.");
+                std::process::exit(1);
+            })
             .require_network(settings.network)
             .expect("correct network")
     });
diff --git a/bin/strata-cli/src/main.rs b/bin/strata-cli/src/main.rs
index f59bb407f7..0af219011d 100644
--- a/bin/strata-cli/src/main.rs
+++ b/bin/strata-cli/src/main.rs
@@ -44,7 +44,10 @@ async fn main() {
 
     assert!(set_data_dir(settings.data_dir.clone()));
 
-    let seed = seed::load_or_create(&persister).unwrap();
+    let seed = seed::load_or_create(&persister).unwrap_or_else(|e| {
+        eprintln!("{:?}", e);
+        std::process::exit(1);
+    });
 
     match cmd {
         Commands::Recover(args) => recover(args, seed, settings).await,
diff --git a/bin/strata-cli/src/net_type.rs b/bin/strata-cli/src/net_type.rs
index a446a019d8..c93910a985 100644
--- a/bin/strata-cli/src/net_type.rs
+++ b/bin/strata-cli/src/net_type.rs
@@ -1,4 +1,4 @@
-use std::str::FromStr;
+use std::{fmt, str::FromStr};
 
 /// Represents a type of network, either Alpen's signet or Strata
 #[non_exhaustive]
@@ -23,6 +23,16 @@ impl FromStr for NetworkType {
     }
 }
 
+impl fmt::Display for NetworkType {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let net_str = match self {
+            NetworkType::Signet => "signet",
+            NetworkType::Strata => "strata",
+        };
+        write!(f, "{}", net_str)
+    }
+}
+
 /// Parses `val` as a [`NetworkType`]. Prints error message and exits if invalid.
 pub fn net_type_or_exit(val: &str) -> NetworkType {
     match NetworkType::from_str(val) {
diff --git a/bin/strata-cli/src/seed.rs b/bin/strata-cli/src/seed.rs
index 0d48f51646..d4058aabcb 100644
--- a/bin/strata-cli/src/seed.rs
+++ b/bin/strata-cli/src/seed.rs
@@ -166,7 +166,6 @@ pub fn load_or_create(
             Err(e) => {
                 let narrowed = e.narrow::<aes_gcm_siv::Error, _>();
                 if let Ok(_aes_error) = narrowed {
-                    println!("Incorrect password");
                     return Err(OneOf::new(IncorrectPassword));
                 }
 


Reviews:
user: login: storopoli
body: Is there a way to not panic?
Would be much better to ask the user to retry entering the address, right?
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-30T05:17:09Z
user: login: barakshani
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-30T08:02:52Z
user: login: pranjalpokharel7
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-30T08:23:12Z
user: login: delbonis
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T02:24:36Z
user: login: storopoli
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-31T03:26:13Z
user: login: storopoli
body: Check my previous review
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-31T03:30:01Z
user: login: pranjalpokharel7
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T03:47:16Z
user: login: pranjalpokharel7
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T07:26:04Z
user: login: storopoli
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T09:50:51Z
user: login: pranjalpokharel7
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T11:15:17Z
user: login: krsnapaudel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T03:00:24Z
user: login: pranjalpokharel7
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T08:02:23Z
user: login: storopoli
body: ACK 4180e01ce82c46900cb5f0f1ab36fa8b87b7877a

BUT
Before merging can you show a screenshot of the new error messages and the wallet-cli not panicking?
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-02T08:36:10Z

Review comments:
diff_hunk: @@ -45,47 +45,8 @@ pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
     #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: barakshani
body: I'd assume the cli message 2 lines above should also be displayed only if we passed the address verification, as this challenge is probably the POW challenge we have in the message below.

Feel free to add an alternative message in the lines of "Making a faucet request" or "Requesting BTC from the faucet" so the user gets some acknowledgment.
created_at: 2025-03-30T08:02:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,47 +45,8 @@ pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
     #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: pranjalpokharel7
body: Makes sense, will make the necessary changes.
created_at: 2025-03-30T08:23:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
+    let network_type = net_type_or_exit(&args.network_type);
+
+    #[cfg(feature = "strata_faucet")]
+    let (address, claim) = match network_type {
+        NetworkType::Signet => {
+            let mut l1w =
+                SignetWallet::new(&seed, settings.network, settings.signet_backend.clone())
+                    .unwrap();
+            let address = match args.address {
+                None => {
+                    let address_info = l1w.reveal_next_address(KeychainKind::External);
+                    l1w.persist().unwrap();
+                    address_info.address
+                }
+                Some(address) => {
+                    let address = Address::from_str(&address).unwrap_or_else(|_| {
+                        eprintln!("Invalid signet address provided as argument.");
+                        std::process::exit(1);
+                    });
+                    address
+                        .require_network(settings.network)
+                        .expect("wrong bitcoin network")
+                }
+            };
+            (address.to_string(), "claim_l1")
+        }
+        NetworkType::Strata => {
+            let l2w = StrataWallet::new(&seed, &settings.strata_endpoint).unwrap();
+            // they said EVMs were advanced 👁️👁️
path: bin/strata-cli/src/cmd/faucet.rs
user: login: storopoli
body: This comment is not needed anymore it was a hot take on alloy's huge trait bounds on generics.
created_at: 2025-03-31T03:22:19Z
author_association: MEMBER
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: storopoli
body: Does it make sense to just `#[cfg(feature = "strata_faucet")]` the function `faucet` instead?
created_at: 2025-03-31T03:26:07Z
author_association: MEMBER
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: pranjalpokharel7
body: Should we write two versions of the function in that case? Or will this feature simply be enabled for all standard builds? From the devnet docs, it's made clear that the faucet deposit will only work for signet, the CLI will not remain consistent in that case (feature is not enabled during devnet CLI build).
created_at: 2025-03-31T03:47:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: pranjalpokharel7
body: Did you mean something like this (two versions of the `faucet` function)? 
```rust
#[cfg(feature = "strata_faucet")]
pub async fn faucet(...) {}

#[cfg(not(feature = "strata_faucet"))]
pub async fn faucet(...) {}
```
created_at: 2025-03-31T07:26:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: storopoli
body: No, I thought that a bunch of `#[cfg(feature = "strata_faucet")]` inside the function was for everything in the whole function.
But no right?
Ok fine.
created_at: 2025-03-31T09:50:51Z
author_association: MEMBER
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: pranjalpokharel7
body: I've refactored the function so that it is more readable.
created_at: 2025-03-31T11:15:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: krsnapaudel
body: @pranjalpokharel7 : Based on discussions with @Zk2u and @bewakes, you could take out the feature `strata_faucet`. This means we don't need the code with `#[cfg(not(feature = "strata_faucet"))]`. Obviously, we do still need the shared code. Hopefully this makes the change cleaner.
created_at: 2025-04-01T03:00:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,13 +70,76 @@ impl fmt::Display for Chain {
 }
 
 pub async fn faucet(args: FaucetArgs, seed: Seed, settings: Settings) {
+    #[cfg(feature = "strata_faucet")]
path: bin/strata-cli/src/cmd/faucet.rs
user: login: pranjalpokharel7
body: Removed the `strata_faucet` feature in this latest commit - [b9a92f2](https://github.com/alpenlabs/strata/pull/756/commits/b9a92f29475f75120740dd2f19e530b41aabac25).
created_at: 2025-04-01T08:02:23Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-30T05:18:38Z
body: ## [Codecov](https://app.codecov.io/gh/alpenlabs/strata/pull/756?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) Report
Attention: Patch coverage is `0%` with `80 lines` in your changes missing coverage. Please review.
> Project coverage is 52.82%. Comparing base [(`b0b0295`)](https://app.codecov.io/gh/alpenlabs/strata/commit/b0b02951df4656e9bef8b35b0e8d293a6be1e58c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) to head [(`4180e01`)](https://app.codecov.io/gh/alpenlabs/strata/commit/4180e01ce82c46900cb5f0f1ab36fa8b87b7877a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs).
> Report is 7 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/alpenlabs/strata/pull/756?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) | Patch % | Lines |
|---|---|---|
| [bin/strata-cli/src/cmd/faucet.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Ffaucet.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC9mYXVjZXQucnM=) | 0.00% | [56 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [bin/strata-cli/src/cmd/send.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Fsend.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC9zZW5kLnJz) | 0.00% | [10 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [bin/strata-cli/src/net\_type.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fnet_type.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL25ldF90eXBlLnJz) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [bin/strata-cli/src/cmd/withdraw.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Fwithdraw.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC93aXRoZHJhdy5ycw==) | 0.00% | [4 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [bin/strata-cli/src/main.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fmain.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL21haW4ucnM=) | 0.00% | [4 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |

```diff
@@            Coverage Diff             @@
##             main     #756      +/-   ##
==========================================
- Coverage   52.82%   52.82%   -0.01%     
==========================================
  Files         299      299              
  Lines       32716    32788      +72     
==========================================
+ Hits        17282    17319      +37     
- Misses      15434    15469      +35     
```

| [Files with missing lines](https://app.codecov.io/gh/alpenlabs/strata/pull/756?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) | Coverage Δ | |
|---|---|---|
| [bin/strata-cli/src/seed.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fseed.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL3NlZWQucnM=) | `66.66% <ø> (+10.18%)` | :arrow_up: |
| [bin/strata-cli/src/cmd/withdraw.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Fwithdraw.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC93aXRoZHJhdy5ycw==) | `0.00% <0.00%> (ø)` | |
| [bin/strata-cli/src/main.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fmain.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL21haW4ucnM=) | `0.00% <0.00%> (ø)` | |
| [bin/strata-cli/src/net\_type.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fnet_type.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL25ldF90eXBlLnJz) | `0.00% <0.00%> (ø)` | |
| [bin/strata-cli/src/cmd/send.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Fsend.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC9zZW5kLnJz) | `0.00% <0.00%> (ø)` | |
| [bin/strata-cli/src/cmd/faucet.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/756?src=pr&el=tree&filepath=bin%2Fstrata-cli%2Fsrc%2Fcmd%2Ffaucet.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-YmluL3N0cmF0YS1jbGkvc3JjL2NtZC9mYXVjZXQucnM=) | `0.00% <0.00%> (ø)` | |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/alpenlabs/strata/pull/756/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs)

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-30T05:48:35Z
body: **Commit**: ad0f858c

**SP1 Execution Results**
 
| program                | cycles      | success  |
|------------------------|-------------|----------|
| Bitcoin Blockspace     |      71,012 | ✅       |
| EVM EE STF             |     301,460 | ✅       |
| CL STF                 |     166,441 | ✅       |
| Checkpoint             |       4,252 | ✅       |


author_association: CONTRIBUTOR
user: login: krsnapaudel
created_at: 2025-03-31T02:06:18Z
body: @pranjalpokharel7 : Your code will have conflicts with [my recent PR](https://github.com/alpenlabs/strata/pull/755). Let me know if you need help fixing conflicts.
author_association: CONTRIBUTOR
user: login: pranjalpokharel7
created_at: 2025-03-31T03:20:45Z
body: @storopoli @barakshani I've made the necessary changes.
@krsnapaudel I've rebased your PR onto this branch, you can review it as needed.
author_association: CONTRIBUTOR
user: login: pranjalpokharel7
created_at: 2025-03-31T11:19:17Z
body: @krsnapaudel is the faucet unusable for strata address as of now? I tried the command on the `main` branch, it's failing due to an unexpected EOF error. Should I look into this as well? 

<img width="1064" alt="Screenshot 2025-03-31 at 16 32 30" src="https://github.com/user-attachments/assets/674a4de7-d175-4bde-b192-2869d926b849" />


author_association: CONTRIBUTOR
user: login: krsnapaudel
created_at: 2025-03-31T12:51:02Z
body: @pranjalpokharel7 : You should use the config from this PR. Note, the PoW difficulty is too high to actually claim tokens.
https://github.com/alpenlabs/docs/pull/7/files
author_association: CONTRIBUTOR
user: login: pranjalpokharel7
created_at: 2025-03-31T16:41:44Z
body: Update: This issue has been resolved.

@barakshani @krsnapaudel regarding ticket [STR-1205](https://alpenlabs.atlassian.net/browse/STR-1205)

I'm working on avoiding panics for incorrect password in the CLI, and I am opting for the first option to solve the issue. Let me know if I should solve this some other way. We can handle this,

1. (Selected) At the calling site (bin/strata-cli/src/main.rs), which will preserve the logic of original `load_or_create` function,
```rust
async fn main() {
// ...

    let seed = seed::load_or_create(&persister).unwrap_or_else(|e| {
        match e.narrow::<IncorrectPassword, _>() {
            Ok(_) => std::process::exit(1), // avoid panic for incorrect password
            Err(err) => panic!("{:?}", err),
        }
    });    
}
```


2. (Alternative) Or within the `load_or_create` function (`bin/strata-cli/src/seed.rs`), which simplifies things but changes the "library" code itself. If we are also not returning the IncorrectPassword error then we should consequently remove it from the codebase (unused elsewhere).
```rust
            Err(e) => {
                let narrowed = e.narrow::<aes_gcm_siv::Error, _>();
                if let Ok(_aes_error) = narrowed {
                    println!("Incorrect password");
                    std::process::exit(1); // exit here only, which means error type is not propagated back
                }

                Err(narrowed.unwrap_err().broaden())
            }
```

[STR-1205]: https://alpenlabs.atlassian.net/browse/STR-1205?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
author_association: CONTRIBUTOR
user: login: krsnapaudel
created_at: 2025-04-01T02:11:11Z
body: @pranjalpokharel7 I think we should not panic. So propagate the error and make the error message as user-friendly as possible.
author_association: CONTRIBUTOR
user: login: pranjalpokharel7
created_at: 2025-04-02T08:49:24Z
body: Invalid Address -
<img width="917" alt="Screenshot 2025-04-02 at 14 31 22" src="https://github.com/user-attachments/assets/e16c2f8d-8e7f-4087-8879-faa048cb7ace" />

Incorrect Password (agree that the error message itself isn't anything special, but that way we could avoid panics with minimum amount of changes) -
<img width="874" alt="Screenshot 2025-04-02 at 14 32 50" src="https://github.com/user-attachments/assets/965cc0e7-ac60-4028-ac95-d8fc059a8fc2" />

author_association: CONTRIBUTOR