Skip to content

Commit 47c2c95

Browse files
committed
Add LSPS2 commands to ldk-server-client and ldk-server-cli
Expose the new LSPS2 JIT invoice endpoints through the Rust client and CLI so callers can request either fixed or variable-amount invoices without constructing protobuf messages manually. Generated with the assistance of AI. Co-Authored-By: HAL 9000
1 parent 9b48868 commit 47c2c95

2 files changed

Lines changed: 123 additions & 18 deletions

File tree

ldk-server-cli/src/main.rs

Lines changed: 94 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use ldk_server_client::error::LdkServerErrorCode::{
2424
use ldk_server_client::ldk_server_protos::api::{
2525
Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, Bolt11FailForHashRequest,
2626
Bolt11FailForHashResponse, Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse,
27-
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse,
27+
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest,
28+
Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest,
29+
Bolt11ReceiveViaJitChannelResponse, Bolt11SendRequest, Bolt11SendResponse,
2830
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
2931
CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse,
3032
DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest,
@@ -178,6 +180,41 @@ enum Commands {
178180
#[arg(help = "The hex-encoded 32-byte payment hash")]
179181
payment_hash: String,
180182
},
183+
#[command(about = "Create a fixed-amount BOLT11 invoice to receive via an LSPS2 JIT channel")]
184+
Bolt11ReceiveViaJitChannel {
185+
#[arg(help = "Amount to request, e.g. 50sat or 50000msat")]
186+
amount: Amount,
187+
#[arg(short, long, help = "Description to attach along with the invoice")]
188+
description: Option<String>,
189+
#[arg(
190+
long,
191+
help = "SHA-256 hash of the description (hex). Use instead of description for longer text"
192+
)]
193+
description_hash: Option<String>,
194+
#[arg(short, long, help = "Invoice expiry time in seconds (default: 86400)")]
195+
expiry_secs: Option<u32>,
196+
#[arg(
197+
long,
198+
help = "Maximum total fee an LSP may deduct for opening the JIT channel, e.g. 50sat or 50000msat"
199+
)]
200+
max_total_lsp_fee_limit: Option<Amount>,
201+
},
202+
#[command(
203+
about = "Create a variable-amount BOLT11 invoice to receive via an LSPS2 JIT channel"
204+
)]
205+
Bolt11ReceiveVariableAmountViaJitChannel {
206+
#[arg(short, long, help = "Description to attach along with the invoice")]
207+
description: Option<String>,
208+
#[arg(
209+
long,
210+
help = "SHA-256 hash of the description (hex). Use instead of description for longer text"
211+
)]
212+
description_hash: Option<String>,
213+
#[arg(short, long, help = "Invoice expiry time in seconds (default: 86400)")]
214+
expiry_secs: Option<u32>,
215+
#[arg(long, help = "Maximum proportional fee the LSP may deduct in ppm-msat")]
216+
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
217+
},
181218
#[command(about = "Pay a BOLT11 invoice")]
182219
Bolt11Send {
183220
#[arg(help = "A BOLT11 invoice for a payment within the Lightning Network")]
@@ -571,21 +608,8 @@ async fn main() {
571608
},
572609
Commands::Bolt11Receive { description, description_hash, expiry_secs, amount } => {
573610
let amount_msat = amount.map(|a| a.to_msat());
574-
let invoice_description = match (description, description_hash) {
575-
(Some(desc), None) => Some(Bolt11InvoiceDescription {
576-
kind: Some(bolt11_invoice_description::Kind::Direct(desc)),
577-
}),
578-
(None, Some(hash)) => Some(Bolt11InvoiceDescription {
579-
kind: Some(bolt11_invoice_description::Kind::Hash(hash)),
580-
}),
581-
(Some(_), Some(_)) => {
582-
handle_error(LdkServerError::new(
583-
InternalError,
584-
"Only one of description or description_hash can be set.".to_string(),
585-
));
586-
},
587-
(None, None) => None,
588-
};
611+
let invoice_description =
612+
parse_bolt11_invoice_description(description, description_hash);
589613

590614
let expiry_secs = expiry_secs.unwrap_or(DEFAULT_EXPIRY_SECS);
591615
let request =
@@ -647,6 +671,40 @@ async fn main() {
647671
client.bolt11_fail_for_hash(Bolt11FailForHashRequest { payment_hash }).await,
648672
);
649673
},
674+
Commands::Bolt11ReceiveViaJitChannel {
675+
amount,
676+
description,
677+
description_hash,
678+
expiry_secs,
679+
max_total_lsp_fee_limit,
680+
} => {
681+
let request = Bolt11ReceiveViaJitChannelRequest {
682+
amount_msat: amount.to_msat(),
683+
description: parse_bolt11_invoice_description(description, description_hash),
684+
expiry_secs: expiry_secs.unwrap_or(DEFAULT_EXPIRY_SECS),
685+
max_total_lsp_fee_limit_msat: max_total_lsp_fee_limit.map(|a| a.to_msat()),
686+
};
687+
688+
handle_response_result::<_, Bolt11ReceiveViaJitChannelResponse>(
689+
client.bolt11_receive_via_jit_channel(request).await,
690+
);
691+
},
692+
Commands::Bolt11ReceiveVariableAmountViaJitChannel {
693+
description,
694+
description_hash,
695+
expiry_secs,
696+
max_proportional_lsp_fee_limit_ppm_msat,
697+
} => {
698+
let request = Bolt11ReceiveVariableAmountViaJitChannelRequest {
699+
description: parse_bolt11_invoice_description(description, description_hash),
700+
expiry_secs: expiry_secs.unwrap_or(DEFAULT_EXPIRY_SECS),
701+
max_proportional_lsp_fee_limit_ppm_msat,
702+
};
703+
704+
handle_response_result::<_, Bolt11ReceiveVariableAmountViaJitChannelResponse>(
705+
client.bolt11_receive_variable_amount_via_jit_channel(request).await,
706+
);
707+
},
650708
Commands::Bolt11Send {
651709
invoice,
652710
amount,
@@ -1054,6 +1112,26 @@ where
10541112
}
10551113
}
10561114

