@@ -120,7 +120,7 @@ impl RefundBuilder {
120120 let refund = RefundContents {
121121 payer : PayerContents ( metadata) , metadata : None , description, absolute_expiry : None ,
122122 issuer : None , paths : None , chain : None , amount_msats,
123- features : InvoiceRequestFeatures :: empty ( ) , payer_id, payer_note : None ,
123+ features : InvoiceRequestFeatures :: empty ( ) , quantity : None , payer_id, payer_note : None ,
124124 } ;
125125
126126 Ok ( RefundBuilder { refund } )
@@ -162,6 +162,20 @@ impl RefundBuilder {
162162 self
163163 }
164164
165+ /// Sets [`Refund::quantity`] of items. This is purely for informational purposes. It is useful
166+ /// when the refund pertains to an [`Invoice`] that paid for more than one item from an
167+ /// [`Offer`] as specified by [`InvoiceRequest::quantity`].
168+ ///
169+ /// Successive calls to this method will override the previous setting.
170+ ///
171+ /// [`Invoice`]: crate::offers::invoice::Invoice
172+ /// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
173+ /// [`Offer`]: crate::offers::offer::Offer
174+ pub fn quantity ( mut self , quantity : u64 ) -> Self {
175+ self . refund . quantity = Some ( quantity) ;
176+ self
177+ }
178+
165179 /// Sets the [`Refund::payer_note`].
166180 ///
167181 /// Successive calls to this method will override the previous setting.
@@ -224,6 +238,7 @@ pub(super) struct RefundContents {
224238 chain : Option < ChainHash > ,
225239 amount_msats : u64 ,
226240 features : InvoiceRequestFeatures ,
241+ quantity : Option < u64 > ,
227242 payer_id : PublicKey ,
228243 payer_note : Option < String > ,
229244}
@@ -285,6 +300,11 @@ impl Refund {
285300 & self . contents . features
286301 }
287302
303+ /// The quantity of an item that refund is for.
304+ pub fn quantity ( & self ) -> Option < u64 > {
305+ self . contents . quantity
306+ }
307+
288308 /// A public node id to send to in the case where there are no [`paths`]. Otherwise, a possibly
289309 /// transient pubkey.
290310 ///
@@ -396,7 +416,7 @@ impl RefundContents {
396416 chain : self . chain . as_ref ( ) ,
397417 amount : Some ( self . amount_msats ) ,
398418 features,
399- quantity : None ,
419+ quantity : self . quantity ,
400420 payer_id : Some ( & self . payer_id ) ,
401421 payer_note : self . payer_note . as_ref ( ) ,
402422 } ;
@@ -514,11 +534,6 @@ impl TryFrom<RefundTlvStream> for RefundContents {
514534
515535 let features = features. unwrap_or_else ( InvoiceRequestFeatures :: empty) ;
516536
517- // TODO: Check why this isn't in the spec.
518- if quantity. is_some ( ) {
519- return Err ( SemanticError :: UnexpectedQuantity ) ;
520- }
521-
522537 let payer_id = match payer_id {
523538 None => return Err ( SemanticError :: MissingPayerId ) ,
524539 Some ( payer_id) => payer_id,
@@ -527,7 +542,7 @@ impl TryFrom<RefundTlvStream> for RefundContents {
527542 // TODO: Should metadata be included?
528543 Ok ( RefundContents {
529544 payer, metadata, description, absolute_expiry, issuer, paths, chain, amount_msats,
530- features, payer_id, payer_note,
545+ features, quantity , payer_id, payer_note,
531546 } )
532547 }
533548}
@@ -755,6 +770,24 @@ mod tests {
755770 assert_eq ! ( tlv_stream. chain, Some ( & testnet) ) ;
756771 }
757772
773+ #[ test]
774+ fn builds_refund_with_quantity ( ) {
775+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
776+ . quantity ( 10 )
777+ . build ( ) . unwrap ( ) ;
778+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
779+ assert_eq ! ( refund. quantity( ) , Some ( 10 ) ) ;
780+ assert_eq ! ( tlv_stream. quantity, Some ( 10 ) ) ;
781+
782+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
783+ . quantity ( 10 )
784+ . quantity ( 1 )
785+ . build ( ) . unwrap ( ) ;
786+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
787+ assert_eq ! ( refund. quantity( ) , Some ( 1 ) ) ;
788+ assert_eq ! ( tlv_stream. quantity, Some ( 1 ) ) ;
789+ }
790+
758791 #[ test]
759792 fn builds_refund_with_payer_note ( ) {
760793 let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
@@ -888,6 +921,7 @@ mod tests {
888921 . path ( paths[ 1 ] . clone ( ) )
889922 . chain ( Network :: Testnet )
890923 . features_unchecked ( InvoiceRequestFeatures :: unknown ( ) )
924+ . quantity ( 10 )
891925 . payer_note ( "baz" . into ( ) )
892926 . build ( )
893927 . unwrap ( ) ;
@@ -900,6 +934,7 @@ mod tests {
900934 assert_eq ! ( refund. issuer( ) , Some ( PrintableString ( "bar" ) ) ) ;
901935 assert_eq ! ( refund. chain( ) , ChainHash :: using_genesis_block( Network :: Testnet ) ) ;
902936 assert_eq ! ( refund. features( ) , & InvoiceRequestFeatures :: unknown( ) ) ;
937+ assert_eq ! ( refund. quantity( ) , Some ( 10 ) ) ;
903938 assert_eq ! ( refund. payer_note( ) , Some ( PrintableString ( "baz" ) ) ) ;
904939 } ,
905940 Err ( e) => panic ! ( "error parsing refund: {:?}" , e) ,
@@ -967,16 +1002,6 @@ mod tests {
9671002 assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: UnexpectedSigningPubkey ) ) ;
9681003 } ,
9691004 }
970-
971- let mut tlv_stream = refund. as_tlv_stream ( ) ;
972- tlv_stream. 2 . quantity = Some ( 10 ) ;
973-
974- match Refund :: try_from ( tlv_stream. to_bytes ( ) ) {
975- Ok ( _) => panic ! ( "expected error" ) ,
976- Err ( e) => {
977- assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: UnexpectedQuantity ) ) ;
978- } ,
979- }
9801005 }
9811006
9821007 #[ test]
0 commit comments