//!
//! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
//! use lightning::offers::offer::{Offer, OfferBuilder, Quantity};
-//! use lightning::offers::parse::ParseError;
+//! use lightning::offers::parse::Bolt12ParseError;
//! use lightning::util::ser::{Readable, Writeable};
//!
//! # use lightning::blinded_path::BlindedPath;
//! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() }
//! #
//! # #[cfg(feature = "std")]
-//! # fn build() -> Result<(), ParseError> {
+//! # fn build() -> Result<(), Bolt12ParseError> {
//! let secp_ctx = Secp256k1::new();
//! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
//! let pubkey = PublicKey::from(keys);
use core::ops::Deref;
use core::str::FromStr;
use core::time::Duration;
-use crate::chain::keysinterface::EntropySource;
+use crate::sign::EntropySource;
use crate::io;
use crate::blinded_path::BlindedPath;
use crate::ln::features::OfferFeatures;
use crate::ln::msgs::MAX_VALUE_MSAT;
use crate::offers::invoice_request::{DerivedPayerId, ExplicitPayerId, InvoiceRequestBuilder};
use crate::offers::merkle::TlvStream;
-use crate::offers::parse::{Bech32Encode, ParseError, ParsedMessage, SemanticError};
+use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::signer::{Metadata, MetadataMaterial, self};
use crate::util::ser::{HighZeroBytesDroppedBigSize, WithoutLength, Writeable, Writer};
use crate::util::string::PrintableString;
/// Sets the [`Offer::metadata`] to the given bytes.
///
/// Successive calls to this method will override the previous setting.
- pub fn metadata(mut self, metadata: Vec<u8>) -> Result<Self, SemanticError> {
+ pub fn metadata(mut self, metadata: Vec<u8>) -> Result<Self, Bolt12SemanticError> {
self.offer.metadata = Some(Metadata::Bytes(metadata));
Ok(self)
}
}
/// Builds an [`Offer`] from the builder's settings.
- pub fn build(mut self) -> Result<Offer, SemanticError> {
+ pub fn build(mut self) -> Result<Offer, Bolt12SemanticError> {
match self.offer.amount {
Some(Amount::Bitcoin { amount_msats }) => {
if amount_msats > MAX_VALUE_MSAT {
- return Err(SemanticError::InvalidAmount);
+ return Err(Bolt12SemanticError::InvalidAmount);
}
},
- Some(Amount::Currency { .. }) => return Err(SemanticError::UnsupportedCurrency),
+ Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
None => {},
}
/// 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
-/// cover that quantity (i.e., at least `quantity * amount`). See [`Offer::amount`].
+/// customer may request an [`Bolt12Invoice`] 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
/// latter.
/// Through the use of [`BlindedPath`]s, offers provide recipient privacy.
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Offer {
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 a
+/// [`Bolt12Invoice`].
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-/// [`Invoice`]: crate::offers::invoice::Invoice
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub(super) struct OfferContents {
/// - derives the [`InvoiceRequest::payer_id`] such that a different key can be used for each
/// request, and
/// - sets the [`InvoiceRequest::metadata`] when [`InvoiceRequestBuilder::build`] is called such
- /// that it can be used by [`Invoice::verify`] to determine if the invoice was requested using
- /// a base [`ExpandedKey`] from which the payer id was derived.
+ /// that it can be used by [`Bolt12Invoice::verify`] to determine if the invoice was requested
+ /// using a base [`ExpandedKey`] from which the payer id was derived.
///
/// Useful to protect the sender's privacy.
///
///
/// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
/// [`InvoiceRequest::metadata`]: crate::offers::invoice_request::InvoiceRequest::metadata
- /// [`Invoice::verify`]: crate::offers::invoice::Invoice::verify
+ /// [`Bolt12Invoice::verify`]: crate::offers::invoice::Bolt12Invoice::verify
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
pub fn request_invoice_deriving_payer_id<'a, 'b, ES: Deref, T: secp256k1::Signing>(
&'a self, expanded_key: &ExpandedKey, entropy_source: ES, secp_ctx: &'b Secp256k1<T>
- ) -> Result<InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T>, SemanticError>
+ ) -> Result<InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T>, Bolt12SemanticError>
where
ES::Target: EntropySource,
{
if self.features().requires_unknown_bits() {
- return Err(SemanticError::UnknownRequiredFeatures);
+ return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
Ok(InvoiceRequestBuilder::deriving_payer_id(self, expanded_key, entropy_source, secp_ctx))
/// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
pub fn request_invoice_deriving_metadata<ES: Deref>(
&self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES
- ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, SemanticError>
+ ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError>
where
ES::Target: EntropySource,
{
if self.features().requires_unknown_bits() {
- return Err(SemanticError::UnknownRequiredFeatures);
+ return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
Ok(InvoiceRequestBuilder::deriving_metadata(self, payer_id, expanded_key, entropy_source))
}
/// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and `payer_id`,
- /// which will be reflected in the `Invoice` response.
+ /// which will be reflected in the `Bolt12Invoice` response.
///
/// The `metadata` is useful for including information about the derivation of `payer_id` such
/// that invoice response handling can be stateless. Also serves as payer-provided entropy while
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub fn request_invoice(
&self, metadata: Vec<u8>, payer_id: PublicKey
- ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, SemanticError> {
+ ) -> Result<InvoiceRequestBuilder<ExplicitPayerId, secp256k1::SignOnly>, Bolt12SemanticError> {
if self.features().requires_unknown_bits() {
- return Err(SemanticError::UnknownRequiredFeatures);
+ return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
Ok(InvoiceRequestBuilder::new(self, metadata, payer_id))
pub(super) fn check_amount_msats_for_quantity(
&self, amount_msats: Option<u64>, quantity: Option<u64>
- ) -> Result<(), SemanticError> {
+ ) -> Result<(), Bolt12SemanticError> {
let offer_amount_msats = match self.amount {
None => 0,
Some(Amount::Bitcoin { amount_msats }) => amount_msats,
- Some(Amount::Currency { .. }) => return Err(SemanticError::UnsupportedCurrency),
+ Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
};
if !self.expects_quantity() || quantity.is_some() {
let expected_amount_msats = offer_amount_msats.checked_mul(quantity.unwrap_or(1))
- .ok_or(SemanticError::InvalidAmount)?;
+ .ok_or(Bolt12SemanticError::InvalidAmount)?;
let amount_msats = amount_msats.unwrap_or(expected_amount_msats);
if amount_msats < expected_amount_msats {
- return Err(SemanticError::InsufficientAmount);
+ return Err(Bolt12SemanticError::InsufficientAmount);
}
if amount_msats > MAX_VALUE_MSAT {
- return Err(SemanticError::InvalidAmount);
+ return Err(Bolt12SemanticError::InvalidAmount);
}
}
self.supported_quantity
}
- pub(super) fn check_quantity(&self, quantity: Option<u64>) -> Result<(), SemanticError> {
+ pub(super) fn check_quantity(&self, quantity: Option<u64>) -> Result<(), Bolt12SemanticError> {
let expects_quantity = self.expects_quantity();
match quantity {
- None if expects_quantity => Err(SemanticError::MissingQuantity),
- Some(_) if !expects_quantity => Err(SemanticError::UnexpectedQuantity),
+ None if expects_quantity => Err(Bolt12SemanticError::MissingQuantity),
+ Some(_) if !expects_quantity => Err(Bolt12SemanticError::UnexpectedQuantity),
Some(quantity) if !self.is_valid_quantity(quantity) => {
- Err(SemanticError::InvalidQuantity)
+ Err(Bolt12SemanticError::InvalidQuantity)
},
_ => Ok(()),
}
}
impl FromStr for Offer {
- type Err = ParseError;
+ type Err = Bolt12ParseError;
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
Self::from_bech32_str(s)
}
impl TryFrom<Vec<u8>> for Offer {
- type Error = ParseError;
+ type Error = Bolt12ParseError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
let offer = ParsedMessage::<OfferTlvStream>::try_from(bytes)?;
}
impl TryFrom<OfferTlvStream> for OfferContents {
- type Error = SemanticError;
+ type Error = Bolt12SemanticError;
fn try_from(tlv_stream: OfferTlvStream) -> Result<Self, Self::Error> {
let OfferTlvStream {
let amount = match (currency, amount) {
(None, None) => None,
(None, Some(amount_msats)) if amount_msats > MAX_VALUE_MSAT => {
- return Err(SemanticError::InvalidAmount);
+ return Err(Bolt12SemanticError::InvalidAmount);
},
(None, Some(amount_msats)) => Some(Amount::Bitcoin { amount_msats }),
- (Some(_), None) => return Err(SemanticError::MissingAmount),
+ (Some(_), None) => return Err(Bolt12SemanticError::MissingAmount),
(Some(iso4217_code), Some(amount)) => Some(Amount::Currency { iso4217_code, amount }),
};
let description = match description {
- None => return Err(SemanticError::MissingDescription),
+ None => return Err(Bolt12SemanticError::MissingDescription),
Some(description) => description,
};
};
let signing_pubkey = match node_id {
- None => return Err(SemanticError::MissingSigningPubkey),
+ None => return Err(Bolt12SemanticError::MissingSigningPubkey),
Some(node_id) => node_id,
};
use core::num::NonZeroU64;
use core::time::Duration;
use crate::blinded_path::{BlindedHop, BlindedPath};
- use crate::chain::keysinterface::KeyMaterial;
+ use crate::sign::KeyMaterial;
use crate::ln::features::OfferFeatures;
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
- use crate::offers::parse::{ParseError, SemanticError};
+ use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
use crate::offers::test_utils::*;
use crate::util::ser::{BigSize, Writeable};
use crate::util::string::PrintableString;
assert_eq!(tlv_stream.currency, Some(b"USD"));
match builder.build() {
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, SemanticError::UnsupportedCurrency),
+ Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedCurrency),
}
let offer = OfferBuilder::new("foo".into(), pubkey(42))
let invalid_amount = Amount::Bitcoin { amount_msats: MAX_VALUE_MSAT + 1 };
match OfferBuilder::new("foo".into(), pubkey(42)).amount(invalid_amount).build() {
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, SemanticError::InvalidAmount),
+ Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount),
}
}
.request_invoice(vec![1; 32], pubkey(43))
{
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, SemanticError::UnknownRequiredFeatures),
+ Err(e) => assert_eq!(e, Bolt12SemanticError::UnknownRequiredFeatures),
}
}
match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount)),
+ Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)),
}
let mut tlv_stream = offer.as_tlv_stream();
match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidAmount)),
+ Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidAmount)),
}
}
match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
Err(e) => {
- assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingDescription));
+ assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription));
},
}
}
match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
Err(e) => {
- assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey));
+ assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
},
}
}
match Offer::try_from(encoded_offer) {
Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+ Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
}
}
}
#[cfg(test)]
mod bech32_tests {
- use super::{Offer, ParseError};
+ use super::{Bolt12ParseError, Offer};
use bitcoin::bech32;
use crate::ln::msgs::DecodeError;
- // TODO: Remove once test vectors are updated.
- #[ignore]
#[test]
fn encodes_offer_as_bech32_without_checksum() {
- let encoded_offer = "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy";
+ let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg";
let offer = dbg!(encoded_offer.parse::<Offer>().unwrap());
let reencoded_offer = offer.to_string();
dbg!(reencoded_offer.parse::<Offer>().unwrap());
assert_eq!(reencoded_offer, encoded_offer);
}
- // TODO: Remove once test vectors are updated.
- #[ignore]
#[test]
fn parses_bech32_encoded_offers() {
let offers = [
// BOLT 12 test vectors
- "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
- "l+no1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
- "l+no1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
- "lno1qcp4256ypqpq+86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn0+0fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0+sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qs+y",
- "lno1qcp4256ypqpq+ 86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn0+ 0fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0+\nsqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43l+\r\nastpwuh73k29qs+\r y",
- // Two blinded paths
- "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0yg06qg2qdd7t628sgykwj5kuc837qmlv9m9gr7sq8ap6erfgacv26nhp8zzcqgzhdvttlk22pw8fmwqqrvzst792mj35ypylj886ljkcmug03wg6heqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6muh550qsfva9fdes0ruph7ctk2s8aqq06r4jxj3msc448wzwy9sqs9w6ckhlv55zuwnkuqqxc9qhu24h9rggzflyw04l9d3hcslzu340jqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
+ "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
+ "l+no1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
+ "lno1pqps7sjqpgt+yzm3qv4uxzmtsd3jjqer9wd3hy6tsw3+5k7msjzfpy7nz5yqcn+ygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd+5xvxg",
+ "lno1pqps7sjqpgt+ yzm3qv4uxzmtsd3jjqer9wd3hy6tsw3+ 5k7msjzfpy7nz5yqcn+\nygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd+\r\n 5xvxg",
];
for encoded_offer in &offers {
if let Err(e) = encoded_offer.parse::<Offer>() {
fn fails_parsing_bech32_encoded_offers_with_invalid_continuations() {
let offers = [
// BOLT 12 test vectors
- "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy+",
- "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy+ ",
- "+lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
- "+ lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
- "ln++o1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy",
+ "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg+",
+ "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg+ ",
+ "+lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
+ "+ lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
+ "ln++o1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg",
];
for encoded_offer in &offers {
match encoded_offer.parse::<Offer>() {
Ok(_) => panic!("Valid offer: {}", encoded_offer),
- Err(e) => assert_eq!(e, ParseError::InvalidContinuation),
+ Err(e) => assert_eq!(e, Bolt12ParseError::InvalidContinuation),
}
}
#[test]
fn fails_parsing_bech32_encoded_offer_with_invalid_hrp() {
- let encoded_offer = "lni1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsy";
+ let encoded_offer = "lni1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg";
match encoded_offer.parse::<Offer>() {
Ok(_) => panic!("Valid offer: {}", encoded_offer),
- Err(e) => assert_eq!(e, ParseError::InvalidBech32Hrp),
+ Err(e) => assert_eq!(e, Bolt12ParseError::InvalidBech32Hrp),
}
}
#[test]
fn fails_parsing_bech32_encoded_offer_with_invalid_bech32_data() {
- let encoded_offer = "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qso";
+ let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxo";
match encoded_offer.parse::<Offer>() {
Ok(_) => panic!("Valid offer: {}", encoded_offer),
- Err(e) => assert_eq!(e, ParseError::Bech32(bech32::Error::InvalidChar('o'))),
+ Err(e) => assert_eq!(e, Bolt12ParseError::Bech32(bech32::Error::InvalidChar('o'))),
}
}
#[test]
fn fails_parsing_bech32_encoded_offer_with_invalid_tlv_data() {
- let encoded_offer = "lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczlqsp9nyu4phcg6dqhlhzgxagfu7zh3d9re0sqp9ts2yfugvnnm9gxkcnnnkdpa084a6t520h5zhkxsdnghvpukvd43lastpwuh73k29qsyqqqqq";
+ let encoded_offer = "lno1pqps7sjqpgtyzm3qv4uxzmtsd3jjqer9wd3hy6tsw35k7msjzfpy7nz5yqcnygrfdej82um5wf5k2uckyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxgqqqqq";
match encoded_offer.parse::<Offer>() {
Ok(_) => panic!("Valid offer: {}", encoded_offer),
- Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)),
+ Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
}
}
}