@@ -1526,6 +1526,105 @@ where
15261526/// # }
15271527/// ```
15281528///
1529+ /// ## BOLT 12 Offers
1530+ ///
1531+ /// The [`offers`] module is useful for creating BOLT 12 offers. An [`Offer`] is a precursor to a
1532+ /// [`Bolt12Invoice`], which must first be requested by the payer. The interchange of these messages
1533+ /// as defined in the specification is handled by [`ChannelManager`] and its implementation of
1534+ /// [`OffersMessageHandler`]. However, this only works with an [`Offer`] created using a builder
1535+ /// returned by [`create_offer_builder`]. With this approach, BOLT 12 offers and invoices are
1536+ /// stateless just as BOLT 11 invoices are.
1537+ ///
1538+ /// ```
1539+ /// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
1540+ /// # use lightning::ln::channelmanager::AChannelManager;
1541+ /// # use lightning::offers::parse::Bolt12SemanticError;
1542+ /// #
1543+ /// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
1544+ /// # let channel_manager = channel_manager.get_cm();
1545+ /// let offer = channel_manager
1546+ /// .create_offer_builder("coffee".to_string())?
1547+ /// # ;
1548+ /// # // Needed for compiling for c_bindings
1549+ /// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
1550+ /// # let offer = builder
1551+ /// .amount_msats(10_000_000)
1552+ /// .build()?;
1553+ /// let bech32_offer = offer.to_string();
1554+ ///
1555+ /// // On the event processing thread
1556+ /// channel_manager.process_pending_events(&|event| match event {
1557+ /// Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
1558+ /// PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
1559+ /// println!("Claiming payment {}", payment_hash);
1560+ /// channel_manager.claim_funds(payment_preimage);
1561+ /// },
1562+ /// PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
1563+ /// println!("Unknown payment hash: {}", payment_hash);
1564+ /// },
1565+ /// // ...
1566+ /// # _ => {},
1567+ /// },
1568+ /// Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
1569+ /// println!("Claimed {} msats", amount_msat);
1570+ /// },
1571+ /// // ...
1572+ /// # _ => {},
1573+ /// });
1574+ /// # Ok(())
1575+ /// # }
1576+ /// ```
1577+ ///
1578+ /// Use [`pay_for_offer`] to initiated payment, which sends an [`InvoiceRequest`] for an [`Offer`]
1579+ /// and pays the [`Bolt12Invoice`] response. In addition to success and failure events,
1580+ /// [`ChannelManager`] may also generate an [`Event::InvoiceRequestFailed`].
1581+ ///
1582+ /// ```
1583+ /// # use lightning::events::{Event, EventsProvider};
1584+ /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
1585+ /// # use lightning::offers::offer::Offer;
1586+ /// #
1587+ /// # fn example<T: AChannelManager>(
1588+ /// # channel_manager: T, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
1589+ /// # payer_note: Option<String>, retry: Retry, max_total_routing_fee_msat: Option<u64>
1590+ /// # ) {
1591+ /// # let channel_manager = channel_manager.get_cm();
1592+ /// let payment_id = PaymentId([42; 32]);
1593+ /// match channel_manager.pay_for_offer(
1594+ /// offer, quantity, amount_msats, payer_note, payment_id, retry, max_total_routing_fee_msat
1595+ /// ) {
1596+ /// Ok(()) => println!("Requesting invoice for offer"),
1597+ /// Err(e) => println!("Unable to request invoice for offer: {:?}", e),
1598+ /// }
1599+ ///
1600+ /// // First the payment will be waiting on an invoice
1601+ /// let expected_payment_id = payment_id;
1602+ /// assert!(
1603+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1604+ /// details,
1605+ /// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
1606+ /// )).is_some()
1607+ /// );
1608+ ///
1609+ /// // Once the invoice is received, a payment will be sent
1610+ /// assert!(
1611+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1612+ /// details,
1613+ /// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
1614+ /// )).is_some()
1615+ /// );
1616+ ///
1617+ /// // On the event processing thread
1618+ /// channel_manager.process_pending_events(&|event| match event {
1619+ /// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
1620+ /// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
1621+ /// Event::InvoiceRequestFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
1622+ /// // ...
1623+ /// # _ => {},
1624+ /// });
1625+ /// # }
1626+ /// ```
1627+ ///
15291628/// # Persistence
15301629///
15311630/// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for
@@ -1601,6 +1700,10 @@ where
16011700/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
16021701/// [`claim_funds`]: Self::claim_funds
16031702/// [`send_payment`]: Self::send_payment
1703+ /// [`offers`]: crate::offers
1704+ /// [`create_offer_builder`]: Self::create_offer_builder
1705+ /// [`pay_for_offer`]: Self::pay_for_offer
1706+ /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
16041707/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
16051708/// [`funding_created`]: msgs::FundingCreated
16061709/// [`funding_transaction_generated`]: Self::funding_transaction_generated
0 commit comments