1use std::sync::{Arc, RwLock};
13
14use bitcoin::hashes::sha256::Hash as Sha256;
15use bitcoin::hashes::Hash;
16use lightning::ln::channelmanager::{
17 Bolt11InvoiceParameters, Bolt11PaymentError, PaymentId, Retry, RetryableSendFailure,
18};
19use lightning::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig};
20use lightning_invoice::{
21 Bolt11Invoice as LdkBolt11Invoice, Bolt11InvoiceDescription as LdkBolt11InvoiceDescription,
22};
23use lightning_types::payment::{PaymentHash, PaymentPreimage};
24
25use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT};
26use crate::connection::ConnectionManager;
27use crate::data_store::DataStoreUpdateResult;
28use crate::error::Error;
29use crate::ffi::{maybe_deref, maybe_try_convert_enum, maybe_wrap};
30use crate::liquidity::LiquiditySource;
31use crate::logger::{log_error, log_info, LdkLogger, Logger};
32use crate::payment::store::{
33 LSPFeeLimits, PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind,
34 PaymentStatus,
35};
36use crate::peer_store::{PeerInfo, PeerStore};
37use crate::runtime::Runtime;
38use crate::types::{ChannelManager, PaymentStore};
39
40#[cfg(not(feature = "uniffi"))]
41type Bolt11Invoice = LdkBolt11Invoice;
42#[cfg(feature = "uniffi")]
43type Bolt11Invoice = Arc<crate::ffi::Bolt11Invoice>;
44
45#[cfg(not(feature = "uniffi"))]
46type Bolt11InvoiceDescription = LdkBolt11InvoiceDescription;
47#[cfg(feature = "uniffi")]
48type Bolt11InvoiceDescription = crate::ffi::Bolt11InvoiceDescription;
49
50pub struct Bolt11Payment {
57 runtime: Arc<Runtime>,
58 channel_manager: Arc<ChannelManager>,
59 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
60 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>,
61 payment_store: Arc<PaymentStore>,
62 peer_store: Arc<PeerStore<Arc<Logger>>>,
63 config: Arc<Config>,
64 is_running: Arc<RwLock<bool>>,
65 logger: Arc<Logger>,
66}
67
68impl Bolt11Payment {
69 pub(crate) fn new(
70 runtime: Arc<Runtime>, channel_manager: Arc<ChannelManager>,
71 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
72 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>,
73 payment_store: Arc<PaymentStore>, peer_store: Arc<PeerStore<Arc<Logger>>>,
74 config: Arc<Config>, is_running: Arc<RwLock<bool>>, logger: Arc<Logger>,
75 ) -> Self {
76 Self {
77 runtime,
78 channel_manager,
79 connection_manager,
80 liquidity_source,
81 payment_store,
82 peer_store,
83 config,
84 is_running,
85 logger,
86 }
87 }
88
89 pub fn send(
94 &self, invoice: &Bolt11Invoice, route_parameters: Option<RouteParametersConfig>,
95 ) -> Result<PaymentId, Error> {
96 if !*self.is_running.read().unwrap() {
97 return Err(Error::NotRunning);
98 }
99
100 let invoice = maybe_deref(invoice);
101 let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array());
102 let payment_id = PaymentId(invoice.payment_hash().to_byte_array());
103 if let Some(payment) = self.payment_store.get(&payment_id) {
104 if payment.status == PaymentStatus::Pending
105 || payment.status == PaymentStatus::Succeeded
106 {
107 log_error!(self.logger, "Payment error: an invoice must not be paid twice.");
108 return Err(Error::DuplicatePayment);
109 }
110 }
111
112 let route_parameters =
113 route_parameters.or(self.config.route_parameters).unwrap_or_default();
114 let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
115 let payment_secret = Some(*invoice.payment_secret());
116
117 match self.channel_manager.pay_for_bolt11_invoice(
118 invoice,
119 payment_id,
120 None,
121 route_parameters,
122 retry_strategy,
123 ) {
124 Ok(()) => {
125 let payee_pubkey = invoice.recover_payee_pub_key();
126 let amt_msat = invoice.amount_milli_satoshis().unwrap();
127 log_info!(self.logger, "Initiated sending {}msat to {}", amt_msat, payee_pubkey);
128
129 let kind = PaymentKind::Bolt11 {
130 hash: payment_hash,
131 preimage: None,
132 secret: payment_secret,
133 };
134 let payment = PaymentDetails::new(
135 payment_id,
136 kind,
137 invoice.amount_milli_satoshis(),
138 None,
139 PaymentDirection::Outbound,
140 PaymentStatus::Pending,
141 );
142
143 self.payment_store.insert(payment)?;
144
145 Ok(payment_id)
146 },
147 Err(Bolt11PaymentError::InvalidAmount) => {
148 log_error!(self.logger,
149 "Failed to send payment due to the given invoice being \"zero-amount\". Please use send_using_amount instead."
150 );
151 return Err(Error::InvalidInvoice);
152 },
153 Err(Bolt11PaymentError::SendingFailed(e)) => {
154 log_error!(self.logger, "Failed to send payment: {:?}", e);
155 match e {
156 RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment),
157 _ => {
158 let kind = PaymentKind::Bolt11 {
159 hash: payment_hash,
160 preimage: None,
161 secret: payment_secret,
162 };
163 let payment = PaymentDetails::new(
164 payment_id,
165 kind,
166 invoice.amount_milli_satoshis(),
167 None,
168 PaymentDirection::Outbound,
169 PaymentStatus::Failed,
170 );
171
172 self.payment_store.insert(payment)?;
173 Err(Error::PaymentSendingFailed)
174 },
175 }
176 },
177 }
178 }
179
180 pub fn send_using_amount(
190 &self, invoice: &Bolt11Invoice, amount_msat: u64,
191 route_parameters: Option<RouteParametersConfig>,
192 ) -> Result<PaymentId, Error> {
193 if !*self.is_running.read().unwrap() {
194 return Err(Error::NotRunning);
195 }
196
197 let invoice = maybe_deref(invoice);
198 if let Some(invoice_amount_msat) = invoice.amount_milli_satoshis() {
199 if amount_msat < invoice_amount_msat {
200 log_error!(
201 self.logger,
202 "Failed to pay as the given amount needs to be at least the invoice amount: required {}msat, gave {}msat.", invoice_amount_msat, amount_msat);
203 return Err(Error::InvalidAmount);
204 }
205 }
206
207 let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array());
208 let payment_id = PaymentId(invoice.payment_hash().to_byte_array());
209 if let Some(payment) = self.payment_store.get(&payment_id) {
210 if payment.status == PaymentStatus::Pending
211 || payment.status == PaymentStatus::Succeeded
212 {
213 log_error!(self.logger, "Payment error: an invoice must not be paid twice.");
214 return Err(Error::DuplicatePayment);
215 }
216 }
217
218 let route_parameters =
219 route_parameters.or(self.config.route_parameters).unwrap_or_default();
220 let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
221 let payment_secret = Some(*invoice.payment_secret());
222
223 match self.channel_manager.pay_for_bolt11_invoice(
224 invoice,
225 payment_id,
226 Some(amount_msat),
227 route_parameters,
228 retry_strategy,
229 ) {
230 Ok(()) => {
231 let payee_pubkey = invoice.recover_payee_pub_key();
232 log_info!(
233 self.logger,
234 "Initiated sending {} msat to {}",
235 amount_msat,
236 payee_pubkey
237 );
238
239 let kind = PaymentKind::Bolt11 {
240 hash: payment_hash,
241 preimage: None,
242 secret: payment_secret,
243 };
244
245 let payment = PaymentDetails::new(
246 payment_id,
247 kind,
248 Some(amount_msat),
249 None,
250 PaymentDirection::Outbound,
251 PaymentStatus::Pending,
252 );
253 self.payment_store.insert(payment)?;
254
255 Ok(payment_id)
256 },
257 Err(Bolt11PaymentError::InvalidAmount) => {
258 log_error!(
259 self.logger,
260 "Failed to send payment due to amount given being insufficient."
261 );
262 return Err(Error::InvalidInvoice);
263 },
264 Err(Bolt11PaymentError::SendingFailed(e)) => {
265 log_error!(self.logger, "Failed to send payment: {:?}", e);
266 match e {
267 RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment),
268 _ => {
269 let kind = PaymentKind::Bolt11 {
270 hash: payment_hash,
271 preimage: None,
272 secret: payment_secret,
273 };
274 let payment = PaymentDetails::new(
275 payment_id,
276 kind,
277 Some(amount_msat),
278 None,
279 PaymentDirection::Outbound,
280 PaymentStatus::Failed,
281 );
282
283 self.payment_store.insert(payment)?;
284 Err(Error::PaymentSendingFailed)
285 },
286 }
287 },
288 }
289 }
290
291 pub fn claim_for_hash(
308 &self, payment_hash: PaymentHash, claimable_amount_msat: u64, preimage: PaymentPreimage,
309 ) -> Result<(), Error> {
310 let payment_id = PaymentId(payment_hash.0);
311
312 let expected_payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
313
314 if expected_payment_hash != payment_hash {
315 log_error!(
316 self.logger,
317 "Failed to manually claim payment as the given preimage doesn't match the hash {}",
318 payment_hash
319 );
320 return Err(Error::InvalidPaymentPreimage);
321 }
322
323 if let Some(details) = self.payment_store.get(&payment_id) {
324 let skimmed_fee_msat = match details.kind {
327 PaymentKind::Bolt11Jit {
328 counterparty_skimmed_fee_msat: Some(skimmed_fee_msat),
329 ..
330 } => skimmed_fee_msat,
331 _ => 0,
332 };
333 if let Some(invoice_amount_msat) = details.amount_msat {
334 if claimable_amount_msat < invoice_amount_msat - skimmed_fee_msat {
335 log_error!(
336 self.logger,
337 "Failed to manually claim payment {} as the claimable amount is less than expected",
338 payment_id
339 );
340 return Err(Error::InvalidAmount);
341 }
342 }
343 } else {
344 log_error!(
345 self.logger,
346 "Failed to manually claim unknown payment with hash: {}",
347 payment_hash
348 );
349 return Err(Error::InvalidPaymentHash);
350 }
351
352 self.channel_manager.claim_funds(preimage);
353 Ok(())
354 }
355
356 pub fn fail_for_hash(&self, payment_hash: PaymentHash) -> Result<(), Error> {
370 let payment_id = PaymentId(payment_hash.0);
371
372 let update = PaymentDetailsUpdate {
373 status: Some(PaymentStatus::Failed),
374 ..PaymentDetailsUpdate::new(payment_id)
375 };
376
377 match self.payment_store.update(&update) {
378 Ok(DataStoreUpdateResult::Updated) | Ok(DataStoreUpdateResult::Unchanged) => (),
379 Ok(DataStoreUpdateResult::NotFound) => {
380 log_error!(
381 self.logger,
382 "Failed to manually fail unknown payment with hash {}",
383 payment_hash,
384 );
385 return Err(Error::InvalidPaymentHash);
386 },
387 Err(e) => {
388 log_error!(
389 self.logger,
390 "Failed to manually fail payment with hash {}: {}",
391 payment_hash,
392 e
393 );
394 return Err(e);
395 },
396 }
397
398 self.channel_manager.fail_htlc_backwards(&payment_hash);
399 Ok(())
400 }
401
402 pub fn receive(
407 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
408 ) -> Result<Bolt11Invoice, Error> {
409 let description = maybe_try_convert_enum(description)?;
410 let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
411 Ok(maybe_wrap(invoice))
412 }
413
414 pub fn receive_for_hash(
429 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
430 payment_hash: PaymentHash,
431 ) -> Result<Bolt11Invoice, Error> {
432 let description = maybe_try_convert_enum(description)?;
433 let invoice =
434 self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
435 Ok(maybe_wrap(invoice))
436 }
437
438 pub fn receive_variable_amount(
443 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
444 ) -> Result<Bolt11Invoice, Error> {
445 let description = maybe_try_convert_enum(description)?;
446 let invoice = self.receive_inner(None, &description, expiry_secs, None)?;
447 Ok(maybe_wrap(invoice))
448 }
449
450 pub fn receive_variable_amount_for_hash(
465 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
466 ) -> Result<Bolt11Invoice, Error> {
467 let description = maybe_try_convert_enum(description)?;
468 let invoice = self.receive_inner(None, &description, expiry_secs, Some(payment_hash))?;
469 Ok(maybe_wrap(invoice))
470 }
471
472 pub(crate) fn receive_inner(
473 &self, amount_msat: Option<u64>, invoice_description: &LdkBolt11InvoiceDescription,
474 expiry_secs: u32, manual_claim_payment_hash: Option<PaymentHash>,
475 ) -> Result<LdkBolt11Invoice, Error> {
476 let invoice = {
477 let invoice_params = Bolt11InvoiceParameters {
478 amount_msats: amount_msat,
479 description: invoice_description.clone(),
480 invoice_expiry_delta_secs: Some(expiry_secs),
481 payment_hash: manual_claim_payment_hash,
482 ..Default::default()
483 };
484
485 match self.channel_manager.create_bolt11_invoice(invoice_params) {
486 Ok(inv) => {
487 log_info!(self.logger, "Invoice created: {}", inv);
488 inv
489 },
490 Err(e) => {
491 log_error!(self.logger, "Failed to create invoice: {}", e);
492 return Err(Error::InvoiceCreationFailed);
493 },
494 }
495 };
496
497 let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array());
498 let payment_secret = invoice.payment_secret();
499 let id = PaymentId(payment_hash.0);
500 let preimage = if manual_claim_payment_hash.is_none() {
501 let res = self
504 .channel_manager
505 .get_payment_preimage(payment_hash, payment_secret.clone())
506 .ok();
507 debug_assert!(res.is_some(), "We just let ChannelManager create an inbound payment, it can't have forgotten the preimage by now.");
508 res
509 } else {
510 None
511 };
512 let kind = PaymentKind::Bolt11 {
513 hash: payment_hash,
514 preimage,
515 secret: Some(payment_secret.clone()),
516 };
517 let payment = PaymentDetails::new(
518 id,
519 kind,
520 amount_msat,
521 None,
522 PaymentDirection::Inbound,
523 PaymentStatus::Pending,
524 );
525 self.payment_store.insert(payment)?;
526
527 Ok(invoice)
528 }
529
530 pub fn receive_via_jit_channel(
541 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
542 max_total_lsp_fee_limit_msat: Option<u64>,
543 ) -> Result<Bolt11Invoice, Error> {
544 let description = maybe_try_convert_enum(description)?;
545 let invoice = self.receive_via_jit_channel_inner(
546 Some(amount_msat),
547 &description,
548 expiry_secs,
549 max_total_lsp_fee_limit_msat,
550 None,
551 None,
552 )?;
553 Ok(maybe_wrap(invoice))
554 }
555
556 pub fn receive_via_jit_channel_for_hash(
580 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
581 max_total_lsp_fee_limit_msat: Option<u64>, payment_hash: PaymentHash,
582 ) -> Result<Bolt11Invoice, Error> {
583 let description = maybe_try_convert_enum(description)?;
584 let invoice = self.receive_via_jit_channel_inner(
585 Some(amount_msat),
586 &description,
587 expiry_secs,
588 max_total_lsp_fee_limit_msat,
589 None,
590 Some(payment_hash),
591 )?;
592 Ok(maybe_wrap(invoice))
593 }
594
595 pub fn receive_variable_amount_via_jit_channel(
607 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
608 max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
609 ) -> Result<Bolt11Invoice, Error> {
610 let description = maybe_try_convert_enum(description)?;
611 let invoice = self.receive_via_jit_channel_inner(
612 None,
613 &description,
614 expiry_secs,
615 None,
616 max_proportional_lsp_fee_limit_ppm_msat,
617 None,
618 )?;
619 Ok(maybe_wrap(invoice))
620 }
621
622 pub fn receive_variable_amount_via_jit_channel_for_hash(
647 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
648 max_proportional_lsp_fee_limit_ppm_msat: Option<u64>, payment_hash: PaymentHash,
649 ) -> Result<Bolt11Invoice, Error> {
650 let description = maybe_try_convert_enum(description)?;
651 let invoice = self.receive_via_jit_channel_inner(
652 None,
653 &description,
654 expiry_secs,
655 None,
656 max_proportional_lsp_fee_limit_ppm_msat,
657 Some(payment_hash),
658 )?;
659 Ok(maybe_wrap(invoice))
660 }
661
662 fn receive_via_jit_channel_inner(
663 &self, amount_msat: Option<u64>, description: &LdkBolt11InvoiceDescription,
664 expiry_secs: u32, max_total_lsp_fee_limit_msat: Option<u64>,
665 max_proportional_lsp_fee_limit_ppm_msat: Option<u64>, payment_hash: Option<PaymentHash>,
666 ) -> Result<LdkBolt11Invoice, Error> {
667 let liquidity_source =
668 self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
669
670 let (node_id, address) =
671 liquidity_source.get_lsps2_lsp_details().ok_or(Error::LiquiditySourceUnavailable)?;
672
673 let peer_info = PeerInfo { node_id, address };
674
675 let con_node_id = peer_info.node_id;
676 let con_addr = peer_info.address.clone();
677 let con_cm = Arc::clone(&self.connection_manager);
678
679 self.runtime.block_on(async move {
682 con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
683 })?;
684
685 log_info!(self.logger, "Connected to LSP {}@{}. ", peer_info.node_id, peer_info.address);
686
687 let liquidity_source = Arc::clone(&liquidity_source);
688 let (invoice, lsp_total_opening_fee, lsp_prop_opening_fee) =
689 self.runtime.block_on(async move {
690 if let Some(amount_msat) = amount_msat {
691 liquidity_source
692 .lsps2_receive_to_jit_channel(
693 amount_msat,
694 description,
695 expiry_secs,
696 max_total_lsp_fee_limit_msat,
697 payment_hash,
698 )
699 .await
700 .map(|(invoice, total_fee)| (invoice, Some(total_fee), None))
701 } else {
702 liquidity_source
703 .lsps2_receive_variable_amount_to_jit_channel(
704 description,
705 expiry_secs,
706 max_proportional_lsp_fee_limit_ppm_msat,
707 payment_hash,
708 )
709 .await
710 .map(|(invoice, prop_fee)| (invoice, None, Some(prop_fee)))
711 }
712 })?;
713
714 let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array());
716 let payment_secret = invoice.payment_secret();
717 let lsp_fee_limits = LSPFeeLimits {
718 max_total_opening_fee_msat: lsp_total_opening_fee,
719 max_proportional_opening_fee_ppm_msat: lsp_prop_opening_fee,
720 };
721 let id = PaymentId(payment_hash.0);
722 let preimage =
723 self.channel_manager.get_payment_preimage(payment_hash, payment_secret.clone()).ok();
724 let kind = PaymentKind::Bolt11Jit {
725 hash: payment_hash,
726 preimage,
727 secret: Some(payment_secret.clone()),
728 counterparty_skimmed_fee_msat: None,
729 lsp_fee_limits,
730 };
731 let payment = PaymentDetails::new(
732 id,
733 kind,
734 amount_msat,
735 None,
736 PaymentDirection::Inbound,
737 PaymentStatus::Pending,
738 );
739 self.payment_store.insert(payment)?;
740
741 self.peer_store.add_peer(peer_info)?;
743
744 Ok(invoice)
745 }
746
747 pub fn send_probes(
764 &self, invoice: &Bolt11Invoice, route_parameters: Option<RouteParametersConfig>,
765 ) -> Result<(), Error> {
766 if !*self.is_running.read().unwrap() {
767 return Err(Error::NotRunning);
768 }
769
770 let invoice = maybe_deref(invoice);
771 let payment_params = PaymentParameters::from_bolt11_invoice(invoice);
772
773 let amount_msat = invoice.amount_milli_satoshis().ok_or_else(|| {
774 log_error!(self.logger, "Failed to send probes due to the given invoice being \"zero-amount\". Please use send_probes_using_amount instead.");
775 Error::InvalidInvoice
776 })?;
777
778 let mut route_params =
779 RouteParameters::from_payment_params_and_value(payment_params, amount_msat);
780
781 if let Some(RouteParametersConfig {
782 max_total_routing_fee_msat,
783 max_total_cltv_expiry_delta,
784 max_path_count,
785 max_channel_saturation_power_of_half,
786 }) = route_parameters.as_ref().or(self.config.route_parameters.as_ref())
787 {
788 route_params.max_total_routing_fee_msat = *max_total_routing_fee_msat;
789 route_params.payment_params.max_total_cltv_expiry_delta = *max_total_cltv_expiry_delta;
790 route_params.payment_params.max_path_count = *max_path_count;
791 route_params.payment_params.max_channel_saturation_power_of_half =
792 *max_channel_saturation_power_of_half;
793 }
794
795 let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
796
797 self.channel_manager
798 .send_preflight_probes(route_params, liquidity_limit_multiplier)
799 .map_err(|e| {
800 log_error!(self.logger, "Failed to send payment probes: {:?}", e);
801 Error::ProbeSendingFailed
802 })?;
803
804 Ok(())
805 }
806
807 pub fn send_probes_using_amount(
818 &self, invoice: &Bolt11Invoice, amount_msat: u64,
819 route_parameters: Option<RouteParametersConfig>,
820 ) -> Result<(), Error> {
821 if !*self.is_running.read().unwrap() {
822 return Err(Error::NotRunning);
823 }
824
825 let invoice = maybe_deref(invoice);
826 let payment_params = PaymentParameters::from_bolt11_invoice(invoice);
827
828 if let Some(invoice_amount_msat) = invoice.amount_milli_satoshis() {
829 if amount_msat < invoice_amount_msat {
830 log_error!(
831 self.logger,
832 "Failed to send probes as the given amount needs to be at least the invoice amount: required {}msat, gave {}msat.",
833 invoice_amount_msat,
834 amount_msat
835 );
836 return Err(Error::InvalidAmount);
837 }
838 }
839
840 let mut route_params =
841 RouteParameters::from_payment_params_and_value(payment_params, amount_msat);
842
843 if let Some(RouteParametersConfig {
844 max_total_routing_fee_msat,
845 max_total_cltv_expiry_delta,
846 max_path_count,
847 max_channel_saturation_power_of_half,
848 }) = route_parameters.as_ref().or(self.config.route_parameters.as_ref())
849 {
850 route_params.max_total_routing_fee_msat = *max_total_routing_fee_msat;
851 route_params.payment_params.max_total_cltv_expiry_delta = *max_total_cltv_expiry_delta;
852 route_params.payment_params.max_path_count = *max_path_count;
853 route_params.payment_params.max_channel_saturation_power_of_half =
854 *max_channel_saturation_power_of_half;
855 }
856
857 let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
858
859 self.channel_manager
860 .send_preflight_probes(route_params, liquidity_limit_multiplier)
861 .map_err(|e| {
862 log_error!(self.logger, "Failed to send payment probes: {:?}", e);
863 Error::ProbeSendingFailed
864 })?;
865
866 Ok(())
867 }
868}