Browse Source

fix: construct proofs with weong keys on mint

thesimplekid 1 year ago
parent
commit
ee417a44c9

+ 1 - 1
crates/cashu-sdk/src/client/gloo_client.rs

@@ -182,7 +182,7 @@ impl Client for HttpClient {
     }
 
     /// Split Token [NUT-06]
-    async fn post_split(
+    async fn post_swap(
         &self,
         mint_url: Url,
         split_request: SwapRequest,

+ 16 - 5
crates/cashu-sdk/src/client/minreq_client.rs

@@ -2,7 +2,7 @@
 
 use async_trait::async_trait;
 use cashu::nuts::{
-    BlindedMessage, CurrencyUnit, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
+    BlindedMessage, CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
     MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
     MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
@@ -33,6 +33,19 @@ impl Client for HttpClient {
         Ok(keys.keysets)
     }
 
+    /// Get Keyset Keys [NUT-01]
+    async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error> {
+        let url = join_url(mint_url, &["v1", "keys", &keyset_id.to_string()])?;
+        println!("{url}");
+        let keys = minreq::get(url).send()?.json::<KeysResponse>()?;
+        println!("{keys:?}");
+
+        // let keys: KeysResponse = serde_json::from_value(keys)?; //
+        // serde_json::from_str(&keys.to_string())?;
+        println!("{keys:?}");
+        Ok(keys.keysets[0].clone())
+    }
+
     /// Get Keysets [NUT-02]
     async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error> {
         let url = join_url(mint_url, &["v1", "keysets"])?;
@@ -60,8 +73,6 @@ impl Client for HttpClient {
 
         let res = minreq::post(url).with_json(&request)?.send()?;
 
-        print!("r: {:?}", res);
-
         let response: Result<MintQuoteBolt11Response, serde_json::Error> =
             serde_json::from_value(res.json()?);
 
@@ -159,7 +170,7 @@ impl Client for HttpClient {
     }
 
     /// Split Token [NUT-06]
-    async fn post_split(
+    async fn post_swap(
         &self,
         mint_url: Url,
         split_request: SwapRequest,
@@ -169,7 +180,7 @@ impl Client for HttpClient {
 
         let res = minreq::post(url).with_json(&split_request)?.send()?;
 
-        println!("{:?}", res);
+        println!("{:?}", res.json::<Value>());
 
         let response: Result<SwapResponse, serde_json::Error> =
             serde_json::from_value(res.json::<Value>()?.clone());

+ 4 - 2
crates/cashu-sdk/src/client/mod.rs

@@ -4,7 +4,7 @@ use async_trait::async_trait;
 #[cfg(feature = "nut07")]
 use cashu::nuts::CheckStateResponse;
 use cashu::nuts::{
-    BlindedMessage, CurrencyUnit, KeySet, KeysetResponse, MeltBolt11Response,
+    BlindedMessage, CurrencyUnit, Id, KeySet, KeysetResponse, MeltBolt11Response,
     MeltQuoteBolt11Response, MintBolt11Response, MintInfo, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
 };
@@ -88,6 +88,8 @@ pub trait Client {
 
     async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error>;
 
+    async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error>;
+
     async fn post_mint_quote(
         &self,
         mint_url: Url,
@@ -120,7 +122,7 @@ pub trait Client {
     // REVIEW: Should be consistent aboue passing in the Request struct or the
     // compnatants and making it within the function. Here the struct is passed
     // in but in check spendable and melt the compants are passed in
-    async fn post_split(
+    async fn post_swap(
         &self,
         mint_url: Url,
         split_request: SwapRequest,

+ 3 - 2
crates/cashu-sdk/src/wallet/localstore/redb_store.rs

@@ -1,4 +1,5 @@
 use std::collections::HashMap;
+use std::str::FromStr;
 use std::sync::Arc;
 
 use async_trait::async_trait;
@@ -91,8 +92,8 @@ impl LocalStore for RedbLocalStore {
             .flatten()
             .map(|(mint, mint_info)| {
                 (
-                    serde_json::from_str(mint.value()).unwrap(),
-                    serde_json::from_str(mint_info.value()).unwrap(),
+                    UncheckedUrl::from_str(mint.value()).unwrap(),
+                    serde_json::from_str(mint_info.value()).ok(),
                 )
             })
             .collect();

+ 72 - 19
crates/cashu-sdk/src/wallet/mod.rs

@@ -7,8 +7,8 @@ use cashu::dhke::{construct_proofs, unblind_message};
 #[cfg(feature = "nut07")]
 use cashu::nuts::nut07::ProofState;
 use cashu::nuts::{
-    BlindedSignature, CurrencyUnit, Id, KeySetInfo, Keys, PreMintSecrets, PreSwap, Proof, Proofs,
-    SwapRequest, Token,
+    BlindedSignature, CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, PreMintSecrets, PreSwap, Proof,
+    Proofs, SwapRequest, Token,
 };
 #[cfg(feature = "nut07")]
 use cashu::secret::Secret;
@@ -119,6 +119,47 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
         Ok(self.localstore.get_proofs(mint_url).await?)
     }
 
+    pub async fn add_mint(&self, mint_url: UncheckedUrl) -> Result<Option<MintInfo>, Error> {
+        let mint_info = match self
+            .client
+            .get_mint_info(mint_url.clone().try_into()?)
+            .await
+        {
+            Ok(mint_info) => Some(mint_info),
+            Err(err) => {
+                warn!("Could not get mint info {}", err);
+                None
+            }
+        };
+
+        self.localstore
+            .add_mint(mint_url, mint_info.clone())
+            .await?;
+
+        Ok(mint_info)
+    }
+
+    pub async fn get_mint_keys(
+        &self,
+        mint_url: &UncheckedUrl,
+        keyset_id: Id,
+    ) -> Result<Keys, Error> {
+        let keys = if let Some(keys) = self.localstore.get_keys(&keyset_id).await? {
+            keys
+        } else {
+            let keys = self
+                .client
+                .get_mint_keyset(mint_url.try_into()?, keyset_id)
+                .await?;
+
+            self.localstore.add_keys(keys.keys.clone()).await?;
+
+            keys.keys
+        };
+
+        Ok(keys)
+    }
+
     /// Check if a proof is spent
     #[cfg(feature = "nut07")]
     pub async fn check_proofs_spent(
@@ -208,12 +249,20 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
                     return Ok(Some(keyset.id));
                 }
             }
-        } else {
-            let keysets = self.client.get_mint_keysets(mint_url.try_into()?).await?;
+        }
 
-            self.localstore
-                .add_mint_keysets(mint_url.clone(), keysets.keysets.into_iter().collect())
-                .await?;
+        let keysets = self.client.get_mint_keysets(mint_url.try_into()?).await?;
+
+        self.localstore
+            .add_mint_keysets(
+                mint_url.clone(),
+                keysets.keysets.clone().into_iter().collect(),
+            )
+            .await?;
+        for keyset in &keysets.keysets {
+            if keyset.unit.eq(unit) && keyset.active {
+                return Ok(Some(keyset.id));
+            }
         }
 
         Ok(None)
@@ -226,19 +275,18 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
     ) -> Result<Option<Keys>, Error> {
         let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?.unwrap();
 
-        let mut keys = None;
+        let keys;
 
         if let Some(k) = self.localstore.get_keys(&active_keyset_id).await? {
             keys = Some(k.clone())
         } else {
-            let keysets = self.client.get_mint_keys(mint_url.try_into()?).await?;
+            let keyset = self
+                .client
+                .get_mint_keyset(mint_url.try_into()?, active_keyset_id)
+                .await?;
 
-            for keyset in keysets {
-                if keyset.id.eq(&active_keyset_id) {
-                    keys = Some(keyset.keys.clone())
-                }
-                self.localstore.add_keys(keyset.keys).await?;
-            }
+            self.localstore.add_keys(keyset.keys.clone()).await?;
+            keys = Some(keyset.keys);
         }
 
         Ok(keys)
@@ -246,10 +294,15 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
 
     /// Mint
     pub async fn mint(&mut 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?;
+        }
+
         let quote_info = self.localstore.get_mint_quote(quote_id).await?;
 
         let quote_info = if let Some(quote) = quote_info {
-            if quote.expiry.le(&unix_time()) {
+            if quote.expiry.le(&unix_time()) && quote.expiry.ne(&0) {
                 return Err(Error::QuoteExpired);
             }
 
@@ -282,7 +335,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
             )
             .await?;
 
-        let keys = self.localstore.get_keys(&active_keyset_id).await?.unwrap();
+        let keys = self.get_mint_keys(&mint_url, active_keyset_id).await?;
 
         let proofs = construct_proofs(
             mint_res.signatures,
@@ -329,7 +382,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
 
             let swap_response = self
                 .client
-                .post_split(token.mint.clone().try_into()?, pre_swap.split_request)
+                .post_swap(token.mint.clone().try_into()?, pre_swap.split_request)
                 .await?;
 
             // Proof to keep
@@ -437,7 +490,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
 
         let swap_response = self
             .client
-            .post_split(mint_url.clone().try_into()?, pre_swap.split_request)
+            .post_swap(mint_url.clone().try_into()?, pre_swap.split_request)
             .await?;
 
         let mut keep_proofs = Proofs::new();

+ 1 - 1
crates/cashu/src/nuts/nut01.rs

@@ -147,7 +147,7 @@ impl Keys {
 #[serde_as]
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct KeysResponse {
-    #[serde_as(as = "VecSkipError<_>")]
+    // #[serde_as(as = "VecSkipError<_>")]
     pub keysets: Vec<KeySet>,
 }