Skip to content

Commit 8505474

Browse files
committed
Add BOLT12 support to bLIP-51 / LSPS1
Previously, bLIP-51 / LSPS1 only supported BOLT11 and onchain payment options. Here we add the necessary fields to allow to pay the LSP via BOLT12 offers.
1 parent 43de15e commit 8505474

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

lightning-liquidity/src/lsps0/ser.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,32 @@ pub(crate) mod string_amount_option {
677677
}
678678
}
679679

680+
pub(crate) mod string_offer {
681+
use crate::prelude::{String, ToString};
682+
use core::str::FromStr;
683+
use lightning::offers::offer::Offer;
684+
use serde::de::Unexpected;
685+
use serde::{Deserialize, Deserializer, Serializer};
686+
687+
pub(crate) fn serialize<S>(x: &Offer, s: S) -> Result<S::Ok, S::Error>
688+
where
689+
S: Serializer,
690+
{
691+
s.serialize_str(&x.to_string())
692+
}
693+
694+
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Offer, D::Error>
695+
where
696+
D: Deserializer<'de>,
697+
{
698+
let buf = String::deserialize(deserializer)?;
699+
700+
Offer::from_str(&buf).map_err(|_| {
701+
serde::de::Error::invalid_value(Unexpected::Str(&buf), &"invalid offer string")
702+
})
703+
}
704+
}
705+
680706
pub(crate) mod unchecked_address {
681707
use crate::prelude::{String, ToString};
682708
use bitcoin::Address;

lightning-liquidity/src/lsps1/msgs.rs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! Message, request, and other primitive types used to implement bLIP-51 / LSPS1.
22
33
use crate::lsps0::ser::{
4-
string_amount, u32_fee_rate, unchecked_address, unchecked_address_option, LSPSDateTime,
5-
LSPSMessage, LSPSRequestId, LSPSResponseError,
4+
string_amount, string_offer, u32_fee_rate, unchecked_address, unchecked_address_option,
5+
LSPSDateTime, LSPSMessage, LSPSRequestId, LSPSResponseError,
66
};
77

88
use crate::prelude::String;
99

1010
use bitcoin::{Address, FeeRate, OutPoint};
1111

12+
use lightning::offers::offer::Offer;
1213
use lightning_invoice::Bolt11Invoice;
1314

1415
use serde::{Deserialize, Serialize};
@@ -172,6 +173,24 @@ pub struct LSPS1Bolt11PaymentInfo {
172173
pub invoice: Bolt11Invoice,
173174
}
174175

176+
/// A Lightning payment using BOLT 12.
177+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
178+
pub struct LSPS1Bolt12PaymentInfo {
179+
/// Indicates the current state of the payment.
180+
pub state: LSPS1PaymentState,
181+
/// The datetime when the payment option expires.
182+
pub expires_at: LSPSDateTime,
183+
/// The total fee the LSP will charge to open this channel in satoshi.
184+
#[serde(with = "string_amount")]
185+
pub fee_total_sat: u64,
186+
/// The amount the client needs to pay to have the requested channel openend.
187+
#[serde(with = "string_amount")]
188+
pub order_total_sat: u64,
189+
/// A BOLT12 offer the client can pay to have to channel opened.
190+
#[serde(with = "string_offer")]
191+
pub offer: Offer,
192+
}
193+
175194
/// An onchain payment.
176195
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
177196
pub struct LSPS1OnchainPaymentInfo {
@@ -387,6 +406,15 @@ mod tests {
387406
}"#;
388407
let _bolt11_payment: LSPS1Bolt11PaymentInfo = serde_json::from_str(json_str).unwrap();
389408

409+
let json_str = r#"{
410+
"state" : "EXPECT_PAYMENT",
411+
"expires_at": "2025-01-01T00:00:00Z",
412+
"fee_total_sat": "8888",
413+
"order_total_sat": "200888",
414+
"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
415+
}"#;
416+
let _bolt11_payment: LSPS1Bolt12PaymentInfo = serde_json::from_str(json_str).unwrap();
417+
390418
let json_str = r#"{
391419
"state": "EXPECT_PAYMENT",
392420
"expires_at": "2025-01-01T00:00:00Z",
@@ -406,6 +434,13 @@ mod tests {
406434
"order_total_sat": "200888",
407435
"invoice": "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
408436
},
437+
"bolt12": {
438+
"state" : "EXPECT_PAYMENT",
439+
"expires_at": "2025-01-01T00:00:00Z",
440+
"fee_total_sat": "8888",
441+
"order_total_sat": "200888",
442+
"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
443+
},
409444
"onchain": {
410445
"state": "EXPECT_PAYMENT",
411446
"expires_at": "2025-01-01T00:00:00Z",
@@ -416,7 +451,10 @@ mod tests {
416451
"min_fee_for_0conf": 253
417452
}
418453
}"#;
419-
let _payment: LSPS1PaymentInfo = serde_json::from_str(json_str).unwrap();
454+
let payment: LSPS1PaymentInfo = serde_json::from_str(json_str).unwrap();
455+
assert!(payment.bolt11.is_some());
456+
assert!(payment.bolt12.is_some());
457+
assert!(payment.onchain.is_some());
420458

421459
let json_str = r#"{
422460
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c",
@@ -437,6 +475,13 @@ mod tests {
437475
"order_total_sat": "2008888",
438476
"invoice" : "lnbc252u1p3aht9ysp580g4633gd2x9lc5al0wd8wx0mpn9748jeyz46kqjrpxn52uhfpjqpp5qgf67tcqmuqehzgjm8mzya90h73deafvr4m5705l5u5l4r05l8cqdpud3h8ymm4w3jhytnpwpczqmt0de6xsmre2pkxzm3qydmkzdjrdev9s7zhgfaqxqyjw5qcqpjrzjqt6xptnd85lpqnu2lefq4cx070v5cdwzh2xlvmdgnu7gqp4zvkus5zapryqqx9qqqyqqqqqqqqqqqcsq9q9qyysgqen77vu8xqjelum24hgjpgfdgfgx4q0nehhalcmuggt32japhjuksq9jv6eksjfnppm4hrzsgyxt8y8xacxut9qv3fpyetz8t7tsymygq8yzn05"
439477
},
478+
"bolt12": {
479+
"state" : "EXPECT_PAYMENT",
480+
"expires_at": "2025-01-01T00:00:00Z",
481+
"fee_total_sat": "8888",
482+
"order_total_sat": "200888",
483+
"offer": "lno1qgsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcgqvp3pwq2q3shxerxzzfqyxdxxkjqxfpt9tz94zj79m4n99kwjddq92uqryuwsu4nt0t3lthfq02jzqla96dtkf4rew8edxw0p85swe89wd8ldekdl5j262n76qyl2qgzajm08clzr74z6ssy0qlvvp9f5kvrxf27yz4pcy99jge69kxu8ttsqt8gw8jsk5397zvvdf4lfd52paf73thcg6xf57xmvtdrwny5mn2r4jw2d5jzalqrq537mmt6u9qpqytzzql6zemrme07jqqwtza76lldcj9wgc0ccd4d2w584cdcx6szsuupvy"
484+
},
440485
"onchain": {
441486
"state": "EXPECT_PAYMENT",
442487
"expires_at": "2015-01-25T19:29:44.612Z",
@@ -450,8 +495,11 @@ mod tests {
450495
},
451496
"channel": null
452497
}"#;
453-
let _create_order_response: LSPS1CreateOrderResponse =
498+
let create_order_response: LSPS1CreateOrderResponse =
454499
serde_json::from_str(json_str).unwrap();
500+
assert!(create_order_response.payment.bolt11.is_some());
501+
assert!(create_order_response.payment.bolt12.is_some());
502+
assert!(create_order_response.payment.onchain.is_some());
455503

456504
let json_str = r#"{
457505
"order_id": "bb4b5d0a-8334-49d8-9463-90a6d413af7c"

0 commit comments

Comments
 (0)