@@ -480,8 +480,9 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBui
480
480
}
481
481
}
482
482
483
- /// Sets the amount in pico BTC. The optimal SI prefix is choosen automatically.
484
- pub fn amount_pico_btc ( mut self , amount : u64 ) -> Self {
483
+ /// Sets the amount in millisatoshis. The optimal SI prefix is choosen automatically.
484
+ pub fn amount_milli_satoshis ( mut self , amount_msat : u64 ) -> Self {
485
+ let amount = amount_msat * 10 ; // Invoices are denominated in "pico BTC"
485
486
let biggest_possible_si_prefix = SiPrefix :: values_desc ( )
486
487
. iter ( )
487
488
. find ( |prefix| amount % prefix. multiplier ( ) == 0 )
@@ -673,6 +674,7 @@ impl<S: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, S> {
673
674
674
675
invoice. check_field_counts ( ) . expect ( "should be ensured by type signature of builder" ) ;
675
676
invoice. check_feature_bits ( ) . expect ( "should be ensured by type signature of builder" ) ;
677
+ invoice. check_amount ( ) . expect ( "should be ensured by type signature of builder" ) ;
676
678
677
679
Ok ( invoice)
678
680
}
@@ -1019,6 +1021,16 @@ impl Invoice {
1019
1021
Ok ( ( ) )
1020
1022
}
1021
1023
1024
+ /// Check that amount is a whole number of millisatoshis
1025
+ fn check_amount ( & self ) -> Result < ( ) , SemanticError > {
1026
+ if let Some ( amount_pico_btc) = self . amount_pico_btc ( ) {
1027
+ if amount_pico_btc % 10 != 0 {
1028
+ return Err ( SemanticError :: ImpreciseAmount ) ;
1029
+ }
1030
+ }
1031
+ Ok ( ( ) )
1032
+ }
1033
+
1022
1034
/// Check that feature bits are set as required
1023
1035
fn check_feature_bits ( & self ) -> Result < ( ) , SemanticError > {
1024
1036
// "If the payment_secret feature is set, MUST include exactly one s field."
@@ -1099,6 +1111,7 @@ impl Invoice {
1099
1111
invoice. check_field_counts ( ) ?;
1100
1112
invoice. check_feature_bits ( ) ?;
1101
1113
invoice. check_signature ( ) ?;
1114
+ invoice. check_amount ( ) ?;
1102
1115
1103
1116
Ok ( invoice)
1104
1117
}
@@ -1408,6 +1421,9 @@ pub enum SemanticError {
1408
1421
1409
1422
/// The invoice's signature is invalid
1410
1423
InvalidSignature ,
1424
+
1425
+ /// The invoice's amount was not a whole number of millisatoshis
1426
+ ImpreciseAmount ,
1411
1427
}
1412
1428
1413
1429
impl Display for SemanticError {
@@ -1421,6 +1437,7 @@ impl Display for SemanticError {
1421
1437
SemanticError :: InvalidFeatures => f. write_str ( "The invoice's features are invalid" ) ,
1422
1438
SemanticError :: InvalidRecoveryId => f. write_str ( "The recovery id doesn't fit the signature/pub key" ) ,
1423
1439
SemanticError :: InvalidSignature => f. write_str ( "The invoice's signature is invalid" ) ,
1440
+ SemanticError :: ImpreciseAmount => f. write_str ( "The invoice's amount was not a whole number of millisatoshis" ) ,
1424
1441
}
1425
1442
}
1426
1443
}
@@ -1670,7 +1687,7 @@ mod test {
1670
1687
. current_timestamp ( ) ;
1671
1688
1672
1689
let invoice = builder. clone ( )
1673
- . amount_pico_btc ( 15000 )
1690
+ . amount_milli_satoshis ( 1500 )
1674
1691
. build_raw ( )
1675
1692
. unwrap ( ) ;
1676
1693
@@ -1679,7 +1696,7 @@ mod test {
1679
1696
1680
1697
1681
1698
let invoice = builder. clone ( )
1682
- . amount_pico_btc ( 1500 )
1699
+ . amount_milli_satoshis ( 150 )
1683
1700
. build_raw ( )
1684
1701
. unwrap ( ) ;
1685
1702
@@ -1810,7 +1827,7 @@ mod test {
1810
1827
] ) ;
1811
1828
1812
1829
let builder = InvoiceBuilder :: new ( Currency :: BitcoinTestnet )
1813
- . amount_pico_btc ( 123 )
1830
+ . amount_milli_satoshis ( 123 )
1814
1831
. timestamp ( UNIX_EPOCH + Duration :: from_secs ( 1234567 ) )
1815
1832
. payee_pub_key ( public_key. clone ( ) )
1816
1833
. expiry_time ( Duration :: from_secs ( 54321 ) )
@@ -1830,7 +1847,7 @@ mod test {
1830
1847
assert ! ( invoice. check_signature( ) . is_ok( ) ) ;
1831
1848
assert_eq ! ( invoice. tagged_fields( ) . count( ) , 10 ) ;
1832
1849
1833
- assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 123 ) ) ;
1850
+ assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 1230 ) ) ;
1834
1851
assert_eq ! ( invoice. currency( ) , Currency :: BitcoinTestnet ) ;
1835
1852
assert_eq ! (
1836
1853
invoice. timestamp( ) . duration_since( UNIX_EPOCH ) . unwrap( ) . as_secs( ) ,
0 commit comments