refactor: cdk-cli use multimint wallet

This commit is contained in:
thesimplekid
2024-07-15 22:07:56 +01:00
parent 59ac008e50
commit ef66273554
13 changed files with 126 additions and 123 deletions

View File

@@ -28,6 +28,7 @@
### Changed
- cdk(wallet): `fn send` returns `Token` so the user can use the struct of convert it to a v3 or v4 string.
- cdk(wallet): Publicly export `MultiMintWallet` ([thesimplekid]).
### Added
- cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]).

View File

@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
@@ -6,9 +5,9 @@ use std::sync::Arc;
use anyhow::{bail, Result};
use bip39::Mnemonic;
use cdk::cdk_database;
use cdk::cdk_database::WalletDatabase;
use cdk::wallet::Wallet;
use cdk::{cdk_database, UncheckedUrl};
use cdk::wallet::{MultiMintWallet, Wallet};
use cdk_redb::WalletRedbDatabase;
use cdk_sqlite::WalletSqliteDatabase;
use clap::{Parser, Subcommand};
@@ -126,7 +125,7 @@ async fn main() -> Result<()> {
}
};
let mut wallets: HashMap<UncheckedUrl, Wallet> = HashMap::new();
let mut wallets: Vec<Wallet> = Vec::new();
let mints = localstore.get_mints().await?;
@@ -139,49 +138,50 @@ async fn main() -> Result<()> {
None,
);
wallets.insert(mint, wallet);
wallets.push(wallet);
}
let multi_mint_wallet = MultiMintWallet::new(wallets);
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::Pay => sub_commands::melt::pay(wallets).await,
Commands::Balance => sub_commands::balance::balance(&multi_mint_wallet).await,
Commands::Pay => sub_commands::melt::pay(multi_mint_wallet).await,
Commands::Receive(sub_command_args) => {
sub_commands::receive::receive(
wallets,
&mnemonic.to_seed_normalized(""),
localstore,
sub_command_args,
)
.await
sub_commands::receive::receive(&multi_mint_wallet, localstore, sub_command_args).await
}
Commands::Send(sub_command_args) => {
sub_commands::send::send(wallets, sub_command_args).await
sub_commands::send::send(&multi_mint_wallet, sub_command_args).await
}
Commands::CheckSpendable => {
sub_commands::check_spent::check_spent(&multi_mint_wallet).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,
&multi_mint_wallet,
&mnemonic.to_seed_normalized(""),
localstore,
sub_command_args,
)
.await
}
Commands::MintPending => sub_commands::pending_mints::mint_pending(wallets).await,
Commands::MintPending => {
sub_commands::pending_mints::mint_pending(&multi_mint_wallet).await
}
Commands::Burn(sub_command_args) => {
sub_commands::burn::burn(wallets, sub_command_args).await
sub_commands::burn::burn(&multi_mint_wallet, sub_command_args).await
}
Commands::Restore(sub_command_args) => {
sub_commands::restore::restore(wallets, sub_command_args).await
sub_commands::restore::restore(&multi_mint_wallet, sub_command_args).await
}
Commands::UpdateMintUrl(sub_command_args) => {
sub_commands::update_mint_url::update_mint_url(wallets, sub_command_args).await
sub_commands::update_mint_url::update_mint_url(&multi_mint_wallet, sub_command_args)
.await
}
}
}

View File

