فهرست منبع

feat: check mint quotes

thesimplekid 11 ماه پیش
والد
کامیت
0cc5e153a8

+ 16 - 0
crates/cdk-redb/src/wallet.rs

@@ -232,6 +232,22 @@ impl WalletDatabase for RedbWalletDatabase {
     }
 
     #[instrument(skip_all)]
+    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err> {
+        let db = self.db.lock().await;
+        let read_txn = db.begin_read().map_err(Into::<Error>::into)?;
+        let table = read_txn
+            .open_table(MINT_QUOTES_TABLE)
+            .map_err(Error::from)?;
+
+        Ok(table
+            .iter()
+            .map_err(Error::from)?
+            .flatten()
+            .flat_map(|(_id, quote)| serde_json::from_str(quote.value()))
+            .collect())
+    }
+
+    #[instrument(skip_all)]
     async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err> {
         let db = self.db.lock().await;
         let write_txn = db.begin_write().map_err(Error::from)?;

+ 22 - 2
crates/cdk-rexie/src/wallet.rs

@@ -265,14 +265,34 @@ impl WalletDatabase for RexieWalletDatabase {
         let quotes_store = transaction.store(MINT_QUOTES).map_err(Error::from)?;
 
         let quote_id = serde_wasm_bindgen::to_value(&quote_id).map_err(Error::from)?;
-        let keysets = quotes_store.get(&quote_id).await.map_err(Error::from)?;
+        let quote = quotes_store.get(&quote_id).await.map_err(Error::from)?;
 
         let quote: Option<MintQuote> =
-            serde_wasm_bindgen::from_value(keysets).map_err(Error::from)?;
+            serde_wasm_bindgen::from_value(quote).map_err(Error::from)?;
 
         Ok(quote)
     }
 
+    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err> {
+        let rexie = self.db.lock().await;
+
+        let transaction = rexie
+            .transaction(&[MINT_QUOTES], TransactionMode::ReadOnly)
+            .map_err(Error::from)?;
+
+        let quotes_store = transaction.store(MINT_QUOTES).map_err(Error::from)?;
+
+        let quotes = quotes_store
+            .get_all(None, None, None, None)
+            .await
+            .map_err(Error::from)?;
+
+        Ok(quotes
+            .into_iter()
+            .flat_map(|(_id, q)| serde_wasm_bindgen::from_value(q))
+            .collect())
+    }
+
     async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err> {
         let rexie = self.db.lock().await;
 

+ 1 - 0
crates/cdk/src/cdk_database/mod.rs

@@ -60,6 +60,7 @@ pub trait WalletDatabase {
     ) -> Result<Option<Vec<KeySetInfo>>, Self::Err>;
     async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err>;
     async fn get_mint_quote(&self, quote_id: &str) -> Result<Option<MintQuote>, Self::Err>;
+    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err>;
     async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Self::Err>;
 
     async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), Self::Err>;

+ 5 - 0
crates/cdk/src/cdk_database/wallet_memory.rs

@@ -109,6 +109,11 @@ impl WalletDatabase for WalletMemoryDatabase {
         Ok(self.mint_quotes.lock().await.get(quote_id).cloned())
     }
 
+    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Error> {
+        let quotes = self.mint_quotes.lock().await;
+        Ok(quotes.values().cloned().collect())
+    }
+
     async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), Error> {
         self.mint_quotes.lock().await.remove(quote_id);
 

+ 3 - 1
crates/cdk/src/mint.rs

@@ -15,6 +15,7 @@ use crate::dhke::{hash_to_curve, sign_message, verify_message};
 use crate::error::ErrorResponse;
 use crate::nuts::*;
 use crate::types::{MeltQuote, MintQuote};
+use crate::url::UncheckedUrl;
 use crate::util::unix_time;
 use crate::Amount;
 
@@ -135,12 +136,13 @@ impl Mint {
 
     pub async fn new_mint_quote(
         &self,
+        mint_url: UncheckedUrl,
         request: String,
         unit: CurrencyUnit,
         amount: Amount,
         expiry: u64,
     ) -> Result<MintQuote, Error> {
-        let quote = MintQuote::new(request, unit, amount, expiry);
+        let quote = MintQuote::new(mint_url, request, unit, amount, expiry);
 
         self.localstore.add_mint_quote(quote.clone()).await?;
 

+ 10 - 1
crates/cdk/src/types.rs

@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 
 use crate::nuts::{CurrencyUnit, Proofs};
+use crate::url::UncheckedUrl;
 use crate::Amount;
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -33,6 +34,7 @@ pub enum InvoiceStatus {
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
 pub struct MintQuote {
     pub id: String,
+    pub mint_url: UncheckedUrl,
     pub amount: Amount,
     pub unit: CurrencyUnit,
     pub request: String,
@@ -41,10 +43,17 @@ pub struct MintQuote {
 }
 
 impl MintQuote {
-    pub fn new(request: String, unit: CurrencyUnit, amount: Amount, expiry: u64) -> Self {
+    pub fn new(
+        mint_url: UncheckedUrl,
+        request: String,
+        unit: CurrencyUnit,
+        amount: Amount,
+        expiry: u64,
+    ) -> Self {
         let id = Uuid::new_v4();
 
         Self {
+            mint_url,
             id: id.to_string(),
             amount,
             unit,

+ 24 - 3
crates/cdk/src/wallet.rs

@@ -364,10 +364,11 @@ impl Wallet {
     ) -> Result<MintQuote, Error> {
         let quote_res = self
             .client
-            .post_mint_quote(mint_url.try_into()?, amount, unit.clone())
+            .post_mint_quote(mint_url.clone().try_into()?, amount, unit.clone())
             .await?;
 
         let quote = MintQuote {
+            mint_url,
             id: quote_res.quote.clone(),
             amount,
             unit: unit.clone(),
@@ -408,9 +409,29 @@ impl Wallet {
         Ok(response)
     }
 
+    /// Check status of pending mint quotes
+    pub async fn check_all_mint_quotes(&self) -> Result<Amount, Error> {
+        let mint_quotes = self.localstore.get_mint_quotes().await?;
+        let mut total_amount = Amount::ZERO;
+
+        for mint_quote in mint_quotes {
+            let mint_quote_response = self
+                .mint_quote_status(mint_quote.mint_url.clone(), &mint_quote.id)
+                .await?;
+
+            if mint_quote_response.paid {
+                let amount = self.mint(mint_quote.mint_url, &mint_quote.id).await?;
+                total_amount += amount;
+            } else if mint_quote.expiry.le(&unix_time()) {
+                self.localstore.remove_mint_quote(&mint_quote.id).await?;
+            }
+        }
+        Ok(total_amount)
+    }
+
     #[instrument(skip(self), fields(mint_url = %mint_url))]
     async fn active_mint_keyset(
-        &mut self,
+        &self,
         mint_url: &UncheckedUrl,
         unit: &CurrencyUnit,
     ) -> Result<Id, Error> {
@@ -466,7 +487,7 @@ impl Wallet {
 
     /// Mint
     #[instrument(skip(self, quote_id), fields(mint_url = %mint_url))]
-    pub async fn mint(&mut self, mint_url: UncheckedUrl, quote_id: &str) -> Result<Amount, Error> {
+    pub async fn mint(&self, mint_url: UncheckedUrl, quote_id: &str) -> Result<Amount, Error> {
         // Check that mint is in store of mints
         if self.localstore.get_mint(mint_url.clone()).await?.is_none() {
             self.add_mint(mint_url.clone()).await?;