Forráskód Böngészése

refactor: move nut06 to nut03
rename 'proofs' to 'to inputs'

thesimplekid 1 éve
szülő
commit
417e3037ee

+ 1 - 2
bindings/cashu-ffi/src/lib.rs

@@ -18,13 +18,12 @@ mod ffi {
     pub use crate::nuts::nut01::public_key::PublicKey;
     pub use crate::nuts::nut01::secret_key::SecretKey;
     pub use crate::nuts::nut02::{Id, KeySet, KeySetResponse, MintKeySet};
-    pub use crate::nuts::nut03::RequestMintResponse;
+    pub use crate::nuts::nut03::{RequestMintResponse, SplitRequest, SplitResponse};
     pub use crate::nuts::nut04::{MintRequest, PostMintResponse};
     pub use crate::nuts::nut05::{
         CheckFeesRequest, CheckFeesResponse, MeltRequest as Nut05MeltRequest,
         MeltResponse as Nut05MeltResponse,
     };
-    pub use crate::nuts::nut06::{SplitRequest, SplitResponse};
     pub use crate::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse};
     pub use crate::nuts::nut08::{MeltRequest, MeltResponse};
     pub use crate::nuts::nut09::{MintInfo, MintVersion};

+ 0 - 1
bindings/cashu-ffi/src/nuts/mod.rs

@@ -4,7 +4,6 @@ pub mod nut02;
 pub mod nut03;
 pub mod nut04;
 pub mod nut05;
-pub mod nut06;
 pub mod nut07;
 pub mod nut08;
 pub mod nut09;

+ 85 - 0
bindings/cashu-ffi/src/nuts/nut03/mod.rs

@@ -1,9 +1,13 @@
+use std::ops::Deref;
 use std::str::FromStr;
+use std::sync::Arc;
 
 use cashu::nuts::nut03::RequestMintResponse as RequestMintResponseSdk;
+use cashu::nuts::{SplitRequest as SplitRequestSdk, SplitResponse as SplitResponseSdk};
 use cashu::Bolt11Invoice;
 
 use crate::error::Result;
+use crate::{Amount, BlindedMessage, BlindedSignature, Proof};
 
 pub struct RequestMintResponse {
     inner: RequestMintResponseSdk,
@@ -34,3 +38,84 @@ impl From<cashu::nuts::nut03::RequestMintResponse> for RequestMintResponse {
         }
     }
 }