@@ -1,25 +1,28 @@
use std::collections::HashMap;
use anyhow::Result;
use cdk::nuts::CurrencyUnit;
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::wallet::multi_mint_wallet::MultiMintWallet;
use cdk::Amount;
pub async fn balance(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
mint_balances(wallets).await?;
pub async fn balance(multi_mint_wallet: &MultiMintWallet) -> Result<()> {
mint_balances(multi_mint_wallet).await?;
Ok(())
}
pub async fn mint_balances(
wallets: HashMap<UncheckedUrl, Wallet>,
) -> Result<Vec<(Wallet, Amount)>> {
let mut wallets_vec: Vec<(Wallet, Amount)> = Vec::with_capacity(wallets.capacity());
multi_mint_wallet: &MultiMintWallet,
) -> Result<Vec<(UncheckedUrl, Amount)>> {
let wallets: HashMap<UncheckedUrl, Amount> =
multi_mint_wallet.get_balances(&CurrencyUnit::Sat).await?;
for (i, (mint_url, wallet)) in wallets.iter().enumerate() {
let mut wallets_vec = Vec::with_capacity(wallets.capacity());
for (i, (mint_url, amount)) in wallets.iter().enumerate() {
let mint_url = mint_url.clone();
let amount = wallet.total_balance().await?;
println!("{i}: {mint_url} {amount}");
wallets_vec.push((wallet.clone(), amount));
wallets_vec.push((mint_url, *amount))
}
Ok(wallets_vec)
}

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap;
use anyhow::Result;
use cdk::wallet::Wallet;
use cdk::nuts::CurrencyUnit;
use cdk::wallet::multi_mint_wallet::WalletKey;
use cdk::wallet::MultiMintWallet;
use cdk::{Amount, UncheckedUrl};
use clap::Args;
@@ -12,17 +12,20 @@ pub struct BurnSubCommand {
}
pub async fn burn(
wallets: HashMap<UncheckedUrl, Wallet>,
multi_mint_wallet: &MultiMintWallet,
sub_command_args: &BurnSubCommand,
) -> Result<()> {
let mut total_burnt = Amount::ZERO;
match &sub_command_args.mint_url {
Some(mint_url) => {
let wallet = wallets.get(mint_url).unwrap();
let wallet = multi_mint_wallet
.get_wallet(&WalletKey::new(mint_url.clone(), CurrencyUnit::Sat))
.await
.unwrap();
total_burnt = wallet.check_all_pending_proofs().await?;
}
None => {
for wallet in wallets.values() {
for wallet in multi_mint_wallet.get_wallets().await {
let amount_burnt = wallet.check_all_pending_proofs().await?;
total_burnt += amount_burnt;
}

View File

@@ -1,11 +1,8 @@
use std::collections::HashMap;
use anyhow::Result;
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::wallet::MultiMintWallet;
pub async fn check_spent(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
for wallet in wallets.values() {
pub async fn check_spent(multi_mint_wallet: &MultiMintWallet) -> Result<()> {
for wallet in multi_mint_wallet.get_wallets().await {
let amount = wallet.check_all_pending_proofs().await?;
println!("Amount marked as spent: {}", amount);

View File

@@ -1,16 +1,16 @@
use std::collections::HashMap;
use std::io;
use std::io::Write;
use std::str::FromStr;
use std::{io, println};
use anyhow::{bail, Result};
use cdk::wallet::Wallet;
use cdk::{Bolt11Invoice, UncheckedUrl};
use cdk::nuts::CurrencyUnit;
use cdk::wallet::multi_mint_wallet::{MultiMintWallet, WalletKey};
use cdk::Bolt11Invoice;
use crate::sub_commands::balance::mint_balances;
pub async fn pay(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
let mints_amounts = mint_balances(wallets).await?;
pub async fn pay(multi_mint_wallet: MultiMintWallet) -> Result<()> {
let mints_amounts = mint_balances(&multi_mint_wallet).await?;
println!("Enter mint number to melt from");
@@ -26,6 +26,10 @@ pub async fn pay(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
}
let wallet = mints_amounts[mint_number].0.clone();
let wallet = multi_mint_wallet
.get_wallet(&WalletKey::new(wallet, CurrencyUnit::Sat))
.await
.expect("Known wallet");
println!("Enter bolt11 invoice request");

View File

@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
@@ -7,7 +6,8 @@ use cdk::amount::SplitTarget;
use cdk::cdk_database::{Error, WalletDatabase};
use cdk::nuts::{CurrencyUnit, MintQuoteState};
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::wallet::multi_mint_wallet::WalletKey;
use cdk::wallet::{MultiMintWallet, Wallet};
use cdk::Amount;
use clap::Args;
use tokio::time::sleep;
@@ -24,21 +24,29 @@ pub struct MintSubCommand {
}
pub async fn mint(
wallets: HashMap<UncheckedUrl, Wallet>,
multi_mint_wallet: &MultiMintWallet,
seed: &[u8],
localstore: Arc<dyn WalletDatabase<Err = Error> + Sync + Send>,
sub_command_args: &MintSubCommand,
) -> Result<()> {
let mint_url = sub_command_args.mint_url.clone();
let wallet = match wallets.get(&mint_url) {
let wallet = match multi_mint_wallet
.get_wallet(&WalletKey::new(mint_url.clone(), CurrencyUnit::Sat))
.await
{
Some(wallet) => wallet.clone(),
None => Wallet::new(
&mint_url.to_string(),
CurrencyUnit::Sat,
localstore,
seed,
None,
),
None => {
let wallet = Wallet::new(
&mint_url.to_string(),
CurrencyUnit::Sat,
localstore,
seed,
None,
);
multi_mint_wallet.add_wallet(wallet.clone()).await;
wallet
}
};
let quote = wallet

View File

@@ -1,16 +1,12 @@
use std::collections::HashMap;
use anyhow::Result;
use cdk::wallet::Wallet;
use cdk::{Amount, UncheckedUrl};
use cdk::wallet::MultiMintWallet;
use cdk::Amount;
pub async fn mint_pending(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
let mut amount_claimed = Amount::ZERO;
for wallet in wallets.values() {
let claimed = wallet.check_all_mint_quotes().await?;
amount_claimed += claimed;
}
pub async fn mint_pending(multi_mint_wallet: &MultiMintWallet) -> Result<()> {
let amounts = multi_mint_wallet.check_all_mint_quotes(None).await?;
println!("Amount minted: {amount_claimed}");
let amount = amounts.into_values().sum::<Amount>();
println!("Amount minted: {amount}");
Ok(())
}

View File

@@ -1,14 +1,13 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::str::FromStr;
use std::sync::Arc;
use anyhow::{anyhow, Result};
use cdk::amount::SplitTarget;
use cdk::cdk_database::{Error, WalletDatabase};
use cdk::nuts::{CurrencyUnit, SecretKey, Token};
use cdk::cdk_database::{self, WalletDatabase};
use cdk::nuts::SecretKey;
use cdk::util::unix_time;
use cdk::wallet::Wallet;
use cdk::{Amount, UncheckedUrl};
use cdk::wallet::multi_mint_wallet::MultiMintWallet;
use cdk::Amount;
use clap::Args;
use nostr_sdk::nips::nip04;
use nostr_sdk::{Filter, Keys, Kind, Timestamp};
@@ -35,9 +34,8 @@ pub struct ReceiveSubCommand {
}
pub async fn receive(
wallets: HashMap<UncheckedUrl, Wallet>,
seed: &[u8],
localstore: Arc<dyn WalletDatabase<Err = Error> + Sync + Send>,
multi_mint_wallet: &MultiMintWallet,
localstore: Arc<dyn WalletDatabase<Err = cdk_database::Error> + Send + Sync>,
sub_command_args: &ReceiveSubCommand,
) -> Result<()> {
let mut signing_keys = Vec::new();
@@ -62,10 +60,8 @@ pub async fn receive(
let amount = match &sub_command_args.token {
Some(token_str) => {
receive_token(
multi_mint_wallet,
token_str,
wallets,
seed,
&localstore,
&signing_keys,
&sub_command_args.preimage,
)
@@ -97,10 +93,8 @@ pub async fn receive(
let mut total_amount = Amount::ZERO;
for token_str in &tokens {
match receive_token(
multi_mint_wallet,
token_str,
wallets.clone(),
seed,
&localstore,
&signing_keys,
&sub_command_args.preimage,
)
@@ -128,29 +122,13 @@ pub async fn receive(
}
async fn receive_token(
token_str: &str,
wallets: HashMap<UncheckedUrl, Wallet>,
seed: &[u8],
localstore: &Arc<dyn WalletDatabase<Err = Error> + Sync + Send>,
multi_mint_wallet: &MultiMintWallet,
token: &str,
signing_keys: &[SecretKey],
preimage: &[String],
) -> Result<Amount> {
let token = Token::from_str(token_str)?;
let mint_url = token.proofs().iter().next().unwrap().0.clone();
let wallet = match wallets.get(&mint_url) {
Some(wallet) => wallet.clone(),
None => Wallet::new(
&mint_url.to_string(),
CurrencyUnit::Sat,
Arc::clone(localstore),
seed,
None,
),
};
let amount = wallet
.receive(token_str, SplitTarget::default(), signing_keys, preimage)
let amount = multi_mint_wallet
.receive(token, signing_keys, preimage)
.await?;
Ok(amount)
}

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap;
use anyhow::{anyhow, Result};
use cdk::nuts::CurrencyUnit;
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::wallet::multi_mint_wallet::WalletKey;
use cdk::wallet::MultiMintWallet;
use clap::Args;
#[derive(Args)]
@@ -12,11 +12,15 @@ pub struct RestoreSubCommand {
}
pub async fn restore(
wallets: HashMap<UncheckedUrl, Wallet>,
multi_mint_wallet: &MultiMintWallet,
sub_command_args: &RestoreSubCommand,
) -> Result<()> {
let wallet = wallets
.get(&sub_command_args.mint_url)
let wallet = multi_mint_wallet
.get_wallet(&WalletKey::new(
sub_command_args.mint_url.clone(),
CurrencyUnit::Sat,
))
.await
.ok_or(anyhow!("Unknown mint url"))?;
let amount = wallet.restore().await?;

View File

@@ -1,14 +1,14 @@
use std::collections::HashMap;
use std::io;
use std::io::Write;
use std::str::FromStr;
use anyhow::{bail, Result};
use cdk::amount::SplitTarget;
use cdk::nuts::{Conditions, PublicKey, SpendingConditions};
use cdk::nuts::{Conditions, CurrencyUnit, PublicKey, SpendingConditions};
use cdk::wallet::multi_mint_wallet::WalletKey;
use cdk::wallet::types::SendKind;
use cdk::wallet::Wallet;
use cdk::{Amount, UncheckedUrl};
use cdk::wallet::MultiMintWallet;
use cdk::Amount;
use clap::Args;
use crate::sub_commands::balance::mint_balances;
@@ -48,10 +48,10 @@ pub struct SendSubCommand {
}
pub async fn send(
wallets: HashMap<UncheckedUrl, Wallet>,
multi_mint_wallet: &MultiMintWallet,
sub_command_args: &SendSubCommand,
) -> Result<()> {
let mints_amounts = mint_balances(wallets).await?;
let mints_amounts = mint_balances(multi_mint_wallet).await?;
println!("Enter mint number to create token");
@@ -155,6 +155,10 @@ pub async fn send(
};
let wallet = mints_amounts[mint_number].0.clone();
let wallet = multi_mint_wallet
.get_wallet(&WalletKey::new(wallet, CurrencyUnit::Sat))
.await
.expect("Known wallet");
let send_kind = match (sub_command_args.offline, sub_command_args.tolerance) {
(true, Some(amount)) => SendKind::OfflineTolerance(Amount::from(amount)),

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap;
use anyhow::{anyhow, Result};
use cdk::nuts::CurrencyUnit;
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::wallet::multi_mint_wallet::WalletKey;
use cdk::wallet::MultiMintWallet;
use clap::Args;
#[derive(Args)]
@@ -14,7 +14,7 @@ pub struct UpdateMintUrlSubCommand {
}
pub async fn update_mint_url(
wallets: HashMap<UncheckedUrl, Wallet>,
multi_mint_wallet: &MultiMintWallet,
sub_command_args: &UpdateMintUrlSubCommand,
) -> Result<()> {
let UpdateMintUrlSubCommand {
@@ -22,8 +22,12 @@ pub async fn update_mint_url(
new_mint_url,
} = sub_command_args;
let mut wallet = wallets
.get(old_mint_url)
let mut wallet = multi_mint_wallet
.get_wallet(&WalletKey::new(
sub_command_args.old_mint_url.clone(),
CurrencyUnit::Sat,
))
.await
.ok_or(anyhow!("Unknown mint url"))?
.clone();

View File

@@ -35,6 +35,7 @@ pub mod multi_mint_wallet;
pub mod types;
pub mod util;
pub use multi_mint_wallet::MultiMintWallet;
pub use types::{MeltQuote, MintQuote, SendKind};
/// CDK Wallet