Skip to content

Commit

Permalink
CLI wallet: Ledger Nano support (#1606)
Browse files Browse the repository at this point in the history
* finish impl

* changelog

* Add Ledger Nano simulator choice

* panic instead of unreachable

* panic message

Co-authored-by: DaughterOfMars <[email protected]>

* full ledger nano support

* fix usability issues

* fix backup/restore

* clean up failed restore

* PR suggestion

* small cleanup

* Update year (how time flies 🙈)

Co-authored-by: Thoralf-M <[email protected]>

* revert breaking change

* fix fs cleanup after failed restore

* getter

* derive ValueEnum

* optional secret manager choice

* remove unnecessary password input

* create initial account for init

* ensure set stronghold password (lazily)

* fix

* changelog

* Edit changelog

* Bump version and changelog

---------

Co-authored-by: DaughterOfMars <[email protected]>
Co-authored-by: Thibault Martinez <[email protected]>
Co-authored-by: Thoralf-M <[email protected]>
  • Loading branch information
4 people authored Jan 23, 2024
1 parent d803602 commit a236939
Show file tree
Hide file tree
Showing 12 changed files with 515 additions and 213 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security -->

## 1.3.0 - 2024-01-23

### Added

- Ledger Nano support;

## 1.2.0 - 2023-10-26

### Added
Expand Down
3 changes: 2 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cli-wallet"
version = "1.2.0"
version = "1.3.0"
authors = ["IOTA Stiftung"]
edition = "2021"
homepage = "https://iota.org"
Expand All @@ -22,6 +22,7 @@ iota-sdk = { path = "../sdk", default-features = false, features = [
"rocksdb",
"stronghold",
"participation",
"ledger_nano",
] }

chrono = { version = "0.4.31", default-features = false, features = ["std"] }
Expand Down
73 changes: 62 additions & 11 deletions cli/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

use clap::Parser;
use colored::Colorize;
use iota_sdk::wallet::{Account, Wallet};
use iota_sdk::{
client::secret::SecretManager,
wallet::{Account, Wallet},
};
use rustyline::{error::ReadlineError, history::MemHistory, Config, Editor};

use crate::{
Expand All @@ -22,7 +25,7 @@ use crate::{
account_completion::AccountPromptHelper,
},
error::Error,
helper::bytes_from_hex_or_file,
helper::{bytes_from_hex_or_file, get_password},
println_log_error,
};

Expand Down Expand Up @@ -62,6 +65,17 @@ pub enum AccountPromptResponse {
Switch(Account),
}

async fn ensure_password(wallet: &Wallet) -> Result<(), Error> {
if matches!(*wallet.get_secret_manager().read().await, SecretManager::Stronghold(_))
&& !wallet.is_stronghold_password_available().await?
{
let password = get_password("Stronghold password", false)?;
wallet.set_stronghold_password(password).await?;
}

Ok(())
}

// loop on the account prompt
pub async fn account_prompt_internal(
wallet: &Wallet,
Expand Down Expand Up @@ -110,19 +124,33 @@ pub async fn account_prompt_internal(
AccountCommand::Addresses => addresses_command(account).await,
AccountCommand::Balance { addresses } => balance_command(account, addresses).await,
AccountCommand::BurnNativeToken { token_id, amount } => {
ensure_password(wallet).await?;
burn_native_token_command(account, token_id, amount).await
}
AccountCommand::BurnNft { nft_id } => burn_nft_command(account, nft_id).await,
AccountCommand::Claim { output_id } => claim_command(account, output_id).await,
AccountCommand::BurnNft { nft_id } => {
ensure_password(wallet).await?;
burn_nft_command(account, nft_id).await
}
AccountCommand::Claim { output_id } => {
ensure_password(wallet).await?;
claim_command(account, output_id).await
}
AccountCommand::ClaimableOutputs => claimable_outputs_command(account).await,
AccountCommand::Consolidate => consolidate_command(account).await,
AccountCommand::CreateAliasOutput => create_alias_outputs_command(account).await,
AccountCommand::Consolidate => {
ensure_password(wallet).await?;
consolidate_command(account).await
}
AccountCommand::CreateAliasOutput => {
ensure_password(wallet).await?;
create_alias_outputs_command(account).await
}
AccountCommand::CreateNativeToken {
circulating_supply,
maximum_supply,
foundry_metadata_hex,
foundry_metadata_file,
} => {
ensure_password(wallet).await?;
create_native_token_command(
account,
circulating_supply,
Expand All @@ -131,18 +159,24 @@ pub async fn account_prompt_internal(
)
.await
}
AccountCommand::DestroyAlias { alias_id } => destroy_alias_command(account, alias_id).await,
AccountCommand::DestroyAlias { alias_id } => {
ensure_password(wallet).await?;
destroy_alias_command(account, alias_id).await
}
AccountCommand::DestroyFoundry { foundry_id } => {
ensure_password(wallet).await?;
destroy_foundry_command(account, foundry_id).await
}
AccountCommand::Exit => {
return Ok(AccountPromptResponse::Done);
}
AccountCommand::Faucet { address, url } => faucet_command(account, address, url).await,
AccountCommand::MeltNativeToken { token_id, amount } => {
ensure_password(wallet).await?;
melt_native_token_command(account, token_id, amount).await
}
AccountCommand::MintNativeToken { token_id, amount } => {
ensure_password(wallet).await?;
mint_native_token(account, token_id, amount).await
}
AccountCommand::MintNft {
Expand All @@ -155,6 +189,7 @@ pub async fn account_prompt_internal(
sender,
issuer,
} => {
ensure_password(wallet).await?;
mint_nft_command(
account,
address,
Expand All @@ -166,7 +201,10 @@ pub async fn account_prompt_internal(
)
.await
}
AccountCommand::NewAddress => new_address_command(account).await,
AccountCommand::NewAddress => {
ensure_password(wallet).await?;
new_address_command(account).await
}
AccountCommand::NodeInfo => node_info_command(account).await,
AccountCommand::Output { selector } => output_command(account, selector).await,
AccountCommand::Outputs => outputs_command(account).await,
Expand All @@ -177,6 +215,7 @@ pub async fn account_prompt_internal(
expiration,
allow_micro_amount,
} => {
ensure_password(wallet).await?;
let allow_micro_amount = if return_address.is_some() || expiration.is_some() {
true
} else {
Expand All @@ -197,8 +236,14 @@ pub async fn account_prompt_internal(
token_id,
amount,
gift_storage_deposit,
} => send_native_token_command(account, address, token_id, amount, gift_storage_deposit).await,
AccountCommand::SendNft { address, nft_id } => send_nft_command(account, address, nft_id).await,
} => {
ensure_password(wallet).await?;
send_native_token_command(account, address, token_id, amount, gift_storage_deposit).await
}
AccountCommand::SendNft { address, nft_id } => {
ensure_password(wallet).await?;
send_nft_command(account, address, nft_id).await
}
AccountCommand::Switch { account_id } => {
return Ok(AccountPromptResponse::Switch(wallet.get_account(account_id).await?));
}
Expand All @@ -208,8 +253,12 @@ pub async fn account_prompt_internal(
transactions_command(account, show_details).await
}
AccountCommand::UnspentOutputs => unspent_outputs_command(account).await,
AccountCommand::Vote { event_id, answers } => vote_command(account, event_id, answers).await,
AccountCommand::Vote { event_id, answers } => {
ensure_password(wallet).await?;
vote_command(account, event_id, answers).await
}
AccountCommand::StopParticipating { event_id } => {
ensure_password(wallet).await?;
stop_participating_command(account, event_id).await
}
AccountCommand::ParticipationOverview { event_ids } => {
Expand All @@ -218,9 +267,11 @@ pub async fn account_prompt_internal(
}
AccountCommand::VotingPower => voting_power_command(account).await,
AccountCommand::IncreaseVotingPower { amount } => {
ensure_password(wallet).await?;
increase_voting_power_command(account, amount).await
}
AccountCommand::DecreaseVotingPower { amount } => {
ensure_password(wallet).await?;
decrease_voting_power_command(account, amount).await
}
AccountCommand::VotingOutput => voting_output_command(account).await,
Expand Down
Loading

0 comments on commit a236939

Please sign in to comment.