use std::str::FromStr;
use lightning::offers::offer::Offer;
use lightning_invoice::Bolt11Invoice;
use crate::error::Error;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PaymentType {
Bolt11,
Bolt12,
}
#[derive(Debug, Clone)]
pub struct DecodedInvoice {
pub payment_type: PaymentType,
pub amount_msat: Option<u64>,
pub expiry: Option<u64>,
pub description: Option<String>,
}
pub fn decode_invoice(invoice_str: &str) -> Result<DecodedInvoice, Error> {
if let Ok(invoice) = Bolt11Invoice::from_str(invoice_str) {
let amount_msat = invoice.amount_milli_satoshis();
let expiry = invoice.expires_at().map(|duration| duration.as_secs());
let description = match invoice.description() {
lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => Some(desc.to_string()),
lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => {
Some(format!("Hash: {}", hash.0))
}
};
return Ok(DecodedInvoice {
payment_type: PaymentType::Bolt11,
amount_msat,
expiry,
description,
});
}
if let Ok(offer) = Offer::from_str(invoice_str) {
let amount_msat = offer.amount().and_then(|amount| {
match amount {
lightning::offers::offer::Amount::Bitcoin { amount_msats } => Some(amount_msats),
_ => None,
}
});
let expiry = offer.absolute_expiry().map(|duration| duration.as_secs());
let description = offer.description().map(|d| d.to_string());
return Ok(DecodedInvoice {
payment_type: PaymentType::Bolt12,
amount_msat,
expiry,
description,
});
}
Err(Error::InvalidInvoice)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decode_bolt11() {
let bolt11 = "lnbc1u1p53kkd9pp5ve8pd9zr60yjyvs6tn77mndavzrl5lwd2gx5hk934f6q8jwguzgsdqqcqzzsxqyz5vqrzjqvueefmrckfdwyyu39m0lf24sqzcr9vcrmxrvgfn6empxz7phrjxvrttncqq0lcqqyqqqqlgqqqqqqgq2qsp5482y73fxmlvg4t66nupdaph93h7dcmfsg2ud72wajf0cpk3a96rq9qxpqysgqujexd0l89u5dutn8hxnsec0c7jrt8wz0z67rut0eah0g7p6zhycn2vff0ts5vwn2h93kx8zzqy3tzu4gfhkya2zpdmqelg0ceqnjztcqma65pr";
let result = decode_invoice(bolt11);
assert!(result.is_ok());
let decoded = result.unwrap();
assert_eq!(decoded.payment_type, PaymentType::Bolt11);
assert_eq!(decoded.amount_msat, Some(100000));
}
#[test]
fn test_invalid_invoice() {
let result = decode_invoice("invalid_string");
assert!(result.is_err());
}
}