Check offer expiry when building invoice in no-std
[rust-lightning] / lightning / src / offers / offer.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Data structures and encoding for `offer` messages.
11 //!
12 //! An [`Offer`] represents an "offer to be paid." It is typically constructed by a merchant and
13 //! published as a QR code to be scanned by a customer. The customer uses the offer to request an
14 //! invoice from the merchant to be paid.
15 //!
16 //! # Example
17 //!
18 //! ```
19 //! extern crate bitcoin;
20 //! extern crate core;
21 //! extern crate lightning;
22 //!
23 //! use core::convert::TryFrom;
24 //! use core::num::NonZeroU64;
25 //! use core::time::Duration;
26 //!
27 //! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
28 //! use lightning::offers::offer::{Offer, OfferBuilder, Quantity};
29 //! use lightning::offers::parse::Bolt12ParseError;
30 //! use lightning::util::ser::{Readable, Writeable};
31 //!
32 //! # use lightning::blinded_path::BlindedPath;
33 //! # #[cfg(feature = "std")]
34 //! # use std::time::SystemTime;
35 //! #
36 //! # fn create_blinded_path() -> BlindedPath { unimplemented!() }
37 //! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() }
38 //! #
39 //! # #[cfg(feature = "std")]
40 //! # fn build() -> Result<(), Bolt12ParseError> {
41 //! let secp_ctx = Secp256k1::new();
42 //! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
43 //! let pubkey = PublicKey::from(keys);
44 //!
45 //! let expiration = SystemTime::now() + Duration::from_secs(24 * 60 * 60);
46 //! let offer = OfferBuilder::new("coffee, large".to_string(), pubkey)
47 //!     .amount_msats(20_000)
48 //!     .supported_quantity(Quantity::Unbounded)
49 //!     .absolute_expiry(expiration.duration_since(SystemTime::UNIX_EPOCH).unwrap())
50 //!     .issuer("Foo Bar".to_string())
51 //!     .path(create_blinded_path())
52 //!     .path(create_another_blinded_path())
53 //!     .build()?;
54 //!
55 //! // Encode as a bech32 string for use in a QR code.
56 //! let encoded_offer = offer.to_string();
57 //!
58 //! // Parse from a bech32 string after scanning from a QR code.
59 //! let offer = encoded_offer.parse::<Offer>()?;
60 //!
61 //! // Encode offer as raw bytes.
62 //! let mut bytes = Vec::new();
63 //! offer.write(&mut bytes).unwrap();
64 //!
65 //! // Decode raw bytes into an offer.
66 //! let offer = Offer::try_from(bytes)?;
67 //! # Ok(())
68 //! # }
69 //! ```
70 //!
71 //! # Note
72 //!
73 //! If constructing an [`Offer`] for use with a [`ChannelManager`], use
74 //! [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`].
75 //!
76 //! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
77 //! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder
78
79 use bitcoin::blockdata::constants::ChainHash;
80 use bitcoin::network::constants::Network;
81 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self};
82 use core::convert::TryFrom;
83 use core::num::NonZeroU64;
84 use core::ops::Deref;
85 use core::str::FromStr;
86 use core::time::Duration;
87 use crate::sign::EntropySource;
88 use crate::io;
89 use crate::blinded_path::BlindedPath;
90 use crate::ln::channelmanager::PaymentId;
91 use crate::ln::features::OfferFeatures;
92 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
93 use crate::ln::msgs::MAX_VALUE_MSAT;
94 use crate::offers::invoice_request::{DerivedPayerId, ExplicitPayerId, InvoiceRequestBuilder};
95 use crate::offers::merkle::TlvStream;
96 use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
97 use crate::offers::signer::{Metadata, MetadataMaterial, self};
98 use crate::util::ser::{HighZeroBytesDroppedBigSize, WithoutLength, Writeable, Writer};
99 use crate::util::string::PrintableString;
100
101 use crate::prelude::*;
102
103 #[cfg(feature = "std")]
104 use std::time::SystemTime;
105
106 pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Offer ~~~~~~";
107
108 /// Builds an [`Offer`] for the "offer to be paid" flow.
109 ///
110 /// See [module-level documentation] for usage.
111 ///
112 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
113 ///
114 /// [module-level documentation]: self
115 pub struct OfferBuilder<'a, M: MetadataStrategy, T: secp256k1::Signing> {
116         offer: OfferContents,
117         metadata_strategy: core::marker::PhantomData<M>,
118         secp_ctx: Option<&'a Secp256k1<T>>,
119 }
120
121 /// Indicates how [`Offer::metadata`] may be set.
122 ///
123 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
124 pub trait MetadataStrategy {}
125
126 /// [`Offer::metadata`] may be explicitly set or left empty.
127 ///
128 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
129 pub struct ExplicitMetadata {}
130
131 /// [`Offer::metadata`] will be derived.
132 ///
133 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
134 pub struct DerivedMetadata {}
135
136 impl MetadataStrategy for ExplicitMetadata {}
137 impl MetadataStrategy for DerivedMetadata {}
138
139 impl<'a> OfferBuilder<'a, ExplicitMetadata, secp256k1::SignOnly> {
140         /// Creates a new builder for an offer setting the [`Offer::description`] and using the
141         /// [`Offer::signing_pubkey`] for signing invoices. The associated secret key must be remembered
142         /// while the offer is valid.
143         ///
144         /// Use a different pubkey per offer to avoid correlating offers.
145         ///
146         /// # Note
147         ///
148         /// If constructing an [`Offer`] for use with a [`ChannelManager`], use
149         /// [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`].
150         ///
151         /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
152         /// [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder
153         pub fn new(description: String, signing_pubkey: PublicKey) -> Self {
154                 OfferBuilder {
155                         offer: OfferContents {
156                                 chains: None, metadata: None, amount: None, description,
157                                 features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
158                                 supported_quantity: Quantity::One, signing_pubkey,
159                         },
160                         metadata_strategy: core::marker::PhantomData,
161                         secp_ctx: None,
162                 }
163         }
164
165         /// Sets the [`Offer::metadata`] to the given bytes.
166         ///
167         /// Successive calls to this method will override the previous setting.
168         pub fn metadata(mut self, metadata: Vec<u8>) -> Result<Self, Bolt12SemanticError> {
169                 self.offer.metadata = Some(Metadata::Bytes(metadata));
170                 Ok(self)
171         }
172 }
173
174 impl<'a, T: secp256k1::Signing> OfferBuilder<'a, DerivedMetadata, T> {
175         /// Similar to [`OfferBuilder::new`] except, if [`OfferBuilder::path`] is called, the signing
176         /// pubkey is derived from the given [`ExpandedKey`] and [`EntropySource`]. This provides
177         /// recipient privacy by using a different signing pubkey for each offer. Otherwise, the
178         /// provided `node_id` is used for the signing pubkey.
179         ///
180         /// Also, sets the metadata when [`OfferBuilder::build`] is called such that it can be used by
181         /// [`InvoiceRequest::verify`] to determine if the request was produced for the offer given an
182         /// [`ExpandedKey`].
183         ///
184         /// [`InvoiceRequest::verify`]: crate::offers::invoice_request::InvoiceRequest::verify
185         /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
186         pub fn deriving_signing_pubkey<ES: Deref>(
187                 description: String, node_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
188                 secp_ctx: &'a Secp256k1<T>
189         ) -> Self where ES::Target: EntropySource {
190                 let nonce = Nonce::from_entropy_source(entropy_source);
191                 let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, None);
192                 let metadata = Metadata::DerivedSigningPubkey(derivation_material);
193                 OfferBuilder {
194                         offer: OfferContents {
195                                 chains: None, metadata: Some(metadata), amount: None, description,
196                                 features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
197                                 supported_quantity: Quantity::One, signing_pubkey: node_id,
198                         },
199                         metadata_strategy: core::marker::PhantomData,
200                         secp_ctx: Some(secp_ctx),
201                 }
202         }
203 }
204
205 impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> {
206         /// Adds the chain hash of the given [`Network`] to [`Offer::chains`]. If not called,
207         /// the chain hash of [`Network::Bitcoin`] is assumed to be the only one supported.
208         ///
209         /// See [`Offer::chains`] on how this relates to the payment currency.
210         ///
211         /// Successive calls to this method will add another chain hash.
212         pub fn chain(self, network: Network) -> Self {
213                 self.chain_hash(ChainHash::using_genesis_block(network))
214         }
215
216         /// Adds the [`ChainHash`] to [`Offer::chains`]. If not called, the chain hash of
217         /// [`Network::Bitcoin`] is assumed to be the only one supported.
218         ///
219         /// See [`Offer::chains`] on how this relates to the payment currency.
220         ///
221         /// Successive calls to this method will add another chain hash.
222         pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Self {
223                 let chains = self.offer.chains.get_or_insert_with(Vec::new);
224                 if !chains.contains(&chain) {
225                         chains.push(chain);
226                 }
227
228                 self
229         }
230
231         /// Sets the [`Offer::amount`] as an [`Amount::Bitcoin`].
232         ///
233         /// Successive calls to this method will override the previous setting.
234         pub fn amount_msats(self, amount_msats: u64) -> Self {
235                 self.amount(Amount::Bitcoin { amount_msats })
236         }
237
238         /// Sets the [`Offer::amount`].
239         ///
240         /// Successive calls to this method will override the previous setting.
241         pub(super) fn amount(mut self, amount: Amount) -> Self {
242                 self.offer.amount = Some(amount);
243                 self
244         }
245
246         /// Sets the [`Offer::absolute_expiry`] as seconds since the Unix epoch. Any expiry that has
247         /// already passed is valid and can be checked for using [`Offer::is_expired`].
248         ///
249         /// Successive calls to this method will override the previous setting.
250         pub fn absolute_expiry(mut self, absolute_expiry: Duration) -> Self {
251                 self.offer.absolute_expiry = Some(absolute_expiry);
252                 self
253         }
254
255         /// Sets the [`Offer::issuer`].
256         ///
257         /// Successive calls to this method will override the previous setting.
258         pub fn issuer(mut self, issuer: String) -> Self {
259                 self.offer.issuer = Some(issuer);
260                 self
261         }
262
263         /// Adds a blinded path to [`Offer::paths`]. Must include at least one path if only connected by
264         /// private channels or if [`Offer::signing_pubkey`] is not a public node id.
265         ///
266         /// Successive calls to this method will add another blinded path. Caller is responsible for not
267         /// adding duplicate paths.
268         pub fn path(mut self, path: BlindedPath) -> Self {
269                 self.offer.paths.get_or_insert_with(Vec::new).push(path);
270                 self
271         }
272
273         /// Sets the quantity of items for [`Offer::supported_quantity`]. If not called, defaults to
274         /// [`Quantity::One`].
275         ///
276         /// Successive calls to this method will override the previous setting.
277         pub fn supported_quantity(mut self, quantity: Quantity) -> Self {
278                 self.offer.supported_quantity = quantity;
279                 self
280         }
281
282         /// Builds an [`Offer`] from the builder's settings.
283         pub fn build(mut self) -> Result<Offer, Bolt12SemanticError> {
284                 match self.offer.amount {
285                         Some(Amount::Bitcoin { amount_msats }) => {
286                                 if amount_msats > MAX_VALUE_MSAT {
287                                         return Err(Bolt12SemanticError::InvalidAmount);
288                                 }
289                         },
290                         Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
291                         None => {},
292                 }
293
294                 if let Some(chains) = &self.offer.chains {
295                         if chains.len() == 1 && chains[0] == self.offer.implied_chain() {
296                                 self.offer.chains = None;
297                         }
298                 }
299
300                 Ok(self.build_without_checks())
301         }
302
303         fn build_without_checks(mut self) -> Offer {
304                 // Create the metadata for stateless verification of an InvoiceRequest.
305                 if let Some(mut metadata) = self.offer.metadata.take() {
306                         if metadata.has_derivation_material() {
307                                 if self.offer.paths.is_none() {
308                                         metadata = metadata.without_keys();
309                                 }
310
311                                 let mut tlv_stream = self.offer.as_tlv_stream();
312                                 debug_assert_eq!(tlv_stream.metadata, None);
313                                 tlv_stream.metadata = None;
314                                 if metadata.derives_recipient_keys() {
315                                         tlv_stream.node_id = None;
316                                 }
317
318                                 let (derived_metadata, keys) = metadata.derive_from(tlv_stream, self.secp_ctx);
319                                 metadata = derived_metadata;
320                                 if let Some(keys) = keys {
321                                         self.offer.signing_pubkey = keys.public_key();
322                                 }
323                         }
324
325                         self.offer.metadata = Some(metadata);
326                 }
327
328                 let mut bytes = Vec::new();
329                 self.offer.write(&mut bytes).unwrap();
330
331                 Offer { bytes, contents: self.offer }
332         }
333 }
334
335 #[cfg(test)]
336 impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> {
337         fn features_unchecked(mut self, features: OfferFeatures) -> Self {
338                 self.offer.features = features;
339                 self
340         }
341
342         pub(super) fn build_unchecked(self) -> Offer {
343                 self.build_without_checks()
344         }
345 }
346
347 /// An `Offer` is a potentially long-lived proposal for payment of a good or service.
348 ///
349 /// An offer is a precursor to an [`InvoiceRequest`]. A merchant publishes an offer from which a
350 /// customer may request an [`Bolt12Invoice`] for a specific quantity and using an amount sufficient
351 /// to cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
352 ///
353 /// Offers may be denominated in currency other than bitcoin but are ultimately paid using the
354 /// latter.
355 ///
356 /// Through the use of [`BlindedPath`]s, offers provide recipient privacy.
357 ///
358 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
359 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
360 #[derive(Clone, Debug)]
361 #[cfg_attr(test, derive(PartialEq))]
362 pub struct Offer {
363         // The serialized offer. Needed when creating an `InvoiceRequest` if the offer contains unknown
364         // fields.
365         pub(super) bytes: Vec<u8>,
366         pub(super) contents: OfferContents,
367 }
368
369 /// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or a
370 /// [`Bolt12Invoice`].
371 ///
372 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
373 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
374 #[derive(Clone, Debug)]
375 #[cfg_attr(test, derive(PartialEq))]
376 pub(super) struct OfferContents {
377         chains: Option<Vec<ChainHash>>,
378         metadata: Option<Metadata>,
379         amount: Option<Amount>,
380         description: String,
381         features: OfferFeatures,
382         absolute_expiry: Option<Duration>,
383         issuer: Option<String>,
384         paths: Option<Vec<BlindedPath>>,
385         supported_quantity: Quantity,
386         signing_pubkey: PublicKey,
387 }
388
389 macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
390         // TODO: Return a slice once ChainHash has constants.
391         // - https://github.com/rust-bitcoin/rust-bitcoin/pull/1283
392         // - https://github.com/rust-bitcoin/rust-bitcoin/pull/1286
393         /// The chains that may be used when paying a requested invoice (e.g., bitcoin mainnet).
394         /// Payments must be denominated in units of the minimal lightning-payable unit (e.g., msats)
395         /// for the selected chain.
396         pub fn chains(&$self) -> Vec<bitcoin::blockdata::constants::ChainHash> {
397                 $contents.chains()
398         }
399
400         // TODO: Link to corresponding method in `InvoiceRequest`.
401         /// Opaque bytes set by the originator. Useful for authentication and validating fields since it
402         /// is reflected in `invoice_request` messages along with all the other fields from the `offer`.
403         pub fn metadata(&$self) -> Option<&Vec<u8>> {
404                 $contents.metadata()
405         }
406
407         /// The minimum amount required for a successful payment of a single item.
408         pub fn amount(&$self) -> Option<&$crate::offers::offer::Amount> {
409                 $contents.amount()
410         }
411
412         /// A complete description of the purpose of the payment. Intended to be displayed to the user
413         /// but with the caveat that it has not been verified in any way.
414         pub fn description(&$self) -> $crate::util::string::PrintableString {
415                 $contents.description()
416         }
417
418         /// Features pertaining to the offer.
419         pub fn offer_features(&$self) -> &$crate::ln::features::OfferFeatures {
420                 &$contents.features()
421         }
422
423         /// Duration since the Unix epoch when an invoice should no longer be requested.
424         ///
425         /// If `None`, the offer does not expire.
426         pub fn absolute_expiry(&$self) -> Option<core::time::Duration> {
427                 $contents.absolute_expiry()
428         }
429
430         /// The issuer of the offer, possibly beginning with `user@domain` or `domain`. Intended to be
431         /// displayed to the user but with the caveat that it has not been verified in any way.
432         pub fn issuer(&$self) -> Option<$crate::util::string::PrintableString> {
433                 $contents.issuer()
434         }
435
436         /// Paths to the recipient originating from publicly reachable nodes. Blinded paths provide
437         /// recipient privacy by obfuscating its node id.
438         pub fn paths(&$self) -> &[$crate::blinded_path::BlindedPath] {
439                 $contents.paths()
440         }
441
442         /// The quantity of items supported.
443         pub fn supported_quantity(&$self) -> $crate::offers::offer::Quantity {
444                 $contents.supported_quantity()
445         }
446
447         /// The public key used by the recipient to sign invoices.
448         pub fn signing_pubkey(&$self) -> bitcoin::secp256k1::PublicKey {
449                 $contents.signing_pubkey()
450         }
451 } }
452
453 impl Offer {
454         offer_accessors!(self, self.contents);
455
456         pub(super) fn implied_chain(&self) -> ChainHash {
457                 self.contents.implied_chain()
458         }
459
460         /// Returns whether the given chain is supported by the offer.
461         pub fn supports_chain(&self, chain: ChainHash) -> bool {
462                 self.contents.supports_chain(chain)
463         }
464
465         /// Whether the offer has expired.
466         #[cfg(feature = "std")]
467         pub fn is_expired(&self) -> bool {
468                 self.contents.is_expired()
469         }
470
471         /// Returns whether the given quantity is valid for the offer.
472         pub fn is_valid_quantity(&self, quantity: u64) -> bool {
473                 self.contents.is_valid_quantity(quantity)
474         }
475
476         /// Returns whether a quantity is expected in an [`InvoiceRequest`] for the offer.
477         ///
478         /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
479         pub fn expects_quantity(&self) -> bool {
480                 self.contents.expects_quantity()
481         }
482
483         /// Similar to [`Offer::request_invoice`] except it:
484         /// - derives the [`InvoiceRequest::payer_id`] such that a different key can be used for each
485         ///   request,
486         /// - sets [`InvoiceRequest::payer_metadata`] when [`InvoiceRequestBuilder::build`] is called
487         ///   such that it can be used by [`Bolt12Invoice::verify`] to determine if the invoice was
488         ///   requested using a base [`ExpandedKey`] from which the payer id was derived, and
489         /// - includes the [`PaymentId`] encrypted in [`InvoiceRequest::payer_metadata`] so that it can
490         ///   be used when sending the payment for the requested invoice.
491         ///
492         /// Useful to protect the sender's privacy.
493         ///
494         /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
495         ///
496         /// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
497         /// [`InvoiceRequest::payer_metadata`]: crate::offers::invoice_request::InvoiceRequest::payer_metadata
498         /// [`Bolt12Invoice::verify`]: crate::offers::invoice::Bolt12Invoice::verify
499         /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
500         pub fn request_invoice_deriving_payer_id<'a, 'b, ES: Deref, T: secp256k1::Signing>(
501                 &'a self, expanded_key: &ExpandedKey, entropy_source: ES, secp_ctx: &'b Secp256k1<T>,
502                 payment_id: PaymentId
503         ) -> Result<InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T>, Bolt12SemanticError>
504         where
505                 ES::Target: EntropySource,
506         {
507                 if self.offer_features().requires_unknown_bits() {
508                         return Err(Bolt12SemanticError::UnknownRequiredFeatures);
509                 }
510
511                 Ok(InvoiceRequestBuilder::deriving_payer_id(
512                         self, expanded_key, entropy_source, secp_ctx, payment_id
513                 ))
514         }
515
516         /// Similar to [`Offer::request_invoice_deriving_payer_id`] except uses `payer_id` for the
517         /// [`InvoiceRequest::payer_id`] instead of deriving a different key for each request.
518         ///
519         /// Useful for recurring payments using the same `payer_id` with different invoices.
520         ///
521         /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
522         ///
523         /// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
524         pub fn request_invoice_deriving_metadata<ES: Deref>(
525                 &self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
526                 payment_id: PaymentId
527         ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError>
528         where
529                 ES::Target: EntropySource,
530         {
531                 if self.offer_features().requires_unknown_bits() {
532                         return Err(Bolt12SemanticError::UnknownRequiredFeatures);
533                 }
534
535                 Ok(InvoiceRequestBuilder::deriving_metadata(
536                         self, payer_id, expanded_key, entropy_source, payment_id
537                 ))
538         }
539
540         /// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and `payer_id`,
541         /// which will be reflected in the `Bolt12Invoice` response.
542         ///
543         /// The `metadata` is useful for including information about the derivation of `payer_id` such
544         /// that invoice response handling can be stateless. Also serves as payer-provided entropy while
545         /// hashing in the signature calculation.
546         ///
547         /// This should not leak any information such as by using a simple BIP-32 derivation path.
548         /// Otherwise, payments may be correlated.
549         ///
550         /// Errors if the offer contains unknown required features.
551         ///
552         /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
553         ///
554         /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
555         pub fn request_invoice(
556                 &self, metadata: Vec<u8>, payer_id: PublicKey
557         ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError> {
558                 if self.offer_features().requires_unknown_bits() {
559                         return Err(Bolt12SemanticError::UnknownRequiredFeatures);
560                 }
561
562                 Ok(InvoiceRequestBuilder::new(self, metadata, payer_id))
563         }
564
565         #[cfg(test)]
566         pub(super) fn as_tlv_stream(&self) -> OfferTlvStreamRef {
567                 self.contents.as_tlv_stream()
568         }
569 }
570
571 impl AsRef<[u8]> for Offer {
572         fn as_ref(&self) -> &[u8] {
573                 &self.bytes
574         }
575 }
576
577 impl OfferContents {
578         pub fn chains(&self) -> Vec<ChainHash> {
579                 self.chains.as_ref().cloned().unwrap_or_else(|| vec![self.implied_chain()])
580         }
581
582         pub fn implied_chain(&self) -> ChainHash {
583                 ChainHash::using_genesis_block(Network::Bitcoin)
584         }
585
586         pub fn supports_chain(&self, chain: ChainHash) -> bool {
587                 self.chains().contains(&chain)
588         }
589
590         pub fn metadata(&self) -> Option<&Vec<u8>> {
591                 self.metadata.as_ref().and_then(|metadata| metadata.as_bytes())
592         }
593
594         pub fn amount(&self) -> Option<&Amount> {
595                 self.amount.as_ref()
596         }
597
598         pub fn description(&self) -> PrintableString {
599                 PrintableString(&self.description)
600         }
601
602         pub fn features(&self) -> &OfferFeatures {
603                 &self.features
604         }
605
606         pub fn absolute_expiry(&self) -> Option<Duration> {
607                 self.absolute_expiry
608         }
609
610         #[cfg(feature = "std")]
611         pub(super) fn is_expired(&self) -> bool {
612                 SystemTime::UNIX_EPOCH
613                         .elapsed()
614                         .map(|duration_since_epoch| self.is_expired_no_std(duration_since_epoch))
615                         .unwrap_or(false)
616         }
617
618         pub(super) fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
619                 self.absolute_expiry
620                         .map(|absolute_expiry| duration_since_epoch > absolute_expiry)
621                         .unwrap_or(false)
622         }
623
624         pub fn issuer(&self) -> Option<PrintableString> {
625                 self.issuer.as_ref().map(|issuer| PrintableString(issuer.as_str()))
626         }
627
628         pub fn paths(&self) -> &[BlindedPath] {
629                 self.paths.as_ref().map(|paths| paths.as_slice()).unwrap_or(&[])
630         }
631
632         pub(super) fn check_amount_msats_for_quantity(
633                 &self, amount_msats: Option<u64>, quantity: Option<u64>
634         ) -> Result<(), Bolt12SemanticError> {
635                 let offer_amount_msats = match self.amount {
636                         None => 0,
637                         Some(Amount::Bitcoin { amount_msats }) => amount_msats,
638                         Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
639                 };
640
641                 if !self.expects_quantity() || quantity.is_some() {
642                         let expected_amount_msats = offer_amount_msats.checked_mul(quantity.unwrap_or(1))
643                                 .ok_or(Bolt12SemanticError::InvalidAmount)?;
644                         let amount_msats = amount_msats.unwrap_or(expected_amount_msats);
645
646                         if amount_msats < expected_amount_msats {
647                                 return Err(Bolt12SemanticError::InsufficientAmount);
648                         }
649
650                         if amount_msats > MAX_VALUE_MSAT {
651                                 return Err(Bolt12SemanticError::InvalidAmount);
652                         }
653                 }
654
655                 Ok(())
656         }
657
658         pub fn supported_quantity(&self) -> Quantity {
659                 self.supported_quantity
660         }
661
662         pub(super) fn check_quantity(&self, quantity: Option<u64>) -> Result<(), Bolt12SemanticError> {
663                 let expects_quantity = self.expects_quantity();
664                 match quantity {
665                         None if expects_quantity => Err(Bolt12SemanticError::MissingQuantity),
666                         Some(_) if !expects_quantity => Err(Bolt12SemanticError::UnexpectedQuantity),
667                         Some(quantity) if !self.is_valid_quantity(quantity) => {
668                                 Err(Bolt12SemanticError::InvalidQuantity)
669                         },
670                         _ => Ok(()),
671                 }
672         }
673
674         fn is_valid_quantity(&self, quantity: u64) -> bool {
675                 match self.supported_quantity {
676                         Quantity::Bounded(n) => quantity <= n.get(),
677                         Quantity::Unbounded => quantity > 0,
678                         Quantity::One => quantity == 1,
679                 }
680         }
681
682         fn expects_quantity(&self) -> bool {
683                 match self.supported_quantity {
684                         Quantity::Bounded(_) => true,
685                         Quantity::Unbounded => true,
686                         Quantity::One => false,
687                 }
688         }
689
690         pub(super) fn signing_pubkey(&self) -> PublicKey {
691                 self.signing_pubkey
692         }
693
694         /// Verifies that the offer metadata was produced from the offer in the TLV stream.
695         pub(super) fn verify<T: secp256k1::Signing>(
696                 &self, bytes: &[u8], key: &ExpandedKey, secp_ctx: &Secp256k1<T>
697         ) -> Result<Option<KeyPair>, ()> {
698                 match self.metadata() {
699                         Some(metadata) => {
700                                 let tlv_stream = TlvStream::new(bytes).range(OFFER_TYPES).filter(|record| {
701                                         match record.r#type {
702                                                 OFFER_METADATA_TYPE => false,
703                                                 OFFER_NODE_ID_TYPE => {
704                                                         !self.metadata.as_ref().unwrap().derives_recipient_keys()
705                                                 },
706                                                 _ => true,
707                                         }
708                                 });
709                                 signer::verify_recipient_metadata(
710                                         metadata, key, IV_BYTES, self.signing_pubkey(), tlv_stream, secp_ctx
711                                 )
712                         },
713                         None => Err(()),
714                 }
715         }
716
717         pub(super) fn as_tlv_stream(&self) -> OfferTlvStreamRef {
718                 let (currency, amount) = match &self.amount {
719                         None => (None, None),
720                         Some(Amount::Bitcoin { amount_msats }) => (None, Some(*amount_msats)),
721                         Some(Amount::Currency { iso4217_code, amount }) => (
722                                 Some(iso4217_code), Some(*amount)
723                         ),
724                 };
725
726                 let features = {
727                         if self.features == OfferFeatures::empty() { None } else { Some(&self.features) }
728                 };
729
730                 OfferTlvStreamRef {
731                         chains: self.chains.as_ref(),
732                         metadata: self.metadata(),
733                         currency,
734                         amount,
735                         description: Some(&self.description),
736                         features,
737                         absolute_expiry: self.absolute_expiry.map(|duration| duration.as_secs()),
738                         paths: self.paths.as_ref(),
739                         issuer: self.issuer.as_ref(),
740                         quantity_max: self.supported_quantity.to_tlv_record(),
741                         node_id: Some(&self.signing_pubkey),
742                 }
743         }
744 }
745
746 impl Writeable for Offer {
747         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
748                 WithoutLength(&self.bytes).write(writer)
749         }
750 }
751
752 impl Writeable for OfferContents {
753         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
754                 self.as_tlv_stream().write(writer)
755         }
756 }
757
758 /// The minimum amount required for an item in an [`Offer`], denominated in either bitcoin or
759 /// another currency.
760 #[derive(Clone, Debug, PartialEq)]
761 pub enum Amount {
762         /// An amount of bitcoin.
763         Bitcoin {
764                 /// The amount in millisatoshi.
765                 amount_msats: u64,
766         },
767         /// An amount of currency specified using ISO 4712.
768         Currency {
769                 /// The currency that the amount is denominated in.
770                 iso4217_code: CurrencyCode,
771                 /// The amount in the currency unit adjusted by the ISO 4712 exponent (e.g., USD cents).
772                 amount: u64,
773         },
774 }
775
776 /// An ISO 4712 three-letter currency code (e.g., USD).
777 pub type CurrencyCode = [u8; 3];
778
779 /// Quantity of items supported by an [`Offer`].
780 #[derive(Clone, Copy, Debug, PartialEq)]
781 pub enum Quantity {
782         /// Up to a specific number of items (inclusive). Use when more than one item can be requested
783         /// but is limited (e.g., because of per customer or inventory limits).
784         ///
785         /// May be used with `NonZeroU64::new(1)` but prefer to use [`Quantity::One`] if only one item
786         /// is supported.
787         Bounded(NonZeroU64),
788         /// One or more items. Use when more than one item can be requested without any limit.
789         Unbounded,
790         /// Only one item. Use when only a single item can be requested.
791         One,
792 }
793
794 impl Quantity {
795         fn to_tlv_record(&self) -> Option<u64> {
796                 match self {
797                         Quantity::Bounded(n) => Some(n.get()),
798                         Quantity::Unbounded => Some(0),
799                         Quantity::One => None,
800                 }
801         }
802 }
803
804 /// Valid type range for offer TLV records.
805 pub(super) const OFFER_TYPES: core::ops::Range<u64> = 1..80;
806
807 /// TLV record type for [`Offer::metadata`].
808 const OFFER_METADATA_TYPE: u64 = 4;
809
810 /// TLV record type for [`Offer::signing_pubkey`].
811 const OFFER_NODE_ID_TYPE: u64 = 22;
812
813 tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, {
814         (2, chains: (Vec<ChainHash>, WithoutLength)),
815         (OFFER_METADATA_TYPE, metadata: (Vec<u8>, WithoutLength)),
816         (6, currency: CurrencyCode),
817         (8, amount: (u64, HighZeroBytesDroppedBigSize)),
818         (10, description: (String, WithoutLength)),
819         (12, features: (OfferFeatures, WithoutLength)),
820         (14, absolute_expiry: (u64, HighZeroBytesDroppedBigSize)),
821         (16, paths: (Vec<BlindedPath>, WithoutLength)),
822         (18, issuer: (String, WithoutLength)),
823         (20, quantity_max: (u64, HighZeroBytesDroppedBigSize)),
824         (OFFER_NODE_ID_TYPE, node_id: PublicKey),
825 });
826
827 impl Bech32Encode for Offer {
828         const BECH32_HRP: &'static str = "lno";
829 }
830
831 impl FromStr for Offer {
832         type Err = Bolt12ParseError;
833
834         fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
835                 Self::from_bech32_str(s)
836         }
837 }
838
839 impl TryFrom<Vec<u8>> for Offer {
840         type Error = Bolt12ParseError;
841
842         fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
843                 let offer = ParsedMessage::<OfferTlvStream>::try_from(bytes)?;
844                 let ParsedMessage { bytes, tlv_stream } = offer;
845                 let contents = OfferContents::try_from(tlv_stream)?;
846                 Ok(Offer { bytes, contents })
847         }
848 }
849
850 impl TryFrom<OfferTlvStream> for OfferContents {
851         type Error = Bolt12SemanticError;
852
853         fn try_from(tlv_stream: OfferTlvStream) -> Result<Self, Self::Error> {
854                 let OfferTlvStream {
855                         chains, metadata, currency, amount, description, features, absolute_expiry, paths,
856                         issuer, quantity_max, node_id,
857                 } = tlv_stream;
858
859                 let metadata = metadata.map(|metadata| Metadata::Bytes(metadata));
860
861                 let amount = match (currency, amount) {
862                         (None, None) => None,
863                         (None, Some(amount_msats)) if amount_msats > MAX_VALUE_MSAT => {
864                                 return Err(Bolt12SemanticError::InvalidAmount);
865                         },
866                         (None, Some(amount_msats)) => Some(Amount::Bitcoin { amount_msats }),
867                         (Some(_), None) => return Err(Bolt12SemanticError::MissingAmount),
868                         (Some(iso4217_code), Some(amount)) => Some(Amount::Currency { iso4217_code, amount }),
869                 };
870
871                 let description = match description {
872                         None => return Err(Bolt12SemanticError::MissingDescription),
873                         Some(description) => description,
874                 };
875
876                 let features = features.unwrap_or_else(OfferFeatures::empty);
877
878                 let absolute_expiry = absolute_expiry
879                         .map(|seconds_from_epoch| Duration::from_secs(seconds_from_epoch));
880
881                 let supported_quantity = match quantity_max {
882                         None => Quantity::One,
883                         Some(0) => Quantity::Unbounded,
884                         Some(n) => Quantity::Bounded(NonZeroU64::new(n).unwrap()),
885                 };
886
887                 let signing_pubkey = match node_id {
888                         None => return Err(Bolt12SemanticError::MissingSigningPubkey),
889                         Some(node_id) => node_id,
890                 };
891
892                 Ok(OfferContents {
893                         chains, metadata, amount, description, features, absolute_expiry, issuer, paths,
894                         supported_quantity, signing_pubkey,
895                 })
896         }
897 }
898
899 impl core::fmt::Display for Offer {
900         fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
901                 self.fmt_bech32_str(f)
902         }
903 }
904
905 #[cfg(test)]
906 mod tests {
907         use super::{Amount, Offer, OfferBuilder, OfferTlvStreamRef, Quantity};
908
909         use bitcoin::blockdata::constants::ChainHash;
910         use bitcoin::network::constants::Network;
911         use bitcoin::secp256k1::Secp256k1;
912         use core::convert::TryFrom;
913         use core::num::NonZeroU64;
914         use core::time::Duration;
915         use crate::blinded_path::{BlindedHop, BlindedPath};
916         use crate::sign::KeyMaterial;
917         use crate::ln::features::OfferFeatures;
918         use crate::ln::inbound_payment::ExpandedKey;
919         use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
920         use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
921         use crate::offers::test_utils::*;
922         use crate::util::ser::{BigSize, Writeable};
923         use crate::util::string::PrintableString;
924
925         #[test]
926         fn builds_offer_with_defaults() {
927                 let offer = OfferBuilder::new("foo".into(), pubkey(42)).build().unwrap();
928
929                 let mut buffer = Vec::new();
930                 offer.write(&mut buffer).unwrap();
931
932                 assert_eq!(offer.bytes, buffer.as_slice());
933                 assert_eq!(offer.chains(), vec![ChainHash::using_genesis_block(Network::Bitcoin)]);
934                 assert!(offer.supports_chain(ChainHash::using_genesis_block(Network::Bitcoin)));
935                 assert_eq!(offer.metadata(), None);
936                 assert_eq!(offer.amount(), None);
937                 assert_eq!(offer.description(), PrintableString("foo"));
938                 assert_eq!(offer.offer_features(), &OfferFeatures::empty());
939                 assert_eq!(offer.absolute_expiry(), None);
940                 #[cfg(feature = "std")]
941                 assert!(!offer.is_expired());
942                 assert_eq!(offer.paths(), &[]);
943                 assert_eq!(offer.issuer(), None);
944                 assert_eq!(offer.supported_quantity(), Quantity::One);
945                 assert_eq!(offer.signing_pubkey(), pubkey(42));
946
947                 assert_eq!(
948                         offer.as_tlv_stream(),
949                         OfferTlvStreamRef {
950                                 chains: None,
951                                 metadata: None,
952                                 currency: None,
953                                 amount: None,
954                                 description: Some(&String::from("foo")),
955                                 features: None,
956                                 absolute_expiry: None,
957                                 paths: None,
958                                 issuer: None,
959                                 quantity_max: None,
960                                 node_id: Some(&pubkey(42)),
961                         },
962                 );
963
964                 if let Err(e) = Offer::try_from(buffer) {
965                         panic!("error parsing offer: {:?}", e);
966                 }
967         }
968
969         #[test]
970         fn builds_offer_with_chains() {
971                 let mainnet = ChainHash::using_genesis_block(Network::Bitcoin);
972                 let testnet = ChainHash::using_genesis_block(Network::Testnet);
973
974                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
975                         .chain(Network::Bitcoin)
976                         .build()
977                         .unwrap();
978                 assert!(offer.supports_chain(mainnet));
979                 assert_eq!(offer.chains(), vec![mainnet]);
980                 assert_eq!(offer.as_tlv_stream().chains, None);
981
982                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
983                         .chain(Network::Testnet)
984                         .build()
985                         .unwrap();
986                 assert!(offer.supports_chain(testnet));
987                 assert_eq!(offer.chains(), vec![testnet]);
988                 assert_eq!(offer.as_tlv_stream().chains, Some(&vec![testnet]));
989
990                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
991                         .chain(Network::Testnet)
992                         .chain(Network::Testnet)
993                         .build()
994                         .unwrap();
995                 assert!(offer.supports_chain(testnet));
996                 assert_eq!(offer.chains(), vec![testnet]);
997                 assert_eq!(offer.as_tlv_stream().chains, Some(&vec![testnet]));
998
999                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1000                         .chain(Network::Bitcoin)
1001                         .chain(Network::Testnet)
1002                         .build()
1003                         .unwrap();
1004                 assert!(offer.supports_chain(mainnet));
1005                 assert!(offer.supports_chain(testnet));
1006                 assert_eq!(offer.chains(), vec![mainnet, testnet]);
1007                 assert_eq!(offer.as_tlv_stream().chains, Some(&vec![mainnet, testnet]));
1008         }
1009
1010         #[test]
1011         fn builds_offer_with_metadata() {
1012                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1013                         .metadata(vec![42; 32]).unwrap()
1014                         .build()
1015                         .unwrap();
1016                 assert_eq!(offer.metadata(), Some(&vec![42; 32]));
1017                 assert_eq!(offer.as_tlv_stream().metadata, Some(&vec![42; 32]));
1018
1019                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1020                         .metadata(vec![42; 32]).unwrap()
1021                         .metadata(vec![43; 32]).unwrap()
1022                         .build()
1023                         .unwrap();
1024                 assert_eq!(offer.metadata(), Some(&vec![43; 32]));
1025                 assert_eq!(offer.as_tlv_stream().metadata, Some(&vec![43; 32]));
1026         }
1027
1028         #[test]
1029         fn builds_offer_with_metadata_derived() {
1030                 let desc = "foo".to_string();
1031                 let node_id = recipient_pubkey();
1032                 let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
1033                 let entropy = FixedEntropy {};
1034                 let secp_ctx = Secp256k1::new();
1035
1036                 let offer = OfferBuilder
1037                         ::deriving_signing_pubkey(desc, node_id, &expanded_key, &entropy, &secp_ctx)
1038                         .amount_msats(1000)
1039                         .build().unwrap();
1040                 assert_eq!(offer.signing_pubkey(), node_id);
1041
1042                 let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1043                         .build().unwrap()
1044                         .sign(payer_sign).unwrap();
1045                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_ok());
1046
1047                 // Fails verification with altered offer field
1048                 let mut tlv_stream = offer.as_tlv_stream();
1049                 tlv_stream.amount = Some(100);
1050
1051                 let mut encoded_offer = Vec::new();
1052                 tlv_stream.write(&mut encoded_offer).unwrap();
1053
1054                 let invoice_request = Offer::try_from(encoded_offer).unwrap()
1055                         .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1056                         .build().unwrap()
1057                         .sign(payer_sign).unwrap();
1058                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err());
1059
1060                 // Fails verification with altered metadata
1061                 let mut tlv_stream = offer.as_tlv_stream();
1062                 let metadata = tlv_stream.metadata.unwrap().iter().copied().rev().collect();
1063                 tlv_stream.metadata = Some(&metadata);
1064
1065                 let mut encoded_offer = Vec::new();
1066                 tlv_stream.write(&mut encoded_offer).unwrap();
1067
1068                 let invoice_request = Offer::try_from(encoded_offer).unwrap()
1069                         .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1070                         .build().unwrap()
1071                         .sign(payer_sign).unwrap();
1072                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err());
1073         }
1074
1075         #[test]
1076         fn builds_offer_with_derived_signing_pubkey() {
1077                 let desc = "foo".to_string();
1078                 let node_id = recipient_pubkey();
1079                 let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
1080                 let entropy = FixedEntropy {};
1081                 let secp_ctx = Secp256k1::new();
1082
1083                 let blinded_path = BlindedPath {
1084                         introduction_node_id: pubkey(40),
1085                         blinding_point: pubkey(41),
1086                         blinded_hops: vec![
1087                                 BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] },
1088                                 BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] },
1089                         ],
1090                 };
1091
1092                 let offer = OfferBuilder
1093                         ::deriving_signing_pubkey(desc, node_id, &expanded_key, &entropy, &secp_ctx)
1094                         .amount_msats(1000)
1095                         .path(blinded_path)
1096                         .build().unwrap();
1097                 assert_ne!(offer.signing_pubkey(), node_id);
1098
1099                 let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1100                         .build().unwrap()
1101                         .sign(payer_sign).unwrap();
1102                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_ok());
1103
1104                 // Fails verification with altered offer field
1105                 let mut tlv_stream = offer.as_tlv_stream();
1106                 tlv_stream.amount = Some(100);
1107
1108                 let mut encoded_offer = Vec::new();
1109                 tlv_stream.write(&mut encoded_offer).unwrap();
1110
1111                 let invoice_request = Offer::try_from(encoded_offer).unwrap()
1112                         .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1113                         .build().unwrap()
1114                         .sign(payer_sign).unwrap();
1115                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err());
1116
1117                 // Fails verification with altered signing pubkey
1118                 let mut tlv_stream = offer.as_tlv_stream();
1119                 let signing_pubkey = pubkey(1);
1120                 tlv_stream.node_id = Some(&signing_pubkey);
1121
1122                 let mut encoded_offer = Vec::new();
1123                 tlv_stream.write(&mut encoded_offer).unwrap();
1124
1125                 let invoice_request = Offer::try_from(encoded_offer).unwrap()
1126                         .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
1127                         .build().unwrap()
1128                         .sign(payer_sign).unwrap();
1129                 assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err());
1130         }
1131
1132         #[test]
1133         fn builds_offer_with_amount() {
1134                 let bitcoin_amount = Amount::Bitcoin { amount_msats: 1000 };
1135                 let currency_amount = Amount::Currency { iso4217_code: *b"USD", amount: 10 };
1136
1137                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1138                         .amount_msats(1000)
1139                         .build()
1140                         .unwrap();
1141                 let tlv_stream = offer.as_tlv_stream();
1142                 assert_eq!(offer.amount(), Some(&bitcoin_amount));
1143                 assert_eq!(tlv_stream.amount, Some(1000));
1144                 assert_eq!(tlv_stream.currency, None);
1145
1146                 let builder = OfferBuilder::new("foo".into(), pubkey(42))
1147                         .amount(currency_amount.clone());
1148                 let tlv_stream = builder.offer.as_tlv_stream();
1149                 assert_eq!(builder.offer.amount, Some(currency_amount.clone()));
1150                 assert_eq!(tlv_stream.amount, Some(10));
1151                 assert_eq!(tlv_stream.currency, Some(b"USD"));
1152                 match builder.build() {
1153                         Ok(_) => panic!("expected error"),
1154                         Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedCurrency),
1155                 }
1156
1157                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1158                         .amount(currency_amount.clone())
1159                         .amount(bitcoin_amount.clone())
1160                         .build()
1161                         .unwrap();
1162                 let tlv_stream = offer.as_tlv_stream();
1163                 assert_eq!(tlv_stream.amount, Some(1000));
1164                 assert_eq!(tlv_stream.currency, None);
1165
1166                 let invalid_amount = Amount::Bitcoin { amount_msats: MAX_VALUE_MSAT + 1 };
1167                 match OfferBuilder::new("foo".into(), pubkey(42)).amount(invalid_amount).build() {
1168                         Ok(_) => panic!("expected error"),
1169                         Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
1170                 }
1171         }
1172
1173         #[test]
1174         fn builds_offer_with_features() {
1175                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1176                         .features_unchecked(OfferFeatures::unknown())
1177                         .build()
1178                         .unwrap();
1179                 assert_eq!(offer.offer_features(), &OfferFeatures::unknown());
1180                 assert_eq!(offer.as_tlv_stream().features, Some(&OfferFeatures::unknown()));
1181
1182                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1183                         .features_unchecked(OfferFeatures::unknown())
1184                         .features_unchecked(OfferFeatures::empty())
1185                         .build()
1186                         .unwrap();
1187                 assert_eq!(offer.offer_features(), &OfferFeatures::empty());
1188                 assert_eq!(offer.as_tlv_stream().features, None);
1189         }
1190
1191         #[test]
1192         fn builds_offer_with_absolute_expiry() {
1193                 let future_expiry = Duration::from_secs(u64::max_value());
1194                 let past_expiry = Duration::from_secs(0);
1195
1196                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1197                         .absolute_expiry(future_expiry)
1198                         .build()
1199                         .unwrap();
1200                 #[cfg(feature = "std")]
1201                 assert!(!offer.is_expired());
1202                 assert_eq!(offer.absolute_expiry(), Some(future_expiry));
1203                 assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(future_expiry.as_secs()));
1204
1205                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1206                         .absolute_expiry(future_expiry)
1207                         .absolute_expiry(past_expiry)
1208                         .build()
1209                         .unwrap();
1210                 #[cfg(feature = "std")]
1211                 assert!(offer.is_expired());
1212                 assert_eq!(offer.absolute_expiry(), Some(past_expiry));
1213                 assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(past_expiry.as_secs()));
1214         }
1215
1216         #[test]
1217         fn builds_offer_with_paths() {
1218                 let paths = vec![
1219                         BlindedPath {
1220                                 introduction_node_id: pubkey(40),
1221                                 blinding_point: pubkey(41),
1222                                 blinded_hops: vec![
1223                                         BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
1224                                         BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
1225                                 ],
1226                         },
1227                         BlindedPath {
1228                                 introduction_node_id: pubkey(40),
1229                                 blinding_point: pubkey(41),
1230                                 blinded_hops: vec![
1231                                         BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] },
1232                                         BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] },
1233                                 ],
1234                         },
1235                 ];
1236
1237                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1238                         .path(paths[0].clone())
1239                         .path(paths[1].clone())
1240                         .build()
1241                         .unwrap();
1242                 let tlv_stream = offer.as_tlv_stream();
1243                 assert_eq!(offer.paths(), paths.as_slice());
1244                 assert_eq!(offer.signing_pubkey(), pubkey(42));
1245                 assert_ne!(pubkey(42), pubkey(44));
1246                 assert_eq!(tlv_stream.paths, Some(&paths));
1247                 assert_eq!(tlv_stream.node_id, Some(&pubkey(42)));
1248         }
1249
1250         #[test]
1251         fn builds_offer_with_issuer() {
1252                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1253                         .issuer("bar".into())
1254                         .build()
1255                         .unwrap();
1256                 assert_eq!(offer.issuer(), Some(PrintableString("bar")));
1257                 assert_eq!(offer.as_tlv_stream().issuer, Some(&String::from("bar")));
1258
1259                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1260                         .issuer("bar".into())
1261                         .issuer("baz".into())
1262                         .build()
1263                         .unwrap();
1264                 assert_eq!(offer.issuer(), Some(PrintableString("baz")));
1265                 assert_eq!(offer.as_tlv_stream().issuer, Some(&String::from("baz")));
1266         }
1267
1268         #[test]
1269         fn builds_offer_with_supported_quantity() {
1270                 let one = NonZeroU64::new(1).unwrap();
1271                 let ten = NonZeroU64::new(10).unwrap();
1272
1273                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1274                         .supported_quantity(Quantity::One)
1275                         .build()
1276                         .unwrap();
1277                 let tlv_stream = offer.as_tlv_stream();
1278                 assert_eq!(offer.supported_quantity(), Quantity::One);
1279                 assert_eq!(tlv_stream.quantity_max, None);
1280
1281                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1282                         .supported_quantity(Quantity::Unbounded)
1283                         .build()
1284                         .unwrap();
1285                 let tlv_stream = offer.as_tlv_stream();
1286                 assert_eq!(offer.supported_quantity(), Quantity::Unbounded);
1287                 assert_eq!(tlv_stream.quantity_max, Some(0));
1288
1289                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1290                         .supported_quantity(Quantity::Bounded(ten))
1291                         .build()
1292                         .unwrap();
1293                 let tlv_stream = offer.as_tlv_stream();
1294                 assert_eq!(offer.supported_quantity(), Quantity::Bounded(ten));
1295                 assert_eq!(tlv_stream.quantity_max, Some(10));
1296
1297                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1298                         .supported_quantity(Quantity::Bounded(one))
1299                         .build()
1300                         .unwrap();
1301                 let tlv_stream = offer.as_tlv_stream();
1302                 assert_eq!(offer.supported_quantity(), Quantity::Bounded(one));
1303                 assert_eq!(tlv_stream.quantity_max, Some(1));
1304
1305                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1306                         .supported_quantity(Quantity::Bounded(ten))
1307                         .supported_quantity(Quantity::One)
1308                         .build()
1309                         .unwrap();
1310                 let tlv_stream = offer.as_tlv_stream();
1311                 assert_eq!(offer.supported_quantity(), Quantity::One);
1312                 assert_eq!(tlv_stream.quantity_max, None);
1313         }
1314
1315         #[test]
1316         fn fails_requesting_invoice_with_unknown_required_features() {
1317                 match OfferBuilder::new("foo".into(), pubkey(42))
1318                         .features_unchecked(OfferFeatures::unknown())
1319                         .build().unwrap()
1320                         .request_invoice(vec![1; 32], pubkey(43))
1321                 {
1322                         Ok(_) => panic!("expected error"),
1323                         Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
1324                 }
1325         }
1326
1327         #[test]
1328         fn parses_offer_with_chains() {
1329                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1330                         .chain(Network::Bitcoin)
1331                         .chain(Network::Testnet)
1332                         .build()
1333                         .unwrap();
1334                 if let Err(e) = offer.to_string().parse::<Offer>() {
1335                         panic!("error parsing offer: {:?}", e);
1336                 }
1337         }
1338
1339         #[test]
1340         fn parses_offer_with_amount() {
1341                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1342                         .amount(Amount::Bitcoin { amount_msats: 1000 })
1343                         .build()
1344                         .unwrap();
1345                 if let Err(e) = offer.to_string().parse::<Offer>() {
1346                         panic!("error parsing offer: {:?}", e);
1347                 }
1348
1349                 let mut tlv_stream = offer.as_tlv_stream();
1350                 tlv_stream.amount = Some(1000);
1351                 tlv_stream.currency = Some(b"USD");
1352
1353                 let mut encoded_offer = Vec::new();
1354                 tlv_stream.write(&mut encoded_offer).unwrap();
1355
1356                 if let Err(e) = Offer::try_from(encoded_offer) {
1357                         panic!("error parsing offer: {:?}", e);
1358                 }
1359
1360                 let mut tlv_stream = offer.as_tlv_stream();
1361                 tlv_stream.amount = None;
1362                 tlv_stream.currency = Some(b"USD");
1363
1364                 let mut encoded_offer = Vec::new();
1365                 tlv_stream.write(&mut encoded_offer).unwrap();
1366
1367                 match Offer::try_from(encoded_offer) {
1368                         Ok(_) => panic!("expected error"),
1369                         Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)),
1370                 }
1371
1372                 let mut tlv_stream = offer.as_tlv_stream();
1373                 tlv_stream.amount = Some(MAX_VALUE_MSAT + 1);
1374                 tlv_stream.currency = None;
1375
1376                 let mut encoded_offer = Vec::new();
1377                 tlv_stream.write(&mut encoded_offer).unwrap();
1378
1379                 match Offer::try_from(encoded_offer) {
1380                         Ok(_) => panic!("expected error"),
1381                         Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidAmount)),
1382                 }
1383         }
1384
1385         #[test]
1386         fn parses_offer_with_description() {
1387                 let offer = OfferBuilder::new("foo".into(), pubkey(42)).build().unwrap();
1388                 if let Err(e) = offer.to_string().parse::<Offer>() {
1389                         panic!("error parsing offer: {:?}", e);
1390                 }
1391
1392                 let mut tlv_stream = offer.as_tlv_stream();
1393                 tlv_stream.description = None;
1394
1395                 let mut encoded_offer = Vec::new();
1396                 tlv_stream.write(&mut encoded_offer).unwrap();
1397
1398                 match Offer::try_from(encoded_offer) {
1399                         Ok(_) => panic!("expected error"),
1400                         Err(e) => {
1401                                 assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription));
1402                         },
1403                 }
1404         }
1405
1406         #[test]
1407         fn parses_offer_with_paths() {
1408                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1409                         .path(BlindedPath {
1410                                 introduction_node_id: pubkey(40),
1411                                 blinding_point: pubkey(41),
1412                                 blinded_hops: vec![
1413                                         BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
1414                                         BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
1415                                 ],
1416                         })
1417                         .path(BlindedPath {
1418                                 introduction_node_id: pubkey(40),
1419                                 blinding_point: pubkey(41),
1420                                 blinded_hops: vec![
1421                                         BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] },
1422                                         BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] },
1423                                 ],
1424                         })
1425                         .build()
1426                         .unwrap();
1427                 if let Err(e) = offer.to_string().parse::<Offer>() {
1428                         panic!("error parsing offer: {:?}", e);
1429                 }
1430
1431                 let mut builder = OfferBuilder::new("foo".into(), pubkey(42));
1432                 builder.offer.paths = Some(vec![]);
1433
1434                 let offer = builder.build().unwrap();
1435                 if let Err(e) = offer.to_string().parse::<Offer>() {
1436                         panic!("error parsing offer: {:?}", e);
1437                 }
1438         }
1439
1440         #[test]
1441         fn parses_offer_with_quantity() {
1442                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1443                         .supported_quantity(Quantity::One)
1444                         .build()
1445                         .unwrap();
1446                 if let Err(e) = offer.to_string().parse::<Offer>() {
1447                         panic!("error parsing offer: {:?}", e);
1448                 }
1449
1450                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1451                         .supported_quantity(Quantity::Unbounded)
1452                         .build()
1453                         .unwrap();
1454                 if let Err(e) = offer.to_string().parse::<Offer>() {
1455                         panic!("error parsing offer: {:?}", e);
1456                 }
1457
1458                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1459                         .supported_quantity(Quantity::Bounded(NonZeroU64::new(10).unwrap()))
1460                         .build()
1461                         .unwrap();
1462                 if let Err(e) = offer.to_string().parse::<Offer>() {
1463                         panic!("error parsing offer: {:?}", e);
1464                 }
1465
1466                 let offer = OfferBuilder::new("foo".into(), pubkey(42))
1467                         .supported_quantity(Quantity::Bounded(NonZeroU64::new(1).unwrap()))
1468                         .build()
1469                         .unwrap();
1470                 if let Err(e) = offer.to_string().parse::<Offer>() {
1471                         panic!("error parsing offer: {:?}", e);
1472                 }
1473         }
1474
1475         #[test]
1476         fn parses_offer_with_node_id() {
1477                 let offer = OfferBuilder::new("foo".into(), pubkey(42)).build().unwrap();
1478                 if let Err(e) = offer.to_string().parse::<Offer>() {
1479                         panic!("error parsing offer: {:?}", e);
1480                 }
1481
1482                 let mut tlv_stream = offer.as_tlv_stream();
1483                 tlv_stream.node_id = None;
1484
1485                 let mut encoded_offer = Vec::new();
1486                 tlv_stream.write(&mut encoded_offer).unwrap();
1487
1488                 match Offer::try_from(encoded_offer) {
1489                         Ok(_) => panic!("expected error"),
1490                         Err(e) => {
1491                                 assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
1492                         },
1493                 }
1494         }
1495
1496         #[test]
1497         fn fails_parsing_offer_with_extra_tlv_records() {
1498                 let offer = OfferBuilder::new("foo".into(), pubkey(42)).build().unwrap();
1499
1500                 let mut encoded_offer = Vec::new();
1501                 offer.write(&mut encoded_offer).unwrap();
1502                 BigSize(80).write(&mut encoded_offer).unwrap();
1503                 BigSize(32).write(&mut encoded_offer).unwrap();
1504                 [42u8; 32].write(&mut encoded_offer).unwrap();
1505
1506                 match Offer::try_from(encoded_offer) {
1507                         Ok(_) => panic!("expected error"),
1508                         Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
1509                 }
1510         }
1511 }
1512
1513 #[cfg(test)]
1514 mod bech32_tests {
1515         use super::{Bolt12ParseError, Offer};
1516         use bitcoin::bech32;
1517         use crate::ln::msgs::DecodeError;
1518
1519         #[test]
1520         fn encodes_offer_as_bech32_without_checksum() {
1521                 let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg";
1522                 let offer = dbg!(encoded_offer.parse::<Offer>().unwrap());
1523                 let reencoded_offer = offer.to_string();
1524                 dbg!(reencoded_offer.parse::<Offer>().unwrap());
1525                 assert_eq!(reencoded_offer, encoded_offer);
1526         }
1527
1528         #[test]
1529         fn parses_bech32_encoded_offers() {
1530                 let offers = [
1531                         // BOLT 12 test vectors
1532                         "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
1533                         "l+no1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
1534                         "lno1pqps7sjqpgt+yzm3qv4uxzmtsd3jjqer9wd3hy6tsw3+5k7msjzfpy7nz5yqcn+ygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd+5xvxg",
1535                         "lno1pqps7sjqpgt+ yzm3qv4uxzmtsd3jjqer9wd3hy6tsw3+  5k7msjzfpy7nz5yqcn+\nygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd+\r\n 5xvxg",
1536                 ];
1537                 for encoded_offer in &offers {
1538                         if let Err(e) = encoded_offer.parse::<Offer>() {
1539                                 panic!("Invalid offer ({:?}): {}", e, encoded_offer);
1540                         }
1541                 }
1542         }
1543
1544         #[test]
1545         fn fails_parsing_bech32_encoded_offers_with_invalid_continuations() {
1546                 let offers = [
1547                         // BOLT 12 test vectors
1548                         "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg+",
1549                         "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg+ ",
1550                         "+lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
1551                         "+ lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
1552                         "ln++o1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
1553                 ];
1554                 for encoded_offer in &offers {
1555                         match encoded_offer.parse::<Offer>() {
1556                                 Ok(_) => panic!("Valid offer: {}", encoded_offer),
1557                                 Err(e) => assert_eq!(e, Bolt12ParseError::InvalidContinuation),
1558                         }
1559                 }
1560
1561         }
1562
1563         #[test]
1564         fn fails_parsing_bech32_encoded_offer_with_invalid_hrp() {
1565                 let encoded_offer = "lni1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg";
1566                 match encoded_offer.parse::<Offer>() {
1567                         Ok(_) => panic!("Valid offer: {}", encoded_offer),
1568                         Err(e) => assert_eq!(e, Bolt12ParseError::InvalidBech32Hrp),
1569                 }
1570         }
1571
1572         #[test]
1573         fn fails_parsing_bech32_encoded_offer_with_invalid_bech32_data() {
1574                 let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxo";
1575                 match encoded_offer.parse::<Offer>() {
1576                         Ok(_) => panic!("Valid offer: {}", encoded_offer),
1577                         Err(e) => assert_eq!(e, Bolt12ParseError::Bech32(bech32::Error::InvalidChar('o'))),
1578                 }
1579         }
1580
1581         #[test]
1582         fn fails_parsing_bech32_encoded_offer_with_invalid_tlv_data() {
1583                 let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxgqqqqq";
1584                 match encoded_offer.parse::<Offer>() {
1585                         Ok(_) => panic!("Valid offer: {}", encoded_offer),
1586                         Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
1587                 }
1588         }
1589 }