@@ -732,6 +732,31 @@ pub struct OptionalOfferPaymentParams {
732732 /// Contact secrets to include in the invoice request for BLIP-42 contact management.
733733 /// If provided, these secrets will be used to establish a contact relationship with the recipient.
734734 pub contact_secrects: Option<ContactSecrets>,
735+ /// A custom payer offer to include in the invoice request for BLIP-42 contact management.
736+ ///
737+ /// If provided, this offer will be included in the invoice request, allowing the recipient to
738+ /// contact you back. If `None`, **no payer offer will be included** in the invoice request.
739+ ///
740+ /// You can create custom offers using [`OffersMessageFlow::create_compact_offer_builder`]:
741+ /// - Pass `None` for no blinded path (smallest size, ~70 bytes)
742+ /// - Pass `Some(intro_node_id)` for a single blinded path (~200 bytes)
743+ ///
744+ /// # Example
745+ /// ```rust,ignore
746+ /// // Include a compact offer with a single blinded path
747+ /// let payer_offer = flow.create_compact_offer_builder(
748+ /// &entropy_source,
749+ /// Some(trusted_peer_pubkey)
750+ /// )?.build()?;
751+ ///
752+ /// let params = OptionalOfferPaymentParams {
753+ /// payer_offer: Some(payer_offer),
754+ /// ..Default::default()
755+ /// };
756+ /// ```
757+ ///
758+ /// [`OffersMessageFlow::create_compact_offer_builder`]: crate::offers::flow::OffersMessageFlow::create_compact_offer_builder
759+ pub payer_offer: Option<Offer>,
735760}
736761
737762impl Default for OptionalOfferPaymentParams {
@@ -744,6 +769,7 @@ impl Default for OptionalOfferPaymentParams {
744769 #[cfg(not(feature = "std"))]
745770 retry_strategy: Retry::Attempts(3),
746771 contact_secrects: None,
772+ payer_offer: None,
747773 }
748774 }
749775}
@@ -12950,6 +12976,7 @@ where
1295012976 None,
1295112977 create_pending_payment_fn,
1295212978 optional_params.contact_secrects,
12979+ optional_params.payer_offer,
1295312980 )
1295412981 }
1295512982
@@ -12980,6 +13007,7 @@ where
1298013007 Some(offer.hrn),
1298113008 create_pending_payment_fn,
1298213009 optional_params.contact_secrects,
13010+ optional_params.payer_offer,
1298313011 )
1298413012 }
1298513013
@@ -13023,6 +13051,7 @@ where
1302313051 None,
1302413052 create_pending_payment_fn,
1302513053 optional_params.contact_secrects,
13054+ optional_params.payer_offer,
1302613055 )
1302713056 }
1302813057
@@ -13031,7 +13060,7 @@ where
1303113060 &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
1303213061 payer_note: Option<String>, payment_id: PaymentId,
1303313062 human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
13034- contacts: Option<ContactSecrets>,
13063+ contacts: Option<ContactSecrets>, payer_offer: Option<Offer>,
1303513064 ) -> Result<(), Bolt12SemanticError> {
1303613065 let entropy = &*self.entropy_source;
1303713066 let nonce = Nonce::from_entropy_source(entropy);
@@ -13062,11 +13091,14 @@ where
1306213091 } else {
1306313092 builder
1306413093 };
13065- // Create a minimal offer for BLIP-42 contact exchange (just node_id, no description/paths)
13066- // TODO: Create a better minimal offer with a single blinded path hop for privacy,
13067- // while keeping the size small enough to fit in the onion packet.
13068- let payer_offer = self.create_offer_builder()?.build()?;
13069- let builder = builder.payer_offer(&payer_offer);
13094+
13095+ // Add payer offer only if provided by the user.
13096+ // If the user explicitly wants to include an offer, they should provide it via payer_offer parameter.
13097+ let builder = if let Some(offer) = payer_offer {
13098+ builder.payer_offer(&offer)
13099+ } else {
13100+ builder
13101+ };
1307013102
1307113103 let invoice_request = builder.build_and_sign()?;
1307213104 let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -15669,7 +15701,7 @@ where
1566915701 self.pending_outbound_payments
1567015702 .received_offer(payment_id, Some(retryable_invoice_request))
1567115703 .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
15672- }, None);
15704+ }, None, None );
1567315705 if offer_pay_res.is_err() {
1567415706 // The offer we tried to pay is the canonical current offer for the name we
1567515707 // wanted to pay. If we can't pay it, there's no way to recover so fail the
0 commit comments