use std::path::PathBuf;
use anyhow::Context;
use clap::Subcommand;
use serde::Serialize;
use crate::wallet::{
default_wallet_path, ensure_wallet_dir, get_new_password, get_password, Wallet,
};
#[derive(Subcommand)]
pub(crate) enum WalletCommand {
New,
Address,
Import {
#[arg(long)]
phrase: String,
},
Export,
}
#[derive(Serialize)]
struct JsonWallet {
address: String,
#[serde(skip_serializing_if = "Option::is_none")]
mnemonic: Option<String>,
}
pub(crate) fn cmd_wallet(
command: WalletCommand,
wallet_path: Option<PathBuf>,
json: bool,
) -> anyhow::Result<()> {
let path = wallet_path.unwrap_or_else(default_wallet_path);
match command {
WalletCommand::New => {
if path.exists() {
anyhow::bail!("wallet already exists at {}", path.display());
}
let wallet = Wallet::new()?;
let password = get_new_password()?;
let save_path = ensure_parent_dir(path)?;
wallet.save_to_file(&save_path, &password)?;
print_wallet(&wallet, None, json)
}
WalletCommand::Address => {
let password = get_password("Enter password: ")?;
let wallet = Wallet::load_from_file(&path, &password)
.with_context(|| format!("failed to load wallet at {}", path.display()))?;
print_wallet(&wallet, None, json)
}
WalletCommand::Import { phrase } => {
let wallet = Wallet::from_phrase(&phrase)?;
let password = get_new_password()?;
let save_path = ensure_parent_dir(path)?;
wallet.save_to_file(&save_path, &password)?;
print_wallet(&wallet, None, json)
}
WalletCommand::Export => {
let password = get_password("Enter password: ")?;
let wallet = Wallet::load_from_file(&path, &password)
.with_context(|| format!("failed to load wallet at {}", path.display()))?;
print_wallet(&wallet, Some(wallet.mnemonic()), json)
}
}
}
fn ensure_parent_dir(path: PathBuf) -> anyhow::Result<PathBuf> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
} else {
let _ = ensure_wallet_dir()?;
}
Ok(path)
}
fn print_wallet(wallet: &Wallet, mnemonic: Option<String>, json: bool) -> anyhow::Result<()> {
if json {
let out = JsonWallet {
address: wallet.address_str(),
mnemonic,
};
println!("{}", serde_json::to_string(&out)?);
} else {
println!("Address: {}", wallet.address_str());
if let Some(phrase) = mnemonic {
println!("Mnemonic: {}", phrase);
}
}
Ok(())
}