diff --git a/lightning-liquidity/src/lsps0/ser.rs b/lightning-liquidity/src/lsps0/ser.rs index a0cb6bfb143..2a1dba4c944 100644 --- a/lightning-liquidity/src/lsps0/ser.rs +++ b/lightning-liquidity/src/lsps0/ser.rs @@ -677,6 +677,32 @@ pub(crate) mod string_amount_option { } } +pub(crate) mod string_offer { + use crate::prelude::{String, ToString}; + use core::str::FromStr; + use lightning::offers::offer::Offer; + use serde::de::Unexpected; + use serde::{Deserialize, Deserializer, Serializer}; + + pub(crate) fn serialize(x: &Offer, s: S) -> Result + where + S: Serializer, + { + s.serialize_str(&x.to_string()) + } + + pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let buf = String::deserialize(deserializer)?; + + Offer::from_str(&buf).map_err(|_| { + serde::de::Error::invalid_value(Unexpected::Str(&buf), &"invalid offer string") + }) + } +} + pub(crate) mod unchecked_address { use crate::prelude::{String, ToString}; use bitcoin::Address; diff --git a/lightning-liquidity/src/lsps1/msgs.rs b/lightning-liquidity/src/lsps1/msgs.rs index c3bcc46cf05..0d9a6cec256 100644 --- a/lightning-liquidity/src/lsps1/msgs.rs +++ b/lightning-liquidity/src/lsps1/msgs.rs @@ -1,14 +1,15 @@ //! Message, request, and other primitive types used to implement bLIP-51 / LSPS1. use crate::lsps0::ser::{ - string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, LSPSDateTime, - LSPSMessage, LSPSRequestId, LSPSResponseError, + string_amount, string_offer, u32_fee_rate, unchecked_address, unchecked_address_option, + LSPSDateTime, LSPSMessage, LSPSRequestId, LSPSResponseError, }; use crate::prelude::String; use bitcoin::{Address, FeeRate, OutPoint}; +use lightning::offers::offer::Offer; use lightning_invoice::Bolt11Invoice; use serde::{Deserialize, Serialize}; @@ -151,6 +152,8 @@ pub enum LSPS1OrderState { pub struct LSPS1PaymentInfo { /// A Lightning payment using BOLT 11. pub bolt11: Option, + /// A Lightning payment using BOLT 12. + pub bolt12: Option, /// An onchain payment. pub onchain: Option, } @@ -172,6 +175,24 @@ pub struct LSPS1Bolt11PaymentInfo { pub invoice: Bolt11Invoice, } +/// A Lightning payment using BOLT 12. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct LSPS1Bolt12PaymentInfo { + /// Indicates the current state of the payment. + pub state: LSPS1PaymentState, + /// The datetime when the payment option expires. + pub expires_at: LSPSDateTime, + /// The total fee the LSP will charge to open this channel in satoshi. + #[serde(with = "string_amount")] + pub fee_total_sat: u64, + /// The amount the client needs to pay to have the requested channel openend. + #[serde(with = "string_amount")] + pub order_total_sat: u64, + /// A BOLT12 offer the client can pay to have to channel opened. + #[serde(with = "string_offer")] + pub offer: Offer, +} + /// An onchain payment. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct LSPS1OnchainPaymentInfo { @@ -387,6 +408,15 @@ mod tests { }"#; let _bolt11_payment: LSPS1Bolt11PaymentInfo = serde_json::from_str(json_str).unwrap(); + let json_str = r#"{ + "state" : "EXPECT_PAYMENT", + "expires_at": "2025-01-01T00:00:00Z", + "fee_total_sat": "8888", + "order_total_sat": "200888", + "offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy" + }"#; + let _bolt11_payment: LSPS1Bolt12PaymentInfo = serde_json::from_str(json_str).unwrap(); + let json_str = r#"{ "state": "EXPECT_PAYMENT", "expires_at": "2025-01-01T00:00:00Z", @@ -406,6 +436,13 @@ mod tests { "order_total_sat": "200888", "invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05" }, + "bolt12": { + "state" : "EXPECT_PAYMENT", + "expires_at": "2025-01-01T00:00:00Z", + "fee_total_sat": "8888", + "order_total_sat": "200888", + "offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy" + }, "onchain": { "state": "EXPECT_PAYMENT", "expires_at": "2025-01-01T00:00:00Z", @@ -416,7 +453,10 @@ mod tests { "min_fee_for_0conf": 253 } }"#; - let _payment: LSPS1PaymentInfo = serde_json::from_str(json_str).unwrap(); + let payment: LSPS1PaymentInfo = serde_json::from_str(json_str).unwrap(); + assert!(payment.bolt11.is_some()); + assert!(payment.bolt12.is_some()); + assert!(payment.onchain.is_some()); let json_str = r#"{ "order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c", @@ -437,6 +477,13 @@ mod tests { "order_total_sat": "2008888", "invoice" : "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05" }, + "bolt12": { + "state" : "EXPECT_PAYMENT", + "expires_at": "2025-01-01T00:00:00Z", + "fee_total_sat": "8888", + "order_total_sat": "200888", + "offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy" + }, "onchain": { "state": "EXPECT_PAYMENT", "expires_at": "2015-01-25T19:29:44.612Z", @@ -450,8 +497,11 @@ mod tests { }, "channel": null }"#; - let _create_order_response: LSPS1CreateOrderResponse = + let create_order_response: LSPS1CreateOrderResponse = serde_json::from_str(json_str).unwrap(); + assert!(create_order_response.payment.bolt11.is_some()); + assert!(create_order_response.payment.bolt12.is_some()); + assert!(create_order_response.payment.onchain.is_some()); let json_str = r#"{ "order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c"