use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError};
use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
use crate::offers::signer::{Metadata, MetadataMaterial};
+use crate::onion_message::dns_resolution::HumanReadableName;
use crate::util::ser::{CursorReadable, HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
use crate::util::string::{PrintableString, UntrustedString};
InvoiceRequestContentsWithoutPayerSigningPubkey {
payer: PayerContents(metadata), offer, chain: None, amount_msats: None,
features: InvoiceRequestFeatures::empty(), quantity: None, payer_note: None,
+ offer_from_hrn: None,
#[cfg(test)]
experimental_bar: None,
}
$return_value
}
+ /// Sets the [`InvoiceRequest::offer_from_hrn`].
+ ///
+ /// Successive calls to this method will override the previous setting.
+ pub fn sourced_from_human_readable_name($($self_mut)* $self: $self_type, hrn: HumanReadableName) -> $return_type {
+ $self.invoice_request.offer_from_hrn = Some(hrn);
+ $return_value
+ }
+
fn build_with_checks($($self_mut)* $self: $self_type) -> Result<
(UnsignedInvoiceRequest, Option<Keypair>, Option<&'b Secp256k1<$secp_context>>),
Bolt12SemanticError
features: InvoiceRequestFeatures,
quantity: Option<u64>,
payer_note: Option<String>,
+ offer_from_hrn: Option<HumanReadableName>,
#[cfg(test)]
experimental_bar: Option<u64>,
}
pub fn payer_note(&$self) -> Option<PrintableString> {
$contents.payer_note()
}
+
+ /// If the [`Offer`] was sourced from a BIP 353 Human Readable Name, this should be set by the
+ /// builder to indicate the original [`HumanReadableName`] which was resolved.
+ pub fn offer_from_hrn(&$self) -> &Option<HumanReadableName> {
+ $contents.offer_from_hrn()
+ }
} }
impl UnsignedInvoiceRequest {
let InvoiceRequestContents {
payer_signing_pubkey,
inner: InvoiceRequestContentsWithoutPayerSigningPubkey {
- payer: _, offer: _, chain: _, amount_msats: _, features: _, quantity, payer_note,
- #[cfg(test)]
- experimental_bar: _,
+ quantity, payer_note, ..
},
} = &self.inner.contents;
.map(|payer_note| PrintableString(payer_note.as_str()))
}
+ pub(super) fn offer_from_hrn(&self) -> &Option<HumanReadableName> {
+ &self.inner.offer_from_hrn
+ }
+
pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef {
let (payer, offer, mut invoice_request, experimental_offer, experimental_invoice_request) =
self.inner.as_tlv_stream();
quantity: self.quantity,
payer_id: None,
payer_note: self.payer_note.as_ref(),
+ offer_from_hrn: self.offer_from_hrn.as_ref(),
paths: None,
};
(89, payer_note: (String, WithoutLength)),
// Only used for Refund since the onion message of an InvoiceRequest has a reply path.
(90, paths: (Vec<BlindedMessagePath>, WithoutLength)),
+ (91, offer_from_hrn: HumanReadableName),
});
/// Valid type range for experimental invoice_request TLV records.
offer_tlv_stream,
InvoiceRequestTlvStream {
chain, amount, features, quantity, payer_id, payer_note, paths,
+ offer_from_hrn,
},
experimental_offer_tlv_stream,
ExperimentalInvoiceRequestTlvStream {
Ok(InvoiceRequestContents {
inner: InvoiceRequestContentsWithoutPayerSigningPubkey {
payer, offer, chain, amount_msats: amount, features, quantity, payer_note,
+ offer_from_hrn,
#[cfg(test)]
experimental_bar,
},
payer_id: Some(&payer_pubkey()),
payer_note: None,
paths: None,
+ offer_from_hrn: None,
},
SignatureTlvStreamRef { signature: Some(&invoice_request.signature()) },
ExperimentalOfferTlvStreamRef {
payer_id: Some(&self.payer_signing_pubkey),
payer_note: self.payer_note.as_ref(),
paths: self.paths.as_ref(),
+ offer_from_hrn: None,
};
let experimental_offer = ExperimentalOfferTlvStreamRef {
issuer_id,
},
InvoiceRequestTlvStream {
- chain, amount, features, quantity, payer_id, payer_note, paths
+ chain, amount, features, quantity, payer_id, payer_note, paths,
+ offer_from_hrn,
},
ExperimentalOfferTlvStream {
#[cfg(test)]
return Err(Bolt12SemanticError::UnexpectedIssuerSigningPubkey);
}
+ if offer_from_hrn.is_some() {
+ // Only offers can be resolved using Human Readable Names
+ return Err(Bolt12SemanticError::UnexpectedHumanReadableName);
+ }
+
let amount_msats = match amount {
None => return Err(Bolt12SemanticError::MissingAmount),
Some(amount_msats) if amount_msats > MAX_VALUE_MSAT => {
payer_id: Some(&payer_pubkey()),
payer_note: None,
paths: None,
+ offer_from_hrn: None,
},
ExperimentalOfferTlvStreamRef {
experimental_foo: None,