Skip to content

Commit e34038e

Browse files
committed
Add BOLT11 underpaying send RPC
Expose Bolt11SendUnderpaying through the proto API, server handler, client, CLI, MCP tool registry, tests, and docs. AI-assisted-by: OpenAI Codex
1 parent 9f960bc commit e34038e

13 files changed

Lines changed: 309 additions & 50 deletions

File tree

docs/api-guide.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,17 @@ All RPCs are unary (single request, single response) unless noted otherwise.
9393

9494
### BOLT11 Payments
9595

96-
| RPC | Description |
97-
|-----------------|-------------------------------------------------------------------|
98-
| `Bolt11Receive` | Create an invoice (fixed or variable amount) with automatic claim |
99-
| `Bolt11Send` | Pay a BOLT11 invoice (with optional routing config) |
96+
| RPC | Description |
97+
|-------------------------|-------------------------------------------------------------------|
98+
| `Bolt11Receive` | Create an invoice (fixed or variable amount) with automatic claim |
99+
| `Bolt11Send` | Pay a BOLT11 invoice (with optional routing config) |
100+
| `Bolt11SendUnderpaying` | Send part of the amount for a BOLT11 invoice |
101+
102+
> [!NOTE]
103+
> `Bolt11SendUnderpaying` sends one part of a multi-part payment (MPP) for a BOLT11
104+
> invoice. Other nodes must send compatible partial payments for the same invoice until
105+
> the combined amount equals the invoice amount. Without those payments, the receiver
106+
> holds the incomplete MPP payment and eventually fails it.
100107
101108
### BOLT11 Hodl Invoices
102109

e2e-tests/tests/e2e.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,58 @@ async fn test_cli_bolt11_send() {
817817
assert!(matches!(&event_b.event, Some(Event::PaymentReceived(_))));
818818
}
819819

