let offer = OfferContents {
chains: None, metadata: None, amount: None, description,
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
- supported_quantity: Quantity::one(), signing_pubkey: Some(signing_pubkey),
+ supported_quantity: Quantity::one(), signing_pubkey,
};
OfferBuilder { offer }
}
/// An `Offer` is a potentially long-lived proposal for payment of a good or service.
///
/// An offer is a precursor to an [`InvoiceRequest`]. A merchant publishes an offer from which a
-/// customer may request an `Invoice` for a specific quantity and using an amount sufficient to
+/// customer may request an [`Invoice`] for a specific quantity and using an amount sufficient to
/// cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
///
/// Offers may be denominated in currency other than bitcoin but are ultimately paid using the
/// Through the use of [`BlindedPath`]s, offers provide recipient privacy.
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
+/// [`Invoice`]: crate::offers::invoice::Invoice
#[derive(Clone, Debug)]
pub struct Offer {
// The serialized offer. Needed when creating an `InvoiceRequest` if the offer contains unknown
pub(super) contents: OfferContents,
}
-/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or an `Invoice`.
+/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or an [`Invoice`].
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
+/// [`Invoice`]: crate::offers::invoice::Invoice
#[derive(Clone, Debug)]
pub(super) struct OfferContents {
chains: Option<Vec<ChainHash>>,
issuer: Option<String>,
paths: Option<Vec<BlindedPath>>,
supported_quantity: Quantity,
- signing_pubkey: Option<PublicKey>,
+ signing_pubkey: PublicKey,
}
impl Offer {
/// Whether the offer has expired.
#[cfg(feature = "std")]
pub fn is_expired(&self) -> bool {
- match self.absolute_expiry() {
- Some(seconds_from_epoch) => match SystemTime::UNIX_EPOCH.elapsed() {
- Ok(elapsed) => elapsed > seconds_from_epoch,
- Err(_) => false,
- },
- None => false,
- }
+ self.contents.is_expired()
}
/// The issuer of the offer, possibly beginning with `user@domain` or `domain`. Intended to be
/// The public key used by the recipient to sign invoices.
pub fn signing_pubkey(&self) -> PublicKey {
- self.contents.signing_pubkey.unwrap()
+ self.contents.signing_pubkey()
}
/// Creates an [`InvoiceRequest`] for the offer with the given `metadata` and `payer_id`, which
self.chains().contains(&chain)
}
+ #[cfg(feature = "std")]
+ pub(super) fn is_expired(&self) -> bool {
+ match self.absolute_expiry {
+ Some(seconds_from_epoch) => match SystemTime::UNIX_EPOCH.elapsed() {
+ Ok(elapsed) => elapsed > seconds_from_epoch,
+ Err(_) => false,
+ },
+ None => false,
+ }
+ }
+
pub fn amount(&self) -> Option<&Amount> {
self.amount.as_ref()
}
}
}
+ pub(super) fn signing_pubkey(&self) -> PublicKey {
+ self.signing_pubkey
+ }
+
pub(super) fn as_tlv_stream(&self) -> OfferTlvStreamRef {
let (currency, amount) = match &self.amount {
None => (None, None),
paths: self.paths.as_ref(),
issuer: self.issuer.as_ref(),
quantity_max: self.supported_quantity.to_tlv_record(),
- node_id: self.signing_pubkey.as_ref(),
+ node_id: Some(&self.signing_pubkey),
}
}
}
(6, currency: CurrencyCode),
(8, amount: (u64, HighZeroBytesDroppedBigSize)),
(10, description: (String, WithoutLength)),
- (12, features: OfferFeatures),
+ (12, features: (OfferFeatures, WithoutLength)),
(14, absolute_expiry: (u64, HighZeroBytesDroppedBigSize)),
(16, paths: (Vec<BlindedPath>, WithoutLength)),
(18, issuer: (String, WithoutLength)),
Some(n) => Quantity::Bounded(NonZeroU64::new(n).unwrap()),
};
- if node_id.is_none() {
- return Err(SemanticError::MissingSigningPubkey);
- }
+ let signing_pubkey = match node_id {
+ None => return Err(SemanticError::MissingSigningPubkey),
+ Some(node_id) => node_id,
+ };
Ok(OfferContents {
chains, metadata, amount, description, features, absolute_expiry, issuer, paths,
- supported_quantity, signing_pubkey: node_id,
+ supported_quantity, signing_pubkey,
})
}
}
panic!("error parsing offer: {:?}", e);
}
- let mut builder = OfferBuilder::new("foo".into(), pubkey(42));
- builder.offer.signing_pubkey = None;
+ let mut tlv_stream = offer.as_tlv_stream();
+ tlv_stream.node_id = None;
- let offer = builder.build().unwrap();
- match offer.to_string().parse::<Offer>() {
+ let mut encoded_offer = Vec::new();
+ tlv_stream.write(&mut encoded_offer).unwrap();
+
+ match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
Err(e) => {
assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey));