@@ -5760,6 +5760,15 @@ impl<
57605760 fn send_payment_for_verified_bolt12_invoice(
57615761 &self, invoice: &Bolt12Invoice, payment_id: PaymentId,
57625762 ) -> Result<(), Bolt12PaymentError> {
5763+ self.check_bolt12_invoice_amount(invoice).inspect_err(|e| {
5764+ if matches!(
5765+ e,
5766+ Bolt12PaymentError::InvalidAmount | Bolt12PaymentError::UnsupportedCurrency
5767+ ) {
5768+ self.abandon_payment_with_reason(payment_id, PaymentFailureReason::UnexpectedError);
5769+ }
5770+ })?;
5771+
57635772 let best_block_height = self.best_block.read().unwrap().height;
57645773 let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
57655774 let features = self.bolt12_invoice_features();
@@ -5781,6 +5790,24 @@ impl<
57815790 )
57825791 }
57835792
5793+ fn check_bolt12_invoice_amount(
5794+ &self, invoice: &Bolt12Invoice,
5795+ ) -> Result<(), Bolt12PaymentError> {
5796+ let requested_amount =
5797+ invoice.payable_amount(&self.currency_conversion).map_err(|e| match e {
5798+ Bolt12SemanticError::UnsupportedCurrency => Bolt12PaymentError::UnsupportedCurrency,
5799+ _ => Bolt12PaymentError::UnexpectedInvoice,
5800+ })?;
5801+ // A returned invoice quotes the amount the payee expects to receive. Make
5802+ // sure it matches the payer's locally expected amount before recording the
5803+ // invoice as received or initiating payment.
5804+ if !requested_amount.contains(invoice.amount_msats()) {
5805+ return Err(Bolt12PaymentError::InvalidAmount);
5806+ }
5807+
5808+ Ok(())
5809+ }
5810+
57845811 fn check_refresh_async_receive_offer_cache(&self, timer_tick_occurred: bool) {
57855812 let peers = self.get_peers_for_blinded_path();
57865813 let channels = self.list_usable_channels();
@@ -5789,6 +5816,7 @@ impl<
57895816 peers,
57905817 channels,
57915818 router,
5819+ &self.currency_conversion,
57925820 timer_tick_occurred,
57935821 );
57945822 match refresh_res {
@@ -16909,12 +16937,12 @@ impl<
1690916937{
1691016938 #[rustfmt::skip]
1691116939 fn handle_message(
16912- &self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>,
16913- ) -> Option<(OffersMessage, ResponseInstruction)> {
16914- macro_rules! handle_pay_invoice_res {
16915- ($res: expr, $invoice: expr, $logger: expr) => {{
16916- let error = match $res {
16917- Err(Bolt12PaymentError::UnknownRequiredFeatures) => {
16940+ &self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>,
16941+ ) -> Option<(OffersMessage, ResponseInstruction)> {
16942+ macro_rules! handle_pay_invoice_res {
16943+ ($res: expr, $invoice: expr, $payment_id : expr, $logger: expr) => {{
16944+ let error = match $res {
16945+ Err(Bolt12PaymentError::UnknownRequiredFeatures) => {
1691816946 log_trace!(
1691916947 $logger, "Invoice requires unknown features: {:?}",
1692016948 $invoice.invoice_features()
@@ -16930,6 +16958,13 @@ impl<
1693016958 log_trace!($logger, "{}", err_msg);
1693116959 InvoiceError::from_string(err_msg.to_string())
1693216960 },
16961+ Err(Bolt12PaymentError::InvalidAmount)
16962+ | Err(Bolt12PaymentError::UnsupportedCurrency) => {
16963+ self.abandon_payment_with_reason(
16964+ $payment_id, PaymentFailureReason::UnexpectedError
16965+ );
16966+ return None;
16967+ },
1693316968 Err(Bolt12PaymentError::UnexpectedInvoice)
1693416969 | Err(Bolt12PaymentError::DuplicateInvoice)
1693516970 | Ok(()) => return None,
@@ -16978,6 +17013,7 @@ impl<
1697817013 &self.router,
1697917014 &request,
1698017015 self.list_usable_channels(),
17016+ &self.currency_conversion,
1698117017 get_payment_info,
1698217018 );
1698317019
@@ -17002,6 +17038,7 @@ impl<
1700217038 &self.router,
1700317039 &request,
1700417040 self.list_usable_channels(),
17041+ &self.currency_conversion,
1700517042 get_payment_info,
1700617043 );
1700717044
@@ -17051,6 +17088,10 @@ impl<
1705117088 );
1705217089
1705317090 if self.config.read().unwrap().manually_handle_bolt12_invoices {
17091+ if let Err(e) = self.check_bolt12_invoice_amount(&invoice) {
17092+ handle_pay_invoice_res!(Err(e), invoice, payment_id, logger);
17093+ }
17094+
1705417095 // Update the corresponding entry in `PendingOutboundPayment` for this invoice.
1705517096 // This ensures that event generation remains idempotent in case we receive
1705617097 // the same invoice multiple times.
@@ -17064,15 +17105,15 @@ impl<
1706417105 }
1706517106
1706617107 let res = self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id);
17067- handle_pay_invoice_res!(res, invoice, logger);
17108+ handle_pay_invoice_res!(res, invoice, payment_id, logger);
1706817109 },
1706917110 OffersMessage::StaticInvoice(invoice) => {
1707017111 let payment_id = match context {
1707117112 Some(OffersContext::OutboundPaymentForOffer { payment_id, .. }) => payment_id,
1707217113 _ => return None
1707317114 };
1707417115 let res = self.initiate_async_payment(&invoice, payment_id);
17075- handle_pay_invoice_res!(res, invoice, self.logger);
17116+ handle_pay_invoice_res!(res, invoice, payment_id, self.logger);
1707617117 },
1707717118 OffersMessage::InvoiceError(invoice_error) => {
1707817119 let payment_hash = match context {
@@ -17144,6 +17185,7 @@ impl<
1714417185 self.list_usable_channels(),
1714517186 &self.entropy_source,
1714617187 &self.router,
17188+ &self.currency_conversion,
1714717189 ) {
1714817190 Some((msg, ctx)) => (msg, ctx),
1714917191 None => return None,
0 commit comments