espresso_contract_deployer/
provider.rs

1use alloy::signers::ledger::{HDPath, LedgerError, LedgerSigner};
2use anyhow::{Result, bail};
3
4/// Try to obtain a ledger signer
5///
6/// Handles some common errors by prompting the user.
7pub async fn connect_ledger(account_index: usize) -> Result<LedgerSigner> {
8    let mut attempt = 1;
9    let max_attempts = 20;
10    Ok(loop {
11        match LedgerSigner::new(HDPath::LedgerLive(account_index), None).await {
12            Ok(signer) => break signer,
13            Err(err) => {
14                match err {
15                    // Sadly, at this point, if we keep the app running unlocking the
16                    // ledger does not make it show up.
17                    LedgerError::LedgerError(ref ledger_error) => {
18                        bail!("Error: {ledger_error:#}. Please unlock ledger and try again")
19                    },
20                    LedgerError::UnexpectedNullResponse => {
21                        eprintln!(
22                            "Failed to access ledger {attempt}/{max_attempts}: {err:#}, please \
23                             unlock ledger and open the Ethereum app"
24                        );
25                    },
26                    _ => {
27                        bail!("Unexpected error accessing the ledger device: {err:#}")
28                    },
29                };
30                if attempt >= max_attempts {
31                    bail!("Failed to create Ledger signer after {max_attempts} attempts");
32                }
33                attempt += 1;
34                tokio::time::sleep(std::time::Duration::from_secs(3)).await;
35            },
36        }
37    })
38}