@@ -4463,6 +4463,91 @@ where
4463
4463
}
4464
4464
}
4465
4465
4466
+ /// Sends a response for a received [`InvoiceRequest`].
4467
+ ///
4468
+ /// The received [`InvoiceRequest`] is first verified to ensure it was created for an
4469
+ /// offer corresponding to the given expanded key. After authentication, the appropriate
4470
+ /// builders are called to generate the response.
4471
+ ///
4472
+ /// Response generation may result in errors in a few cases:
4473
+ ///
4474
+ /// - If there are semantic issues with the received messages, a
4475
+ /// [`Bolt12ResponseError::SemanticError`] is generated, for which a corresponding
4476
+ /// [`InvoiceError`] is created.
4477
+ ///
4478
+ /// - If verification of the received [`InvoiceRequest`] fails, a
4479
+ /// [`Bolt12ResponseError::VerificationError`] is generated. In this case, no
4480
+ /// [`InvoiceError`] is created to prevent probing attacks by potential attackers.
4481
+ ///
4482
+ /// ## Custom Amount:
4483
+ /// The received [`InvoiceRequest`] might not contain the corresponding amount.
4484
+ /// In such cases, the user may provide their custom amount in millisatoshis (msats).
4485
+ /// If the user chooses not to, the builder defaults to using the amount specified in the Offers.
4486
+ ///
4487
+ /// However, if the received [`InvoiceRequest`] does contain an amount, a custom amount must
4488
+ /// not be provided. Doing so will result in a [`Bolt12ResponseError::UnexpectedAmount`].
4489
+ ///
4490
+ /// ## Currency:
4491
+ /// The corresponding [`Offer`] for the received [`InvoiceRequest`] might be denominated
4492
+ /// in [`Amount::Currency`].
4493
+ /// If that is the case, the user must ensure the following:
4494
+ ///
4495
+ /// - If the `InvoiceRequest` contains an amount (denominated in [`Amount::Bitcoin`]),
4496
+ /// it should be checked that it appropriately pays for the amount and quantity specified
4497
+ /// within the corresponding [`Offer`].
4498
+ ///
4499
+ /// - If the `InvoiceRequest` does not contain an amount, an appropriate custom amount
4500
+ /// should be provided to create the corresponding [`Bolt12Invoice`] for the response.
4501
+ ///
4502
+ /// To retry, the user can reuse the same [`InvoiceRequest`] to generate the appropriate
4503
+ /// response.
4504
+ ///
4505
+ /// [`Amount::Bitcoin`]: crate::offers::offer::Amount::Bitcoin
4506
+ /// [`Amount::Currency`]: crate::offers::offer::Amount::Currency
4507
+ pub fn send_invoice_request_response(
4508
+ &self, invoice_request: InvoiceRequest, context: Option<OffersContext>,
4509
+ custom_amount_msat: Option<u64>, responder: Responder
4510
+ ) -> Result<(), Bolt12ResponseError> {
4511
+ let result = self.get_response_for_invoice_request(invoice_request, context, custom_amount_msat);
4512
+ let mut pending_offers_message = self.pending_offers_messages.lock().unwrap();
4513
+
4514
+ match result {
4515
+ Ok((response, payment_hash)) => {
4516
+ match response {
4517
+ OffersMessage::Invoice(invoice) => {
4518
+ let nonce = Nonce::from_entropy_source(&*self.entropy_source);
4519
+ let hmac = payment_hash.hmac_for_offer_payment(nonce, &self.inbound_payment_key);
4520
+ let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash: invoice.payment_hash(), nonce, hmac });
4521
+ let instructions = responder.respond_with_reply_path(context).into_instructions();
4522
+ let message = OffersMessage::Invoice(invoice);
4523
+
4524
+ pending_offers_message.push((message, instructions))
4525
+ },
4526
+ _ => {
4527
+ let instructions = responder.respond().into_instructions();
4528
+
4529
+ pending_offers_message.push((response, instructions))
4530
+ }
4531
+ }
4532
+ }
4533
+ Err(error) => {
4534
+ match error {
4535
+ Bolt12ResponseError::SemanticError(error) => {
4536
+ let invoice_error = InvoiceError::from(error);
4537
+ let message = OffersMessage::InvoiceError(invoice_error);
4538
+
4539
+ let instructions = responder.respond().into_instructions();
4540
+
4541
+ pending_offers_message.push((message, instructions))
4542
+ }
4543
+ _ => return Err(error),
4544
+ }
4545
+ }
4546
+ };
4547
+
4548
+ Ok(())
4549
+ }
4550
+
4466
4551
#[cfg(async_payments)]
4467
4552
fn initiate_async_payment(
4468
4553
&self, invoice: &StaticInvoice, payment_id: PaymentId
0 commit comments