mirror of
https://github.com/aljazceru/cdk.git
synced 2026-01-03 04:55:39 +01:00
feat(NUT04): update with quote state feat: db migrations for mint state chore: remove logging
181 lines
5.5 KiB
Rust
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
|
|
}
|
|
}
|
|
}
|