quantity: self.quantity,
payer_id: None,
payer_note: self.payer_note.as_ref(),
+ paths: None,
};
(payer, offer, invoice_request)
/// [`Refund::payer_id`]: crate::offers::refund::Refund::payer_id
pub(super) const INVOICE_REQUEST_PAYER_ID_TYPE: u64 = 88;
+// This TLV stream is used for both InvoiceRequest and Refund, but not all TLV records are valid for
+// InvoiceRequest as noted below.
tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, INVOICE_REQUEST_TYPES, {
(80, chain: ChainHash),
(82, amount: (u64, HighZeroBytesDroppedBigSize)),
(86, quantity: (u64, HighZeroBytesDroppedBigSize)),
(INVOICE_REQUEST_PAYER_ID_TYPE, payer_id: PublicKey),
(89, payer_note: (String, WithoutLength)),
+ // Only used for Refund since the onion message of an InvoiceRequest has a reply path.
+ (90, paths: (Vec<BlindedPath>, WithoutLength)),
});
type FullInvoiceRequestTlvStream =
let (
PayerTlvStream { metadata },
offer_tlv_stream,
- InvoiceRequestTlvStream { chain, amount, features, quantity, payer_id, payer_note },
+ InvoiceRequestTlvStream {
+ chain, amount, features, quantity, payer_id, payer_note, paths,
+ },
) = tlv_stream;
let payer = match metadata {
Some(payer_id) => payer_id,
};
+ if paths.is_some() {
+ return Err(Bolt12SemanticError::UnexpectedPaths);
+ }
+
Ok(InvoiceRequestContents {
inner: InvoiceRequestContentsWithoutPayerId {
payer, offer, chain, amount_msats: amount, features, quantity, payer_note,
quantity: None,
payer_id: Some(&payer_pubkey()),
payer_note: None,
+ paths: None,
},
SignatureTlvStreamRef { signature: Some(&invoice_request.signature()) },
),
Ok(Self {
refund: RefundContents {
payer: PayerContents(metadata), description, absolute_expiry: None, issuer: None,
- paths: None, chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
- quantity: None, payer_id, payer_note: None,
+ chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
+ quantity: None, payer_id, payer_note: None, paths: None,
},
secp_ctx: None,
})
Ok(Self {
refund: RefundContents {
payer: PayerContents(metadata), description, absolute_expiry: None, issuer: None,
- paths: None, chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
- quantity: None, payer_id: node_id, payer_note: None,
+ chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
+ quantity: None, payer_id: node_id, payer_note: None, paths: None,
},
secp_ctx: Some(secp_ctx),
})
description: String,
absolute_expiry: Option<Duration>,
issuer: Option<String>,
- paths: Option<Vec<BlindedPath>>,
// invoice_request fields
chain: Option<ChainHash>,
amount_msats: u64,
quantity: Option<u64>,
payer_id: PublicKey,
payer_note: Option<String>,
+ paths: Option<Vec<BlindedPath>>,
}
impl Refund {
description: Some(&self.description),
features: None,
absolute_expiry: self.absolute_expiry.map(|duration| duration.as_secs()),
- paths: self.paths.as_ref(),
+ paths: None,
issuer: self.issuer.as_ref(),
quantity_max: None,
node_id: None,
quantity: self.quantity,
payer_id: Some(&self.payer_id),
payer_note: self.payer_note.as_ref(),
+ paths: self.paths.as_ref(),
};
(payer, offer, invoice_request)
PayerTlvStream { metadata: payer_metadata },
OfferTlvStream {
chains, metadata, currency, amount: offer_amount, description,
- features: offer_features, absolute_expiry, paths, issuer, quantity_max, node_id,
+ features: offer_features, absolute_expiry, paths: offer_paths, issuer, quantity_max,
+ node_id,
+ },
+ InvoiceRequestTlvStream {
+ chain, amount, features, quantity, payer_id, payer_note, paths
},
- InvoiceRequestTlvStream { chain, amount, features, quantity, payer_id, payer_note },
) = tlv_stream;
let payer = match payer_metadata {
let absolute_expiry = absolute_expiry.map(Duration::from_secs);
+ if offer_paths.is_some() {
+ return Err(Bolt12SemanticError::UnexpectedPaths);
+ }
+
if quantity_max.is_some() {
return Err(Bolt12SemanticError::UnexpectedQuantity);
}
};
Ok(RefundContents {
- payer, description, absolute_expiry, issuer, paths, chain, amount_msats, features,
- quantity, payer_id, payer_note,
+ payer, description, absolute_expiry, issuer, chain, amount_msats, features, quantity,
+ payer_id, payer_note, paths,
})
}
}
quantity: None,
payer_id: Some(&payer_pubkey()),
payer_note: None,
+ paths: None,
},
),
);
.path(paths[1].clone())
.build()
.unwrap();
- let (_, offer_tlv_stream, invoice_request_tlv_stream) = refund.as_tlv_stream();
- assert_eq!(refund.paths(), paths.as_slice());
+ let (_, _, invoice_request_tlv_stream) = refund.as_tlv_stream();
assert_eq!(refund.payer_id(), pubkey(42));
+ assert_eq!(refund.paths(), paths.as_slice());
assert_ne!(pubkey(42), pubkey(44));
- assert_eq!(offer_tlv_stream.paths, Some(&paths));
assert_eq!(invoice_request_tlv_stream.payer_id, Some(&pubkey(42)));
+ assert_eq!(invoice_request_tlv_stream.paths, Some(&paths));
}
#[test]