Browse Source

Return amount and fee_paid for Melted response

David Caseria 7 months ago
parent
commit
ce7729538c
3 changed files with 120 additions and 4 deletions
  1. 5 0
      crates/cdk/src/amount.rs
  2. 109 0
      crates/cdk/src/types.rs
  3. 6 4
      crates/cdk/src/wallet/mod.rs

+ 5 - 0
crates/cdk/src/amount.rs

@@ -103,6 +103,11 @@ impl Amount {
         self.0.checked_add(other.0).map(Amount)
     }
 
+    /// Checked subtraction for Amount. Returns None if overflow occurs.
+    pub fn checked_sub(self, other: Amount) -> Option<Amount> {
+        self.0.checked_sub(other.0).map(Amount)
+    }
+
     /// Try sum to check for overflow
     pub fn try_sum<I>(iter: I) -> Result<Self, Error>
     where

+ 109 - 0
crates/cdk/src/types.rs

@@ -7,6 +7,7 @@ use crate::mint_url::MintUrl;
 use crate::nuts::{
     CurrencyUnit, MeltQuoteState, Proof, Proofs, PublicKey, SpendingConditions, State,
 };
+use crate::Amount;
 
 /// Melt response with proofs
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Default, Serialize, Deserialize)]
@@ -17,6 +18,42 @@ pub struct Melted {
     pub preimage: Option<String>,
     /// Melt change
     pub change: Option<Proofs>,
+    /// Melt amount
+    pub amount: Amount,
+    /// Fee paid
+    pub fee_paid: Amount,
+}
+
+impl Melted {
+    /// Create new [`Melted`]
+    pub fn from_proofs(
+        state: MeltQuoteState,
+        preimage: Option<String>,
+        amount: Amount,
+        proofs: Proofs,
+        change_proofs: Option<Proofs>,
+    ) -> Result<Self, Error> {
+        let proofs_amount = Amount::try_sum(proofs.iter().map(|p| p.amount))?;
+        let change_amount = match &change_proofs {
+            Some(change_proofs) => Amount::try_sum(change_proofs.iter().map(|p| p.amount))?,
+            None => Amount::ZERO,
+        };
+        let fee_paid = proofs_amount
+            .checked_sub(amount + change_amount)
+            .ok_or(Error::AmountOverflow)?;
+        Ok(Self {
+            state,
+            preimage,
+            change: change_proofs,
+            amount,
+            fee_paid,
+        })
+    }
+
+    /// Total amount melted
+    pub fn total_amount(&self) -> Amount {
+        self.amount + self.fee_paid
+    }
 }
 
 /// Prooinfo
@@ -98,3 +135,75 @@ impl ProofInfo {
         true
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use std::str::FromStr;
+
+    use crate::{
+        nuts::{Id, Proof, PublicKey},
+        secret::Secret,
+        Amount,
+    };
+
+    use super::Melted;
+
+    #[test]
+    fn test_melted() {
+        let keyset_id = Id::from_str("00deadbeef123456").unwrap();
+        let proof = Proof::new(
+            Amount::from(64),
+            keyset_id,
+            Secret::generate(),
+            PublicKey::from_hex(
+                "02deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+            )
+            .unwrap(),
+        );
+        let melted = Melted::from_proofs(
+            super::MeltQuoteState::Paid,
+            Some("preimage".to_string()),
+            Amount::from(64),
+            vec![proof.clone()],
+            None,
+        )
+        .unwrap();
+        assert_eq!(melted.amount, Amount::from(64));
+        assert_eq!(melted.fee_paid, Amount::ZERO);
+        assert_eq!(melted.total_amount(), Amount::from(64));
+    }
+
+    #[test]
+    fn test_melted_with_change() {
+        let keyset_id = Id::from_str("00deadbeef123456").unwrap();
+        let proof = Proof::new(
+            Amount::from(64),
+            keyset_id,
+            Secret::generate(),
+            PublicKey::from_hex(
+                "02deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+            )
+            .unwrap(),
+        );
+        let change_proof = Proof::new(
+            Amount::from(32),
+            keyset_id,
+            Secret::generate(),
+            PublicKey::from_hex(
+                "03deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+            )
+            .unwrap(),
+        );
+        let melted = Melted::from_proofs(
+            super::MeltQuoteState::Paid,
+            Some("preimage".to_string()),
+            Amount::from(31),
+            vec![proof.clone()],
+            Some(vec![change_proof.clone()]),
+        )
+        .unwrap();
+        assert_eq!(melted.amount, Amount::from(31));
+        assert_eq!(melted.fee_paid, Amount::from(1));
+        assert_eq!(melted.total_amount(), Amount::from(32));
+    }
+}

+ 6 - 4
crates/cdk/src/wallet/mod.rs

@@ -1433,11 +1433,13 @@ impl Wallet {
             false => MeltQuoteState::Unpaid,
         };
 
-        let melted = Melted {
+        let melted = Melted::from_proofs(
             state,
-            preimage: melt_response.payment_preimage,
-            change: change_proofs.clone(),
-        };
+            melt_response.payment_preimage,
+            quote_info.amount,
+            proofs.clone(),
+            change_proofs.clone(),
+        )?;
 
         let change_proof_infos = match change_proofs {
             Some(change_proofs) => {