+
+pub struct SplitRequest {
+    inner: SplitRequestSdk,
+}
+
+impl Deref for SplitRequest {
+    type Target = SplitRequestSdk;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl SplitRequest {
+    pub fn new(proofs: Vec<Arc<Proof>>, outputs: Vec<Arc<BlindedMessage>>) -> Self {
+        let proofs = proofs.into_iter().map(|p| p.as_ref().into()).collect();
+        let outputs = outputs.into_iter().map(|o| o.as_ref().into()).collect();
+
+        Self {
+            inner: SplitRequestSdk::new(proofs, outputs),
+        }
+    }
+
+    pub fn proofs(&self) -> Vec<Arc<Proof>> {
+        self.inner
+            .inputs
+            .clone()
+            .into_iter()
+            .map(|p| Arc::new(p.into()))
+            .collect()
+    }
+
+    pub fn outputs(&self) -> Vec<Arc<BlindedMessage>> {
+        self.inner
+            .outputs
+            .clone()
+            .into_iter()
+            .map(|o| Arc::new(o.into()))
+            .collect()
+    }
+
+    pub fn proofs_amount(&self) -> Arc<Amount> {
+        Arc::new(self.inner.input_amount().into())
+    }
+
+    pub fn output_amount(&self) -> Arc<Amount> {
+        Arc::new(self.inner.output_amount().into())
+    }
+}
+
+pub struct SplitResponse {
+    inner: SplitResponseSdk,
+}
+
+impl SplitResponse {
+    pub fn new(promises: Vec<Arc<BlindedSignature>>) -> Self {
+        let promises = promises.into_iter().map(|p| p.as_ref().into()).collect();
+        Self {
+            inner: SplitResponseSdk::new(promises),
+        }
+    }
+
+    pub fn promises(&self) -> Vec<Arc<BlindedSignature>> {
+        self.inner
+            .promises
+            .clone()
+            .unwrap_or_default()
+            .into_iter()
+            .map(|p| Arc::new(p.into()))
+            .collect()
+    }
+
+    pub fn promises_amount(&self) -> Option<Arc<Amount>> {
+        self.inner.promises_amount().map(|a| Arc::new(a.into()))
+    }
+}
+
+impl From<cashu::nuts::SplitResponse> for SplitResponse {
+    fn from(inner: cashu::nuts::SplitResponse) -> SplitResponse {
+        SplitResponse { inner }
+    }
+}

+ 0 - 87
bindings/cashu-ffi/src/nuts/nut06/mod.rs

@@ -1,87 +0,0 @@
-use std::ops::Deref;
-use std::sync::Arc;
-
-use cashu::nuts::nut06::{SplitRequest as SplitRequestSdk, SplitResponse as SplitResponseSdk};
-
-use crate::{Amount, BlindedMessage, BlindedSignature, Proof};
-
-pub struct SplitRequest {
-    inner: SplitRequestSdk,
-}
-
-impl Deref for SplitRequest {
-    type Target = SplitRequestSdk;
-    fn deref(&self) -> &Self::Target {
-        &self.inner
-    }
-}
-
-impl SplitRequest {
-    pub fn new(proofs: Vec<Arc<Proof>>, outputs: Vec<Arc<BlindedMessage>>) -> Self {
-        let proofs = proofs.into_iter().map(|p| p.as_ref().into()).collect();
-        let outputs = outputs.into_iter().map(|o| o.as_ref().into()).collect();
-
-        Self {
-            inner: SplitRequestSdk::new(proofs, outputs),
-        }
-    }
-
-    pub fn proofs(&self) -> Vec<Arc<Proof>> {
-        self.inner
-            .proofs
-            .clone()
-            .into_iter()
-            .map(|p| Arc::new(p.into()))
-            .collect()
-    }
-
-    pub fn outputs(&self) -> Vec<Arc<BlindedMessage>> {
-        self.inner
-            .outputs
-            .clone()
-            .into_iter()
-            .map(|o| Arc::new(o.into()))
-            .collect()
-    }
-
-    pub fn proofs_amount(&self) -> Arc<Amount> {
-        Arc::new(self.inner.proofs_amount().into())
-    }
-
-    pub fn output_amount(&self) -> Arc<Amount> {
-        Arc::new(self.inner.output_amount().into())
-    }
-}
-
-pub struct SplitResponse {
-    inner: SplitResponseSdk,
-}
-
-impl SplitResponse {
-    pub fn new(promises: Vec<Arc<BlindedSignature>>) -> Self {
-        let promises = promises.into_iter().map(|p| p.as_ref().into()).collect();
-        Self {
-            inner: SplitResponseSdk::new(promises),
-        }
-    }
-
-    pub fn promises(&self) -> Vec<Arc<BlindedSignature>> {
-        self.inner
-            .promises
-            .clone()
-            .unwrap_or_default()
-            .into_iter()
-            .map(|p| Arc::new(p.into()))
-            .collect()
-    }
-
-    pub fn promises_amount(&self) -> Option<Arc<Amount>> {
-        self.inner.promises_amount().map(|a| Arc::new(a.into()))
-    }
-}
-
-impl From<cashu::nuts::nut06::SplitResponse> for SplitResponse {
-    fn from(inner: cashu::nuts::nut06::SplitResponse) -> SplitResponse {
-        SplitResponse { inner }
-    }
-}

+ 9 - 1
bindings/cashu-js/src/nuts/mod.rs

@@ -4,9 +4,17 @@ pub mod nut02;
 pub mod nut03;
 pub mod nut04;
 pub mod nut05;
-pub mod nut06;
 #[cfg(feature = "nut07")]
 pub mod nut07;
 pub mod nut08;
 #[cfg(feature = "nut09")]
 pub mod nut09;
+
+pub use nut00::{JsBlindedMessage, JsBlindedMessages, JsBlindedSignature, JsProof, JsToken};
+pub use nut01::{JsKeyPair, JsKeys, JsPublicKey, JsSecretKey};
+pub use nut02::{JsId, JsKeySet, JsKeySetsResponse, JsKeysResponse, JsMintKeySet};
+pub use nut03::{JsRequestMintResponse, JsSplitRequest, JsSplitResponse};
+pub use nut04::{JsMintRequest, JsPostMintResponse};
+#[cfg(feature = "nut07")]
+pub use nut07::{JsCheckSpendableRequest, JsCheckSpendableResponse};
+pub use nut08::{JsMeltRequest, JsMeltResponse};

+ 102 - 2
bindings/cashu-js/src/nuts/nut03.rs

@@ -1,9 +1,10 @@
 use std::ops::Deref;
 
-use cashu::nuts::nut03::RequestMintResponse;
+use cashu::nuts::{RequestMintResponse, SplitRequest, SplitResponse};
 use wasm_bindgen::prelude::*;
 
-use crate::types::JsBolt11Invoice;
+use crate::error::{into_err, Result};
+use crate::types::{JsAmount, JsBolt11Invoice};
 
 #[wasm_bindgen(js_name = RequestMintResponse)]
 pub struct JsRequestMintResponse {
@@ -47,3 +48,102 @@ impl JsRequestMintResponse {
         self.inner.hash.to_string()
     }
 }
+
+#[wasm_bindgen(js_name = SplitRequest)]
+pub struct JsSplitRequest {
+    inner: SplitRequest,
+}
+
+impl Deref for JsSplitRequest {
+    type Target = SplitRequest;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SplitRequest> for JsSplitRequest {
+    fn from(inner: SplitRequest) -> JsSplitRequest {
+        JsSplitRequest { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = SplitRequest)]
+impl JsSplitRequest {
+    #[wasm_bindgen(constructor)]
+    pub fn new(inputs: JsValue, outputs: JsValue) -> Result<JsSplitRequest> {
+        let inputs = serde_wasm_bindgen::from_value(inputs).map_err(into_err)?;
+        let outputs = serde_wasm_bindgen::from_value(outputs).map_err(into_err)?;
+
+        Ok(JsSplitRequest {
+            inner: SplitRequest { inputs, outputs },
+        })
+    }
+
+    /// Get Proofs
+    #[wasm_bindgen(getter)]
+    pub fn proofs(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.inputs).map_err(into_err)
+    }
+
+    /// Get Outputs
+    #[wasm_bindgen(getter)]
+    pub fn outputs(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.outputs).map_err(into_err)
+    }
+
+    /// Proofs Amount
+    #[wasm_bindgen(js_name = proofsAmount)]
+    pub fn proofs_amount(&self) -> JsAmount {
+        self.inner.input_amount().into()
+    }
+
+    /// Output Amount
+    #[wasm_bindgen(js_name = outputAmount)]
+    pub fn output_amount(&self) -> JsAmount {
+        self.inner.output_amount().into()
+    }
+}
+
+#[wasm_bindgen(js_name = SplitResponse)]
+pub struct JsSplitResponse {
+    inner: SplitResponse,
+}
+
+impl Deref for JsSplitResponse {
+    type Target = SplitResponse;
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+impl From<SplitResponse> for JsSplitResponse {
+    fn from(inner: SplitResponse) -> JsSplitResponse {
+        JsSplitResponse { inner }
+    }
+}
+
+#[wasm_bindgen(js_class = SplitResponse)]
+impl JsSplitResponse {
+    #[wasm_bindgen(constructor)]
+    pub fn new(promises: JsValue) -> Result<JsSplitResponse> {
+        let promises = serde_wasm_bindgen::from_value(promises).map_err(into_err)?;
+
+        Ok(JsSplitResponse {
+            inner: SplitResponse {
+                promises: Some(promises),
+            },
+        })
+    }
+
+    /// Get Promises
+    #[wasm_bindgen(getter)]
+    pub fn promises(&self) -> Result<JsValue> {
+        serde_wasm_bindgen::to_value(&self.inner.promises).map_err(into_err)
+    }
+
+    /// Promises Amount
+    #[wasm_bindgen(js_name = promisesAmount)]
+    pub fn promises_amount(&self) -> Option<JsAmount> {
+        self.inner.promises_amount().map(|a| a.into())
+    }
+}

+ 6 - 12
bindings/cashu-js/src/nuts/nut06.rs

@@ -1,6 +1,6 @@
 use std::ops::Deref;
 
-use cashu::nuts::nut06::{SplitRequest, SplitResponse};
+use cashu::nuts::{SplitRequest, SplitResponse};
 use wasm_bindgen::prelude::*;
 
 use crate::error::{into_err, Result};
@@ -27,23 +27,19 @@ impl From<SplitRequest> for JsSplitRequest {
 #[wasm_bindgen(js_class = SplitRequest)]
 impl JsSplitRequest {
     #[wasm_bindgen(constructor)]
-    pub fn new(proofs: JsValue, outputs: JsValue) -> Result<JsSplitRequest> {
-        let proofs = serde_wasm_bindgen::from_value(proofs).map_err(into_err)?;
+    pub fn new(inputs: JsValue, outputs: JsValue) -> Result<JsSplitRequest> {
+        let inputs = serde_wasm_bindgen::from_value(inputs).map_err(into_err)?;
         let outputs = serde_wasm_bindgen::from_value(outputs).map_err(into_err)?;
 
         Ok(JsSplitRequest {
-            inner: SplitRequest {
-                amount: None,
-                proofs,
-                outputs,
-            },
+            inner: SplitRequest { inputs, outputs },
         })
     }
 
     /// Get Proofs
     #[wasm_bindgen(getter)]
     pub fn proofs(&self) -> Result<JsValue> {
-        serde_wasm_bindgen::to_value(&self.inner.proofs).map_err(into_err)
+        serde_wasm_bindgen::to_value(&self.inner.inputs).map_err(into_err)
     }
 
     /// Get Outputs
@@ -55,7 +51,7 @@ impl JsSplitRequest {
     /// Proofs Amount
     #[wasm_bindgen(js_name = proofsAmount)]
     pub fn proofs_amount(&self) -> JsAmount {
-        self.inner.proofs_amount().into()
+        self.inner.input_amount().into()
     }
 
     /// Output Amount
@@ -91,8 +87,6 @@ impl JsSplitResponse {
 
         Ok(JsSplitResponse {
             inner: SplitResponse {
-                fst: None,
-                snd: None,
                 promises: Some(promises),
             },
         })

+ 5 - 5
bindings/cashu-sdk-js/src/mint.rs

@@ -1,11 +1,11 @@
 use std::ops::Deref;
 
-use cashu_js::nuts::nut02::{JsId, JsKeySet, JsKeySetsResponse, JsKeysResponse, JsMintKeySet};
-use cashu_js::nuts::nut04::{JsMintRequest, JsPostMintResponse};
-use cashu_js::nuts::nut06::{JsSplitRequest, JsSplitResponse};
 #[cfg(feature = "nut07")]
-use cashu_js::nuts::nut07::{JsCheckSpendableRequest, JsCheckSpendableResponse};
-use cashu_js::nuts::nut08::{JsMeltRequest, JsMeltResponse};
+use cashu_js::nuts::{JsCheckSpendableRequest, JsCheckSpendableResponse};
+use cashu_js::nuts::{
+    JsId, JsKeySet, JsKeySetsResponse, JsKeysResponse, JsMeltRequest, JsMeltResponse, JsMintKeySet,
+    JsMintRequest, JsPostMintResponse, JsSplitRequest, JsSplitResponse,
+};
 use cashu_js::JsAmount;
 use cashu_sdk::mint::Mint;
 use cashu_sdk::nuts::{KeySet, KeysResponse};

+ 7 - 11
crates/cashu-sdk/src/client/gloo_client.rs

@@ -1,19 +1,15 @@
 //! gloo wasm http Client
 
 use async_trait::async_trait;
-use cashu::nuts::nut00::wallet::BlindedMessages;
-use cashu::nuts::nut00::{BlindedMessage, Proof};
-use cashu::nuts::nut01::Keys;
-use cashu::nuts::nut03::RequestMintResponse;
-use cashu::nuts::nut04::{MintRequest, PostMintResponse};
-use cashu::nuts::nut05::{CheckFeesRequest, CheckFeesResponse};
-use cashu::nuts::nut06::{SplitRequest, SplitResponse};
-#[cfg(feature = "nut07")]
-use cashu::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse};
-use cashu::nuts::nut08::{MeltRequest, MeltResponse};
 #[cfg(feature = "nut09")]
 use cashu::nuts::MintInfo;
-use cashu::nuts::*;
+use cashu::nuts::{
+    BlindedMessage, BlindedMessages, CheckFeesRequest, CheckFeesResponse, Keys, MeltRequest,
+    MeltResponse, MintRequest, PostMintResponse, Proof, RequestMintResponse, SplitRequest,
+    SplitResponse, *,
+};
+#[cfg(feature = "nut07")]
+use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
 use cashu::{Amount, Bolt11Invoice};
 use gloo::net::http::Request;
 use serde_json::Value;

+ 7 - 11
crates/cashu-sdk/src/client/minreq_client.rs

@@ -3,19 +3,15 @@
 use std::println;
 
 use async_trait::async_trait;
-use cashu::nuts::nut00::wallet::BlindedMessages;
-use cashu::nuts::nut00::{BlindedMessage, Proof};
-use cashu::nuts::nut01::Keys;
-use cashu::nuts::nut03::RequestMintResponse;
-use cashu::nuts::nut04::{MintRequest, PostMintResponse};
-use cashu::nuts::nut05::{CheckFeesRequest, CheckFeesResponse};
-use cashu::nuts::nut06::{SplitRequest, SplitResponse};
-#[cfg(feature = "nut07")]
-use cashu::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse};
-use cashu::nuts::nut08::{MeltRequest, MeltResponse};
 #[cfg(feature = "nut09")]
 use cashu::nuts::MintInfo;
-use cashu::nuts::*;
+use cashu::nuts::{
+    BlindedMessage, BlindedMessages, CheckFeesRequest, CheckFeesResponse, Keys, MeltRequest,
+    MeltResponse, MintRequest, PostMintResponse, Proof, RequestMintResponse, SplitRequest,
+    SplitResponse, *,
+};
+#[cfg(feature = "nut07")]
+use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
 use cashu::{Amount, Bolt11Invoice};
 use serde_json::Value;
 use url::Url;

+ 10 - 33
crates/cashu-sdk/src/mint.rs

@@ -147,7 +147,7 @@ impl Mint {
         &mut self,
         split_request: SplitRequest,
     ) -> Result<SplitResponse, Error> {
-        let proofs_total = split_request.proofs_amount();
+        let proofs_total = split_request.input_amount();
 
         let output_total = split_request.output_amount();
 
@@ -155,10 +155,10 @@ impl Mint {
             return Err(Error::Amount);
         }
 
-        let proof_count = split_request.proofs.len();
+        let proof_count = split_request.inputs.len();
 
         let secrets: HashSet<Secret> = split_request
-            .proofs
+            .inputs
             .iter()
             .map(|p| p.secret.clone())
             .collect();
@@ -168,7 +168,7 @@ impl Mint {
             return Err(Error::DuplicateProofs);
         }
 
-        for proof in &split_request.proofs {
+        for proof in &split_request.inputs {
             self.verify_proof(proof)?
         }
 
@@ -176,36 +176,13 @@ impl Mint {
             self.spent_secrets.insert(secret);
         }
 
-        match &split_request.amount {
-            None => {
-                let promises: Vec<BlindedSignature> = split_request
-                    .outputs
-                    .iter()
-                    .map(|b| self.blind_sign(b).unwrap())
-                    .collect();
-
-                Ok(SplitResponse::new(promises))
-            }
-            Some(amount) => {
-                let outs_fst = (proofs_total.to_owned() - amount.to_owned()).split();
-
-                // Blinded change messages
-                let b_fst = split_request.outputs[0..outs_fst.len()].to_vec();
-                let b_snd = split_request.outputs[outs_fst.len()..].to_vec();
-                let fst: Vec<BlindedSignature> =
-                    b_fst.iter().map(|b| self.blind_sign(b).unwrap()).collect();
-                let snd: Vec<BlindedSignature> =
-                    b_snd.iter().map(|b| self.blind_sign(b).unwrap()).collect();
-
-                let split_response = SplitResponse::new_from_amount(fst, snd);
-
-                if split_response.target_amount() != split_request.amount {
-                    return Err(Error::CustomError("Output order".to_string()));
-                }
+        let promises: Vec<BlindedSignature> = split_request
+            .outputs
+            .iter()
+            .map(|b| self.blind_sign(b).unwrap())
+            .collect();
 
-                Ok(split_response)
-            }
-        }
+        Ok(SplitResponse::new(promises))
     }
 
     fn verify_proof(&self, proof: &Proof) -> Result<(), Error> {

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

@@ -18,14 +18,12 @@ pub use nut00::{BlindedMessage, BlindedSignature, Proof};
 pub use nut01::{Keys, KeysResponse, PublicKey, SecretKey};
 pub use nut02::mint::KeySet as MintKeySet;
 pub use nut02::{Id, KeySet, KeySetInfo, KeysetResponse};
-pub use nut03::RequestMintResponse;
+pub use nut03::{RequestMintResponse, SplitPayload, SplitRequest, SplitResponse};
 pub use nut04::{MintRequest, PostMintResponse};
 pub use nut05::{CheckFeesRequest, CheckFeesResponse};
 #[cfg(not(feature = "nut08"))]
 pub use nut05::{MeltRequest, MeltResponse};
 #[cfg(feature = "wallet")]
-pub use nut06::SplitPayload;
-pub use nut06::{SplitRequest, SplitResponse};
 #[cfg(feature = "nut07")]
 pub use nut07::{CheckSpendableRequest, CheckSpendableResponse};
 #[cfg(feature = "nut08")]

+ 61 - 0
crates/cashu/src/nuts/nut03.rs

@@ -3,6 +3,11 @@
 
 use serde::{Deserialize, Serialize};
 
+use super::nut00::BlindedSignature;
+#[cfg(feature = "wallet")]
+use crate::nuts::BlindedMessages;
+use crate::nuts::{BlindedMessage, Proofs};
+use crate::Amount;
 pub use crate::Bolt11Invoice;
 
 /// Mint request response [NUT-03]
@@ -13,3 +18,59 @@ pub struct RequestMintResponse {
     /// Random hash MUST not be the hash of invoice
     pub hash: String,
 }
+
+#[cfg(feature = "wallet")]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
+pub struct SplitPayload {
+    pub blinded_messages: BlindedMessages,
+    pub split_payload: SplitRequest,
+}
+
+/// Split Request [NUT-06]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SplitRequest {
+    /// Proofs that are to be spent in `Split`
+    pub inputs: Proofs,
+    /// Blinded Messages for Mint to sign
+    pub outputs: Vec<BlindedMessage>,
+}
+
+impl SplitRequest {
+    pub fn new(inputs: Proofs, outputs: Vec<BlindedMessage>) -> Self {
+        Self { inputs, outputs }
+    }
+
+    /// Total value of proofs in `SplitRequest`
+    pub fn input_amount(&self) -> Amount {
+        self.inputs.iter().map(|proof| proof.amount).sum()
+    }
+
+    /// Total value of outputs in `SplitRequest`
+    pub fn output_amount(&self) -> Amount {
+        self.outputs.iter().map(|proof| proof.amount).sum()
+    }
+}
+
+/// Split Response [NUT-06]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SplitResponse {
+    /// Promises
+    pub promises: Option<Vec<BlindedSignature>>,
+}
+
+impl SplitResponse {
+    pub fn new(promises: Vec<BlindedSignature>) -> SplitResponse {
+        SplitResponse {
+            promises: Some(promises),
+        }
+    }
+
+    pub fn promises_amount(&self) -> Option<Amount> {
+        self.promises.as_ref().map(|promises| {
+            promises
+                .iter()
+                .map(|BlindedSignature { amount, .. }| *amount)
+                .sum()
+        })
+    }
+}