-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cast wallet list
) issue #6958: Include HW wallets in cast wallet ls
#7123
Conversation
cast wallet list
) issue #6958: Include HW wallets in cast wallet ls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is great.
I want to make this more like a utility function that this command then consumes
crates/cast/bin/cmd/wallet/mod.rs
Outdated
Some(Ok(path)) | ||
} else { | ||
None | ||
WalletSubcommands::List { dir, ledger, trezor, aws, all } => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be useful in the wallet crate @klkvr
like a struct that looks up all configured sources and returns the results
so I think we want to do this a bit differently,
the helper struct should gather all the info and then we print them here in the command
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense, happy to accommodate such after things moved to new crate or leave up to @klkvr lmk what you guys decide
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grandizzy we should merge #7141 soon which will change structure of foundry-wallets, so I think for now this PR is somewhat blocked, but feel free to take a look at the code structure and entities in #7141 as those are unlikely to change much
once its merged I believe we can extend WalletSigner
enum from there with async fn available_senders(&self, max: usize) -> Vec<Address>
and then use it for the list command
you should be able to obtain WalletSigner
s either by calling utils functions directly or by constructing MultiWalletOpts
with hw wallets opts + keystore paths, and then calling get_multi_wallet
on it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, checked and makes sense (I might need to derive builder for MultiWalletOpts
), will prepare changes and make a PR once #7141 in master
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I redid PR with new wallet structure, pretty tidy now imo, please review
2d72592
to
b8f8c01
Compare
b8f8c01
to
e8a8bf5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few more nits.
pending @klkvr and @DaniPopes
@@ -24,6 +24,7 @@ foundry-common.workspace = true | |||
|
|||
async-trait = "0.1" | |||
clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } | |||
derive_builder = "0.20.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm personally okay with this
any objections @DaniPopes ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fine
crates/cast/bin/cmd/wallet/list.rs
Outdated
.private_keys(None) | ||
.private_key(None) | ||
.mnemonics(None) | ||
.mnemonic_passphrases(None) | ||
.hd_paths(None) | ||
.keystore_paths(None) | ||
.keystore_account_names(None) | ||
.keystore_passwords(None) | ||
.keystore_password_files(None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think these are required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per builder doc The build method returns Result<T, E>, where T is the struct you started with and E is a generated builder error type. It returns Err if you didn’t initialize all fields and no default values were provided.
I removed the code and made builder defaults as annotations
@@ -57,6 +57,37 @@ impl WalletSigner { | |||
Ok(Self::Local(wallet)) | |||
} | |||
|
|||
pub async fn available_senders(&self, max: usize) -> Result<Vec<ethers_core::types::Address>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add one line doc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. Also updated impl to handle Local signer too and to return Ledger addresses for legacy derivation path as well
crates/cast/bin/cmd/wallet/list.rs
Outdated
let keystore_path = self.dir.clone().unwrap_or_default(); | ||
let keystore_dir = if keystore_path.is_empty() { | ||
let default_dir = Config::foundry_keystores_dir() | ||
.ok_or_else(|| eyre::eyre!("Could not find the default keystore directory."))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be if let Some else instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simplified handle logic for creating default dir, need the unwrap_or_default
as this code handles the cast wallet ls
command where dir
is None
crates/cast/bin/cmd/wallet/list.rs
Outdated
impl ListArgs { | ||
pub async fn run(self) -> Result<()> { | ||
// list local accounts as files in keystore dir, no need to unlock / provide password | ||
if self.dir.is_some() || self.all || !self.ledger && !self.trezor && !self.aws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, this will always be true if any leder,trezor,aws argument is missing
should this be || (!self.ledger && !self.trezor && !self.aws)
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, changed
- use annotations for builder defaults - handle Local signer in available_senders, return Ledger addresses for legacy derivation, add doc - fix condition to list files in keystore dir - simplify creation of keystore default directory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you, lgtm! just a nit
crates/cast/bin/cmd/wallet/list.rs
Outdated
// List ledger accounts | ||
match list_opts.ledgers().await { | ||
Ok(signers) => { | ||
self.list_senders(signers.unwrap_or_default(), max_senders, "Ledger").await? | ||
} | ||
Err(e) => { | ||
if !self.all { | ||
println!("{}", e) | ||
} | ||
} | ||
} | ||
|
||
// List Trezor accounts | ||
match list_opts.trezors().await { | ||
Ok(signers) => { | ||
self.list_senders(signers.unwrap_or_default(), max_senders, "Trezor").await? | ||
} | ||
Err(e) => { | ||
if !self.all { | ||
println!("{}", e) | ||
} | ||
} | ||
} | ||
|
||
// List AWS accounts | ||
match list_opts.aws_signers().await { | ||
Ok(signers) => { | ||
self.list_senders(signers.unwrap_or_default(), max_senders, "AWS").await? | ||
} | ||
Err(e) => { | ||
if !self.all { | ||
println!("{}", e) | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice if we could reduce duplication here via macro/fn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, good point, changed in c4ce461
crates/cast/bin/cmd/wallet/list.rs
Outdated
aws: bool, | ||
|
||
/// List all configured accounts. | ||
#[clap(long, help_heading = "List all accounts")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove help_heading
s, these don't need sections for each option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed in 38fc356
crates/cast/bin/cmd/wallet/list.rs
Outdated
dunce::canonicalize(keystore_path)? | ||
}; | ||
|
||
match std::fs::read_dir(keystore_dir) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove match, use ?
as it already exists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed in 38fc356
crates/cast/bin/cmd/wallet/list.rs
Outdated
Ok(()) | ||
} | ||
|
||
async fn list_local_senders(&self) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't need async
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated in 38fc356
crates/cast/bin/cmd/wallet/list.rs
Outdated
.expect("build multi wallet"); | ||
|
||
// max number of senders to be shown for ledger and trezor signers | ||
let max_senders = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be an argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, made this a wallet list argument, grouped with hardware wallets and all option 38fc356
crates/wallets/src/wallet_signer.rs
Outdated
match self { | ||
WalletSigner::Local(local) => { | ||
senders.push(local.address()); | ||
Ok(senders) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move Ok(senders) to the bottom outside of the match
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 38fc356
/// - the result for Ledger signers includes addresses available for both LedgerLive and Legacy | ||
/// derivation paths | ||
/// - for Local and AWS signers the result contains a single address | ||
pub async fn available_senders(&self, max: usize) -> Result<Vec<ethers_core::types::Address>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can't fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed list_senders
fn to reflect this in 38fc356
crates/cast/bin/cmd/wallet/list.rs
Outdated
|
||
async fn list_senders( | ||
&self, | ||
signers: Vec<WalletSigner>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signers: Vec<WalletSigner>, | |
signers: &[WalletSigner], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -24,6 +24,7 @@ foundry-common.workspace = true | |||
|
|||
async-trait = "0.1" | |||
clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } | |||
derive_builder = "0.20.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fine
- remove help_headings - remove match and use ? as dir already exists - remove async from list_local_senders fn - move Ok(senders) at the bottom of available_senders fn - list_senders doesn't need match as available_senders cannot fail - make max_senders arg for ls command , default 3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
last style nit
otherwise lgtm
pending @DaniPopes
crates/cast/bin/cmd/wallet/list.rs
Outdated
let label = "Ledger"; | ||
let signers = list_opts.ledgers(); | ||
list_senders!(signers, label); | ||
|
||
let label = "Trezor"; | ||
let signers = list_opts.trezors(); | ||
list_senders!(signers, label); | ||
|
||
let label = "AWS"; | ||
let signers = list_opts.aws_signers(); | ||
list_senders!(signers, label); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let label = "Ledger"; | |
let signers = list_opts.ledgers(); | |
list_senders!(signers, label); | |
let label = "Trezor"; | |
let signers = list_opts.trezors(); | |
list_senders!(signers, label); | |
let label = "AWS"; | |
let signers = list_opts.aws_signers(); | |
list_senders!(signers, label); | |
list_senders!(list_opts.ledgers(), "Ledger"); | |
list_senders!(list_opts.trezors(), "Trezor"); | |
list_senders!(list_opts.aws_signers(), "AWS"); |
crates/cast/bin/cmd/wallet/list.rs
Outdated
|
||
// macro to print senders for a list of signers | ||
macro_rules! list_senders { | ||
($signers:ident, $label: ident) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
($signers:ident, $label: ident) => { | |
($signers:expr, $label:literal) => { |
yep, nicer :) added in a9cd6ad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
for ledger display 3 addresses for each ledger live and legacy HD
for trezor display 3 addresses for trezor live HD path
for AWS display all keys configured
for local keystore list files in dir
unit tests
Note: I don't have Trezor / AWS configured
Things to discuss:
Motivation
Solution