mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-18 21:25:09 +01:00
feat: store melt_request (#1045)
This commit is contained in:
@@ -2,6 +2,28 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cashu::quote_id::QuoteId;
|
||||
use cashu::{Amount, MintInfo};
|
||||
|
||||
use super::Error;
|
||||
use crate::common::QuoteTTL;
|
||||
use crate::mint::{self, MintKeySetInfo, MintQuote as MintMintQuote};
|
||||
use crate::nuts::{
|
||||
BlindSignature, BlindedMessage, CurrencyUnit, Id, MeltQuoteState, Proof, Proofs, PublicKey,
|
||||
State,
|
||||
};
|
||||
use crate::payment::PaymentIdentifier;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
mod auth;
|
||||
|
||||
#[cfg(feature = "test")]
|
||||
pub mod test;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
pub use auth::{MintAuthDatabase, MintAuthTransaction};
|
||||
|
||||
/// Valid ASCII characters for namespace and key strings in KV store
|
||||
pub const KVSTORE_NAMESPACE_KEY_ALPHABET: &str =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
|
||||
@@ -62,26 +84,16 @@ pub fn validate_kvstore_params(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cashu::quote_id::QuoteId;
|
||||
use cashu::{Amount, MintInfo};
|
||||
|
||||
use super::Error;
|
||||
use crate::common::QuoteTTL;
|
||||
use crate::mint::{self, MintKeySetInfo, MintQuote as MintMintQuote};
|
||||
use crate::nuts::{
|
||||
BlindSignature, CurrencyUnit, Id, MeltQuoteState, Proof, Proofs, PublicKey, State,
|
||||
};
|
||||
use crate::payment::PaymentIdentifier;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
mod auth;
|
||||
|
||||
#[cfg(feature = "test")]
|
||||
pub mod test;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
pub use auth::{MintAuthDatabase, MintAuthTransaction};
|
||||
/// Information about a melt request stored in the database
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MeltRequestInfo {
|
||||
/// Total amount of all input proofs in the melt request
|
||||
pub inputs_amount: Amount,
|
||||
/// Fee amount associated with the input proofs
|
||||
pub inputs_fee: Amount,
|
||||
/// Blinded messages for change outputs
|
||||
pub change_outputs: Vec<BlindedMessage>,
|
||||
}
|
||||
|
||||
/// KeysDatabaseWriter
|
||||
#[async_trait]
|
||||
@@ -123,6 +135,24 @@ pub trait QuotesTransaction<'a> {
|
||||
/// Mint Quotes Database Error
|
||||
type Err: Into<Error> + From<Error>;
|
||||
|
||||
/// Add melt_request with quote_id, inputs_amount, and blinded_messages
|
||||
async fn add_melt_request_and_blinded_messages(
|
||||
&mut self,
|
||||
quote_id: &QuoteId,
|
||||
inputs_amount: Amount,
|
||||
inputs_fee: Amount,
|
||||
blinded_messages: &[BlindedMessage],
|
||||
) -> Result<(), Self::Err>;
|
||||
|
||||
/// Get melt_request and associated blinded_messages by quote_id
|
||||
async fn get_melt_request_and_blinded_messages(
|
||||
&mut self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Option<MeltRequestInfo>, Self::Err>;
|
||||
|
||||
/// Delete melt_request and associated blinded_messages by quote_id
|
||||
async fn delete_melt_request(&mut self, quote_id: &QuoteId) -> Result<(), Self::Err>;
|
||||
|
||||
/// Get [`MintMintQuote`] and lock it for update in this transaction
|
||||
async fn get_mint_quote(
|
||||
&mut self,
|
||||
@@ -242,6 +272,12 @@ pub trait ProofsTransaction<'a> {
|
||||
ys: &[PublicKey],
|
||||
quote_id: Option<QuoteId>,
|
||||
) -> Result<(), Self::Err>;
|
||||
|
||||
/// Get ys by quote id
|
||||
async fn get_proof_ys_by_quote_id(
|
||||
&self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Vec<PublicKey>, Self::Err>;
|
||||
}
|
||||
|
||||
/// Mint Proof Database trait
|
||||
|
||||
0
crates/cdk-postgres/start_db_for_test.sh
Normal file → Executable file
0
crates/cdk-postgres/start_db_for_test.sh
Normal file → Executable file
@@ -4,6 +4,7 @@ pub static MIGRATIONS: &[(&str, &str, &str)] = &[
|
||||
("postgres", "1_initial.sql", include_str!(r#"./migrations/postgres/1_initial.sql"#)),
|
||||
("postgres", "2_remove_request_lookup_kind_constraints.sql", include_str!(r#"./migrations/postgres/2_remove_request_lookup_kind_constraints.sql"#)),
|
||||
("postgres", "20250901090000_add_kv_store.sql", include_str!(r#"./migrations/postgres/20250901090000_add_kv_store.sql"#)),
|
||||
("postgres", "20250902140000_add_melt_request_and_blinded_messages.sql", include_str!(r#"./migrations/postgres/20250902140000_add_melt_request_and_blinded_messages.sql"#)),
|
||||
("postgres", "20250903200000_add_signatory_amounts.sql", include_str!(r#"./migrations/postgres/20250903200000_add_signatory_amounts.sql"#)),
|
||||
("sqlite", "1_fix_sqlx_migration.sql", include_str!(r#"./migrations/sqlite/1_fix_sqlx_migration.sql"#)),
|
||||
("sqlite", "20240612124932_init.sql", include_str!(r#"./migrations/sqlite/20240612124932_init.sql"#)),
|
||||
@@ -30,5 +31,6 @@ pub static MIGRATIONS: &[(&str, &str, &str)] = &[
|
||||
("sqlite", "20250812132015_drop_melt_request.sql", include_str!(r#"./migrations/sqlite/20250812132015_drop_melt_request.sql"#)),
|
||||
("sqlite", "20250819200000_remove_request_lookup_kind_constraints.sql", include_str!(r#"./migrations/sqlite/20250819200000_remove_request_lookup_kind_constraints.sql"#)),
|
||||
("sqlite", "20250901090000_add_kv_store.sql", include_str!(r#"./migrations/sqlite/20250901090000_add_kv_store.sql"#)),
|
||||
("sqlite", "20250902140000_add_melt_request_and_blinded_messages.sql", include_str!(r#"./migrations/sqlite/20250902140000_add_melt_request_and_blinded_messages.sql"#)),
|
||||
("sqlite", "20250903200000_add_signatory_amounts.sql", include_str!(r#"./migrations/sqlite/20250903200000_add_signatory_amounts.sql"#)),
|
||||
];
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Drop existing melt_request table and recreate with new schema
|
||||
DROP TABLE IF EXISTS melt_request;
|
||||
CREATE TABLE melt_request (
|
||||
quote_id TEXT PRIMARY KEY,
|
||||
inputs_amount INTEGER NOT NULL,
|
||||
inputs_fee INTEGER NOT NULL,
|
||||
FOREIGN KEY (quote_id) REFERENCES melt_quote(id)
|
||||
);
|
||||
|
||||
-- Add blinded_messages table
|
||||
CREATE TABLE blinded_messages (
|
||||
quote_id TEXT NOT NULL,
|
||||
blinded_message BYTEA NOT NULL,
|
||||
keyset_id TEXT NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
FOREIGN KEY (quote_id) REFERENCES melt_request(quote_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Add index for faster lookups on blinded_messages
|
||||
CREATE INDEX blinded_messages_quote_id_index ON blinded_messages(quote_id);
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
-- Drop existing melt_request table and recreate with new schema
|
||||
DROP TABLE IF EXISTS melt_request;
|
||||
CREATE TABLE melt_request (
|
||||
quote_id TEXT PRIMARY KEY,
|
||||
inputs_amount INTEGER NOT NULL,
|
||||
inputs_fee INTEGER NOT NULL,
|
||||
FOREIGN KEY (quote_id) REFERENCES melt_quote(id)
|
||||
);
|
||||
|
||||
-- Add blinded_messages table
|
||||
CREATE TABLE blinded_messages (
|
||||
quote_id TEXT NOT NULL,
|
||||
blinded_message BLOB NOT NULL,
|
||||
amount INTEGER NOT NULL DEFAULT 0,
|
||||
keyset_id TEXT NOT NULL,
|
||||
FOREIGN KEY (quote_id) REFERENCES melt_request(quote_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Add index for faster lookups on blinded_messages
|
||||
CREATE INDEX blinded_messages_quote_id_index ON blinded_messages(quote_id);
|
||||
-- Create an index on keyset_id for better query performance
|
||||
CREATE INDEX blinded_messages_keyset_id_index ON blinded_messages(keyset_id);
|
||||
@@ -32,8 +32,8 @@ use cdk_common::secret::Secret;
|
||||
use cdk_common::state::check_state_transition;
|
||||
use cdk_common::util::unix_time;
|
||||
use cdk_common::{
|
||||
Amount, BlindSignature, BlindSignatureDleq, CurrencyUnit, Id, MeltQuoteState, MintInfo,
|
||||
PaymentMethod, Proof, Proofs, PublicKey, SecretKey, State,
|
||||
Amount, BlindSignature, BlindSignatureDleq, BlindedMessage, CurrencyUnit, Id, MeltQuoteState,
|
||||
MintInfo, PaymentMethod, Proof, Proofs, PublicKey, SecretKey, State,
|
||||
};
|
||||
use lightning_invoice::Bolt11Invoice;
|
||||
use migrations::MIGRATIONS;
|
||||
@@ -277,6 +277,33 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_proof_ys_by_quote_id(
|
||||
&self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Vec<PublicKey>, Self::Err> {
|
||||
Ok(query(
|
||||
r#"
|
||||
SELECT
|
||||
amount,
|
||||
keyset_id,
|
||||
secret,
|
||||
c,
|
||||
witness
|
||||
FROM
|
||||
proof
|
||||
WHERE
|
||||
quote_id = :quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.fetch_all(&self.inner)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(sql_row_to_proof)
|
||||
.collect::<Result<Vec<Proof>, _>>()?
|
||||
.ys()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -564,6 +591,123 @@ where
|
||||
{
|
||||
type Err = Error;
|
||||
|
||||
async fn add_melt_request_and_blinded_messages(
|
||||
&mut self,
|
||||
quote_id: &QuoteId,
|
||||
inputs_amount: Amount,
|
||||
inputs_fee: Amount,
|
||||
blinded_messages: &[BlindedMessage],
|
||||
) -> Result<(), Self::Err> {
|
||||
query(
|
||||
r#"
|
||||
INSERT INTO melt_request
|
||||
(quote_id, inputs_amount, inputs_fee)
|
||||
VALUES
|
||||
(:quote_id, :inputs_amount, :inputs_fee)
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.bind("inputs_amount", inputs_amount.to_i64())
|
||||
.bind("inputs_fee", inputs_fee.to_i64())
|
||||
.execute(&self.inner)
|
||||
.await?;
|
||||
|
||||
for message in blinded_messages {
|
||||
query(
|
||||
r#"
|
||||
INSERT INTO blinded_messages
|
||||
(quote_id, blinded_message, keyset_id, amount)
|
||||
VALUES
|
||||
(:quote_id, :blinded_message, :keyset_id, :amount)
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.bind(
|
||||
"blinded_message",
|
||||
message.blinded_secret.to_bytes().to_vec(),
|
||||
)
|
||||
.bind("keyset_id", message.keyset_id.to_string())
|
||||
.bind("amount", message.amount.to_i64())
|
||||
.execute(&self.inner)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_melt_request_and_blinded_messages(
|
||||
&mut self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Option<database::mint::MeltRequestInfo>, Self::Err> {
|
||||
let melt_request_row = query(
|
||||
r#"
|
||||
SELECT inputs_amount, inputs_fee
|
||||
FROM melt_request
|
||||
WHERE quote_id = :quote_id
|
||||
FOR UPDATE
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.fetch_one(&self.inner)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = melt_request_row {
|
||||
let inputs_amount: u64 = column_as_number!(row[0].clone());
|
||||
let inputs_fee: u64 = column_as_number!(row[1].clone());
|
||||
|
||||
let blinded_messages_rows = query(
|
||||
r#"
|
||||
SELECT blinded_message, keyset_id, amount
|
||||
FROM blinded_messages
|
||||
WHERE quote_id = :quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.fetch_all(&self.inner)
|
||||
.await?;
|
||||
|
||||
let blinded_messages: Result<Vec<BlindedMessage>, Error> = blinded_messages_rows
|
||||
.into_iter()
|
||||
.map(|row| -> Result<BlindedMessage, Error> {
|
||||
let blinded_message_key =
|
||||
column_as_string!(&row[0], PublicKey::from_hex, PublicKey::from_slice);
|
||||
let keyset_id = column_as_string!(&row[1], Id::from_str, Id::from_bytes);
|
||||
let amount: u64 = column_as_number!(row[2].clone());
|
||||
|
||||
Ok(BlindedMessage {
|
||||
blinded_secret: blinded_message_key,
|
||||
keyset_id,
|
||||
amount: Amount::from(amount),
|
||||
witness: None, // Not storing witness in database currently
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let blinded_messages = blinded_messages?;
|
||||
|
||||
Ok(Some(database::mint::MeltRequestInfo {
|
||||
inputs_amount: Amount::from(inputs_amount),
|
||||
inputs_fee: Amount::from(inputs_fee),
|
||||
change_outputs: blinded_messages,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_melt_request(&mut self, quote_id: &QuoteId) -> Result<(), Self::Err> {
|
||||
query(
|
||||
r#"
|
||||
DELETE FROM melt_request
|
||||
WHERE quote_id = :quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.execute(&self.inner)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn increment_mint_quote_amount_paid(
|
||||
&mut self,
|
||||
@@ -788,8 +932,6 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
}
|
||||
|
||||
async fn add_melt_quote(&mut self, quote: mint::MeltQuote) -> Result<(), Self::Err> {
|
||||
// First try to find and replace any expired UNPAID quotes with the same request_lookup_id
|
||||
|
||||
// Now insert the new quote
|
||||
query(
|
||||
r#"
|
||||
@@ -916,6 +1058,10 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
let old_state = quote.state;
|
||||
quote.state = state;
|
||||
|
||||
if state == MeltQuoteState::Unpaid || state == MeltQuoteState::Failed {
|
||||
self.delete_melt_request(quote_id).await?;
|
||||
}
|
||||
|
||||
Ok((old_state, quote))
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::bail;
|
||||
use cdk_common::amount::amount_for_offer;
|
||||
use cdk_common::database::mint::MeltRequestInfo;
|
||||
use cdk_common::database::{self, MintTransaction};
|
||||
use cdk_common::melt::MeltQuoteRequest;
|
||||
use cdk_common::mint::MeltPaymentRequest;
|
||||
use cdk_common::nut00::ProofsMethods;
|
||||
use cdk_common::nut05::MeltMethodOptions;
|
||||
use cdk_common::payment::{
|
||||
Bolt11OutgoingPaymentOptions, Bolt12OutgoingPaymentOptions, OutgoingPaymentOptions,
|
||||
@@ -501,6 +501,25 @@ impl Mint {
|
||||
input_verification: Verification,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
) -> Result<(ProofWriter, MeltQuote), Error> {
|
||||
let Verification {
|
||||
amount: input_amount,
|
||||
unit: input_unit,
|
||||
} = input_verification;
|
||||
|
||||
ensure_cdk!(input_unit.is_some(), Error::UnsupportedUnit);
|
||||
|
||||
let mut proof_writer =
|
||||
ProofWriter::new(self.localstore.clone(), self.pubsub_manager.clone());
|
||||
|
||||
proof_writer
|
||||
.add_proofs(
|
||||
tx,
|
||||
melt_request.inputs(),
|
||||
Some(melt_request.quote_id().to_owned()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Only after proof verification succeeds, proceed with quote state check
|
||||
let (state, quote) = tx
|
||||
.update_melt_quote_state(melt_request.quote(), MeltQuoteState::Pending, None)
|
||||
.await?;
|
||||
@@ -515,13 +534,6 @@ impl Mint {
|
||||
self.pubsub_manager
|
||||
.melt_quote_status("e, None, None, MeltQuoteState::Pending);
|
||||
|
||||
let Verification {
|
||||
amount: input_amount,
|
||||
unit: input_unit,
|
||||
} = input_verification;
|
||||
|
||||
ensure_cdk!(input_unit.is_some(), Error::UnsupportedUnit);
|
||||
|
||||
let fee = self.get_proofs_fee(melt_request.inputs()).await?;
|
||||
|
||||
let required_total = quote.amount + quote.fee_reserve + fee;
|
||||
@@ -542,11 +554,6 @@ impl Mint {
|
||||
));
|
||||
}
|
||||
|
||||
let mut proof_writer =
|
||||
ProofWriter::new(self.localstore.clone(), self.pubsub_manager.clone());
|
||||
|
||||
proof_writer.add_proofs(tx, melt_request.inputs()).await?;
|
||||
|
||||
let EnforceSigFlag { sig_flag, .. } = enforce_sig_flag(melt_request.inputs().clone());
|
||||
|
||||
if sig_flag == SigFlag::SigAll {
|
||||
@@ -619,6 +626,16 @@ impl Mint {
|
||||
}
|
||||
};
|
||||
|
||||
let inputs_fee = self.get_proofs_fee(melt_request.inputs()).await?;
|
||||
|
||||
tx.add_melt_request_and_blinded_messages(
|
||||
melt_request.quote_id(),
|
||||
melt_request.inputs_amount()?,
|
||||
inputs_fee,
|
||||
melt_request.outputs().as_ref().unwrap_or(&Vec::new()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let settled_internally_amount = match self
|
||||
.handle_internal_melt_mint(&mut tx, "e, melt_request)
|
||||
.await
|
||||
@@ -811,14 +828,7 @@ impl Mint {
|
||||
// If we made it here the payment has been made.
|
||||
// We process the melt burning the inputs and returning change
|
||||
let res = match self
|
||||
.process_melt_request(
|
||||
tx,
|
||||
proof_writer,
|
||||
quote,
|
||||
melt_request,
|
||||
preimage,
|
||||
amount_spent_quote_unit,
|
||||
)
|
||||
.process_melt_request(tx, proof_writer, quote, preimage, amount_spent_quote_unit)
|
||||
.await
|
||||
{
|
||||
Ok(response) => response,
|
||||
@@ -854,14 +864,22 @@ impl Mint {
|
||||
mut tx: Box<dyn MintTransaction<'_, database::Error> + Send + Sync + '_>,
|
||||
mut proof_writer: ProofWriter,
|
||||
quote: MeltQuote,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
payment_preimage: Option<String>,
|
||||
total_spent: Amount,
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
#[cfg(feature = "prometheus")]
|
||||
METRICS.inc_in_flight_requests("process_melt_request");
|
||||
|
||||
let input_ys = melt_request.inputs().ys()?;
|
||||
// Try to get input_ys from the stored melt request, fall back to original request if not found
|
||||
let input_ys: Vec<_> = tx.get_proof_ys_by_quote_id("e.id).await?;
|
||||
|
||||
assert!(!input_ys.is_empty());
|
||||
|
||||
tracing::debug!(
|
||||
"Updating {} proof states to Spent for quote {}",
|
||||
input_ys.len(),
|
||||
quote.id
|
||||
);
|
||||
|
||||
let update_proof_states_result = proof_writer
|
||||
.update_proofs_states(&mut tx, &input_ys, State::Spent)
|
||||
@@ -872,22 +890,28 @@ impl Mint {
|
||||
self.record_melt_quote_failure("process_melt_request");
|
||||
return Err(update_proof_states_result.err().unwrap());
|
||||
}
|
||||
tracing::debug!("Successfully updated proof states to Spent");
|
||||
|
||||
tx.update_melt_quote_state(
|
||||
melt_request.quote(),
|
||||
MeltQuoteState::Paid,
|
||||
payment_preimage.clone(),
|
||||
)
|
||||
.await?;
|
||||
tx.update_melt_quote_state("e.id, MeltQuoteState::Paid, payment_preimage.clone())
|
||||
.await?;
|
||||
|
||||
let mut change = None;
|
||||
|
||||
let inputs_amount = melt_request.inputs_amount()?;
|
||||
let MeltRequestInfo {
|
||||
inputs_amount,
|
||||
inputs_fee,
|
||||
change_outputs,
|
||||
} = tx
|
||||
.get_melt_request_and_blinded_messages("e.id)
|
||||
.await?
|
||||
.ok_or(Error::UnknownQuote)?;
|
||||
|
||||
// Check if there is change to return
|
||||
if inputs_amount > total_spent {
|
||||
// Check if wallet provided change outputs
|
||||
if let Some(outputs) = melt_request.outputs().clone() {
|
||||
if !change_outputs.is_empty() {
|
||||
let outputs = change_outputs;
|
||||
|
||||
let blinded_messages: Vec<PublicKey> =
|
||||
outputs.iter().map(|b| b.blinded_secret).collect();
|
||||
|
||||
@@ -904,9 +928,7 @@ impl Mint {
|
||||
return Err(Error::BlindedMessageAlreadySigned);
|
||||
}
|
||||
|
||||
let fee = self.get_proofs_fee(melt_request.inputs()).await?;
|
||||
|
||||
let change_target = melt_request.inputs_amount()? - total_spent - fee;
|
||||
let change_target = inputs_amount - total_spent - inputs_fee;
|
||||
|
||||
let mut amounts = change_target.split();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use cdk_common::database::{self, MintDatabase, MintTransaction};
|
||||
use cdk_common::{Error, Proofs, ProofsMethods, PublicKey, State};
|
||||
use cdk_common::{Error, Proofs, ProofsMethods, PublicKey, QuoteId, State};
|
||||
|
||||
use super::subscription::PubSubManager;
|
||||
|
||||
@@ -49,6 +49,7 @@ impl ProofWriter {
|
||||
&mut self,
|
||||
tx: &mut Tx<'_, '_>,
|
||||
proofs: &Proofs,
|
||||
quote_id: Option<QuoteId>,
|
||||
) -> Result<Vec<PublicKey>, Error> {
|
||||
let proof_states = if let Some(proofs) = self.proof_original_states.as_mut() {
|
||||
proofs
|
||||
@@ -56,7 +57,7 @@ impl ProofWriter {
|
||||
return Err(Error::Internal);
|
||||
};
|
||||
|
||||
if let Some(err) = tx.add_proofs(proofs.clone(), None).await.err() {
|
||||
if let Some(err) = tx.add_proofs(proofs.clone(), quote_id).await.err() {
|
||||
return match err {
|
||||
cdk_common::database::Error::Duplicate => Err(Error::TokenPending),
|
||||
cdk_common::database::Error::AttemptUpdateSpentProof => {
|
||||
|
||||
@@ -61,7 +61,7 @@ impl Mint {
|
||||
let mut proof_writer =
|
||||
ProofWriter::new(self.localstore.clone(), self.pubsub_manager.clone());
|
||||
let input_ys = match proof_writer
|
||||
.add_proofs(&mut tx, swap_request.inputs())
|
||||
.add_proofs(&mut tx, swap_request.inputs(), None)
|
||||
.await
|
||||
{
|
||||
Ok(ys) => ys,
|
||||
|
||||
Reference in New Issue
Block a user