Files
cdk/crates/cdk-cli/src/main.rs
thesimplekid 7223c5bda8 feat(NUT05): update with quote state
feat(NUT04): update with quote state

feat: db migrations for mint state

chore: remove logging
2024-06-27 20:35:19 +01:00

181 lines
5.5 KiB
Rust

use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use anyhow::{bail, Result};
use bip39::Mnemonic;
use cdk::cdk_database::WalletDatabase;
use cdk::wallet::Wallet;
use cdk::{cdk_database, UncheckedUrl};
use cdk_redb::RedbWalletDatabase;
use cdk_sqlite::WalletSQLiteDatabase;
use clap::{Parser, Subcommand};
use rand::Rng;
mod sub_commands;
const DEFAULT_WORK_DIR: &str = ".cdk-cli";
/// Simple CLI application to interact with cashu
#[derive(Parser)]
#[command(name = "cashu-tool")]
#[command(author = "thesimplekid <tsk@thesimplekid.com>")]
#[command(version = "0.1")]
#[command(author, version, about, long_about = None)]
struct Cli {
/// Database engine to use (sqlite/redb)
#[arg(short, long, default_value = "sqlite")]
engine: String,
/// Path to Seed
#[arg(short, long)]
work_dir: Option<PathBuf>,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Decode a token
DecodeToken(sub_commands::decode_token::DecodeTokenSubCommand),
/// Balance
Balance,
/// Pay bolt11 invoice
Melt(sub_commands::melt::MeltSubCommand),
/// Claim pending mints
PendingMint,
/// Receive token
Receive(sub_commands::receive::ReceiveSubCommand),
/// Send
Send(sub_commands::send::SendSubCommand),
/// Check if wallet balance is spendable
CheckSpendable,
/// View mint info
MintInfo(sub_commands::mint_info::MintInfoSubcommand),
/// Mint proofs via bolt11
Mint(sub_commands::mint::MintSubCommand),
/// Burn Spent tokens
Burn(sub_commands::burn::BurnSubCommand),
/// Restore proofs from seed
Restore(sub_commands::restore::RestoreSubCommand),
/// Update Mint Url
UpdateMintUrl(sub_commands::update_mint_url::UpdateMintUrlSubCommand),
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();
// Parse input
let args: Cli = Cli::parse();
let work_dir = match &args.work_dir {
Some(work_dir) => work_dir.clone(),
None => {
let home_dir = home::home_dir().unwrap();
home_dir.join(DEFAULT_WORK_DIR)
}
};
fs::create_dir_all(&work_dir)?;
let localstore: Arc<dyn WalletDatabase<Err = cdk_database::Error> + Send + Sync> =
match args.engine.as_str() {
"sqlite" => {
let sql_path = work_dir.join("cdk-cli.sqlite");
let sql = WalletSQLiteDatabase::new(&sql_path).await?;
sql.migrate().await;
Arc::new(sql)
}
"redb" => {
let redb_path = work_dir.join("cdk-cli.redb");
Arc::new(RedbWalletDatabase::new(&redb_path)?)
}
_ => bail!("Unknown DB engine"),
};
let seed_path = work_dir.join("seed");
let mnemonic = match fs::metadata(seed_path.clone()) {
Ok(_) => {
let contents = fs::read_to_string(seed_path.clone())?;
Mnemonic::from_str(&contents)?
}
Err(_e) => {
let mut rng = rand::thread_rng();
let random_bytes: [u8; 32] = rng.gen();
let mnemnic = Mnemonic::from_entropy(&random_bytes)?;
tracing::info!("Using randomly generated seed you will not be able to restore");
mnemnic
}
};
let mut wallets: HashMap<UncheckedUrl, Wallet> = HashMap::new();
let mints = localstore.get_mints().await?;
for (mint, _) in mints {
let wallet = Wallet::new(
&mint.to_string(),
cdk::nuts::CurrencyUnit::Sat,
localstore.clone(),
&mnemonic.to_seed_normalized(""),
);
wallets.insert(mint, wallet);
}
match &args.command {
Commands::DecodeToken(sub_command_args) => {
sub_commands::decode_token::decode_token(sub_command_args)
}
Commands::Balance => sub_commands::balance::balance(wallets).await,
Commands::Melt(sub_command_args) => {
sub_commands::melt::melt(wallets, sub_command_args).await
}
Commands::Receive(sub_command_args) => {
sub_commands::receive::receive(
wallets,
&mnemonic.to_seed_normalized(""),
localstore,
sub_command_args,
)
.await
}
Commands::Send(sub_command_args) => {
sub_commands::send::send(wallets, sub_command_args).await
}
Commands::CheckSpendable => sub_commands::check_spent::check_spent(wallets).await,
Commands::MintInfo(sub_command_args) => {
sub_commands::mint_info::mint_info(sub_command_args).await
}
Commands::Mint(sub_command_args) => {
sub_commands::mint::mint(
wallets,
&mnemonic.to_seed_normalized(""),
localstore,
sub_command_args,
)
.await
}
Commands::PendingMint => sub_commands::pending_mints::pending_mints(wallets).await,
Commands::Burn(sub_command_args) => {
sub_commands::burn::burn(wallets, sub_command_args).await
}
Commands::Restore(sub_command_args) => {
sub_commands::restore::restore(wallets, sub_command_args).await
}
Commands::UpdateMintUrl(sub_command_args) => {
sub_commands::update_mint_url::update_mint_url(wallets, sub_command_args).await
}
}
}