@@ -138,7 +138,7 @@ use crate::offers::offer::{
138138 Amount , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OfferTlvStream ,
139139 OfferTlvStreamRef , Quantity , EXPERIMENTAL_OFFER_TYPES , OFFER_TYPES ,
140140} ;
141- use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
141+ use crate :: offers:: parse:: { Bech32Encode , Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
142142use crate :: offers:: payer:: { PayerTlvStream , PayerTlvStreamRef , PAYER_METADATA_TYPE } ;
143143use crate :: offers:: refund:: {
144144 Refund , RefundContents , IV_BYTES_WITHOUT_METADATA as REFUND_IV_BYTES_WITHOUT_METADATA ,
@@ -158,6 +158,7 @@ use bitcoin::secp256k1::schnorr::Signature;
158158use bitcoin:: secp256k1:: { self , Keypair , PublicKey , Secp256k1 } ;
159159use bitcoin:: { Network , WitnessProgram , WitnessVersion } ;
160160use core:: hash:: { Hash , Hasher } ;
161+ use core:: str:: FromStr ;
161162use core:: time:: Duration ;
162163
163164#[ allow( unused_imports) ]
@@ -1416,6 +1417,30 @@ impl Writeable for InvoiceContents {
14161417 }
14171418}
14181419
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+
14191444impl TryFrom < Vec < u8 > > for UnsignedBolt12Invoice {
14201445 type Error = Bolt12ParseError ;
14211446
@@ -2572,6 +2597,22 @@ mod tests {
25722597 }
25732598 }
25742599
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+
25752616 #[ test]
25762617 fn parses_invoice_with_payment_paths ( ) {
25772618 let expanded_key = ExpandedKey :: new ( [ 42 ; 32 ] ) ;
0 commit comments