@@ -1526,6 +1526,105 @@ where
1526
1526
/// # }
1527
1527
/// ```
1528
1528
///
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
+ ///
1529
1628
/// # Persistence
1530
1629
///
1531
1630
/// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for
@@ -1601,6 +1700,10 @@ where
1601
1700
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
1602
1701
/// [`claim_funds`]: Self::claim_funds
1603
1702
/// [`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
1604
1707
/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
1605
1708
/// [`funding_created`]: msgs::FundingCreated
1606
1709
/// [`funding_transaction_generated`]: Self::funding_transaction_generated
0 commit comments