@@ -1577,6 +1577,100 @@ where
1577
1577
/// # }
1578
1578
/// ```
1579
1579
///
1580
+ /// ## BOLT 12 Refunds
1581
+ ///
1582
+ /// A [`Refund`] is a request for an invoice to be paid. Like *paying* for an [`Offer`], *creating*
1583
+ /// a [`Refund`] involves maintaining state since it represents a future outbound payment.
1584
+ /// Therefore, use [`create_refund_builder`] when creating one, otherwise [`ChannelManager`] will
1585
+ /// refuse to pay any corresponding [`Bolt12Invoice`] that it receives.
1586
+ ///
1587
+ /// ```
1588
+ /// # use core::time::Duration;
1589
+ /// # use lightning::events::{Event, EventsProvider};
1590
+ /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
1591
+ /// # use lightning::offers::parse::Bolt12SemanticError;
1592
+ /// #
1593
+ /// # fn example<T: AChannelManager>(
1594
+ /// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration,
1595
+ /// # max_total_routing_fee_msat: Option<u64>
1596
+ /// # ) -> Result<(), Bolt12SemanticError> {
1597
+ /// # let channel_manager = channel_manager.get_cm();
1598
+ /// let payment_id = PaymentId([42; 32]);
1599
+ /// let retry = Retry::Timeout(Duration::from_secs(60));
1600
+ /// let refund = channel_manager
1601
+ /// .create_refund_builder(
1602
+ /// "coffee".to_string(), amount_msats, absolute_expiry, payment_id, retry,
1603
+ /// max_total_routing_fee_msat
1604
+ /// )?
1605
+ /// .payer_note("refund for order 1234".to_string())
1606
+ /// .build()?;
1607
+ /// let bech32_refund = refund.to_string();
1608
+ ///
1609
+ /// // First the payment will be waiting on an invoice
1610
+ /// let expected_payment_id = payment_id;
1611
+ /// assert!(
1612
+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1613
+ /// details,
1614
+ /// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
1615
+ /// )).is_some()
1616
+ /// );
1617
+ ///
1618
+ /// // Once the invoice is received, a payment will be sent
1619
+ /// assert!(
1620
+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1621
+ /// details,
1622
+ /// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
1623
+ /// )).is_some()
1624
+ /// );
1625
+ ///
1626
+ /// // On the event processing thread
1627
+ /// channel_manager.process_pending_events(&|event| match event {
1628
+ /// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
1629
+ /// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
1630
+ /// // ...
1631
+ /// # _ => {},
1632
+ /// });
1633
+ /// # Ok(())
1634
+ /// # }
1635
+ /// ```
1636
+ ///
1637
+ /// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
1638
+ /// *creating* an [`Offer`], this is stateless as it represents an inbound payment.
1639
+ ///
1640
+ /// ```
1641
+ /// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
1642
+ /// # use lightning::ln::channelmanager::AChannelManager;
1643
+ /// # use lightning::offers::refund::Refund;
1644
+ /// #
1645
+ /// # fn example<T: AChannelManager>(channel_manager: T, refund: &Refund) {
1646
+ /// # let channel_manager = channel_manager.get_cm();
1647
+ /// match channel_manager.request_refund_payment(refund) {
1648
+ /// Ok(()) => println!("Requesting payment for refund"),
1649
+ /// Err(e) => println!("Unable to request payment for refund: {:?}", e),
1650
+ /// }
1651
+ ///
1652
+ /// // On the event processing thread
1653
+ /// channel_manager.process_pending_events(&|event| match event {
1654
+ /// Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
1655
+ /// PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
1656
+ /// println!("Claiming payment {}", payment_hash);
1657
+ /// channel_manager.claim_funds(payment_preimage);
1658
+ /// },
1659
+ /// PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
1660
+ /// println!("Unknown payment hash: {}", payment_hash);
1661
+ /// },
1662
+ /// // ...
1663
+ /// # _ => {},
1664
+ /// },
1665
+ /// Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
1666
+ /// println!("Claimed {} msats", amount_msat);
1667
+ /// },
1668
+ /// // ...
1669
+ /// # _ => {},
1670
+ /// });
1671
+ /// # }
1672
+ /// ```
1673
+ ///
1580
1674
/// # Persistence
1581
1675
///
1582
1676
/// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for
@@ -1653,6 +1747,8 @@ where
1653
1747
/// [`create_offer_builder`]: Self::create_offer_builder
1654
1748
/// [`pay_for_offer`]: Self::pay_for_offer
1655
1749
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
1750
+ /// [`create_refund_builder`]: Self::create_refund_builder
1751
+ /// [`request_refund_payment`]: Self::request_refund_payment
1656
1752
/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
1657
1753
/// [`funding_created`]: msgs::FundingCreated
1658
1754
/// [`funding_transaction_generated`]: Self::funding_transaction_generated
0 commit comments