@@ -4463,6 +4463,91 @@ where
44634463 }
44644464 }
44654465
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+
44664551 #[cfg(async_payments)]
44674552 fn initiate_async_payment(
44684553 &self, invoice: &StaticInvoice, payment_id: PaymentId
0 commit comments