Browse Source

feat: wallet mpp

thesimplekid 10 months ago
parent
commit
16dbc48012

+ 7 - 1
bindings/cdk-js/src/wallet.rs

@@ -218,11 +218,17 @@ impl JsWallet {
         mint_url: String,
         unit: JsCurrencyUnit,
         request: String,
+        mpp_amount: Option<JsAmount>,
     ) -> Result<JsMeltQuote> {
         let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
         let melt_quote = self
             .inner
-            .melt_quote(mint_url, unit.into(), request)
+            .melt_quote(
+                mint_url,
+                unit.into(),
+                request,
+                mpp_amount.map(|a| *a.deref()),
+            )
             .await
             .map_err(into_err)?;
 

+ 1 - 0
crates/cdk-cli/src/sub_commands/melt.rs

@@ -57,6 +57,7 @@ pub async fn melt(wallet: Wallet, _sub_command_args: &MeltSubCommand) -> Result<
             mint_url.clone(),
             cdk::nuts::CurrencyUnit::Sat,
             bolt11.to_string(),
+            None,
         )
         .await?;
 

+ 2 - 0
crates/cdk/src/nuts/mod.rs

@@ -13,6 +13,7 @@ pub mod nut11;
 pub mod nut12;
 pub mod nut13;
 pub mod nut14;
+pub mod nut15;
 
 pub use nut00::{
     BlindSignature, BlindedMessage, CurrencyUnit, MintProofs, PaymentMethod, PreMint,
@@ -40,3 +41,4 @@ pub use nut10::{Kind, Secret as Nut10Secret, SecretData};
 pub use nut11::{Conditions, P2PKWitness, SigFlag, SpendingConditions};
 pub use nut12::{BlindSignatureDleq, ProofDleq};
 pub use nut14::HTLCWitness;
+pub use nut15::{Mpp, MppMethodSettings, Settings as NUT15Settings};

+ 4 - 1
crates/cdk/src/nuts/nut05.rs

@@ -5,16 +5,19 @@
 use serde::{Deserialize, Serialize};
 
 use super::nut00::{BlindSignature, BlindedMessage, CurrencyUnit, PaymentMethod, Proofs};
+use super::nut15::Mpp;
 use crate::types::MeltQuote;
 use crate::{Amount, Bolt11Invoice};
 
 /// Melt quote request [NUT-05]
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 pub struct MeltQuoteBolt11Request {
     /// Bolt11 invoice to be paid
     pub request: Bolt11Invoice,
     /// Unit wallet would like to pay with
     pub unit: CurrencyUnit,
+    /// Payment Options
+    pub options: Option<Mpp>,
 }
 
 /// Melt quote response [NUT-05]

+ 4 - 1
crates/cdk/src/nuts/nut06.rs

@@ -5,7 +5,7 @@
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 
 use super::nut01::PublicKey;
-use super::{nut04, nut05};
+use super::{nut04, nut05, nut15};
 
 /// Mint Version
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -102,6 +102,9 @@ pub struct Nuts {
     #[serde(default)]
     #[serde(rename = "14")]
     pub nut14: SupportedSettings,
+    #[serde(default)]
+    #[serde(rename = "15")]
+    pub nut15: nut15::MppMethodSettings,
 }
 
 /// Check state Settings

+ 31 - 0
crates/cdk/src/nuts/nut15.rs

@@ -0,0 +1,31 @@
+//! NUT-15: Multipart payments
+//!
+//! <https://github.com/cashubtc/nuts/blob/main/15.md>
+
+use serde::{Deserialize, Serialize};
+
+use super::{CurrencyUnit, PaymentMethod};
+use crate::Amount;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename = "lowercase")]
+pub struct Mpp {
+    pub amount: Amount,
+}
+
+/// Mpp Method Settings
+#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct MppMethodSettings {
+    /// Payment Method e.g. bolt11
+    pub method: PaymentMethod,
+    /// Currency Unit e.g. sat
+    pub unit: CurrencyUnit,
+    /// Multi part payment support
+    pub mpp: bool,
+}
+
+/// Mpp Settings
+#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Settings {
+    pub methods: Vec<MppMethodSettings>,
+}

+ 9 - 1
crates/cdk/src/wallet/client.rs

@@ -7,6 +7,7 @@ use url::Url;
 
 use super::Error;
 use crate::error::ErrorResponse;
+use crate::nuts::nut15::Mpp;
 use crate::nuts::{
     BlindedMessage, CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysResponse,
     KeysetResponse, MeltBolt11Request, MeltBolt11Response, MeltQuoteBolt11Request,
@@ -169,10 +170,17 @@ impl HttpClient {
         mint_url: Url,
         unit: CurrencyUnit,
         request: Bolt11Invoice,
+        mpp_amount: Option<Amount>,
     ) -> Result<MeltQuoteBolt11Response, Error> {
         let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?;
 
-        let request = MeltQuoteBolt11Request { request, unit };
+        let options = mpp_amount.map(|amount| Mpp { amount });
+
+        let request = MeltQuoteBolt11Request {
+            request,
+            unit,
+            options,
+        };
 
         let res = self
             .inner

+ 3 - 1
crates/cdk/src/wallet/mod.rs

@@ -965,6 +965,7 @@ impl Wallet {
         mint_url: UncheckedUrl,
         unit: CurrencyUnit,
         request: String,
+        mpp: Option<Amount>,
     ) -> Result<MeltQuote, Error> {
         let quote_res = self
             .client
@@ -972,6 +973,7 @@ impl Wallet {
                 mint_url.clone().try_into()?,
                 unit.clone(),
                 Bolt11Invoice::from_str(&request.clone())?,
+                mpp,
             )
             .await?;
 
@@ -1018,7 +1020,7 @@ impl Wallet {
     }
 
     /// Melt
-    #[instrument(skip(self, quote_id), fields(mint_url = %mint_url))]
+    #[instrument(skip(self), fields(mint_url = %mint_url))]
     pub async fn melt(
         &self,
         mint_url: &UncheckedUrl,