From f2418ccccade9c0f84f2e9659de8ad71ea570694 Mon Sep 17 00:00:00 2001 From: d4rp4t Date: Tue, 26 May 2026 19:43:44 +0200 Subject: [PATCH 1/3] feat: add mints_strict field to payment requests --- .../payment_request_encoding_benchmark.rs | 7 ++++ .../cashu/src/nuts/nut18/payment_request.rs | 14 ++++++++ crates/cashu/src/nuts/nut26/encoding.rs | 35 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/crates/cashu/examples/payment_request_encoding_benchmark.rs b/crates/cashu/examples/payment_request_encoding_benchmark.rs index 38100e1b31..9c1cdca0f4 100644 --- a/crates/cashu/examples/payment_request_encoding_benchmark.rs +++ b/crates/cashu/examples/payment_request_encoding_benchmark.rs @@ -94,6 +94,7 @@ fn minimal_comparison() -> Result<(), Box> { unit: None, single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com")?], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -110,6 +111,7 @@ fn amount_unit_comparison() -> Result<(), Box> { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com")?], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -131,6 +133,7 @@ fn multiple_mints_comparison() -> Result<(), Box> { MintUrl::from_str("https://mint3.example.com")?, MintUrl::from_str("https://backup-mint.cashu.space")?, ], + mints_strict: None, description: Some("Payment with multiple mint options".to_string()), transports: vec![], nut10: None, @@ -156,6 +159,7 @@ fn transport_comparison() -> Result<(), Box> { unit: Some(CurrencyUnit::Sat), single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com")?], + mints_strict: None, description: Some("Payment with callback transport".to_string()), transports: vec![transport], nut10: None, @@ -193,6 +197,7 @@ fn complete_with_nut10_comparison() -> Result<(), Box> { MintUrl::from_str("https://mint1.example.com")?, MintUrl::from_str("https://mint2.example.com")?, ], + mints_strict: None, description: Some("Complete payment with P2PK locking and refund key".to_string()), transports: vec![transport], nut10: Some(nut10), @@ -245,6 +250,7 @@ fn very_complex_comparison() -> Result<(), Box> { MintUrl::from_str("https://backup-mint-2.example.net")?, MintUrl::from_str("https://emergency-mint.example.io")?, ], + mints_strict: None, description: Some("Complex payment with multiple mints and transports".to_string()), transports: vec![transport1, transport2], nut10: Some(nut10), @@ -503,6 +509,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Test".to_string()), transports: vec![], nut10: None, diff --git a/crates/cashu/src/nuts/nut18/payment_request.rs b/crates/cashu/src/nuts/nut18/payment_request.rs index 8964b3fa08..8e5d9ea9e5 100644 --- a/crates/cashu/src/nuts/nut18/payment_request.rs +++ b/crates/cashu/src/nuts/nut18/payment_request.rs @@ -36,6 +36,10 @@ pub struct PaymentRequest { #[serde(rename = "m")] #[serde(skip_serializing_if = "Vec::is_empty", default)] pub mints: Vec, + /// Mints strict flag + #[serde(rename = "ms")] + #[serde(skip_serializing_if = "Option::is_none")] + pub mints_strict: Option, /// Description #[serde(rename = "d")] pub description: Option, @@ -102,6 +106,7 @@ pub struct PaymentRequestBuilder { unit: Option, single_use: Option, mints: Vec, + mints_strict: Option, description: Option, transports: Vec, nut10: Option, @@ -150,6 +155,12 @@ impl PaymentRequestBuilder { self } + /// Set mints strict flag + pub fn mints_strict(mut self, mints_strict: bool) -> Self { + self.mints_strict = Some(mints_strict); + self + } + /// Set description pub fn description>(mut self, description: S) -> Self { self.description = Some(description.into()); @@ -182,6 +193,7 @@ impl PaymentRequestBuilder { unit: self.unit, single_use: self.single_use, mints: self.mints, + mints_strict: self.mints_strict, description: self.description, transports: self.transports, nut10: self.nut10, @@ -249,6 +261,7 @@ mod tests { mints: vec!["https://nofees.testnut.cashu.space" .parse() .expect("valid mint url")], + mints_strict: None, description: None, transports: vec![transport.clone()], nut10: None, @@ -693,6 +706,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Test both formats".to_string()), transports: vec![], nut10: None, diff --git a/crates/cashu/src/nuts/nut26/encoding.rs b/crates/cashu/src/nuts/nut26/encoding.rs index e18c704f92..7da6cfbd1e 100644 --- a/crates/cashu/src/nuts/nut26/encoding.rs +++ b/crates/cashu/src/nuts/nut26/encoding.rs @@ -145,6 +145,7 @@ impl PaymentRequest { /// unit: Some(cashu::nuts::CurrencyUnit::Sat), /// single_use: None, /// mints: vec![MintUrl::from_str("https://mint.example.com")?], + /// mints_strict: None, /// description: None, /// transports: vec![], /// nut10: None, @@ -221,6 +222,7 @@ impl PaymentRequest { let mut unit: Option = None; let mut single_use: Option = None; let mut mints: Vec = Vec::new(); + let mut mints_strict: Option = None; let mut description: Option = None; let mut transports: Vec = Vec::new(); let mut nut10: Option = None; @@ -292,6 +294,15 @@ impl PaymentRequest { // nut10: sub-TLV nut10 = Some(Self::decode_nut10(&value)?); } + 0x09 => { + // mint_strict: u8 (0 or 1) + if mints_strict.is_some() { + return Err(Error::InvalidStructure); + } + if !value.is_empty() { + mints_strict = Some(value[0] != 0); + } + } _ => { // Unknown tags are ignored } @@ -304,6 +315,7 @@ impl PaymentRequest { unit, single_use, mints, + mints_strict, description, transports, nut10, @@ -362,6 +374,11 @@ impl PaymentRequest { writer.write_tlv(0x08, &nut10_bytes); } + // 0x09 mint_strict: u8 (0 or 1) + if let Some(mints_strict) = self.mints_strict { + writer.write_tlv(0x09, &[if mints_strict { 1 } else { 0 }]); + } + Ok(writer.into_bytes()) } @@ -787,6 +804,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Test payment".to_string()), transports: vec![transport], nut10: None, @@ -816,6 +834,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -844,6 +863,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("P2PK locked payment".to_string()), transports: vec![], nut10: Some(nut10.clone()), @@ -866,6 +886,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -911,6 +932,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -930,6 +952,7 @@ mod tests { unit: Some(CurrencyUnit::Usd), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -1106,6 +1129,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Nostr payment".to_string()), transports: vec![transport], nut10: None, @@ -1150,6 +1174,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Nostr payment with relays".to_string()), transports: vec![transport], nut10: None, @@ -1197,6 +1222,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Coffee".to_string()), transports: vec![transport], nut10: None, @@ -1273,6 +1299,7 @@ mod tests { MintUrl::from_str("https://mint2.example.com").unwrap(), MintUrl::from_str("https://testnut.cashu.space").unwrap(), ], + mints_strict: None, description: Some("Payment with multiple transports and mints".to_string()), transports: vec![transport1, transport2], nut10: None, @@ -1767,6 +1794,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: Some("Test payment description".to_string()), transports: vec![], nut10: None, @@ -1802,6 +1830,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -1832,6 +1861,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: Some(false), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -1862,6 +1892,7 @@ mod tests { unit: Some(CurrencyUnit::Msat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -1893,6 +1924,7 @@ mod tests { unit: Some(CurrencyUnit::Usd), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -2087,6 +2119,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], // Empty transports = in-band per NUT-26 nut10: None, @@ -2186,6 +2219,7 @@ mod tests { unit: Some(CurrencyUnit::Sat), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, @@ -2223,6 +2257,7 @@ mod tests { unit: Some(CurrencyUnit::Custom("btc".to_string())), single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], + mints_strict: None, description: None, transports: vec![], nut10: None, From 4490e3cc18c169c0924eed0622930a6c1e6eaffd Mon Sep 17 00:00:00 2001 From: d4rp4t Date: Sat, 13 Jun 2026 14:31:44 +0200 Subject: [PATCH 2/3] feat: add mints_strict field to payment requests --- crates/cashu/src/nuts/nut18/payment_request.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cashu/src/nuts/nut18/payment_request.rs b/crates/cashu/src/nuts/nut18/payment_request.rs index 8e5d9ea9e5..8f0bdfbc67 100644 --- a/crates/cashu/src/nuts/nut18/payment_request.rs +++ b/crates/cashu/src/nuts/nut18/payment_request.rs @@ -39,7 +39,7 @@ pub struct PaymentRequest { /// Mints strict flag #[serde(rename = "ms")] #[serde(skip_serializing_if = "Option::is_none")] - pub mints_strict: Option, + pub mints_strict: Option,n /// Description #[serde(rename = "d")] pub description: Option, From da6ce5088497b54124d86bb5443b13c635dbc367 Mon Sep 17 00:00:00 2001 From: d4rp4t Date: Mon, 15 Jun 2026 00:04:08 +0200 Subject: [PATCH 3/3] feat: add fee_reserve and supported_methods to payment requests --- .../payment_request_encoding_benchmark.rs | 14 ++++ .../cashu/src/nuts/nut18/payment_request.rs | 33 ++++++++- crates/cashu/src/nuts/nut26/encoding.rs | 71 +++++++++++++++++++ crates/cdk-ffi/src/types/payment_request.rs | 15 ++++ crates/cdk/src/wallet/payment_request.rs | 6 ++ fuzz/src/arbitrary_ext.rs | 3 + 6 files changed, 141 insertions(+), 1 deletion(-) diff --git a/crates/cashu/examples/payment_request_encoding_benchmark.rs b/crates/cashu/examples/payment_request_encoding_benchmark.rs index 9c1cdca0f4..c14a0c39f0 100644 --- a/crates/cashu/examples/payment_request_encoding_benchmark.rs +++ b/crates/cashu/examples/payment_request_encoding_benchmark.rs @@ -95,6 +95,8 @@ fn minimal_comparison() -> Result<(), Box> { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com")?], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -112,6 +114,8 @@ fn amount_unit_comparison() -> Result<(), Box> { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com")?], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -134,6 +138,8 @@ fn multiple_mints_comparison() -> Result<(), Box> { MintUrl::from_str("https://backup-mint.cashu.space")?, ], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Payment with multiple mint options".to_string()), transports: vec![], nut10: None, @@ -160,6 +166,8 @@ fn transport_comparison() -> Result<(), Box> { single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com")?], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Payment with callback transport".to_string()), transports: vec![transport], nut10: None, @@ -198,6 +206,8 @@ fn complete_with_nut10_comparison() -> Result<(), Box> { MintUrl::from_str("https://mint2.example.com")?, ], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Complete payment with P2PK locking and refund key".to_string()), transports: vec![transport], nut10: Some(nut10), @@ -251,6 +261,8 @@ fn very_complex_comparison() -> Result<(), Box> { MintUrl::from_str("https://emergency-mint.example.io")?, ], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Complex payment with multiple mints and transports".to_string()), transports: vec![transport1, transport2], nut10: Some(nut10), @@ -510,6 +522,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Test".to_string()), transports: vec![], nut10: None, diff --git a/crates/cashu/src/nuts/nut18/payment_request.rs b/crates/cashu/src/nuts/nut18/payment_request.rs index 8f0bdfbc67..07eee0a693 100644 --- a/crates/cashu/src/nuts/nut18/payment_request.rs +++ b/crates/cashu/src/nuts/nut18/payment_request.rs @@ -39,7 +39,15 @@ pub struct PaymentRequest { /// Mints strict flag #[serde(rename = "ms")] #[serde(skip_serializing_if = "Option::is_none")] - pub mints_strict: Option,n + pub mints_strict: Option, + /// Additional fee reserve for payments from non-preferred mints + #[serde(rename = "fr")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_reserve: Option, + /// Supported payment methods the mint must support + #[serde(rename = "sm")] + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub supported_methods: Vec, /// Description #[serde(rename = "d")] pub description: Option, @@ -107,6 +115,8 @@ pub struct PaymentRequestBuilder { single_use: Option, mints: Vec, mints_strict: Option, + fee_reserve: Option, + supported_methods: Vec, description: Option, transports: Vec, nut10: Option, @@ -161,6 +171,21 @@ impl PaymentRequestBuilder { self } + /// Set fee reserve for payments from non-preferred mints + pub fn fee_reserve(mut self, fee_reserve: A) -> Self + where + A: Into, + { + self.fee_reserve = Some(fee_reserve.into()); + self + } + + /// Set supported payment methods + pub fn supported_methods(mut self, methods: Vec) -> Self { + self.supported_methods = methods; + self + } + /// Set description pub fn description>(mut self, description: S) -> Self { self.description = Some(description.into()); @@ -194,6 +219,8 @@ impl PaymentRequestBuilder { single_use: self.single_use, mints: self.mints, mints_strict: self.mints_strict, + fee_reserve: self.fee_reserve, + supported_methods: self.supported_methods, description: self.description, transports: self.transports, nut10: self.nut10, @@ -262,6 +289,8 @@ mod tests { .parse() .expect("valid mint url")], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![transport.clone()], nut10: None, @@ -707,6 +736,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Test both formats".to_string()), transports: vec![], nut10: None, diff --git a/crates/cashu/src/nuts/nut26/encoding.rs b/crates/cashu/src/nuts/nut26/encoding.rs index 7da6cfbd1e..9885a17956 100644 --- a/crates/cashu/src/nuts/nut26/encoding.rs +++ b/crates/cashu/src/nuts/nut26/encoding.rs @@ -146,6 +146,8 @@ impl PaymentRequest { /// single_use: None, /// mints: vec![MintUrl::from_str("https://mint.example.com")?], /// mints_strict: None, + /// fee_reserve: None, + /// supported_methods: vec![], /// description: None, /// transports: vec![], /// nut10: None, @@ -223,6 +225,8 @@ impl PaymentRequest { let mut single_use: Option = None; let mut mints: Vec = Vec::new(); let mut mints_strict: Option = None; + let mut fee_reserve: Option = None; + let mut supported_methods: Vec = Vec::new(); let mut description: Option = None; let mut transports: Vec = Vec::new(); let mut nut10: Option = None; @@ -303,6 +307,25 @@ impl PaymentRequest { mints_strict = Some(value[0] != 0); } } + 0x0a => { + // fee_reserve: u64 + if fee_reserve.is_some() { + return Err(Error::InvalidStructure); + } + if value.len() != 8 { + return Err(Error::InvalidLength); + } + let fr_val = u64::from_be_bytes([ + value[0], value[1], value[2], value[3], value[4], value[5], value[6], + value[7], + ]); + fee_reserve = Some(Amount::from(fr_val)); + } + 0x0b => { + // supported_methods: string (repeatable) + let method = String::from_utf8(value).map_err(|_| Error::InvalidUtf8)?; + supported_methods.push(method); + } _ => { // Unknown tags are ignored } @@ -316,6 +339,8 @@ impl PaymentRequest { single_use, mints, mints_strict, + fee_reserve, + supported_methods, description, transports, nut10, @@ -379,6 +404,16 @@ impl PaymentRequest { writer.write_tlv(0x09, &[if mints_strict { 1 } else { 0 }]); } + // 0x0a fee_reserve: u64 + if let Some(fee_reserve) = self.fee_reserve { + writer.write_tlv(0x0a, &fee_reserve.to_u64().to_be_bytes()); + } + + // 0x0b supported_methods: string (repeatable) + for method in &self.supported_methods { + writer.write_tlv(0x0b, method.as_bytes()); + } + Ok(writer.into_bytes()) } @@ -805,6 +840,8 @@ mod tests { single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Test payment".to_string()), transports: vec![transport], nut10: None, @@ -835,6 +872,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -864,6 +903,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("P2PK locked payment".to_string()), transports: vec![], nut10: Some(nut10.clone()), @@ -887,6 +928,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -933,6 +976,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -953,6 +998,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -1130,6 +1177,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Nostr payment".to_string()), transports: vec![transport], nut10: None, @@ -1175,6 +1224,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Nostr payment with relays".to_string()), transports: vec![transport], nut10: None, @@ -1223,6 +1274,8 @@ mod tests { single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Coffee".to_string()), transports: vec![transport], nut10: None, @@ -1300,6 +1353,8 @@ mod tests { MintUrl::from_str("https://testnut.cashu.space").unwrap(), ], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Payment with multiple transports and mints".to_string()), transports: vec![transport1, transport2], nut10: None, @@ -1795,6 +1850,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: Some("Test payment description".to_string()), transports: vec![], nut10: None, @@ -1831,6 +1888,8 @@ mod tests { single_use: Some(true), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -1862,6 +1921,8 @@ mod tests { single_use: Some(false), mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -1893,6 +1954,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -1925,6 +1988,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -2120,6 +2185,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], // Empty transports = in-band per NUT-26 nut10: None, @@ -2220,6 +2287,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, @@ -2258,6 +2327,8 @@ mod tests { single_use: None, mints: vec![MintUrl::from_str("https://mint.example.com").unwrap()], mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: None, transports: vec![], nut10: None, diff --git a/crates/cdk-ffi/src/types/payment_request.rs b/crates/cdk-ffi/src/types/payment_request.rs index 4623dead94..16a9dfbe76 100644 --- a/crates/cdk-ffi/src/types/payment_request.rs +++ b/crates/cdk-ffi/src/types/payment_request.rs @@ -159,6 +159,21 @@ impl PaymentRequest { self.inner.mints.iter().map(|m| m.to_string()).collect() } + /// Get whether the mint list is strict + pub fn mints_strict(&self) -> Option { + self.inner.mints_strict + } + + /// Get the fee reserve for payments from non-preferred mints + pub fn fee_reserve(&self) -> Option { + self.inner.fee_reserve.map(|a| a.into()) + } + + /// Get the list of supported payment methods the mint must support + pub fn supported_methods(&self) -> Vec { + self.inner.supported_methods.clone() + } + /// Get the description pub fn description(&self) -> Option { self.inner.description.clone() diff --git a/crates/cdk/src/wallet/payment_request.rs b/crates/cdk/src/wallet/payment_request.rs index 4cccf10bcb..6b1ec62a45 100644 --- a/crates/cdk/src/wallet/payment_request.rs +++ b/crates/cdk/src/wallet/payment_request.rs @@ -546,6 +546,9 @@ impl WalletRepository { unit: Some(CurrencyUnit::from_str(¶ms.unit)?), single_use: Some(true), mints, + mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: params.description, transports, nut10, @@ -615,6 +618,9 @@ impl WalletRepository { unit: Some(CurrencyUnit::from_str(¶ms.unit)?), single_use: Some(true), mints, + mints_strict: None, + fee_reserve: None, + supported_methods: vec![], description: params.description, transports, nut10, diff --git a/fuzz/src/arbitrary_ext.rs b/fuzz/src/arbitrary_ext.rs index e96879969b..1f16f6d449 100644 --- a/fuzz/src/arbitrary_ext.rs +++ b/fuzz/src/arbitrary_ext.rs @@ -623,6 +623,9 @@ impl<'a> Arbitrary<'a> for PaymentRequestArb { unit, single_use, mints, + mints_strict: None, + fee_reserve: None, + supported_methods: Vec::new(), description, transports: Vec::new(), nut10: None,