Bladeren bron

feat: get mint keysets and keys

thesimplekid 1 jaar geleden
bovenliggende
commit
f45a0b19b7

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

@@ -2,8 +2,8 @@
 
 use async_trait::async_trait;
 use cashu::nuts::{
-    BlindedMessage, Keys, MeltBolt11Request, MeltBolt11Response, MintBolt11Request,
-    MintBolt11Response, MintInfo, PreMintSecrets, Proof, SwapRequest, SwapResponse, *,
+    BlindedMessage, MeltBolt11Request, MeltBolt11Response, MintBolt11Request, MintBolt11Response,
+    MintInfo, PreMintSecrets, Proof, SwapRequest, SwapResponse, *,
 };
 #[cfg(feature = "nut07")]
 use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
@@ -21,7 +21,7 @@ pub struct HttpClient {}
 #[async_trait(?Send)]
 impl Client for HttpClient {
     /// Get Mint Keys [NUT-01]
-    async fn get_mint_keys(&self, mint_url: Url) -> Result<Keys, Error> {
+    async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {
         let url = join_url(mint_url, &["v1", "keys"])?;
         let keys = Request::get(url.as_str())
             .send()
@@ -31,8 +31,8 @@ impl Client for HttpClient {
             .await
             .map_err(|err| Error::Gloo(err.to_string()))?;
 
-        let keys: Keys = serde_json::from_str(&keys.to_string())?;
-        Ok(keys)
+        let keys: KeysResponse = serde_json::from_str(&keys.to_string())?;
+        Ok(keys.keysets)
     }
 
     /// Get Keysets [NUT-02]

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

@@ -4,7 +4,7 @@ use std::println;
 
 use async_trait::async_trait;
 use cashu::nuts::{
-    nut00, BlindedMessage, CurrencyUnit, Keys, KeysResponse, KeysetResponse, MeltBolt11Request,
+    nut00, BlindedMessage, CurrencyUnit, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
     MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
     MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
@@ -25,14 +25,12 @@ pub struct HttpClient {}
 #[async_trait(?Send)]
 impl Client for HttpClient {
     /// Get Mint Keys [NUT-01]
-    async fn get_mint_keys(&self, mint_url: Url) -> Result<Keys, Error> {
+    async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {
         let url = join_url(mint_url, &["v1", "keys"])?;
         let keys = minreq::get(url).send()?.json::<Value>()?;
 
-        println!("{}", keys);
-
         let keys: KeysResponse = serde_json::from_str(&keys.to_string())?;
-        Ok(keys.keysets[0].keys.clone())
+        Ok(keys.keysets)
     }
 
     /// Get Keysets [NUT-02]

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

@@ -6,7 +6,7 @@ use cashu::nuts::nut00;
 #[cfg(feature = "nut07")]
 use cashu::nuts::CheckSpendableResponse;
 use cashu::nuts::{
-    BlindedMessage, CurrencyUnit, Keys, KeysetResponse, MeltBolt11Response,
+    BlindedMessage, CurrencyUnit, KeySet, KeysetResponse, MeltBolt11Response,
     MeltQuoteBolt11Response, MintBolt11Response, MintInfo, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
 };
@@ -84,7 +84,7 @@ pub struct MintErrorResponse {
 
 #[async_trait(?Send)]
 pub trait Client {
-    async fn get_mint_keys(&self, mint_url: Url) -> Result<Keys, Error>;
+    async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error>;
 
     async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error>;
 

+ 58 - 23
crates/cashu-sdk/src/wallet.rs

@@ -52,7 +52,7 @@ pub struct BackupInfo {
 pub struct Wallet<C: Client> {
     backup_info: Option<BackupInfo>,
     pub client: C,
-    pub mints: HashMap<UncheckedUrl, MintInfo>,
+    pub mints: HashMap<UncheckedUrl, Option<MintInfo>>,
     pub mint_keysets: HashMap<UncheckedUrl, HashSet<KeySetInfo>>,
     pub mint_quotes: HashMap<String, MintQuote>,
     pub melt_quotes: HashMap<String, MeltQuote>,
@@ -63,7 +63,7 @@ pub struct Wallet<C: Client> {
 impl<C: Client> Wallet<C> {
     pub fn new(
         client: C,
-        mints: HashMap<UncheckedUrl, MintInfo>,
+        mints: HashMap<UncheckedUrl, Option<MintInfo>>,
         mint_keysets: HashMap<UncheckedUrl, HashSet<KeySetInfo>>,
         mint_quotes: Vec<MintQuote>,
         melt_quotes: Vec<MeltQuote>,
@@ -164,22 +164,50 @@ impl<C: Client> Wallet<C> {
         Ok(quote)
     }
 
-    fn active_mint_keyset(&self, mint_url: &UncheckedUrl, unit: &CurrencyUnit) -> Option<Id> {
+    async fn active_mint_keyset(
+        &mut self,
+        mint_url: &UncheckedUrl,
+        unit: &CurrencyUnit,
+    ) -> Result<Option<Id>, Error> {
         if let Some(keysets) = self.mint_keysets.get(mint_url) {
             for keyset in keysets {
                 if keyset.unit.eq(unit) && keyset.active {
-                    return Some(keyset.id);
+                    return Ok(Some(keyset.id));
                 }
             }
+        } else {
+            let keysets = self.client.get_mint_keysets(mint_url.try_into()?).await?;
+
+            self.mint_keysets
+                .insert(mint_url.clone(), keysets.keysets.into_iter().collect());
         }
 
-        None
+        Ok(None)
     }
 
-    fn active_keys(&self, mint_url: &UncheckedUrl, unit: &CurrencyUnit) -> Option<Keys> {
-        self.active_mint_keyset(mint_url, unit)
-            .and_then(|id| self.mint_keys.get(&id))
-            .cloned()
+    async fn active_keys(
+        &mut self,
+        mint_url: &UncheckedUrl,
+        unit: &CurrencyUnit,
+    ) -> Result<Option<Keys>, Error> {
+        let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?.unwrap();
+
+        let mut keys = None;
+
+        if let Some(k) = self.mint_keys.get(&active_keyset_id) {
+            keys = Some(k.clone())
+        } else {
+            let keysets = self.client.get_mint_keys(mint_url.try_into()?).await?;
+
+            for keyset in keysets {
+                if keyset.id.eq(&active_keyset_id) {
+                    keys = Some(keyset.keys.clone())
+                }
+                self.mint_keys.insert(keyset.id, keyset.keys);
+            }
+        }
+
+        Ok(keys)
     }
 
     /// Mint
@@ -198,6 +226,7 @@ impl<C: Client> Wallet<C> {
 
         let active_keyset_id = self
             .active_mint_keyset(&mint_url, &quote_info.unit)
+            .await?
             .unwrap();
 
         let premint_secrets = match &self.backup_info {
@@ -234,7 +263,7 @@ impl<C: Client> Wallet<C> {
     }
 
     /// Receive
-    pub async fn receive(&self, encoded_token: &str) -> Result<Proofs, Error> {
+    pub async fn receive(&mut self, encoded_token: &str) -> Result<Proofs, Error> {
         let token_data = Token::from_str(encoded_token)?;
 
         let unit = token_data.unit.unwrap_or_default();
@@ -252,16 +281,18 @@ impl<C: Client> Wallet<C> {
                         };
             */
 
-            let active_keyset_id = self.active_mint_keyset(&token.mint, &unit);
+            let active_keyset_id = self.active_mint_keyset(&token.mint, &unit).await?;
 
             // TODO: if none fetch keyset for mint
 
-            let keys = self.mint_keys.get(&active_keyset_id.unwrap());
+            let keys = self.mint_keys.get(&active_keyset_id.unwrap()).cloned();
 
             // Sum amount of all proofs
             let amount: Amount = token.proofs.iter().map(|p| p.amount).sum();
 
-            let pre_swap = self.create_split(&token.mint, &unit, Some(amount), token.proofs)?;
+            let pre_swap = self
+                .create_split(&token.mint, &unit, Some(amount), token.proofs)
+                .await?;
 
             let swap_response = self
                 .client
@@ -273,7 +304,7 @@ impl<C: Client> Wallet<C> {
                 swap_response.signatures,
                 pre_swap.pre_mint_secrets.rs(),
                 pre_swap.pre_mint_secrets.secrets(),
-                keys.unwrap(),
+                &keys.unwrap(),
             )?;
             proofs.push(p);
         }
@@ -281,8 +312,8 @@ impl<C: Client> Wallet<C> {
     }
 
     /// Create Split Payload
-    fn create_split(
-        &self,
+    async fn create_split(
+        &mut self,
         mint_url: &UncheckedUrl,
         unit: &CurrencyUnit,
         amount: Option<Amount>,
@@ -291,7 +322,7 @@ impl<C: Client> Wallet<C> {
         // Since split is used to get the needed combination of tokens for a specific
         // amount first blinded messages are created for the amount
 
-        let active_keyset_id = self.active_mint_keyset(mint_url, unit).unwrap();
+        let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?.unwrap();
 
         let pre_mint_secrets = if let Some(amount) = amount {
             let mut desired_messages = PreMintSecrets::random(active_keyset_id, amount)?;
@@ -352,7 +383,7 @@ impl<C: Client> Wallet<C> {
 
     /// Send
     pub async fn send(
-        &self,
+        &mut self,
         mint_url: &UncheckedUrl,
         unit: &CurrencyUnit,
         amount: Amount,
@@ -365,7 +396,9 @@ impl<C: Client> Wallet<C> {
             return Err(Error::InsufficientFunds);
         }
 
-        let pre_swap = self.create_split(mint_url, unit, Some(amount), proofs)?;
+        let pre_swap = self
+            .create_split(mint_url, unit, Some(amount), proofs)
+            .await?;
 
         let swap_response = self
             .client
@@ -379,7 +412,7 @@ impl<C: Client> Wallet<C> {
             swap_response.signatures,
             pre_swap.pre_mint_secrets.rs(),
             pre_swap.pre_mint_secrets.secrets(),
-            &self.active_keys(mint_url, unit).unwrap(),
+            &self.active_keys(mint_url, unit).await?.unwrap(),
         )?;
 
         proofs.reverse();
@@ -439,7 +472,7 @@ impl<C: Client> Wallet<C> {
 
     /// Melt
     pub async fn melt(
-        &self,
+        &mut self,
         mint_url: &UncheckedUrl,
         quote_id: &str,
         proofs: Proofs,
@@ -457,7 +490,9 @@ impl<C: Client> Wallet<C> {
         };
 
         let blinded = PreMintSecrets::blank(
-            self.active_mint_keyset(mint_url, &quote_info.unit).unwrap(),
+            self.active_mint_keyset(mint_url, &quote_info.unit)
+                .await?
+                .unwrap(),
             quote_info.fee_reserve,
         )?;
 
@@ -476,7 +511,7 @@ impl<C: Client> Wallet<C> {
                 change,
                 blinded.rs(),
                 blinded.secrets(),
-                &self.active_keys(mint_url, &quote_info.unit).unwrap(),
+                &self.active_keys(mint_url, &quote_info.unit).await?.unwrap(),
             )?),
             None => None,
         };