Skip to content

Commit 38b65b2

Browse files
committed
Extract BOLT11 send helper
Share the common BOLT11 payment send flow between fixed-amount and explicit-amount sends so follow-up API variants can reuse the same payment-store and error handling path. AI-Tool-Disclosure: Created with OpenAI Codex.
1 parent 010b483 commit 38b65b2

1 file changed

Lines changed: 47 additions & 103 deletions

File tree

src/payment/bolt11.rs

Lines changed: 47 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -279,20 +279,15 @@ mod tests {
279279
}
280280
}
281281

282-
#[cfg_attr(feature = "uniffi", uniffi::export)]
283282
impl Bolt11Payment {
284-
/// Send a payment given an invoice.
285-
///
286-
/// If `route_parameters` are provided they will override the default as well as the
287-
/// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis.
288-
pub fn send(
289-
&self, invoice: &Bolt11Invoice, route_parameters: Option<RouteParametersConfig>,
283+
fn send_internal(
284+
&self, invoice: &LdkBolt11Invoice, amount_msat: Option<u64>,
285+
route_parameters: Option<RouteParametersConfig>, invalid_amount_log: &'static str,
290286
) -> Result<PaymentId, Error> {
291287
if !*self.is_running.read().expect("lock") {
292288
return Err(Error::NotRunning);
293289
}
294290

295-
let invoice = maybe_deref(invoice);
296291
let payment_hash = invoice.payment_hash();
297292
let payment_id = PaymentId(invoice.payment_hash().0);
298293
if let Some(payment) = self.payment_store.get(&payment_id) {
@@ -308,6 +303,13 @@ impl Bolt11Payment {
308303
route_parameters.or(self.config.route_parameters).unwrap_or_default();
309304
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
310305
let payment_secret = Some(*invoice.payment_secret());
306+
let payment_amount_msat = match amount_msat.or_else(|| invoice.amount_milli_satoshis()) {
307+
Some(amount_msat) => amount_msat,
308+
None => {
309+
log_error!(self.logger, "{}", invalid_amount_log);
310+
return Err(Error::InvalidInvoice);
311+
},
312+
};
311313

312314
let optional_params = OptionalBolt11PaymentParams {
313315
retry_strategy,
@@ -317,14 +319,17 @@ impl Bolt11Payment {
317319
match self.channel_manager.pay_for_bolt11_invoice(
318320
invoice,
319321
payment_id,
320-
None,
322+
amount_msat,
321323
optional_params,
322324
) {
323325
Ok(()) => {
324326
let payee_pubkey = invoice.recover_payee_pub_key();
325-
let amt_msat =
326-
invoice.amount_milli_satoshis().expect("invoice amount should be set");
327-
log_info!(self.logger, "Initiated sending {}msat to {}", amt_msat, payee_pubkey);
327+
log_info!(
328+
self.logger,
329+
"Initiated sending {} msat to {}",
330+
payment_amount_msat,
331+
payee_pubkey
332+
);
328333

329334
let kind = PaymentKind::Bolt11 {
330335
hash: payment_hash,
@@ -335,7 +340,7 @@ impl Bolt11Payment {
335340
let payment = PaymentDetails::new(
336341
payment_id,
337342
kind,
338-
invoice.amount_milli_satoshis(),
343+
Some(payment_amount_msat),
339344
None,
340345
PaymentDirection::Outbound,
341346
PaymentStatus::Pending,
@@ -346,9 +351,7 @@ impl Bolt11Payment {
346351
Ok(payment_id)
347352
},
348353
Err(Bolt11PaymentError::InvalidAmount) => {
349-
log_error!(self.logger,
350-
"Failed to send payment due to the given invoice being \"zero-amount\". Please use send_using_amount instead."
351-
);
354+
log_error!(self.logger, "{}", invalid_amount_log);
352355
return Err(Error::InvalidInvoice);
353356
},
354357
Err(Bolt11PaymentError::SendingFailed(e)) => {
@@ -365,7 +368,7 @@ impl Bolt11Payment {
365368
let payment = PaymentDetails::new(
366369
payment_id,
367370
kind,
368-
invoice.amount_milli_satoshis(),
371+
Some(payment_amount_msat),
369372
None,
370373
PaymentDirection::Outbound,
371374
PaymentStatus::Failed,
@@ -378,6 +381,29 @@ impl Bolt11Payment {
378381
},
379382
}
380383
}
384+
}
385+
386+
#[cfg_attr(feature = "uniffi", uniffi::export)]
387+
impl Bolt11Payment {
388+
/// Send a payment given an invoice.
389+
///
390+
/// If `route_parameters` are provided they will override the default as well as the
391+
/// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis.
392+
pub fn send(
393+
&self, invoice: &Bolt11Invoice, route_parameters: Option<RouteParametersConfig>,
394+
) -> Result<PaymentId, Error> {
395+
if !*self.is_running.read().expect("lock") {
396+
return Err(Error::NotRunning);
397+
}
398+
399+
let invoice = maybe_deref(invoice);
400+
self.send_internal(
401+
invoice,
402+
None,
403+
route_parameters,
404+
"Failed to send payment due to the given invoice being \"zero-amount\". Please use send_using_amount instead.",
405+
)
406+
}
381407

382408
/// Send a payment given an invoice and an amount in millisatoshis.
383409
///
@@ -406,94 +432,12 @@ impl Bolt11Payment {
406432
}
407433
}
408434

409-
let payment_hash = invoice.payment_hash();
410-
let payment_id = PaymentId(invoice.payment_hash().0);
411-
if let Some(payment) = self.payment_store.get(&payment_id) {
412-
if payment.status == PaymentStatus::Pending
413-
|| payment.status == PaymentStatus::Succeeded
414-
{
415-
log_error!(self.logger, "Payment error: an invoice must not be paid twice.");
416-
return Err(Error::DuplicatePayment);
417-
}
418-
}
419-
420-
let route_params_config =
421-
route_parameters.or(self.config.route_parameters).unwrap_or_default();
422-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
423-
let payment_secret = Some(*invoice.payment_secret());
424-
425-
let optional_params = OptionalBolt11PaymentParams {
426-
retry_strategy,
427-
route_params_config,
428-
..Default::default()
429-
};
430-
match self.channel_manager.pay_for_bolt11_invoice(
435+
self.send_internal(
431436
invoice,
432-
payment_id,
433437
Some(amount_msat),
434-
optional_params,
435-
) {
436-
Ok(()) => {
437-
let payee_pubkey = invoice.recover_payee_pub_key();
438-
log_info!(
439-
self.logger,
440-
"Initiated sending {} msat to {}",
441-
amount_msat,
442-
payee_pubkey
443-
);
444-
445-
let kind = PaymentKind::Bolt11 {
446-
hash: payment_hash,
447-
preimage: None,
448-
secret: payment_secret,
449-
counterparty_skimmed_fee_msat: None,
450-
};
451-
452-
let payment = PaymentDetails::new(
453-
payment_id,
454-
kind,
455-
Some(amount_msat),
456-
None,
457-
PaymentDirection::Outbound,
458-
PaymentStatus::Pending,
459-
);
460-
self.runtime.block_on(self.payment_store.insert(payment))?;
461-
462-
Ok(payment_id)
463-
},
464-
Err(Bolt11PaymentError::InvalidAmount) => {
465-
log_error!(
466-
self.logger,
467-
"Failed to send payment due to amount given being insufficient."
468-
);
469-
return Err(Error::InvalidInvoice);
470-
},
471-
Err(Bolt11PaymentError::SendingFailed(e)) => {
472-
log_error!(self.logger, "Failed to send payment: {:?}", e);
473-
match e {
474-
RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment),
475-
_ => {
476-
let kind = PaymentKind::Bolt11 {
477-
hash: payment_hash,
478-
preimage: None,
479-
secret: payment_secret,
480-
counterparty_skimmed_fee_msat: None,
481-
};
482-
let payment = PaymentDetails::new(
483-
payment_id,
484-
kind,
485-
Some(amount_msat),
486-
None,
487-
PaymentDirection::Outbound,
488-
PaymentStatus::Failed,
489-
);
490-
491-
self.runtime.block_on(self.payment_store.insert(payment))?;
492-
Err(Error::PaymentSendingFailed)
493-
},
494-
}
495-
},
496-
}
438+
route_parameters,
439+
"Failed to send payment due to amount given being insufficient.",
440+
)
497441
}
498442

499443
/// Allows to attempt manually claiming payments with the given preimage that have previously

0 commit comments

Comments
 (0)