@@ -1625,6 +1625,103 @@ where
16251625/// # }
16261626/// ```
16271627///
1628+ /// ## BOLT 12 Refunds
1629+ ///
1630+ /// A [`Refund`] is a request for an invoice to be paid. Like *paying* for an [`Offer`], *creating*
1631+ /// a [`Refund`] involves maintaining state since it represents a future outbound payment.
1632+ /// Therefore, use [`create_refund_builder`] when creating one, otherwise [`ChannelManager`] will
1633+ /// refuse to pay any corresponding [`Bolt12Invoice`] that it receives.
1634+ ///
1635+ /// ```
1636+ /// # use core::time::Duration;
1637+ /// # use lightning::events::{Event, EventsProvider};
1638+ /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
1639+ /// # use lightning::offers::parse::Bolt12SemanticError;
1640+ /// #
1641+ /// # fn example<T: AChannelManager>(
1642+ /// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
1643+ /// # max_total_routing_fee_msat: Option<u64>
1644+ /// # ) -> Result<(), Bolt12SemanticError> {
1645+ /// # let channel_manager = channel_manager.get_cm();
1646+ /// let payment_id = PaymentId([42; 32]);
1647+ /// let refund = channel_manager
1648+ /// .create_refund_builder(
1649+ /// "coffee".to_string(), amount_msats, absolute_expiry, payment_id, retry,
1650+ /// max_total_routing_fee_msat
1651+ /// )?
1652+ /// # ;
1653+ /// # // Needed for compiling for c_bindings
1654+ /// # let builder: lightning::offers::refund::RefundBuilder<_> = refund.into();
1655+ /// # let refund = builder
1656+ /// .payer_note("refund for order 1234".to_string())
1657+ /// .build()?;
1658+ /// let bech32_refund = refund.to_string();
1659+ ///
1660+ /// // First the payment will be waiting on an invoice
1661+ /// let expected_payment_id = payment_id;
1662+ /// assert!(
1663+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1664+ /// details,
1665+ /// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
1666+ /// )).is_some()
1667+ /// );
1668+ ///
1669+ /// // Once the invoice is received, a payment will be sent
1670+ /// assert!(
1671+ /// channel_manager.list_recent_payments().iter().find(|details| matches!(
1672+ /// details,
1673+ /// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
1674+ /// )).is_some()
1675+ /// );
1676+ ///
1677+ /// // On the event processing thread
1678+ /// channel_manager.process_pending_events(&|event| match event {
1679+ /// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
1680+ /// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
1681+ /// // ...
1682+ /// # _ => {},
1683+ /// });
1684+ /// # Ok(())
1685+ /// # }
1686+ /// ```
1687+ ///
1688+ /// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
1689+ /// *creating* an [`Offer`], this is stateless as it represents an inbound payment.
1690+ ///
1691+ /// ```
1692+ /// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
1693+ /// # use lightning::ln::channelmanager::AChannelManager;
1694+ /// # use lightning::offers::refund::Refund;
1695+ /// #
1696+ /// # fn example<T: AChannelManager>(channel_manager: T, refund: &Refund) {
1697+ /// # let channel_manager = channel_manager.get_cm();
1698+ /// match channel_manager.request_refund_payment(refund) {
1699+ /// Ok(()) => println!("Requesting payment for refund"),
1700+ /// Err(e) => println!("Unable to request payment for refund: {:?}", e),
1701+ /// }
1702+ ///
1703+ /// // On the event processing thread
1704+ /// channel_manager.process_pending_events(&|event| match event {
1705+ /// Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
1706+ /// PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
1707+ /// println!("Claiming payment {}", payment_hash);
1708+ /// channel_manager.claim_funds(payment_preimage);
1709+ /// },
1710+ /// PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
1711+ /// println!("Unknown payment hash: {}", payment_hash);
1712+ /// },
1713+ /// // ...
1714+ /// # _ => {},
1715+ /// },
1716+ /// Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
1717+ /// println!("Claimed {} msats", amount_msat);
1718+ /// },
1719+ /// // ...
1720+ /// # _ => {},
1721+ /// });
1722+ /// # }
1723+ /// ```
1724+ ///
16281725/// # Persistence
16291726///
16301727/// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for
@@ -1704,6 +1801,8 @@ where
17041801/// [`create_offer_builder`]: Self::create_offer_builder
17051802/// [`pay_for_offer`]: Self::pay_for_offer
17061803/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
1804+ /// [`create_refund_builder`]: Self::create_refund_builder
1805+ /// [`request_refund_payment`]: Self::request_refund_payment
17071806/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
17081807/// [`funding_created`]: msgs::FundingCreated
17091808/// [`funding_transaction_generated`]: Self::funding_transaction_generated
0 commit comments