1115+
fn parse_bolt11_invoice_description(
1116+
description: Option<String>, description_hash: Option<String>,
1117+
) -> Option<Bolt11InvoiceDescription> {
1118+
match (description, description_hash) {
1119+
(Some(desc), None) => Some(Bolt11InvoiceDescription {
1120+
kind: Some(bolt11_invoice_description::Kind::Direct(desc)),
1121+
}),
1122+
(None, Some(hash)) => Some(Bolt11InvoiceDescription {
1123+
kind: Some(bolt11_invoice_description::Kind::Hash(hash)),
1124+
}),
1125+
(Some(_), Some(_)) => {
1126+
handle_error(LdkServerError::new(
1127+
InternalError,
1128+
"Only one of description or description_hash can be set.".to_string(),
1129+
));
1130+
},
1131+
(None, None) => None,
1132+
}
1133+
}
1134+
10571135
fn parse_page_token(token_str: &str) -> Result<PageToken, LdkServerError> {
10581136
let parts: Vec<&str> = token_str.split(':').collect();
10591137
if parts.len() != 2 {

ldk-server-client/src/client.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use bitcoin_hashes::{sha256, Hash, HashEngine};
1414
use ldk_server_protos::api::{
1515
Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, Bolt11FailForHashRequest,
1616
Bolt11FailForHashResponse, Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse,
17-
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse,
17+
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest,
18+
Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest,
19+
Bolt11ReceiveViaJitChannelResponse, Bolt11SendRequest, Bolt11SendResponse,
1820
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
1921
CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse,
2022
DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest,
@@ -33,7 +35,8 @@ use ldk_server_protos::api::{
3335
};
3436
use ldk_server_protos::endpoints::{
3537
BOLT11_CLAIM_FOR_HASH_PATH, BOLT11_FAIL_FOR_HASH_PATH, BOLT11_RECEIVE_FOR_HASH_PATH,
36-
BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH,
38+
BOLT11_RECEIVE_PATH, BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH,
39+
BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH,
3740
CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH,
3841
FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH,
3942
GRAPH_GET_CHANNEL_PATH, GRAPH_GET_NODE_PATH, GRAPH_LIST_CHANNELS_PATH, GRAPH_LIST_NODES_PATH,
@@ -174,6 +177,30 @@ impl LdkServerClient {
174177
self.post_request(&request, &url).await
175178
}
176179

180+
/// Retrieve a new fixed-amount BOLT11 invoice for receiving via an LSPS2 JIT channel.
181+
/// For API contract/usage, refer to docs for [`Bolt11ReceiveViaJitChannelRequest`] and
182+
/// [`Bolt11ReceiveViaJitChannelResponse`].
183+
pub async fn bolt11_receive_via_jit_channel(
184+
&self, request: Bolt11ReceiveViaJitChannelRequest,
185+
) -> Result<Bolt11ReceiveViaJitChannelResponse, LdkServerError> {
186+
let url = format!("https://{}/{BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH}", self.base_url);
187+
self.post_request(&request, &url).await
188+
}
189+
190+
/// Retrieve a new variable-amount BOLT11 invoice for receiving via an LSPS2 JIT channel.
191+
/// For API contract/usage, refer to docs for
192+
/// [`Bolt11ReceiveVariableAmountViaJitChannelRequest`] and
193+
/// [`Bolt11ReceiveVariableAmountViaJitChannelResponse`].
194+
pub async fn bolt11_receive_variable_amount_via_jit_channel(
195+
&self, request: Bolt11ReceiveVariableAmountViaJitChannelRequest,
196+
) -> Result<Bolt11ReceiveVariableAmountViaJitChannelResponse, LdkServerError> {
197+
let url = format!(
198+
"https://{}/{BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH}",
199+
self.base_url,
200+
);
201+
self.post_request(&request, &url).await
202+
}
203+
177204
/// Send a payment for a BOLT11 invoice.
178205
/// For API contract/usage, refer to docs for [`Bolt11SendRequest`] and [`Bolt11SendResponse`].
179206
pub async fn bolt11_send(

0 commit comments

Comments
 (0)