//! published as a QR code to be scanned by a customer. The customer uses the offer to request an
//! invoice from the merchant to be paid.
//!
+//! # Example
+//!
//! ```
//! extern crate bitcoin;
//! extern crate core;
//! # Ok(())
//! # }
//! ```
+//!
+//! # Note
+//!
+//! If constructing an [`Offer`] for use with a [`ChannelManager`], use
+//! [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`].
+//!
+//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+//! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder
use bitcoin::blockdata::constants::ChainHash;
use bitcoin::network::constants::Network;
/// while the offer is valid.
///
/// Use a different pubkey per offer to avoid correlating offers.
+ ///
+ /// # Note
+ ///
+ /// If constructing an [`Offer`] for use with a [`ChannelManager`], use
+ /// [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`].
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ /// [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder
pub fn new(description: String, signing_pubkey: PublicKey) -> Self {
OfferBuilder {
offer: OfferContents {
/// See [`Offer::chains`] on how this relates to the payment currency.
///
/// Successive calls to this method will add another chain hash.
- pub fn chain(mut self, network: Network) -> Self {
+ pub fn chain(self, network: Network) -> Self {
+ self.chain_hash(ChainHash::using_genesis_block(network))
+ }
+
+ /// Adds the [`ChainHash`] to [`Offer::chains`]. If not called, the chain hash of
+ /// [`Network::Bitcoin`] is assumed to be the only one supported.
+ ///
+ /// See [`Offer::chains`] on how this relates to the payment currency.
+ ///
+ /// Successive calls to this method will add another chain hash.
+ pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Self {
let chains = self.offer.chains.get_or_insert_with(Vec::new);
- let chain = ChainHash::using_genesis_block(network);
if !chains.contains(&chain) {
chains.push(chain);
}
self.contents.is_expired()
}
+ /// Whether the offer has expired given the duration since the Unix epoch.
+ pub fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
+ self.contents.is_expired_no_std(duration_since_epoch)
+ }
+
/// Returns whether the given quantity is valid for the offer.
pub fn is_valid_quantity(&self, quantity: u64) -> bool {
self.contents.is_valid_quantity(quantity)
#[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,
- }
+ SystemTime::UNIX_EPOCH
+ .elapsed()
+ .map(|duration_since_epoch| self.is_expired_no_std(duration_since_epoch))
+ .unwrap_or(false)
+ }
+
+ pub(super) fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool {
+ self.absolute_expiry
+ .map(|absolute_expiry| duration_since_epoch > absolute_expiry)
+ .unwrap_or(false)
}
pub fn issuer(&self) -> Option<PrintableString> {
fn builds_offer_with_absolute_expiry() {
let future_expiry = Duration::from_secs(u64::max_value());
let past_expiry = Duration::from_secs(0);
+ let now = future_expiry - Duration::from_secs(1_000);
let offer = OfferBuilder::new("foo".into(), pubkey(42))
.absolute_expiry(future_expiry)
.unwrap();
#[cfg(feature = "std")]
assert!(!offer.is_expired());
+ assert!(!offer.is_expired_no_std(now));
assert_eq!(offer.absolute_expiry(), Some(future_expiry));
assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(future_expiry.as_secs()));
.unwrap();
#[cfg(feature = "std")]
assert!(offer.is_expired());
+ assert!(offer.is_expired_no_std(now));
assert_eq!(offer.absolute_expiry(), Some(past_expiry));
assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(past_expiry.as_secs()));
}