BasicMPP,
]);
define_context!(OfferContext, []);
+ define_context!(InvoiceRequestContext, []);
// This isn't a "real" feature context, and is only used in the channel_type field in an
// `OpenChannel` message.
define_context!(ChannelTypeContext, [
supports_keysend, requires_keysend);
#[cfg(test)]
- define_feature!(123456789, UnknownFeature, [NodeContext, ChannelContext, InvoiceContext, OfferContext],
+ define_feature!(123456789, UnknownFeature,
+ [NodeContext, ChannelContext, InvoiceContext, OfferContext, InvoiceRequestContext],
"Feature flags for an unknown feature used in testing.", set_unknown_feature_optional,
set_unknown_feature_required, supports_unknown_test_feature, requires_unknown_test_feature);
}
pub type ChannelFeatures = Features<sealed::ChannelContext>;
/// Features used within an invoice.
pub type InvoiceFeatures = Features<sealed::InvoiceContext>;
-/// Features used within an offer.
+/// Features used within an `offer`.
pub type OfferFeatures = Features<sealed::OfferContext>;
+/// Features used within an `invoice_request`.
+pub type InvoiceRequestFeatures = Features<sealed::InvoiceRequestContext>;
/// Features used within the channel_type field in an OpenChannel message.
///
impl_feature_tlv_write!(ChannelTypeFeatures);
impl_feature_tlv_write!(OfferFeatures);
+impl_feature_tlv_write!(InvoiceRequestFeatures);
#[cfg(test)]
mod tests {
--- /dev/null
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Data structures and encoding for `invoice_request` messages.
+
+use bitcoin::blockdata::constants::ChainHash;
+use bitcoin::secp256k1::PublicKey;
+use bitcoin::secp256k1::schnorr::Signature;
+use crate::ln::features::InvoiceRequestFeatures;
+use crate::offers::offer::OfferContents;
+use crate::offers::payer::PayerContents;
+use crate::util::string::PrintableString;
+
+use crate::prelude::*;
+
+/// An `InvoiceRequest` is a request for an `Invoice` formulated from an [`Offer`].
+///
+/// An offer may provide choices such as quantity, amount, chain, features, etc. An invoice request
+/// specifies these such that its recipient can send an invoice for payment.
+///
+/// [`Offer`]: crate::offers::offer::Offer
+#[derive(Clone, Debug)]
+pub struct InvoiceRequest {
+ bytes: Vec<u8>,
+ contents: InvoiceRequestContents,
+ signature: Option<Signature>,
+}
+
+/// The contents of an [`InvoiceRequest`], which may be shared with an `Invoice`.
+#[derive(Clone, Debug)]
+pub(crate) struct InvoiceRequestContents {
+ payer: PayerContents,
+ offer: OfferContents,
+ chain: Option<ChainHash>,
+ amount_msats: Option<u64>,
+ features: InvoiceRequestFeatures,
+ quantity: Option<u64>,
+ payer_id: PublicKey,
+ payer_note: Option<String>,
+}
+
+impl InvoiceRequest {
+ /// An unpredictable series of bytes, typically containing information about the derivation of
+ /// [`payer_id`].
+ ///
+ /// [`payer_id`]: Self::payer_id
+ pub fn metadata(&self) -> &[u8] {
+ &self.contents.payer.0[..]
+ }
+
+ /// A chain from [`Offer::chains`] that the offer is valid for.
+ ///
+ /// [`Offer::chains`]: crate::offers::offer::Offer::chains
+ pub fn chain(&self) -> ChainHash {
+ self.contents.chain.unwrap_or_else(|| self.contents.offer.implied_chain())
+ }
+
+ /// The amount to pay in msats (i.e., the minimum lightning-payable unit for [`chain`]), which
+ /// must be greater than or equal to [`Offer::amount`], converted if necessary.
+ ///
+ /// [`chain`]: Self::chain
+ /// [`Offer::amount`]: crate::offers::offer::Offer::amount
+ pub fn amount_msats(&self) -> Option<u64> {
+ self.contents.amount_msats
+ }
+
+ /// Features for paying the invoice.
+ pub fn features(&self) -> &InvoiceRequestFeatures {
+ &self.contents.features
+ }
+
+ /// The quantity of the offer's item conforming to [`Offer::supported_quantity`].
+ ///
+ /// [`Offer::supported_quantity`]: crate::offers::offer::Offer::supported_quantity
+ pub fn quantity(&self) -> Option<u64> {
+ self.contents.quantity
+ }
+
+ /// A possibly transient pubkey used to sign the invoice request.
+ pub fn payer_id(&self) -> PublicKey {
+ self.contents.payer_id
+ }
+
+ /// Payer provided note to include in the invoice.
+ pub fn payer_note(&self) -> Option<PrintableString> {
+ self.contents.payer_note.as_ref().map(|payer_note| PrintableString(payer_note.as_str()))
+ }
+
+ /// Signature of the invoice request using [`payer_id`].
+ ///
+ /// [`payer_id`]: Self::payer_id
+ pub fn signature(&self) -> Option<Signature> {
+ self.signature
+ }
+}
//!
//! Offers are a flexible protocol for Lightning payments.
+pub mod invoice_request;
pub mod offer;
pub mod parse;
+mod payer;
/// An `Offer` is a potentially long-lived proposal for payment of a good or service.
///
-/// An offer is a precursor to an `InvoiceRequest`. A merchant publishes an offer from which a
+/// An offer is a precursor to an [`InvoiceRequest`]. A merchant publishes an offer from which a
/// customer may request an `Invoice` for a specific quantity and using an amount sufficient to
/// cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
///
/// latter.
///
/// Through the use of [`BlindedPath`]s, offers provide recipient privacy.
+///
+/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
#[derive(Clone, Debug)]
pub struct Offer {
// The serialized offer. Needed when creating an `InvoiceRequest` if the offer contains unknown
contents: OfferContents,
}
-/// The contents of an [`Offer`], which may be shared with an `InvoiceRequest` or an `Invoice`.
+/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or an `Invoice`.
+///
+/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
#[derive(Clone, Debug)]
pub(super) struct OfferContents {
chains: Option<Vec<ChainHash>>,
/// Payments must be denominated in units of the minimal lightning-payable unit (e.g., msats)
/// for the selected chain.
pub fn chains(&self) -> Vec<ChainHash> {
- self.contents.chains
- .as_ref()
- .cloned()
- .unwrap_or_else(|| vec![self.contents.implied_chain()])
+ self.contents.chains()
}
// TODO: Link to corresponding method in `InvoiceRequest`.
}
impl OfferContents {
+ pub fn chains(&self) -> Vec<ChainHash> {
+ self.chains.as_ref().cloned().unwrap_or_else(|| vec![self.implied_chain()])
+ }
+
pub fn implied_chain(&self) -> ChainHash {
ChainHash::using_genesis_block(Network::Bitcoin)
}
--- /dev/null
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Data structures and encoding for `invoice_request_metadata` records.
+
+use crate::prelude::*;
+
+/// An unpredictable sequence of bytes typically containing information needed to derive
+/// [`InvoiceRequest::payer_id`].
+///
+/// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
+#[derive(Clone, Debug)]
+pub(crate) struct PayerContents(pub Vec<u8>);