@@ -138,7 +138,7 @@ use crate::offers::offer::{
138
138
Amount , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OfferTlvStream ,
139
139
OfferTlvStreamRef , Quantity , EXPERIMENTAL_OFFER_TYPES , OFFER_TYPES ,
140
140
} ;
141
- use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
141
+ use crate :: offers:: parse:: { Bech32Encode , Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
142
142
use crate :: offers:: payer:: { PayerTlvStream , PayerTlvStreamRef , PAYER_METADATA_TYPE } ;
143
143
use crate :: offers:: refund:: {
144
144
Refund , RefundContents , IV_BYTES_WITHOUT_METADATA as REFUND_IV_BYTES_WITHOUT_METADATA ,
@@ -158,6 +158,7 @@ use bitcoin::secp256k1::schnorr::Signature;
158
158
use bitcoin:: secp256k1:: { self , Keypair , PublicKey , Secp256k1 } ;
159
159
use bitcoin:: { Network , WitnessProgram , WitnessVersion } ;
160
160
use core:: hash:: { Hash , Hasher } ;
161
+ use core:: str:: FromStr ;
161
162
use core:: time:: Duration ;
162
163
163
164
#[ allow( unused_imports) ]
@@ -1416,6 +1417,30 @@ impl Writeable for InvoiceContents {
1416
1417
}
1417
1418
}
1418
1419
1420
+ impl AsRef < [ u8 ] > for Bolt12Invoice {
1421
+ fn as_ref ( & self ) -> & [ u8 ] {
1422
+ & self . bytes
1423
+ }
1424
+ }
1425
+
1426
+ impl Bech32Encode for Bolt12Invoice {
1427
+ const BECH32_HRP : & ' static str = "lni" ;
1428
+ }
1429
+
1430
+ impl FromStr for Bolt12Invoice {
1431
+ type Err = Bolt12ParseError ;
1432
+
1433
+ fn from_str ( s : & str ) -> Result < Self , <Self as FromStr >:: Err > {
1434
+ Self :: from_bech32_str ( s)
1435
+ }
1436
+ }
1437
+
1438
+ impl core:: fmt:: Display for Bolt12Invoice {
1439
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter ) -> Result < ( ) , core:: fmt:: Error > {
1440
+ self . fmt_bech32_str ( f)
1441
+ }
1442
+ }
1443
+
1419
1444
impl TryFrom < Vec < u8 > > for UnsignedBolt12Invoice {
1420
1445
type Error = Bolt12ParseError ;
1421
1446
@@ -2572,6 +2597,22 @@ mod tests {
2572
2597
}
2573
2598
}
2574
2599
2600
+ #[ test]
2601
+ fn parses_bech32_encoded_invoices ( ) {
2602
+ let invoices = [
2603
+ "lni1qqsg7jpsyzz4hcsj0hu6rvjevwhmkceurq7sd5ez8ne3js4qt8acvxcgqgp7szsqzcss9w6ckhlv55zuwnkuqqxc9qhu24h9rggzflyw04l9d3hcslzu340jtqss9l7txvy6ukzg8zkxdnvzmg2at4stt004vdqrm0zedsez596nf5w55r7sr3qzhfe2d696205tjuddpjvz8952aaxh3n527f26ks7llqcq8jgzlwxsxhzwphk8y90zdqee8pesuhjst2nz2px6ska9wyr2g666ysz0e8vwqgptkk94lm99qhr5ahqqpkpg9lz4deg6zqj0erna0etvd7y8chydtusq9vqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz3afsfc3h8etwulthfjufa8c6lm8saelrud6h7xyeprcxnk4rd3sqqtqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq46w2nw3wjnazuhrtgvnq3edzh0f4uvazhj2k458hlcxqpujqhm35p4cnsda3eptcngxwfcwv89u5z65cjsfk59hft3q6jxkk3yqn7fmrszqw2gk576jl7lvaxqsae3tt9uepmp4gae5kptgwvc97a04jvljuss7qpdqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0vc5l00vl5rwqgc7cmxyrgtuz8dvv6yma5qs2609uvyfe7wvq2gxqpwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz3rsqqqqqqsqqqraqqz5qqqqqqqqqqqvsqqqq8g6jj3qqqqqqqqqqqpqqqq86qq9gqqqqqqqqqqqeqqqqqw3499zqqqqq9yq35rr8sh4qsz52329g4z52329g4z52329g4z52329g4z52329g4z52329g4z5242qgp73tzaqqqzpcasc3pf3lquzjd0haxgn9hmjfp84eq7geymjdx2f9verdu99wz4qqqpf67qrgen88wz7kzlkpyp480l5rgzecaz2qgqyza43d07efg9ca8dcqqds2p0c4tw2xssyn7gult72mr03p79er2l9vppq2a43d07efg9ca8dcqqds2p0c4tw2xssyn7gult72mr03p79er2l9uzq9wktr4p2qxgmdnpw8qvs05qr0zvam2h52lxt4zz7lah7yp6vmsczevlvqdgjxtwdlp84304uqcygvqcgzpj8p44smqjpzeua0xryrrc"
2604
+ ] ;
2605
+ for encoded in invoices {
2606
+ let decoded = match encoded. parse :: < Bolt12Invoice > ( ) {
2607
+ Ok ( decoded) => decoded,
2608
+ Err ( e) => panic ! ( "Invalid invoice ({:?}): {}" , e, encoded) ,
2609
+ } ;
2610
+
2611
+ let reencoded = decoded. to_string ( ) ;
2612
+ assert_eq ! ( reencoded, encoded, "Re-encoded invoice does not match original" ) ;
2613
+ }
2614
+ }
2615
+
2575
2616
#[ test]
2576
2617
fn parses_invoice_with_payment_paths ( ) {
2577
2618
let expanded_key = ExpandedKey :: new ( [ 42 ; 32 ] ) ;
0 commit comments