1use bitcoin::constants::ChainHash;
2use bitcoin::Network;
3pub use lightning::offers::offer::{Offer, Amount as OfferAmount};
4pub use lightning::offers::invoice::Bolt12Invoice;
5
6use std::fmt;
7use std::borrow::Borrow;
8use std::str::FromStr;
9
10use bitcoin::Amount;
11use bitcoin::bech32::{encode_to_fmt, EncodeError, Hrp, NoChecksum, primitives::decode::CheckedHrpstring};
12use bitcoin::hashes::{sha256, Hash};
13use bitcoin::secp256k1::{Message, PublicKey};
14use bitcoin::taproot::TaprootSpendInfo;
15use lightning::offers::parse::Bolt12ParseError;
16use lightning::util::ser::Writeable;
17use lightning_invoice::Bolt11Invoice;
18
19use bitcoin_ext::{BlockDelta, BlockHeight, P2TR_DUST};
20
21use crate::{musig, scripts, SECP};
22
23const BECH32_BOLT12_INVOICE_HRP: &str = "lni";
24
25pub const HTLC_MIN_FEE: Amount = P2TR_DUST;
27
28
29#[derive(Clone, Copy, PartialEq, Eq, Hash)]
31pub struct Preimage([u8; 32]);
32impl_byte_newtype!(Preimage, 32);
33
34impl Preimage {
35 pub fn random() -> Preimage {
37 Preimage(rand::random())
38 }
39
40 pub fn compute_payment_hash(&self) -> PaymentHash {
42 sha256::Hash::hash(self.as_ref()).into()
43 }
44}
45
46#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
48pub struct PaymentHash([u8; 32]);
49impl_byte_newtype!(PaymentHash, 32);
50
51impl From<sha256::Hash> for PaymentHash {
52 fn from(hash: sha256::Hash) -> Self {
53 PaymentHash(hash.to_byte_array())
54 }
55}
56
57impl From<Preimage> for PaymentHash {
58 fn from(preimage: Preimage) -> Self {
59 preimage.compute_payment_hash()
60 }
61}
62
63impl From<lightning::types::payment::PaymentHash> for PaymentHash {
64 fn from(hash: lightning::types::payment::PaymentHash) -> Self {
65 PaymentHash(hash.0)
66 }
67}
68
69impl<'a> From<&'a Bolt11Invoice> for PaymentHash {
70 fn from(i: &'a Bolt11Invoice) -> Self {
71 (*i.payment_hash()).into()
72 }
73}
74
75impl From<Bolt11Invoice> for PaymentHash {
76 fn from(i: Bolt11Invoice) -> Self {
77 (&i).into()
78 }
79}
80
81impl PaymentHash {
82 pub fn to_sha256_hash(&self) -> bitcoin::hashes::sha256::Hash {
84 bitcoin::hashes::sha256::Hash::from_slice(&self.0)
85 .expect("PaymentHash must be 32 bytes, which is always valid for sha256::Hash")
86 }
87}
88
89pub fn server_htlc_send_taproot(
108 payment_hash: PaymentHash,
109 server_pubkey: PublicKey,
110 user_pubkey: PublicKey,
111 exit_delta: BlockDelta,
112 htlc_expiry: BlockHeight,
113) -> TaprootSpendInfo {
114 let server_branch = scripts::hash_delay_sign(
115 payment_hash.to_sha256_hash(), exit_delta, server_pubkey.x_only_public_key().0,
116 );
117 let user_branch = scripts::delay_timelock_sign(
118 2 * exit_delta, htlc_expiry, user_pubkey.x_only_public_key().0,
119 );
120
121 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey]);
122 bitcoin::taproot::TaprootBuilder::new()
123 .add_leaf(1, server_branch).unwrap()
124 .add_leaf(1, user_branch).unwrap()
125 .finalize(&SECP, combined_pk).unwrap()
126}
127
128pub fn server_htlc_receive_taproot(
146 payment_hash: PaymentHash,
147 server_pubkey: PublicKey,
148 user_pubkey: PublicKey,
149 exit_delta: BlockDelta,
150 htlc_expiry_delta: BlockDelta,
151 htlc_expiry: BlockHeight,
152) -> TaprootSpendInfo {
153 let server_branch =
154 scripts::delay_timelock_sign(exit_delta, htlc_expiry, server_pubkey.x_only_public_key().0);
155 let user_branch = scripts::hash_delay_sign(
156 payment_hash.to_sha256_hash(),
157 exit_delta + htlc_expiry_delta,
158 user_pubkey.x_only_public_key().0,
159 );
160
161 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey]);
162 bitcoin::taproot::TaprootBuilder::new()
163 .add_leaf(1, server_branch).unwrap()
164 .add_leaf(1, user_branch).unwrap()
165 .finalize(&SECP, combined_pk).unwrap()
166}
167
168
169#[derive(Debug, Clone)]
170pub enum PaymentStatus {
171 Pending,
172 Complete,
173 Failed,
174}
175
176impl fmt::Display for PaymentStatus {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 fmt::Debug::fmt(self, f)
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184pub enum Invoice {
185 Bolt11(Bolt11Invoice),
186 Bolt12(Bolt12Invoice),
187}
188
189#[derive(Debug, thiserror::Error)]
190#[error("cannot parse invoice")]
191pub struct InvoiceParseError;
192
193impl FromStr for Invoice {
194 type Err = InvoiceParseError;
195
196 fn from_str(s: &str) -> Result<Self, Self::Err> {
197 if let Ok(bolt11) = Bolt11Invoice::from_str(s) {
198 Ok(Invoice::Bolt11(bolt11))
199 } else if let Ok(bolt12) = Bolt12Invoice::from_str(s) {
200 Ok(Invoice::Bolt12(bolt12))
201 } else {
202 Err(InvoiceParseError)
203 }
204 }
205}
206
207impl From<Bolt11Invoice> for Invoice {
208 fn from(invoice: Bolt11Invoice) -> Self {
209 Invoice::Bolt11(invoice)
210 }
211}
212
213impl From<Bolt12Invoice> for Invoice {
214 fn from(invoice: Bolt12Invoice) -> Self {
215 Invoice::Bolt12(invoice)
216 }
217}
218
219impl serde::Serialize for Invoice {
220 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
221 s.collect_str(self)
222 }
223}
224
225impl<'de> serde::Deserialize<'de> for Invoice {
226 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
227 struct Visitor;
228 impl<'de> serde::de::Visitor<'de> for Visitor {
229 type Value = Invoice;
230 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(f, "a lightning invoice")
232 }
233 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
234 Invoice::from_str(v).map_err(serde::de::Error::custom)
235 }
236 }
237 d.deserialize_str(Visitor)
238 }
239}
240
241#[derive(Debug, thiserror::Error)]
242#[error("invalid invoice signature: {0}")]
243pub struct CheckSignatureError(pub String);
244
245impl Invoice {
246 pub fn into_bolt11(self) -> Option<Bolt11Invoice> {
247 match self {
248 Invoice::Bolt11(invoice) => Some(invoice),
249 Invoice::Bolt12(_) => None
250 }
251 }
252
253 pub fn payment_hash(&self) -> PaymentHash {
254 match self {
255 Invoice::Bolt11(invoice) => PaymentHash::from(*invoice.payment_hash().as_byte_array()),
256 Invoice::Bolt12(invoice) => PaymentHash::from(invoice.payment_hash()),
257 }
258 }
259
260 pub fn network(&self) -> Network {
261 match self {
262 Invoice::Bolt11(invoice) => invoice.network(),
263 Invoice::Bolt12(invoice) => match invoice.chain() {
264 ChainHash::BITCOIN => Network::Bitcoin,
265 ChainHash::TESTNET3 => Network::Testnet,
266 ChainHash::TESTNET4 => Network::Testnet4,
267 ChainHash::SIGNET => Network::Signet,
268 ChainHash::REGTEST => Network::Regtest,
269 _ => panic!("unsupported network"),
270 },
271 }
272 }
273
274 pub fn amount_msat(&self) -> Option<u64> {
275 match self {
276 Invoice::Bolt11(invoice) => invoice.amount_milli_satoshis(),
277 Invoice::Bolt12(invoice) => Some(invoice.amount_msats()),
278 }
279 }
280
281 pub fn check_signature(&self) -> Result<(), CheckSignatureError> {
282 match self {
283 Invoice::Bolt11(invoice) => invoice
284 .check_signature()
285 .map_err(|e| CheckSignatureError(e.to_string())),
286 Invoice::Bolt12(invoice) => invoice.check_signature(),
287 }
288 }
289}
290
291impl fmt::Display for Invoice {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 match self {
294 Invoice::Bolt11(invoice) => write!(f, "{}", invoice.to_string()),
295 Invoice::Bolt12(invoice) => encode_to_fmt::<NoChecksum, _>(
296 f,
297 Hrp::parse("lni").unwrap(),
298 &invoice.bytes(),
299 )
300 .map_err(|e| match e {
301 EncodeError::Fmt(e) => e,
302 _ => fmt::Error {},
303 }),
304 }
305 }
306}
307
308pub trait Bolt12InvoiceExt: Borrow<Bolt12Invoice> {
309 fn payment_hash(&self) -> PaymentHash { PaymentHash::from(self.borrow().payment_hash()) }
310
311 fn check_signature(&self) -> Result<(), CheckSignatureError> {
312 let message = Message::from_digest(self.borrow().signable_hash());
313 let signature = self.borrow().signature();
314
315 if let Some(pubkey) = self.borrow().issuer_signing_pubkey() {
316 Ok(SECP.verify_schnorr(&signature, &message, &pubkey.into())
317 .map_err(|_| CheckSignatureError("invalid signature".to_string()))?)
318 } else {
319 Err(CheckSignatureError("no pubkey on offer, cannot verify signature".to_string()))
320 }
321 }
322
323 fn bytes(&self) -> Vec<u8> {
324 let mut bytes = Vec::new();
325 self.borrow().write(&mut bytes).expect("Writing into a Vec is infallible");
326 bytes
327 }
328
329 fn from_bytes(bytes: &[u8]) -> Result<Bolt12Invoice, Bolt12ParseError> {
330 Bolt12Invoice::try_from(bytes.to_vec())
331 }
332
333 fn validate_issuance(&self, offer: Offer) -> Result<(), CheckSignatureError> {
334 if self.borrow().issuer_signing_pubkey() != offer.issuer_signing_pubkey() {
335 Err(CheckSignatureError("public keys mismatch".to_string()))
336 } else {
337 Ok(())
338 }
339 }
340
341 fn from_str(s: &str) -> Result<Bolt12Invoice, Bolt12ParseError> {
342 let dec = CheckedHrpstring::new::<NoChecksum>(&s)?;
343 if dec.hrp().to_lowercase() != BECH32_BOLT12_INVOICE_HRP {
344 return Err(Bolt12ParseError::InvalidBech32Hrp);
345 }
346
347 let data = dec.byte_iter().collect::<Vec<_>>();
348 Bolt12Invoice::try_from(data)
349 }
350}
351
352impl Bolt12InvoiceExt for Bolt12Invoice {}