@@ -79,7 +79,7 @@ use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
79
79
use crate :: ln:: msgs:: DecodeError ;
80
80
use crate :: offers:: merkle:: { SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , self , SIGNATURE_TLV_RECORD_SIZE } ;
81
81
use crate :: offers:: nonce:: Nonce ;
82
- use crate :: offers:: offer:: { EXPERIMENTAL_OFFER_TYPES , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OFFER_TYPES , Offer , OfferContents , OfferId , OfferTlvStream , OfferTlvStreamRef } ;
82
+ use crate :: offers:: offer:: { Amount , EXPERIMENTAL_OFFER_TYPES , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OFFER_TYPES , Offer , OfferContents , OfferId , OfferTlvStream , OfferTlvStreamRef } ;
83
83
use crate :: offers:: parse:: { Bolt12ParseError , ParsedMessage , Bolt12SemanticError } ;
84
84
use crate :: offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
85
85
use crate :: offers:: signer:: { Metadata , MetadataMaterial } ;
@@ -665,6 +665,15 @@ macro_rules! invoice_request_accessors { ($self: ident, $contents: expr) => {
665
665
$contents. amount_msats( )
666
666
}
667
667
668
+ /// Returns whether an amount was set in the request; otherwise, if [`amount_msats`] is `Some`
669
+ /// then it was inferred from the [`Offer::amount`] and [`quantity`].
670
+ ///
671
+ /// [`amount_msats`]: Self::amount_msats
672
+ /// [`quantity`]: Self::quantity
673
+ pub fn has_amount_msats( & $self) -> bool {
674
+ $contents. has_amount_msats( )
675
+ }
676
+
668
677
/// Features pertaining to requesting an invoice.
669
678
pub fn invoice_request_features( & $self) -> & InvoiceRequestFeatures {
670
679
& $contents. features( )
@@ -974,7 +983,19 @@ impl InvoiceRequestContents {
974
983
}
975
984
976
985
pub ( super ) fn amount_msats ( & self ) -> Option < u64 > {
977
- self . inner . amount_msats
986
+ self . inner
987
+ . amount_msats ( )
988
+ . or_else ( || match self . inner . offer . amount ( ) {
989
+ Some ( Amount :: Bitcoin { amount_msats } ) => {
990
+ Some ( amount_msats. saturating_mul ( self . quantity ( ) . unwrap_or ( 1 ) ) )
991
+ } ,
992
+ Some ( Amount :: Currency { .. } ) => None ,
993
+ None => { debug_assert ! ( false ) ; None } ,
994
+ } )
995
+ }
996
+
997
+ pub ( super ) fn has_amount_msats ( & self ) -> bool {
998
+ self . inner . amount_msats ( ) . is_some ( )
978
999
}
979
1000
980
1001
pub ( super ) fn features ( & self ) -> & InvoiceRequestFeatures {
@@ -1015,6 +1036,10 @@ impl InvoiceRequestContentsWithoutPayerSigningPubkey {
1015
1036
self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
1016
1037
}
1017
1038
1039
+ pub ( super ) fn amount_msats ( & self ) -> Option < u64 > {
1040
+ self . amount_msats
1041
+ }
1042
+
1018
1043
pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
1019
1044
let payer = PayerTlvStreamRef {
1020
1045
metadata : self . payer . 0 . as_bytes ( ) ,
@@ -1381,7 +1406,7 @@ mod tests {
1381
1406
assert_eq ! ( invoice_request. supported_quantity( ) , Quantity :: One ) ;
1382
1407
assert_eq ! ( invoice_request. issuer_signing_pubkey( ) , Some ( recipient_pubkey( ) ) ) ;
1383
1408
assert_eq ! ( invoice_request. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1384
- assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1409
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
1385
1410
assert_eq ! ( invoice_request. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1386
1411
assert_eq ! ( invoice_request. quantity( ) , None ) ;
1387
1412
assert_eq ! ( invoice_request. payer_note( ) , None ) ;
@@ -1657,6 +1682,7 @@ mod tests {
1657
1682
. amount_msats ( 1000 ) . unwrap ( )
1658
1683
. build_and_sign ( ) . unwrap ( ) ;
1659
1684
let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1685
+ assert ! ( invoice_request. has_amount_msats( ) ) ;
1660
1686
assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
1661
1687
assert_eq ! ( tlv_stream. amount, Some ( 1000 ) ) ;
1662
1688
@@ -1668,6 +1694,7 @@ mod tests {
1668
1694
. amount_msats ( 1000 ) . unwrap ( )
1669
1695
. build_and_sign ( ) . unwrap ( ) ;
1670
1696
let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1697
+ assert ! ( invoice_request. has_amount_msats( ) ) ;
1671
1698
assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
1672
1699
assert_eq ! ( tlv_stream. amount, Some ( 1000 ) ) ;
1673
1700
@@ -1678,6 +1705,7 @@ mod tests {
1678
1705
. amount_msats ( 1001 ) . unwrap ( )
1679
1706
. build_and_sign ( ) . unwrap ( ) ;
1680
1707
let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1708
+ assert ! ( invoice_request. has_amount_msats( ) ) ;
1681
1709
assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1001 ) ) ;
1682
1710
assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
1683
1711
@@ -1748,6 +1776,47 @@ mod tests {
1748
1776
}
1749
1777
}
1750
1778
1779
+ #[ test]
1780
+ fn builds_invoice_request_without_amount ( ) {
1781
+ let expanded_key = ExpandedKey :: new ( [ 42 ; 32 ] ) ;
1782
+ let entropy = FixedEntropy { } ;
1783
+ let nonce = Nonce :: from_entropy_source ( & entropy) ;
1784
+ let secp_ctx = Secp256k1 :: new ( ) ;
1785
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1786
+
1787
+ let invoice_request = OfferBuilder :: new ( recipient_pubkey ( ) )
1788
+ . amount_msats ( 1000 )
1789
+ . build ( ) . unwrap ( )
1790
+ . request_invoice ( & expanded_key, nonce, & secp_ctx, payment_id) . unwrap ( )
1791
+ . build_and_sign ( ) . unwrap ( ) ;
1792
+ let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1793
+ assert ! ( !invoice_request. has_amount_msats( ) ) ;
1794
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
1795
+ assert_eq ! ( tlv_stream. amount, None ) ;
1796
+
1797
+ let invoice_request = OfferBuilder :: new ( recipient_pubkey ( ) )
1798
+ . amount_msats ( 1000 )
1799
+ . supported_quantity ( Quantity :: Unbounded )
1800
+ . build ( ) . unwrap ( )
1801
+ . request_invoice ( & expanded_key, nonce, & secp_ctx, payment_id) . unwrap ( )
1802
+ . quantity ( 2 ) . unwrap ( )
1803
+ . build_and_sign ( ) . unwrap ( ) ;
1804
+ let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1805
+ assert ! ( !invoice_request. has_amount_msats( ) ) ;
1806
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 2000 ) ) ;
1807
+ assert_eq ! ( tlv_stream. amount, None ) ;
1808
+
1809
+ let invoice_request = OfferBuilder :: new ( recipient_pubkey ( ) )
1810
+ . amount ( Amount :: Currency { iso4217_code : * b"USD" , amount : 10 } )
1811
+ . build_unchecked ( )
1812
+ . request_invoice ( & expanded_key, nonce, & secp_ctx, payment_id) . unwrap ( )
1813
+ . build_unchecked_and_sign ( ) ;
1814
+ let ( _, _, tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
1815
+ assert ! ( !invoice_request. has_amount_msats( ) ) ;
1816
+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1817
+ assert_eq ! ( tlv_stream. amount, None ) ;
1818
+ }
1819
+
1751
1820
#[ test]
1752
1821
fn builds_invoice_request_with_features ( ) {
1753
1822
let expanded_key = ExpandedKey :: new ( [ 42 ; 32 ] ) ;
0 commit comments