thesimplekid 1 рік тому
батько
коміт
f9f88edfd8

+ 4 - 6
crates/cashu-sdk/src/client/gloo_client.rs

@@ -209,15 +209,13 @@ impl Client for HttpClient {
 
     /// Spendable check [NUT-07]
     #[cfg(feature = "nut07")]
-    async fn post_check_spendable(
+    async fn post_check_state(
         &self,
         mint_url: Url,
-        proofs: Vec<nut00::mint::Proof>,
-    ) -> Result<CheckSpendableResponse, Error> {
+        secrets: Vec<Secret>,
+    ) -> Result<CheckStateResponse, Error> {
         let url = join_url(mint_url, &["v1", "check"])?;
-        let request = CheckSpendableRequest {
-            proofs: proofs.to_owned(),
-        };
+        let request = CheckSpendableRequest { secrets };
 
         let res = Request::post(url.as_str())
             .json(&request)

+ 9 - 8
crates/cashu-sdk/src/client/minreq_client.rs

@@ -4,13 +4,14 @@ use std::println;
 
 use async_trait::async_trait;
 use cashu::nuts::{
-    nut00, BlindedMessage, CurrencyUnit, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
+    BlindedMessage, CurrencyUnit, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
     MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
     MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
 };
 #[cfg(feature = "nut07")]
-use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
+use cashu::nuts::{CheckStateRequest, CheckStateResponse};
+use cashu::secret::Secret;
 use cashu::{Amount, Bolt11Invoice};
 use serde_json::Value;
 use tracing::warn;
@@ -179,20 +180,20 @@ impl Client for HttpClient {
 
     /// Spendable check [NUT-07]
     #[cfg(feature = "nut07")]
-    async fn post_check_spendable(
+    async fn post_check_state(
         &self,
         mint_url: Url,
-        proofs: Vec<nut00::mint::Proof>,
-    ) -> Result<CheckSpendableResponse, Error> {
-        let url = join_url(mint_url, &["v1", "check"])?;
-        let request = CheckSpendableRequest { proofs };
+        secrets: Vec<Secret>,
+    ) -> Result<CheckStateResponse, Error> {
+        let url = join_url(mint_url, &["v1", "checkstate"])?;
+        let request = CheckStateRequest { secrets };
 
         let res = minreq::post(url)
             .with_json(&request)?
             .send()?
             .json::<Value>()?;
 
-        let response: Result<CheckSpendableResponse, serde_json::Error> =
+        let response: Result<CheckStateResponse, serde_json::Error> =
             serde_json::from_value(res.clone());
 
         match response {

+ 5 - 6
crates/cashu-sdk/src/client/mod.rs

@@ -1,15 +1,14 @@
 //! Client to connet to mint
 
 use async_trait::async_trait;
-#[cfg(feature = "mint")]
-use cashu::nuts::nut00;
 #[cfg(feature = "nut07")]
-use cashu::nuts::CheckSpendableResponse;
+use cashu::nuts::CheckStateResponse;
 use cashu::nuts::{
     BlindedMessage, CurrencyUnit, KeySet, KeysetResponse, MeltBolt11Response,
     MeltQuoteBolt11Response, MintBolt11Response, MintInfo, MintQuoteBolt11Response, PreMintSecrets,
     Proof, SwapRequest, SwapResponse,
 };
+use cashu::secret::Secret;
 use cashu::{utils, Amount};
 use serde::{Deserialize, Serialize};
 use thiserror::Error;
@@ -127,11 +126,11 @@ pub trait Client {
     ) -> Result<SwapResponse, Error>;
 
     #[cfg(feature = "nut07")]
-    async fn post_check_spendable(
+    async fn post_check_state(
         &self,
         mint_url: Url,
-        proofs: Vec<nut00::mint::Proof>,
-    ) -> Result<CheckSpendableResponse, Error>;
+        secrets: Vec<Secret>,
+    ) -> Result<CheckStateResponse, Error>;
 
     async fn get_mint_info(&self, mint_url: Url) -> Result<MintInfo, Error>;
 }

+ 36 - 22
crates/cashu-sdk/src/mint/mod.rs

@@ -1,12 +1,14 @@
 use std::collections::HashSet;
 
 use cashu::dhke::{sign_message, verify_message};
+#[cfg(feature = "nut07")]
+use cashu::nuts::nut07::State;
 use cashu::nuts::{
     BlindedMessage, BlindedSignature, MeltBolt11Request, MeltBolt11Response, Proof, SwapRequest,
     SwapResponse, *,
 };
 #[cfg(feature = "nut07")]
-use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
+use cashu::nuts::{CheckStateRequest, CheckStateResponse};
 use cashu::secret::Secret;
 use cashu::types::{MeltQuote, MintQuote};
 use cashu::Amount;
@@ -369,29 +371,41 @@ impl<L: LocalStore> Mint<L> {
     #[cfg(feature = "nut07")]
     pub async fn check_spendable(
         &self,
-        check_spendable: &CheckSpendableRequest,
-    ) -> Result<CheckSpendableResponse, Error> {
-        let mut spendable = Vec::with_capacity(check_spendable.proofs.len());
-        let mut pending = Vec::with_capacity(check_spendable.proofs.len());
-
-        for proof in &check_spendable.proofs {
-            spendable.push(
-                self.localstore
-                    .get_spent_proof(&proof.secret)
-                    .await
-                    .unwrap()
-                    .is_none(),
-            );
-            pending.push(
-                self.localstore
-                    .get_pending_proof(&proof.secret)
-                    .await
-                    .unwrap()
-                    .is_some(),
-            );
+        check_spendable: &CheckStateRequest,
+    ) -> Result<CheckStateResponse, Error> {
+        use cashu::nuts::nut07::ProofState;
+
+        let mut states = Vec::with_capacity(check_spendable.secrets.len());
+
+        for secret in &check_spendable.secrets {
+            let state = if self
+                .localstore
+                .get_spent_proof(secret)
+                .await
+                .unwrap()
+                .is_some()
+            {
+                State::Spent
+            } else if self
+                .localstore
+                .get_pending_proof(secret)
+                .await
+                .unwrap()
+                .is_some()
+            {
+                State::Pending
+            } else {
+                State::Unspent
+            };
+
+            states.push(ProofState {
+                secret: secret.clone(),
+                state,
+                witness: None,
+            })
         }
 
-        Ok(CheckSpendableResponse { spendable, pending })
+        Ok(CheckStateResponse { states })
     }
 
     pub async fn verify_melt_request(

+ 8 - 15
crates/cashu-sdk/src/wallet/mod.rs

@@ -5,13 +5,13 @@ use std::str::FromStr;
 use bip39::Mnemonic;
 use cashu::dhke::{construct_proofs, unblind_message};
 #[cfg(feature = "nut07")]
-use cashu::nuts::nut00::mint;
+use cashu::nuts::nut07::ProofState;
 use cashu::nuts::{
     BlindedSignature, CurrencyUnit, Id, KeySetInfo, Keys, PreMintSecrets, PreSwap, Proof, Proofs,
     SwapRequest, Token,
 };
 #[cfg(feature = "nut07")]
-use cashu::types::ProofsStatus;
+use cashu::secret::Secret;
 use cashu::types::{MeltQuote, Melted, MintQuote};
 use cashu::url::UncheckedUrl;
 use cashu::{Amount, Bolt11Invoice};
@@ -125,30 +125,23 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
         &self,
         mint_url: UncheckedUrl,
         proofs: Proofs,
-    ) -> Result<ProofsStatus, Error> {
+    ) -> Result<Vec<ProofState>, Error> {
         let spendable = self
             .client
-            .post_check_spendable(
+            .post_check_state(
                 mint_url.try_into()?,
                 proofs
                     .clone()
                     .into_iter()
-                    .map(|p| p.into())
-                    .collect::<mint::Proofs>()
+                    .map(|p| p.secret)
+                    .collect::<Vec<Secret>>()
                     .clone(),
             )
             .await?;
 
         // Separate proofs in spent and unspent based on mint response
-        let (spendable, spent): (Vec<_>, Vec<_>) = proofs
-            .iter()
-            .zip(spendable.spendable.iter())
-            .partition(|(_, &b)| b);
-
-        Ok(ProofsStatus {
-            spendable: spendable.into_iter().map(|(s, _)| s).cloned().collect(),
-            spent: spent.into_iter().map(|(s, _)| s).cloned().collect(),
-        })
+
+        Ok(spendable.states)
     }
 
     /*

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

@@ -28,7 +28,7 @@ pub use nut05::{MeltQuoteBolt11Request, MeltQuoteBolt11Response};
 pub use nut06::{MintInfo, MintVersion, Nuts};
 #[cfg(feature = "wallet")]
 #[cfg(feature = "nut07")]
-pub use nut07::{CheckSpendableRequest, CheckSpendableResponse};
+pub use nut07::{CheckStateRequest, CheckStateResponse};
 #[cfg(feature = "nut08")]
 pub use nut08::{MeltBolt11Request, MeltBolt11Response};
 

+ 24 - 8
crates/cashu/src/nuts/nut07.rs

@@ -3,21 +3,37 @@
 
 use serde::{Deserialize, Serialize};
 
-use super::nut00::mint;
+use crate::secret::Secret;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum State {
+    Spent,
+    Unspent,
+    Pending,
+}
 
 /// Check spendabale request [NUT-07]
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub struct CheckSpendableRequest {
-    pub proofs: mint::Proofs,
+pub struct CheckStateRequest {
+    pub secrets: Vec<Secret>,
+}
+
+/// Proof state [NUT-07]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct ProofState {
+    /// Secret of proof
+    pub secret: Secret,
+    /// State of proof
+    pub state: State,
+    /// Witness data if it is supplied
+    pub witness: Option<String>,
 }
 
 /// Check Spendable Response [NUT-07]
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub struct CheckSpendableResponse {
-    /// booleans indicating whether the provided Proof is still spendable.
-    /// In same order as provided proofs
-    pub spendable: Vec<bool>,
-    pub pending: Vec<bool>,
+pub struct CheckStateResponse {
+    pub states: Vec<ProofState>,
 }
 
 /// Spendable Settings