Skip to content

Add BOLT12 support to bLIP-51 / LSPS1 #3649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lightning-liquidity/src/lsps0/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S>(x: &Offer, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(&x.to_string())
}

pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Offer, D::Error>
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;
Expand Down
58 changes: 54 additions & 4 deletions lightning-liquidity/src/lsps1/msgs.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -151,6 +152,8 @@ pub enum LSPS1OrderState {
pub struct LSPS1PaymentInfo {
/// A Lightning payment using BOLT 11.
pub bolt11: Option<LSPS1Bolt11PaymentInfo>,
/// A Lightning payment using BOLT 12.
pub bolt12: Option<LSPS1Bolt12PaymentInfo>,
/// An onchain payment.
pub onchain: Option<LSPS1OnchainPaymentInfo>,
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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"
Expand Down
Loading