820+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
821+
async fn test_cli_bolt11_send_underpaying_split_payment() {
822+
let bitcoind = TestBitcoind::new();
823+
let server_a = LdkServerHandle::start(&bitcoind).await;
824+
let server_b = LdkServerHandle::start(&bitcoind).await;
825+
let server_c = LdkServerHandle::start(&bitcoind).await;
826+
827+
// Subscribe to events on all three nodes before any payment is sent.
828+
let mut events_a = server_a.client().subscribe_events().await.unwrap();
829+
let mut events_b = server_b.client().subscribe_events().await.unwrap();
830+
let mut events_c = server_c.client().subscribe_events().await.unwrap();
831+
832+
// Each payer gets its own direct channel into the receiver. The channels are sized well
833+
// above the 50,000 sat HTLCs because LDK limits a channel's maximum HTLC size to a fraction
834+
// of its capacity.
835+
setup_funded_channel(&bitcoind, &server_a, &server_c, 300_000).await;
836+
setup_funded_channel(&bitcoind, &server_b, &server_c, 300_000).await;
837+
838+
// Create one invoice for the full amount that the two payers will jointly cover.
839+
let invoice_resp = server_c
840+
.client()
841+
.bolt11_receive(Bolt11ReceiveRequest {
842+
amount_msat: Some(100_000_000),
843+
description: Some(Bolt11InvoiceDescription {
844+
kind: Some(bolt11_invoice_description::Kind::Direct(
845+
"split payment test".to_string(),
846+
)),
847+
}),
848+
expiry_secs: 3600,
849+
})
850+
.await
851+
.unwrap();
852+
853+
// Both payers independently send half of the invoice amount.
854+
let output_a =
855+
run_cli(&server_a, &["bolt11-send-underpaying", &invoice_resp.invoice, "50000sat"]);
856+
let output_b =
857+
run_cli(&server_b, &["bolt11-send-underpaying", &invoice_resp.invoice, "50000sat"]);
858+
assert!(!output_a["payment_id"].as_str().unwrap().is_empty());
859+
assert!(!output_b["payment_id"].as_str().unwrap().is_empty());
860+
861+
// The receiver completes the payment only after both partial HTLCs arrive.
862+
let event_c = wait_for_event(&mut events_c, |e| matches!(e, Event::PaymentReceived(_))).await;
863+
assert!(matches!(&event_c.event, Some(Event::PaymentReceived(_))));
864+
865+
// Both payers complete their part of the payment successfully.
866+
let event_a = wait_for_event(&mut events_a, |e| matches!(e, Event::PaymentSuccessful(_))).await;
867+
assert!(matches!(&event_a.event, Some(Event::PaymentSuccessful(_))));
868+
let event_b = wait_for_event(&mut events_b, |e| matches!(e, Event::PaymentSuccessful(_))).await;
869+
assert!(matches!(&event_b.event, Some(Event::PaymentSuccessful(_))));
870+
}
871+
820872
#[tokio::test]
821873
async fn test_cli_pay() {
822874
let bitcoind = TestBitcoind::new();

ldk-server-cli/src/main.rs

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ use ldk_server_client::ldk_server_grpc::api::{
2828
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest,
2929
Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest,
3030
Bolt11ReceiveViaJitChannelResponse, Bolt11SendRequest, Bolt11SendResponse,
31-
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
32-
CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse,
33-
DecodeInvoiceRequest, DecodeInvoiceResponse, DecodeOfferRequest, DecodeOfferResponse,
34-
DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest,
35-
ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse,
36-
GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse,
31+
Bolt11SendUnderpayingRequest, Bolt11SendUnderpayingResponse, Bolt12ReceiveRequest,
32+
Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest,
33+
CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, DecodeInvoiceRequest,
34+
DecodeInvoiceResponse, DecodeOfferRequest, DecodeOfferResponse, DisconnectPeerRequest,
35+
DisconnectPeerResponse, ExportPathfindingScoresRequest, ForceCloseChannelRequest,
36+
ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest,
37+
GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse,
3738
GraphGetChannelRequest, GraphGetChannelResponse, GraphGetNodeRequest, GraphGetNodeResponse,
3839
GraphListChannelsRequest, GraphListChannelsResponse, GraphListNodesRequest,
3940
GraphListNodesResponse, ListChannelsRequest, ListChannelsResponse,
@@ -246,6 +247,34 @@ enum Commands {
246247
)]
247248
max_channel_saturation_power_of_half: Option<u32>,
248249
},
250+
#[command(
251+
about = "Send part of a BOLT11 invoice. Other nodes must send partial payments for the same invoice until the combined amount equals the invoice amount"
252+
)]
253+
Bolt11SendUnderpaying {
254+
#[arg(help = "A BOLT11 invoice for a payment within the Lightning Network")]
255+
invoice: String,
256+
#[arg(
257+
help = "Amount from this payer, for example 50sat or 50000msat. Must be less than the invoice amount"
258+
)]
259+
amount: Amount,
260+
#[arg(
261+
long,
262+
help = "Maximum total routing fee, e.g. 50sat or 50000msat. Defaults to 1% of payment + 50 sats"
263+
)]
264+
max_total_routing_fee: Option<Amount>,
265+
#[arg(long, help = "Maximum total CLTV delta we accept for the route (default: 1008)")]
266+
max_total_cltv_expiry_delta: Option<u32>,
267+
#[arg(
268+
long,
269+
help = "Maximum number of paths that may be used by MPP payments (default: 10)"
270+
)]
271+
max_path_count: Option<u32>,
272+
#[arg(
273+
long,
274+
help = "Maximum share of a channel's total capacity to send over a channel, as a power of 1/2 (default: 2)"
275+
)]
276+
max_channel_saturation_power_of_half: Option<u32>,
277+
},
249278
#[command(about = "Return a BOLT12 offer for receiving payments")]
250279
Bolt12Receive {
251280
#[arg(help = "Description to attach along with the offer")]
@@ -765,6 +794,34 @@ async fn main() {
765794
.await,
766795
);
767796
},
797+
Commands::Bolt11SendUnderpaying {
798+
invoice,
799+
amount,
800+
max_total_routing_fee,
801+
max_total_cltv_expiry_delta,
802+
max_path_count,
803+
max_channel_saturation_power_of_half,
804+
} => {
805+
let amount_msat = amount.to_msat();
806+
let max_total_routing_fee_msat = max_total_routing_fee.map(|a| a.to_msat());
807+
let route_parameters = RouteParametersConfig {
808+
max_total_routing_fee_msat,
809+
max_total_cltv_expiry_delta: max_total_cltv_expiry_delta
810+
.unwrap_or(DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA),
811+
max_path_count: max_path_count.unwrap_or(DEFAULT_MAX_PATH_COUNT),
812+
max_channel_saturation_power_of_half: max_channel_saturation_power_of_half
813+
.unwrap_or(DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF),
814+
};
815+
handle_response_result::<_, Bolt11SendUnderpayingResponse>(
816+
client
817+
.bolt11_send_underpaying(Bolt11SendUnderpayingRequest {
818+
invoice,
819+
amount_msat,
820+
route_parameters: Some(route_parameters),
821+
})
822+
.await,
823+
);
824+
},
768825
Commands::Bolt12Receive { description, amount, expiry_secs, quantity } => {
769826
let amount_msat = amount.map(|a| a.to_msat());
770827
handle_response_result::<_, Bolt12ReceiveResponse>(

ldk-server-client/src/client.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,38 @@ use ldk_server_grpc::api::{
2121
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest,
2222
Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest,
2323
Bolt11ReceiveViaJitChannelResponse, Bolt11SendRequest, Bolt11SendResponse,
24-
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
25-
CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse,
26-
DecodeInvoiceRequest, DecodeInvoiceResponse, DecodeOfferRequest, DecodeOfferResponse,
27-
DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest,
28-
ExportPathfindingScoresResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
29-
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
30-
GetPaymentDetailsRequest, GetPaymentDetailsResponse, GraphGetChannelRequest,
31-
GraphGetChannelResponse, GraphGetNodeRequest, GraphGetNodeResponse, GraphListChannelsRequest,
32-
GraphListChannelsResponse, GraphListNodesRequest, GraphListNodesResponse, ListChannelsRequest,
33-
ListChannelsResponse, ListForwardedPaymentsRequest, ListForwardedPaymentsResponse,
34-
ListPaymentsRequest, ListPaymentsResponse, ListPeersRequest, ListPeersResponse,
35-
OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse,
36-
OpenChannelRequest, OpenChannelResponse, SignMessageRequest, SignMessageResponse,
37-
SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, SpontaneousSendRequest,
24+
Bolt11SendUnderpayingRequest, Bolt11SendUnderpayingResponse, Bolt12ReceiveRequest,
25+
Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest,
26+
CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, DecodeInvoiceRequest,
27+
DecodeInvoiceResponse, DecodeOfferRequest, DecodeOfferResponse, DisconnectPeerRequest,
28+
DisconnectPeerResponse, ExportPathfindingScoresRequest, ExportPathfindingScoresResponse,
29+
ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse,
30+
GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse,
31+
GraphGetChannelRequest, GraphGetChannelResponse, GraphGetNodeRequest, GraphGetNodeResponse,
32+
GraphListChannelsRequest, GraphListChannelsResponse, GraphListNodesRequest,
33+
GraphListNodesResponse, ListChannelsRequest, ListChannelsResponse,
34+
ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, ListPaymentsRequest,
35+
ListPaymentsResponse, ListPeersRequest, ListPeersResponse, OnchainReceiveRequest,
36+
OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest,
37+
OpenChannelResponse, SignMessageRequest, SignMessageResponse, SpliceInRequest,
38+
SpliceInResponse, SpliceOutRequest, SpliceOutResponse, SpontaneousSendRequest,
3839
SpontaneousSendResponse, SubscribeEventsRequest, UnifiedSendRequest, UnifiedSendResponse,
3940
UpdateChannelConfigRequest, UpdateChannelConfigResponse, VerifySignatureRequest,
4041
VerifySignatureResponse,
4142
};
4243
use ldk_server_grpc::endpoints::{
4344
BOLT11_CLAIM_FOR_HASH_PATH, BOLT11_FAIL_FOR_HASH_PATH, BOLT11_RECEIVE_FOR_HASH_PATH,
4445
BOLT11_RECEIVE_PATH, BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH,
45-
BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH,
46-
CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DECODE_INVOICE_PATH, DECODE_OFFER_PATH,
47-
DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, FORCE_CLOSE_CHANNEL_PATH,
48-
GET_BALANCES_PATH, GET_METRICS_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH,
49-
GRAPH_GET_CHANNEL_PATH, GRAPH_GET_NODE_PATH, GRAPH_LIST_CHANNELS_PATH, GRAPH_LIST_NODES_PATH,
50-
GRPC_SERVICE_PREFIX, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH,
51-
LIST_PEERS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH,
52-
SPLICE_IN_PATH, SPLICE_OUT_PATH, SPONTANEOUS_SEND_PATH, SUBSCRIBE_EVENTS_PATH,
53-
UNIFIED_SEND_PATH, UPDATE_CHANNEL_CONFIG_PATH, VERIFY_SIGNATURE_PATH,
46+
BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH, BOLT11_SEND_PATH, BOLT11_SEND_UNDERPAYING_PATH,
47+
BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH,
48+
DECODE_INVOICE_PATH, DECODE_OFFER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH,
49+
FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_METRICS_PATH, GET_NODE_INFO_PATH,
50+
GET_PAYMENT_DETAILS_PATH, GRAPH_GET_CHANNEL_PATH, GRAPH_GET_NODE_PATH,
51+
GRAPH_LIST_CHANNELS_PATH, GRAPH_LIST_NODES_PATH, GRPC_SERVICE_PREFIX, LIST_CHANNELS_PATH,
52+
LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, LIST_PEERS_PATH, ONCHAIN_RECEIVE_PATH,
53+
ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH,
54+
SPONTANEOUS_SEND_PATH, SUBSCRIBE_EVENTS_PATH, UNIFIED_SEND_PATH, UPDATE_CHANNEL_CONFIG_PATH,
55+
VERIFY_SIGNATURE_PATH,
5456
};
5557
use ldk_server_grpc::events::EventEnvelope;
5658
use ldk_server_grpc::grpc::{
@@ -242,6 +244,17 @@ impl LdkServerClient {
242244
self.grpc_unary(&request, BOLT11_SEND_PATH).await
243245
}
244246

247+
/// Send part of the amount for a BOLT11 invoice.
248+
///
249+
/// Other nodes must send partial payments for the same invoice until the combined amount equals
250+
/// the invoice amount. Without those payments, the receiver holds the incomplete MPP payment
251+
/// and eventually fails it.
252+
pub async fn bolt11_send_underpaying(
253+
&self, request: Bolt11SendUnderpayingRequest,
254+
) -> Result<Bolt11SendUnderpayingResponse, LdkServerError> {
255+
self.grpc_unary(&request, BOLT11_SEND_UNDERPAYING_PATH).await
256+
}
257+
245258
/// Retrieve a new BOLT12 offer.
246259
pub async fn bolt12_receive(
247260
&self, request: Bolt12ReceiveRequest,

ldk-server-grpc/src/api.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,37 @@ pub struct Bolt11SendResponse {
376376
#[prost(string, tag = "1")]
377377
pub payment_id: ::prost::alloc::string::String,
378378
}
379+
/// Send part of the amount for a BOLT11 invoice.
380+
/// Other nodes must send partial payments for the same invoice until the combined amount equals the invoice amount.
381+
/// Without those payments, the receiver holds the incomplete MPP payment and eventually fails it.
382+
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send_using_amount_underpaying>
383+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
384+
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
385+
#[cfg_attr(feature = "serde", serde(default))]
386+
#[allow(clippy::derive_partial_eq_without_eq)]
387+
#[derive(Clone, PartialEq, ::prost::Message)]
388+
pub struct Bolt11SendUnderpayingRequest {
389+
/// An invoice for a payment within the Lightning Network.
390+
#[prost(string, tag = "1")]
391+
pub invoice: ::prost::alloc::string::String,
392+
/// Amount in millisatoshis from this payer. Must be less than the amount required by the invoice.
393+
#[prost(uint64, tag = "2")]
394+
pub amount_msat: u64,
395+
/// Configuration options for payment routing and pathfinding.
396+
#[prost(message, optional, tag = "3")]
397+
pub route_parameters: ::core::option::Option<super::types::RouteParametersConfig>,
398+
}
399+
/// The response for the `Bolt11SendUnderpaying` RPC. On failure, a gRPC error status is returned.
400+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
401+
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
402+
#[cfg_attr(feature = "serde", serde(default))]
403+
#[allow(clippy::derive_partial_eq_without_eq)]
404+
#[derive(Clone, PartialEq, ::prost::Message)]
405+
pub struct Bolt11SendUnderpayingResponse {
406+
/// An identifier used to uniquely identify a payment in hex-encoded form.
407+
#[prost(string, tag = "1")]
408+
pub payment_id: ::prost::alloc::string::String,
409+
}
379410
/// Returns a BOLT12 offer for the given amount, if specified.
380411
///
381412
/// See more:

ldk-server-grpc/src/endpoints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub const BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH: &str = "Bolt11ReceiveViaJitChanne
2222
pub const BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH: &str =
2323
"Bolt11ReceiveVariableAmountViaJitChannel";
2424
pub const BOLT11_SEND_PATH: &str = "Bolt11Send";
25+
pub const BOLT11_SEND_UNDERPAYING_PATH: &str = "Bolt11SendUnderpaying";
2526
pub const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive";
2627
pub const BOLT12_SEND_PATH: &str = "Bolt12Send";
2728
pub const OPEN_CHANNEL_PATH: &str = "OpenChannel";

ldk-server-grpc/src/proto/api.proto

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,30 @@ message Bolt11SendResponse {
296296
string payment_id = 1;
297297
}
298298

299+
// Send part of the amount for a BOLT11 invoice.
300+
// Other nodes must send partial payments for the same invoice until the combined amount equals the invoice amount.
301+
// Without those payments, the receiver holds the incomplete MPP payment and eventually fails it.
302+
// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send_using_amount_underpaying
303+
message Bolt11SendUnderpayingRequest {
304+
305+
// An invoice for a payment within the Lightning Network.
306+
string invoice = 1;
307+
308+
// Amount in millisatoshis from this payer. Must be less than the amount required by the invoice.
309+
uint64 amount_msat = 2;
310+
311+
// Configuration options for payment routing and pathfinding.
312+
optional types.RouteParametersConfig route_parameters = 3;
313+
314+
}
315+
316+
// The response for the `Bolt11SendUnderpaying` RPC. On failure, a gRPC error status is returned.
317+
message Bolt11SendUnderpayingResponse {
318+
319+
// An identifier used to uniquely identify a payment in hex-encoded form.
320+
string payment_id = 1;
321+
}
322+
299323
// Returns a BOLT12 offer for the given amount, if specified.
300324
//
301325
// See more:
@@ -928,6 +952,9 @@ service LightningNode {
928952
rpc Bolt11ReceiveVariableAmountViaJitChannel(Bolt11ReceiveVariableAmountViaJitChannelRequest) returns (Bolt11ReceiveVariableAmountViaJitChannelResponse);
929953
// Send a payment for a BOLT11 invoice.
930954
rpc Bolt11Send(Bolt11SendRequest) returns (Bolt11SendResponse);
955+
// Send part of the amount for a BOLT11 invoice.
956+
// Other nodes must send partial payments for the same invoice until the combined amount equals the invoice amount.
957+
rpc Bolt11SendUnderpaying(Bolt11SendUnderpayingRequest) returns (Bolt11SendUnderpayingResponse);
931958
// Return a BOLT12 offer.
932959
rpc Bolt12Receive(Bolt12ReceiveRequest) returns (Bolt12ReceiveResponse);
933960
// Send a payment for a BOLT12 offer.

0 commit comments

Comments
 (0)