mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-23 07:35:03 +01:00
feat(wallet): make wallet single mint and unit
feat(wallet): cli use mint with one url and unit feat(wallet): remove p2pk keys from wallet feat(wallet): multimint wallet
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@@ -5,9 +6,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_redb::RedbWalletDatabase;
|
||||
use cdk_sqlite::WalletSQLiteDatabase;
|
||||
use clap::{Parser, Subcommand};
|
||||
@@ -117,38 +118,63 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
let wallet = Wallet::new(localstore, &mnemonic.to_seed_normalized(""), vec![]);
|
||||
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(wallet).await,
|
||||
Commands::Balance => sub_commands::balance::balance(wallets).await,
|
||||
Commands::Melt(sub_command_args) => {
|
||||
sub_commands::melt::melt(wallet, sub_command_args).await
|
||||
sub_commands::melt::melt(wallets, sub_command_args).await
|
||||
}
|
||||
Commands::Receive(sub_command_args) => {
|
||||
sub_commands::receive::receive(wallet, sub_command_args).await
|
||||
sub_commands::receive::receive(
|
||||
wallets,
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
localstore,
|
||||
sub_command_args,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::Send(sub_command_args) => {
|
||||
sub_commands::send::send(wallet, sub_command_args).await
|
||||
sub_commands::send::send(wallets, sub_command_args).await
|
||||
}
|
||||
Commands::CheckSpendable => sub_commands::check_spent::check_spent(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(wallet, sub_command_args).await
|
||||
sub_commands::mint::mint(
|
||||
wallets,
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
localstore,
|
||||
sub_command_args,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::PendingMint => sub_commands::pending_mints::pending_mints(wallet).await,
|
||||
Commands::PendingMint => sub_commands::pending_mints::pending_mints(wallets).await,
|
||||
Commands::Burn(sub_command_args) => {
|
||||
sub_commands::burn::burn(wallet, sub_command_args).await
|
||||
sub_commands::burn::burn(wallets, sub_command_args).await
|
||||
}
|
||||
Commands::Restore(sub_command_args) => {
|
||||
sub_commands::restore::restore(wallet, sub_command_args).await
|
||||
sub_commands::restore::restore(wallets, sub_command_args).await
|
||||
}
|
||||
Commands::UpdateMintUrl(sub_command_args) => {
|
||||
sub_commands::update_mint_url::update_mint_url(wallet, sub_command_args).await
|
||||
sub_commands::update_mint_url::update_mint_url(wallets, sub_command_args).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use cdk::nuts::CurrencyUnit;
|
||||
use cdk::url::UncheckedUrl;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::Amount;
|
||||
|
||||
pub async fn balance(wallet: Wallet) -> Result<()> {
|
||||
let _ = mint_balances(&wallet).await;
|
||||
pub async fn balance(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
|
||||
mint_balances(wallets).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn mint_balances(
|
||||
wallet: &Wallet,
|
||||
) -> Result<Vec<(UncheckedUrl, HashMap<CurrencyUnit, Amount>)>> {
|
||||
let mints_amounts: Vec<(UncheckedUrl, HashMap<_, _>)> =
|
||||
wallet.mint_balances().await?.into_iter().collect();
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
) -> Result<Vec<(Wallet, Amount)>> {
|
||||
let mut wallets_vec: Vec<(Wallet, Amount)> = Vec::with_capacity(wallets.capacity());
|
||||
|
||||
for (i, (mint, balance)) in mints_amounts.iter().enumerate() {
|
||||
println!("{i}: {mint}:");
|
||||
for (unit, amount) in balance {
|
||||
println!("- {amount} {unit}");
|
||||
}
|
||||
println!("---------");
|
||||
for (i, (mint_url, wallet)) 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));
|
||||
}
|
||||
|
||||
Ok(mints_amounts)
|
||||
Ok(wallets_vec)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::{Amount, UncheckedUrl};
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct BurnSubCommand {
|
||||
/// Mint Url
|
||||
mint_url: Option<String>,
|
||||
mint_url: Option<UncheckedUrl>,
|
||||
}
|
||||
|
||||
pub async fn burn(wallet: Wallet, sub_command_args: &BurnSubCommand) -> Result<()> {
|
||||
let amount_burnt = wallet
|
||||
.check_all_pending_proofs(sub_command_args.mint_url.clone().map(|u| u.into()), None)
|
||||
.await?;
|
||||
pub async fn burn(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
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();
|
||||
total_burnt = wallet.check_all_pending_proofs().await?;
|
||||
}
|
||||
None => {
|
||||
for wallet in wallets.values() {
|
||||
let amount_burnt = wallet.check_all_pending_proofs().await?;
|
||||
total_burnt += amount_burnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{amount_burnt} burned");
|
||||
println!("{total_burnt} burned");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,40 +1,15 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::{io, println};
|
||||
use std::println;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::Result;
|
||||
use cdk::url::UncheckedUrl;
|
||||
use cdk::wallet::Wallet;
|
||||
|
||||
pub async fn check_spent(wallet: Wallet) -> Result<()> {
|
||||
let mints_amounts: Vec<(UncheckedUrl, HashMap<_, _>)> =
|
||||
wallet.mint_balances().await?.into_iter().collect();
|
||||
pub async fn check_spent(wallets: HashMap<UncheckedUrl, Wallet>) -> Result<()> {
|
||||
for wallet in wallets.values() {
|
||||
let amount = wallet.check_all_pending_proofs().await?;
|
||||
|
||||
for (i, (mint, amount)) in mints_amounts.iter().enumerate() {
|
||||
println!("{}: {}, {:?} sats", i, mint, amount);
|
||||
}
|
||||
|
||||
println!("Enter mint number to create token");
|
||||
|
||||
let mut user_input = String::new();
|
||||
let stdin = io::stdin();
|
||||
io::stdout().flush().unwrap();
|
||||
stdin.read_line(&mut user_input)?;
|
||||
|
||||
let mint_number: usize = user_input.trim().parse()?;
|
||||
|
||||
if mint_number.gt(&(mints_amounts.len() - 1)) {
|
||||
bail!("Invalid mint number");
|
||||
}
|
||||
|
||||
let mint_url = mints_amounts[mint_number].0.clone();
|
||||
|
||||
let proofs = wallet.get_proofs(mint_url.clone()).await?.unwrap();
|
||||
|
||||
let send_proofs = wallet.check_proofs_spent(mint_url, proofs.to_vec()).await?;
|
||||
|
||||
for proof in send_proofs {
|
||||
println!("{:#?}", proof);
|
||||
println!("Amount marked as spent: {}", amount);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
use std::{io, println};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::nuts::CurrencyUnit;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::Bolt11Invoice;
|
||||
use cdk::{Bolt11Invoice, UncheckedUrl};
|
||||
use clap::Args;
|
||||
|
||||
use crate::sub_commands::balance::mint_balances;
|
||||
@@ -14,8 +14,11 @@ use crate::sub_commands::balance::mint_balances;
|
||||
#[derive(Args)]
|
||||
pub struct MeltSubCommand {}
|
||||
|
||||
pub async fn melt(wallet: Wallet, _sub_command_args: &MeltSubCommand) -> Result<()> {
|
||||
let mints_amounts = mint_balances(&wallet).await?;
|
||||
pub async fn melt(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
_sub_command_args: &MeltSubCommand,
|
||||
) -> Result<()> {
|
||||
let mints_amounts = mint_balances(wallets).await?;
|
||||
|
||||
println!("Enter mint number to create token");
|
||||
|
||||
@@ -30,7 +33,7 @@ pub async fn melt(wallet: Wallet, _sub_command_args: &MeltSubCommand) -> Result<
|
||||
bail!("Invalid mint number");
|
||||
}
|
||||
|
||||
let mint_url = mints_amounts[mint_number].0.clone();
|
||||
let wallet = mints_amounts[mint_number].0.clone();
|
||||
|
||||
println!("Enter bolt11 invoice request");
|
||||
|
||||
@@ -43,26 +46,14 @@ pub async fn melt(wallet: Wallet, _sub_command_args: &MeltSubCommand) -> Result<
|
||||
if bolt11
|
||||
.amount_milli_satoshis()
|
||||
.unwrap()
|
||||
.gt(&(<cdk::Amount as Into<u64>>::into(
|
||||
*mints_amounts[mint_number]
|
||||
.1
|
||||
.get(&CurrencyUnit::Sat)
|
||||
.unwrap(),
|
||||
) * 1000_u64))
|
||||
.gt(&(<cdk::Amount as Into<u64>>::into(mints_amounts[mint_number].1) * 1000_u64))
|
||||
{
|
||||
bail!("Not enough funds");
|
||||
}
|
||||
let quote = wallet
|
||||
.melt_quote(
|
||||
mint_url.clone(),
|
||||
cdk::nuts::CurrencyUnit::Sat,
|
||||
bolt11.to_string(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let quote = wallet.melt_quote(bolt11.to_string(), None).await?;
|
||||
|
||||
let melt = wallet
|
||||
.melt(&mint_url, "e.id, SplitTarget::default())
|
||||
.melt("e.id, SplitTarget::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::{Error, WalletDatabase};
|
||||
use cdk::nuts::CurrencyUnit;
|
||||
use cdk::url::UncheckedUrl;
|
||||
use cdk::wallet::Wallet;
|
||||
@@ -19,15 +22,20 @@ pub struct MintSubCommand {
|
||||
unit: String,
|
||||
}
|
||||
|
||||
pub async fn mint(wallet: Wallet, sub_command_args: &MintSubCommand) -> Result<()> {
|
||||
pub async fn mint(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
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) {
|
||||
Some(wallet) => wallet.clone(),
|
||||
None => Wallet::new(&mint_url.to_string(), CurrencyUnit::Sat, localstore, seed),
|
||||
};
|
||||
|
||||
let quote = wallet
|
||||
.mint_quote(
|
||||
mint_url.clone(),
|
||||
CurrencyUnit::from(&sub_command_args.unit),
|
||||
Amount::from(sub_command_args.amount),
|
||||
)
|
||||
.mint_quote(Amount::from(sub_command_args.amount))
|
||||
.await?;
|
||||
|
||||
println!("Quote: {:#?}", quote);
|
||||
@@ -35,9 +43,7 @@ pub async fn mint(wallet: Wallet, sub_command_args: &MintSubCommand) -> Result<(
|
||||
println!("Please pay: {}", quote.request);
|
||||
|
||||
loop {
|
||||
let status = wallet
|
||||
.mint_quote_status(mint_url.clone(), "e.id)
|
||||
.await?;
|
||||
let status = wallet.mint_quote_status("e.id).await?;
|
||||
|
||||
if status.paid {
|
||||
break;
|
||||
@@ -46,9 +52,7 @@ pub async fn mint(wallet: Wallet, sub_command_args: &MintSubCommand) -> Result<(
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
}
|
||||
|
||||
let receive_amount = wallet
|
||||
.mint(mint_url.clone(), "e.id, SplitTarget::default(), None)
|
||||
.await?;
|
||||
let receive_amount = wallet.mint("e.id, SplitTarget::default(), None).await?;
|
||||
|
||||
println!("Received {receive_amount} from mint {mint_url}");
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::{Amount, UncheckedUrl};
|
||||
|
||||
pub async fn pending_mints(wallet: Wallet) -> Result<()> {
|
||||
let amount_claimed = wallet.check_all_mint_quotes().await?;
|
||||
pub async fn pending_mints(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;
|
||||
}
|
||||
|
||||
println!("Amount minted: {amount_claimed}");
|
||||
Ok(())
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::nuts::SecretKey;
|
||||
use cdk::cdk_database::{Error, WalletDatabase};
|
||||
use cdk::nuts::{CurrencyUnit, SecretKey, Token};
|
||||
use cdk::util::unix_time;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::{Amount, UncheckedUrl};
|
||||
use clap::Args;
|
||||
use nostr_sdk::nips::nip04;
|
||||
use nostr_sdk::{Filter, Keys, Kind, Timestamp};
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct ReceiveSubCommand {
|
||||
@@ -27,54 +34,82 @@ pub struct ReceiveSubCommand {
|
||||
preimage: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn receive(wallet: Wallet, sub_command_args: &ReceiveSubCommand) -> Result<()> {
|
||||
let nostr_key = match sub_command_args.nostr_key.as_ref() {
|
||||
Some(nostr_key) => {
|
||||
let secret_key = SecretKey::from_str(nostr_key)?;
|
||||
wallet.add_p2pk_signing_key(secret_key.clone()).await;
|
||||
Some(secret_key)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
pub async fn receive(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
seed: &[u8],
|
||||
localstore: Arc<dyn WalletDatabase<Err = Error> + Sync + Send>,
|
||||
sub_command_args: &ReceiveSubCommand,
|
||||
) -> Result<()> {
|
||||
let mut signing_keys = Vec::new();
|
||||
|
||||
if !sub_command_args.signing_key.is_empty() {
|
||||
let signing_keys: Vec<SecretKey> = sub_command_args
|
||||
let mut s_keys: Vec<SecretKey> = sub_command_args
|
||||
.signing_key
|
||||
.iter()
|
||||
.map(|s| SecretKey::from_str(s).unwrap())
|
||||
.collect();
|
||||
|
||||
for signing_key in signing_keys {
|
||||
wallet.add_p2pk_signing_key(signing_key).await;
|
||||
}
|
||||
signing_keys.append(&mut s_keys);
|
||||
}
|
||||
|
||||
let preimage = match sub_command_args.preimage.is_empty() {
|
||||
true => None,
|
||||
false => Some(sub_command_args.preimage.clone()),
|
||||
};
|
||||
|
||||
let amount = match nostr_key {
|
||||
Some(nostr_key) => {
|
||||
assert!(!sub_command_args.relay.is_empty());
|
||||
wallet
|
||||
.add_nostr_relays(sub_command_args.relay.clone())
|
||||
.await?;
|
||||
wallet
|
||||
.nostr_receive(nostr_key, sub_command_args.since, SplitTarget::default())
|
||||
.await?
|
||||
let amount = match &sub_command_args.token {
|
||||
Some(token_str) => {
|
||||
receive_token(
|
||||
token_str,
|
||||
wallets,
|
||||
seed,
|
||||
&localstore,
|
||||
&signing_keys,
|
||||
&sub_command_args.preimage,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
None => {
|
||||
wallet
|
||||
.receive(
|
||||
sub_command_args
|
||||
.token
|
||||
.as_ref()
|
||||
.ok_or(anyhow!("Token Required"))?,
|
||||
&SplitTarget::default(),
|
||||
preimage,
|
||||
//wallet.add_p2pk_signing_key(nostr_signing_key).await;
|
||||
let nostr_key = match sub_command_args.nostr_key.as_ref() {
|
||||
Some(nostr_key) => {
|
||||
let secret_key = SecretKey::from_str(nostr_key)?;
|
||||
Some(secret_key)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let nostr_key =
|
||||
nostr_key.ok_or(anyhow!("Nostr key required if token is not provided"))?;
|
||||
|
||||
signing_keys.push(nostr_key.clone());
|
||||
|
||||
let relays = sub_command_args.relay.clone();
|
||||
let since = localstore
|
||||
.get_nostr_last_checked(&nostr_key.public_key())
|
||||
.await?;
|
||||
|
||||
let tokens = nostr_receive(relays, nostr_key.clone(), since).await?;
|
||||
|
||||
let mut total_amount = Amount::ZERO;
|
||||
for token_str in &tokens {
|
||||
match receive_token(
|
||||
token_str,
|
||||
wallets.clone(),
|
||||
seed,
|
||||
&localstore,
|
||||
&signing_keys,
|
||||
&sub_command_args.preimage,
|
||||
)
|
||||
.await?
|
||||
.await
|
||||
{
|
||||
Ok(amount) => {
|
||||
total_amount += amount;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localstore
|
||||
.add_nostr_last_checked(nostr_key.public_key(), unix_time() as u32)
|
||||
.await?;
|
||||
total_amount
|
||||
}
|
||||
};
|
||||
|
||||
@@ -82,3 +117,82 @@ pub async fn receive(wallet: Wallet, sub_command_args: &ReceiveSubCommand) -> Re
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn receive_token(
|
||||
token_str: &str,
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
seed: &[u8],
|
||||
localstore: &Arc<dyn WalletDatabase<Err = Error> + Sync + Send>,
|
||||
signing_keys: &[SecretKey],
|
||||
preimage: &[String],
|
||||
) -> Result<Amount> {
|
||||
let token = Token::from_str(token_str)?;
|
||||
let mint_url = token.token.first().unwrap().mint.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,
|
||||
),
|
||||
};
|
||||
|
||||
let amount = wallet
|
||||
.receive(token_str, &SplitTarget::default(), signing_keys, preimage)
|
||||
.await?;
|
||||
Ok(amount)
|
||||
}
|
||||
|
||||
/// Receive tokens sent to nostr pubkey via dm
|
||||
async fn nostr_receive(
|
||||
relays: Vec<String>,
|
||||
nostr_signing_key: SecretKey,
|
||||
since: Option<u32>,
|
||||
) -> Result<HashSet<String>> {
|
||||
let verifying_key = nostr_signing_key.public_key();
|
||||
|
||||
let x_only_pubkey = verifying_key.x_only_public_key();
|
||||
|
||||
let nostr_pubkey = nostr_sdk::PublicKey::from_hex(x_only_pubkey.to_string())?;
|
||||
|
||||
let since = since.map(|s| Timestamp::from(s as u64));
|
||||
|
||||
let filter = match since {
|
||||
Some(since) => Filter::new()
|
||||
.pubkey(nostr_pubkey)
|
||||
.kind(Kind::EncryptedDirectMessage)
|
||||
.since(since),
|
||||
None => Filter::new()
|
||||
.pubkey(nostr_pubkey)
|
||||
.kind(Kind::EncryptedDirectMessage),
|
||||
};
|
||||
|
||||
let client = nostr_sdk::Client::default();
|
||||
|
||||
client.add_relays(relays).await?;
|
||||
|
||||
client.connect().await;
|
||||
|
||||
let events = client.get_events_of(vec![filter], None).await?;
|
||||
|
||||
let mut tokens: HashSet<String> = HashSet::new();
|
||||
|
||||
let keys = Keys::from_str(&(nostr_signing_key).to_secret_hex())?;
|
||||
|
||||
for event in events {
|
||||
if event.kind() == Kind::EncryptedDirectMessage {
|
||||
if let Ok(msg) = nip04::decrypt(keys.secret_key()?, event.author_ref(), event.content())
|
||||
{
|
||||
if let Some(token) = cdk::wallet::util::token_from_text(&msg) {
|
||||
tokens.insert(token.to_string());
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Impossible to decrypt direct message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cdk::url::UncheckedUrl;
|
||||
use cdk::wallet::Wallet;
|
||||
use clap::Args;
|
||||
@@ -9,10 +11,15 @@ pub struct RestoreSubCommand {
|
||||
mint_url: UncheckedUrl,
|
||||
}
|
||||
|
||||
pub async fn restore(wallet: Wallet, sub_command_args: &RestoreSubCommand) -> Result<()> {
|
||||
let mint_url = sub_command_args.mint_url.clone();
|
||||
pub async fn restore(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
sub_command_args: &RestoreSubCommand,
|
||||
) -> Result<()> {
|
||||
let wallet = wallets
|
||||
.get(&sub_command_args.mint_url)
|
||||
.ok_or(anyhow!("Unknown mint url"))?;
|
||||
|
||||
let amount = wallet.restore(mint_url).await?;
|
||||
let amount = wallet.restore().await?;
|
||||
|
||||
println!("Restored {}", amount);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
use std::{io, println};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::nuts::{Conditions, CurrencyUnit, PublicKey, SpendingConditions};
|
||||
use cdk::nuts::{Conditions, PublicKey, SpendingConditions};
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::Amount;
|
||||
use cdk::{Amount, UncheckedUrl};
|
||||
use clap::Args;
|
||||
|
||||
use crate::sub_commands::balance::mint_balances;
|
||||
@@ -33,8 +34,11 @@ pub struct SendSubCommand {
|
||||
refund_keys: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn send(wallet: Wallet, sub_command_args: &SendSubCommand) -> Result<()> {
|
||||
let mints_amounts = mint_balances(&wallet).await?;
|
||||
pub async fn send(
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
sub_command_args: &SendSubCommand,
|
||||
) -> Result<()> {
|
||||
let mints_amounts = mint_balances(wallets).await?;
|
||||
|
||||
println!("Enter mint number to create token");
|
||||
|
||||
@@ -49,8 +53,6 @@ pub async fn send(wallet: Wallet, sub_command_args: &SendSubCommand) -> Result<(
|
||||
bail!("Invalid mint number");
|
||||
}
|
||||
|
||||
let mint_url = mints_amounts[mint_number].0.clone();
|
||||
|
||||
println!("Enter value of token in sats");
|
||||
|
||||
let mut user_input = String::new();
|
||||
@@ -59,11 +61,7 @@ pub async fn send(wallet: Wallet, sub_command_args: &SendSubCommand) -> Result<(
|
||||
stdin.read_line(&mut user_input)?;
|
||||
let token_amount = Amount::from(user_input.trim().parse::<u64>()?);
|
||||
|
||||
if token_amount.gt(mints_amounts[mint_number]
|
||||
.1
|
||||
.get(&CurrencyUnit::Sat)
|
||||
.unwrap())
|
||||
{
|
||||
if token_amount.gt(&mints_amounts[mint_number].1) {
|
||||
bail!("Not enough funds");
|
||||
}
|
||||
|
||||
@@ -145,10 +143,10 @@ pub async fn send(wallet: Wallet, sub_command_args: &SendSubCommand) -> Result<(
|
||||
},
|
||||
};
|
||||
|
||||
let wallet = mints_amounts[mint_number].0.clone();
|
||||
|
||||
let token = wallet
|
||||
.send(
|
||||
&mint_url,
|
||||
CurrencyUnit::Sat,
|
||||
token_amount,
|
||||
sub_command_args.memo.clone(),
|
||||
conditions,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cdk::url::UncheckedUrl;
|
||||
use cdk::wallet::Wallet;
|
||||
use clap::Args;
|
||||
@@ -12,7 +14,7 @@ pub struct UpdateMintUrlSubCommand {
|
||||
}
|
||||
|
||||
pub async fn update_mint_url(
|
||||
wallet: Wallet,
|
||||
wallets: HashMap<UncheckedUrl, Wallet>,
|
||||
sub_command_args: &UpdateMintUrlSubCommand,
|
||||
) -> Result<()> {
|
||||
let UpdateMintUrlSubCommand {
|
||||
@@ -20,9 +22,12 @@ pub async fn update_mint_url(
|
||||
new_mint_url,
|
||||
} = sub_command_args;
|
||||
|
||||
wallet
|
||||
.update_mint_url(old_mint_url.clone(), new_mint_url.clone())
|
||||
.await?;
|
||||
let mut wallet = wallets
|
||||
.get(old_mint_url)
|
||||
.ok_or(anyhow!("Unknown mint url"))?
|
||||
.clone();
|
||||
|
||||
wallet.update_mint_url(new_mint_url.clone()).await?;
|
||||
|
||||
println!("Mint Url changed from {} to {}", old_mint_url, new_mint_url);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user