mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-20 14:14:49 +01:00
Add Proofs trait to consolidate aggregate fns
This commit is contained in:
@@ -10,6 +10,7 @@ use async_trait::async_trait;
|
||||
use cdk::cdk_database::MintDatabase;
|
||||
use cdk::dhke::hash_to_curve;
|
||||
use cdk::mint::{MintKeySetInfo, MintQuote};
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::{
|
||||
BlindSignature, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState, MintQuoteState, Proof,
|
||||
Proofs, PublicKey, State,
|
||||
@@ -603,10 +604,7 @@ impl MintDatabase for MintRedbDatabase {
|
||||
.filter(|p| &p.keyset_id == keyset_id)
|
||||
.collect::<Proofs>();
|
||||
|
||||
let proof_ys = proofs_for_id
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let proof_ys = proofs_for_id.ys()?;
|
||||
|
||||
assert_eq!(proofs_for_id.len(), proof_ys.len());
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use bitcoin::bip32::DerivationPath;
|
||||
use cdk::cdk_database::{self, MintDatabase};
|
||||
use cdk::mint::{MintKeySetInfo, MintQuote};
|
||||
use cdk::mint_url::MintUrl;
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::nut05::QuoteState;
|
||||
use cdk::nuts::{
|
||||
BlindSignature, BlindSignatureDleq, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState,
|
||||
@@ -838,10 +839,7 @@ WHERE quote_id=?;
|
||||
.map(sqlite_row_to_proof)
|
||||
.collect::<Result<Vec<Proof>, _>>()?;
|
||||
|
||||
proofs
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?
|
||||
proofs.ys()?
|
||||
}
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => {
|
||||
|
||||
@@ -9,6 +9,7 @@ use tokio::sync::{Mutex, RwLock};
|
||||
use super::{Error, MintDatabase};
|
||||
use crate::dhke::hash_to_curve;
|
||||
use crate::mint::{self, MintKeySetInfo, MintQuote};
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::nut07::State;
|
||||
use crate::nuts::{
|
||||
nut07, BlindSignature, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState, MintQuoteState,
|
||||
@@ -346,10 +347,7 @@ impl MintDatabase for MintMemoryDatabase {
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let proof_ys = proofs_for_id
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let proof_ys = proofs_for_id.ys()?;
|
||||
|
||||
assert_eq!(proofs_for_id.len(), proof_ys.len());
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use tracing::instrument;
|
||||
use crate::cdk_lightning;
|
||||
use crate::cdk_lightning::MintLightning;
|
||||
use crate::cdk_lightning::PayInvoiceResponse;
|
||||
use crate::dhke::hash_to_curve;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::nut11::enforce_sig_flag;
|
||||
use crate::nuts::nut11::EnforceSigFlag;
|
||||
use crate::{
|
||||
@@ -264,11 +264,7 @@ impl Mint {
|
||||
}
|
||||
}
|
||||
|
||||
let ys = melt_request
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let ys = melt_request.inputs.ys()?;
|
||||
|
||||
// Ensure proofs are unique and not being double spent
|
||||
if melt_request.inputs.len() != ys.iter().collect::<HashSet<_>>().len() {
|
||||
@@ -374,11 +370,7 @@ impl Mint {
|
||||
/// quote should be unpaid
|
||||
#[instrument(skip_all)]
|
||||
pub async fn process_unpaid_melt(&self, melt_request: &MeltBolt11Request) -> Result<(), Error> {
|
||||
let input_ys = melt_request
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let input_ys = melt_request.inputs.ys()?;
|
||||
|
||||
self.localstore
|
||||
.update_proofs_states(&input_ys, State::Unspent)
|
||||
@@ -615,11 +607,7 @@ impl Mint {
|
||||
.await?
|
||||
.ok_or(Error::UnknownQuote)?;
|
||||
|
||||
let input_ys = melt_request
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let input_ys = melt_request.inputs.ys()?;
|
||||
|
||||
self.localstore
|
||||
.update_proofs_states(&input_ys, State::Spent)
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
||||
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::dhke::hash_to_curve;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::Error;
|
||||
|
||||
use super::nut11::{enforce_sig_flag, EnforceSigFlag};
|
||||
@@ -59,11 +59,7 @@ impl Mint {
|
||||
|
||||
let proof_count = swap_request.inputs.len();
|
||||
|
||||
let input_ys = swap_request
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|p| hash_to_curve(&p.secret.to_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let input_ys = swap_request.inputs.ys()?;
|
||||
|
||||
self.localstore
|
||||
.add_proofs(swap_request.inputs.clone(), None)
|
||||
|
||||
@@ -29,6 +29,28 @@ pub use token::{Token, TokenV3, TokenV4};
|
||||
/// List of [Proof]
|
||||
pub type Proofs = Vec<Proof>;
|
||||
|
||||
/// Utility methods for [Proofs]
|
||||
pub trait ProofsMethods {
|
||||
/// Try to sum up the amounts of all [Proof]s
|
||||
fn total_amount(&self) -> Result<Amount, Error>;
|
||||
|
||||
/// Try to fetch the pubkeys of all [Proof]s
|
||||
fn ys(&self) -> Result<Vec<PublicKey>, Error>;
|
||||
}
|
||||
|
||||
impl ProofsMethods for Proofs {
|
||||
fn total_amount(&self) -> Result<Amount, Error> {
|
||||
Amount::try_sum(self.iter().map(|p| p.amount)).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn ys(&self) -> Result<Vec<PublicKey>, Error> {
|
||||
self.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// NUT00 Error
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
|
||||
@@ -13,6 +13,7 @@ use url::Url;
|
||||
|
||||
use super::{Error, Proof, ProofV4, Proofs};
|
||||
use crate::mint_url::MintUrl;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::{CurrencyUnit, Id};
|
||||
use crate::Amount;
|
||||
|
||||
@@ -211,7 +212,7 @@ impl TokenV3 {
|
||||
Ok(Amount::try_sum(
|
||||
self.token
|
||||
.iter()
|
||||
.map(|t| Amount::try_sum(t.proofs.iter().map(|p| p.amount)))
|
||||
.map(|t| t.proofs.total_amount())
|
||||
.collect::<Result<Vec<Amount>, _>>()?,
|
||||
)?)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::mint_url::MintUrl;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::{
|
||||
CurrencyUnit, MeltQuoteState, PaymentMethod, Proof, Proofs, PublicKey, SpendingConditions,
|
||||
State,
|
||||
@@ -34,9 +35,9 @@ impl Melted {
|
||||
proofs: Proofs,
|
||||
change_proofs: Option<Proofs>,
|
||||
) -> Result<Self, Error> {
|
||||
let proofs_amount = Amount::try_sum(proofs.iter().map(|p| p.amount))?;
|
||||
let proofs_amount = proofs.total_amount()?;
|
||||
let change_amount = match &change_proofs {
|
||||
Some(change_proofs) => Amount::try_sum(change_proofs.iter().map(|p| p.amount))?,
|
||||
Some(change_proofs) => change_proofs.total_amount()?,
|
||||
None => Amount::ZERO,
|
||||
};
|
||||
let fee_paid = proofs_amount
|
||||
|
||||
@@ -3,9 +3,10 @@ use std::str::FromStr;
|
||||
use lightning_invoice::Bolt11Invoice;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::{
|
||||
dhke::construct_proofs,
|
||||
nuts::{CurrencyUnit, MeltQuoteBolt11Response, PreMintSecrets, Proofs, PublicKey, State},
|
||||
nuts::{CurrencyUnit, MeltQuoteBolt11Response, PreMintSecrets, Proofs, State},
|
||||
types::{Melted, ProofInfo},
|
||||
util::unix_time,
|
||||
Amount, Error, Wallet,
|
||||
@@ -121,15 +122,12 @@ impl Wallet {
|
||||
return Err(Error::UnknownQuote);
|
||||
};
|
||||
|
||||
let proofs_total = Amount::try_sum(proofs.iter().map(|p| p.amount))?;
|
||||
let proofs_total = proofs.total_amount()?;
|
||||
if proofs_total < quote_info.amount + quote_info.fee_reserve {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
|
||||
let ys = proofs
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let ys = proofs.ys()?;
|
||||
self.localstore.set_pending_proofs(ys).await?;
|
||||
|
||||
let active_keyset_id = self.get_active_mint_keyset().await?.id;
|
||||
@@ -213,7 +211,7 @@ impl Wallet {
|
||||
Some(change_proofs) => {
|
||||
tracing::debug!(
|
||||
"Change amount returned from melt: {}",
|
||||
Amount::try_sum(change_proofs.iter().map(|p| p.amount))?
|
||||
change_proofs.total_amount()?
|
||||
);
|
||||
|
||||
// Update counter for keyset
|
||||
@@ -238,10 +236,7 @@ impl Wallet {
|
||||
|
||||
self.localstore.remove_melt_quote("e_info.id).await?;
|
||||
|
||||
let deleted_ys = proofs
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let deleted_ys = proofs.ys()?;
|
||||
self.localstore
|
||||
.update_proofs(change_proof_infos, deleted_ys)
|
||||
.await?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use tracing::instrument;
|
||||
|
||||
use super::MintQuote;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::{
|
||||
amount::SplitTarget,
|
||||
dhke::construct_proofs,
|
||||
@@ -242,7 +243,7 @@ impl Wallet {
|
||||
&keys,
|
||||
)?;
|
||||
|
||||
let minted_amount = Amount::try_sum(proofs.iter().map(|p| p.amount))?;
|
||||
let minted_amount = proofs.total_amount()?;
|
||||
|
||||
// Remove filled quote from store
|
||||
self.localstore.remove_mint_quote("e_info.id).await?;
|
||||
|
||||
@@ -35,6 +35,7 @@ mod swap;
|
||||
pub mod types;
|
||||
pub mod util;
|
||||
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
pub use multi_mint_wallet::MultiMintWallet;
|
||||
pub use types::{MeltQuote, MintQuote, SendKind};
|
||||
|
||||
@@ -327,7 +328,7 @@ impl Wallet {
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
restored_value += Amount::try_sum(unspent_proofs.iter().map(|p| p.amount))?;
|
||||
restored_value += unspent_proofs.total_amount()?;
|
||||
|
||||
let unspent_proofs = unspent_proofs
|
||||
.into_iter()
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::collections::HashSet;
|
||||
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::{
|
||||
amount::SplitTarget,
|
||||
dhke::hash_to_curve,
|
||||
nuts::{Proof, ProofState, Proofs, PublicKey, State},
|
||||
types::ProofInfo,
|
||||
Amount, Error, Wallet,
|
||||
@@ -73,11 +73,7 @@ impl Wallet {
|
||||
/// Checks the stats of [`Proofs`] swapping for a new [`Proof`] if unspent
|
||||
#[instrument(skip(self, proofs))]
|
||||
pub async fn reclaim_unspent(&self, proofs: Proofs) -> Result<(), Error> {
|
||||
let proof_ys = proofs
|
||||
.iter()
|
||||
// Find Y for the secret
|
||||
.map(|p| hash_to_curve(p.secret.as_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let proof_ys = proofs.ys()?;
|
||||
|
||||
let spendable = self
|
||||
.client
|
||||
@@ -102,14 +98,7 @@ impl Wallet {
|
||||
pub async fn check_proofs_spent(&self, proofs: Proofs) -> Result<Vec<ProofState>, Error> {
|
||||
let spendable = self
|
||||
.client
|
||||
.post_check_state(
|
||||
self.mint_url.clone().try_into()?,
|
||||
proofs
|
||||
.iter()
|
||||
// Find Y for the secret
|
||||
.map(|p| hash_to_curve(p.secret.as_bytes()))
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?,
|
||||
)
|
||||
.post_check_state(self.mint_url.clone().try_into()?, proofs.ys()?)
|
||||
.await?;
|
||||
let spent_ys: Vec<_> = spendable
|
||||
.states
|
||||
@@ -186,7 +175,7 @@ impl Wallet {
|
||||
) -> Result<Proofs, Error> {
|
||||
// TODO: Check all proofs are same unit
|
||||
|
||||
if Amount::try_sum(proofs.iter().map(|p| p.amount))? < amount {
|
||||
if proofs.total_amount()? < amount {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
|
||||
@@ -226,7 +215,7 @@ impl Wallet {
|
||||
}
|
||||
|
||||
remaining_amount = amount.checked_add(fees).ok_or(Error::AmountOverflow)?
|
||||
- Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
- selected_proofs.total_amount()?;
|
||||
(proofs_larger, proofs_smaller) = proofs_smaller
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
@@ -262,7 +251,7 @@ impl Wallet {
|
||||
|
||||
for inactive_proof in inactive_proofs {
|
||||
selected_proofs.push(inactive_proof);
|
||||
let selected_total = Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_total = selected_proofs.total_amount()?;
|
||||
let fees = self.get_proofs_fee(&selected_proofs).await?;
|
||||
|
||||
if selected_total >= amount + fees {
|
||||
@@ -274,7 +263,7 @@ impl Wallet {
|
||||
|
||||
for active_proof in active_proofs {
|
||||
selected_proofs.push(active_proof);
|
||||
let selected_total = Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_total = selected_proofs.total_amount()?;
|
||||
let fees = self.get_proofs_fee(&selected_proofs).await?;
|
||||
|
||||
if selected_total >= amount + fees {
|
||||
|
||||
@@ -4,6 +4,7 @@ use bitcoin::hashes::Hash;
|
||||
use bitcoin::{hashes::sha256::Hash as Sha256Hash, XOnlyPublicKey};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::nut10::Kind;
|
||||
use crate::nuts::{Conditions, Token};
|
||||
use crate::{
|
||||
@@ -148,7 +149,7 @@ impl Wallet {
|
||||
.increment_keyset_counter(&active_keyset_id, recv_proofs.len() as u32)
|
||||
.await?;
|
||||
|
||||
let total_amount = Amount::try_sum(recv_proofs.iter().map(|p| p.amount))?;
|
||||
let total_amount = recv_proofs.total_amount()?;
|
||||
|
||||
let recv_proof_infos = recv_proofs
|
||||
.into_iter()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::{
|
||||
amount::SplitTarget,
|
||||
nuts::{Proofs, PublicKey, SpendingConditions, State, Token},
|
||||
nuts::{Proofs, SpendingConditions, State, Token},
|
||||
Amount, Error, Wallet,
|
||||
};
|
||||
|
||||
@@ -12,10 +13,7 @@ impl Wallet {
|
||||
/// Send specific proofs
|
||||
#[instrument(skip(self))]
|
||||
pub async fn send_proofs(&self, memo: Option<String>, proofs: Proofs) -> Result<Token, Error> {
|
||||
let ys = proofs
|
||||
.iter()
|
||||
.map(|p| p.y())
|
||||
.collect::<Result<Vec<PublicKey>, _>>()?;
|
||||
let ys = proofs.ys()?;
|
||||
self.localstore.reserve_proofs(ys).await?;
|
||||
|
||||
Ok(Token::new(
|
||||
@@ -114,8 +112,7 @@ impl Wallet {
|
||||
let send_proofs: Proofs = match (send_kind, selected, conditions.clone()) {
|
||||
// Handle exact matches offline
|
||||
(SendKind::OfflineExact, Ok(selected_proofs), _) => {
|
||||
let selected_proofs_amount =
|
||||
Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_proofs_amount = selected_proofs.total_amount()?;
|
||||
|
||||
let amount_to_send = match include_fees {
|
||||
true => amount + self.get_proofs_fee(&selected_proofs).await?,
|
||||
@@ -131,8 +128,7 @@ impl Wallet {
|
||||
|
||||
// Handle exact matches
|
||||
(SendKind::OnlineExact, Ok(selected_proofs), _) => {
|
||||
let selected_proofs_amount =
|
||||
Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_proofs_amount = selected_proofs.total_amount()?;
|
||||
|
||||
let amount_to_send = match include_fees {
|
||||
true => amount + self.get_proofs_fee(&selected_proofs).await?,
|
||||
@@ -152,8 +148,7 @@ impl Wallet {
|
||||
|
||||
// Handle offline tolerance
|
||||
(SendKind::OfflineTolerance(tolerance), Ok(selected_proofs), _) => {
|
||||
let selected_proofs_amount =
|
||||
Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_proofs_amount = selected_proofs.total_amount()?;
|
||||
|
||||
let amount_to_send = match include_fees {
|
||||
true => amount + self.get_proofs_fee(&selected_proofs).await?,
|
||||
@@ -178,8 +173,7 @@ impl Wallet {
|
||||
|
||||
// Handle online tolerance with successful selection
|
||||
(SendKind::OnlineTolerance(tolerance), Ok(selected_proofs), _) => {
|
||||
let selected_proofs_amount =
|
||||
Amount::try_sum(selected_proofs.iter().map(|p| p.amount))?;
|
||||
let selected_proofs_amount = selected_proofs.total_amount()?;
|
||||
let amount_to_send = match include_fees {
|
||||
true => amount + self.get_proofs_fee(&selected_proofs).await?,
|
||||
false => amount,
|
||||
|
||||
@@ -2,6 +2,7 @@ use tracing::instrument;
|
||||
|
||||
use crate::amount::SplitTarget;
|
||||
use crate::dhke::construct_proofs;
|
||||
use crate::nuts::nut00::ProofsMethods;
|
||||
use crate::nuts::nut10;
|
||||
use crate::nuts::PreMintSecrets;
|
||||
use crate::nuts::PreSwap;
|
||||
@@ -85,8 +86,7 @@ impl Wallet {
|
||||
let mut proofs_to_keep = Vec::new();
|
||||
|
||||
for proof in all_proofs {
|
||||
let proofs_to_send_amount =
|
||||
Amount::try_sum(proofs_to_send.iter().map(|p| p.amount))?;
|
||||
let proofs_to_send_amount = proofs_to_send.total_amount()?;
|
||||
if proof.amount + proofs_to_send_amount <= amount + pre_swap.fee {
|
||||
proofs_to_send.push(proof);
|
||||
} else {
|
||||
@@ -98,7 +98,7 @@ impl Wallet {
|
||||
}
|
||||
};
|
||||
|
||||
let send_amount = Amount::try_sum(proofs_to_send.iter().map(|p| p.amount))?;
|
||||
let send_amount = proofs_to_send.total_amount()?;
|
||||
|
||||
if send_amount.ne(&(amount + pre_swap.fee)) {
|
||||
tracing::warn!(
|
||||
@@ -199,9 +199,9 @@ impl Wallet {
|
||||
let active_keyset_id = self.get_active_mint_keyset().await?.id;
|
||||
|
||||
// Desired amount is either amount passed or value of all proof
|
||||
let proofs_total = Amount::try_sum(proofs.iter().map(|p| p.amount))?;
|
||||
let proofs_total = proofs.total_amount()?;
|
||||
|
||||
let ys: Vec<PublicKey> = proofs.iter().map(|p| p.y()).collect::<Result<_, _>>()?;
|
||||
let ys: Vec<PublicKey> = proofs.ys()?;
|
||||
self.localstore.set_pending_proofs(ys).await?;
|
||||
|
||||
let fee = self.get_proofs_fee(&proofs).await?;
|
||||
|
||||
Reference in New Issue
Block a user