Răsfoiți Sursa

fix(mint): ensure change is needed on process melt

thesimplekid 7 luni în urmă
părinte
comite
24647a0c7e
1 a modificat fișierele cu 62 adăugiri și 64 ștergeri
  1. 62 64
      crates/cdk/src/mint/mod.rs

+ 62 - 64
crates/cdk/src/mint/mod.rs

@@ -1004,91 +1004,89 @@ impl Mint {
         total_spent: Amount,
     ) -> Result<MeltQuoteBolt11Response, Error> {
         tracing::debug!("Processing melt quote: {}", melt_request.quote);
+
         let quote = self
             .localstore
             .get_melt_quote(&melt_request.quote)
             .await?
             .ok_or(Error::UnknownQuote)?;
 
-        if let Some(outputs) = &melt_request.outputs {
-            let blinded_messages: Vec<PublicKey> =
-                outputs.iter().map(|b| b.blinded_secret).collect();
+        let input_ys = melt_request
+            .inputs
+            .iter()
+            .map(|p| hash_to_curve(&p.secret.to_bytes()))
+            .collect::<Result<Vec<PublicKey>, _>>()?;
 
-            if self
-                .localstore
-                .get_blind_signatures(&blinded_messages)
-                .await?
-                .iter()
-                .flatten()
-                .next()
-                .is_some()
-            {
-                tracing::info!("Output has already been signed",);
+        self.localstore
+            .update_proofs_states(&input_ys, State::Spent)
+            .await?;
 
-                return Err(Error::BlindedMessageAlreadySigned);
-            }
-        }
+        self.localstore
+            .update_melt_quote_state(&melt_request.quote, MeltQuoteState::Paid)
+            .await?;
 
         let mut change = None;
 
-        if let Some(outputs) = melt_request.outputs.clone() {
-            let change_target = melt_request.proofs_amount() - total_spent;
-            let mut amounts = change_target.split();
-            let mut change_sigs = Vec::with_capacity(amounts.len());
+        // Check if there is change to return
+        if melt_request.proofs_amount() > total_spent {
+            // Check if wallet provided change outputs
+            if let Some(outputs) = melt_request.outputs.clone() {
+                let blinded_messages: Vec<PublicKey> =
+                    outputs.iter().map(|b| b.blinded_secret).collect();
 
-            if outputs.len().lt(&amounts.len()) {
-                tracing::debug!(
-                    "Providing change requires {} blinded messages, but only {} provided",
-                    amounts.len(),
-                    outputs.len()
-                );
+                if self
+                    .localstore
+                    .get_blind_signatures(&blinded_messages)
+                    .await?
+                    .iter()
+                    .flatten()
+                    .next()
+                    .is_some()
+                {
+                    tracing::info!("Output has already been signed");
 
-                // In the case that not enough outputs are provided to return all change
-                // Reverse sort the amounts so that the most amount of change possible is
-                // returned. The rest is burnt
-                amounts.sort_by(|a, b| b.cmp(a));
-            }
+                    return Err(Error::BlindedMessageAlreadySigned);
+                }
 
-            let mut outputs = outputs;
+                let change_target = melt_request.proofs_amount() - total_spent;
+                let mut amounts = change_target.split();
+                let mut change_sigs = Vec::with_capacity(amounts.len());
 
-            for (amount, blinded_message) in amounts.iter().zip(&mut outputs) {
-                blinded_message.amount = *amount;
+                if outputs.len().lt(&amounts.len()) {
+                    tracing::debug!(
+                        "Providing change requires {} blinded messages, but only {} provided",
+                        amounts.len(),
+                        outputs.len()
+                    );
 
-                let blinded_signature = self.blind_sign(blinded_message).await?;
-                change_sigs.push(blinded_signature)
-            }
+                    // In the case that not enough outputs are provided to return all change
+                    // Reverse sort the amounts so that the most amount of change possible is
+                    // returned. The rest is burnt
+                    amounts.sort_by(|a, b| b.cmp(a));
+                }
 
-            self.localstore
-                .add_blind_signatures(
-                    &outputs[0..change_sigs.len()]
-                        .iter()
-                        .map(|o| o.blinded_secret)
-                        .collect::<Vec<PublicKey>>(),
-                    &change_sigs,
-                )
-                .await?;
+                let mut outputs = outputs;
 
-            change = Some(change_sigs);
-        } else {
-            tracing::info!(
-                "No change outputs provided. Burnt: {:?} sats",
-                (melt_request.proofs_amount() - total_spent)
-            );
-        }
+                for (amount, blinded_message) in amounts.iter().zip(&mut outputs) {
+                    blinded_message.amount = *amount;
 
-        let input_ys: Vec<PublicKey> = melt_request
-            .inputs
-            .iter()
-            .flat_map(|p| hash_to_curve(&p.secret.to_bytes()))
-            .collect();
+                    let blinded_signature = self.blind_sign(blinded_message).await?;
+                    change_sigs.push(blinded_signature)
+                }
 
-        self.localstore
-            .update_proofs_states(&input_ys, State::Spent)
-            .await?;
+                self.localstore
+                    .add_blind_signatures(
+                        &outputs[0..change_sigs.len()]
+                            .iter()
+                            .map(|o| o.blinded_secret)
+                            .collect::<Vec<PublicKey>>(),
+                        &change_sigs,
+                    )
+                    .await?;
 
-        self.localstore
-            .update_melt_quote_state(&melt_request.quote, MeltQuoteState::Paid)
-            .await?;
+                change = Some(change_sigs);
+            }
+        }
 
         Ok(MeltQuoteBolt11Response {
             amount: quote.amount,