diff --git a/waila-wasm/src/lib.rs b/waila-wasm/src/lib.rs index d5e1f46..0628642 100644 --- a/waila-wasm/src/lib.rs +++ b/waila-wasm/src/lib.rs @@ -64,6 +64,11 @@ impl PaymentParams { self.params.offer().map(|offer| offer.to_string()) } + #[wasm_bindgen(getter)] + pub fn refund(&self) -> Option { + self.params.refund().map(|refund| refund.to_string()) + } + #[wasm_bindgen(getter)] pub fn node_pubkey(&self) -> Option { self.params.node_pubkey().map(|pubkey| pubkey.to_string()) diff --git a/waila/src/lib.rs b/waila/src/lib.rs index b3a243f..53a6cfb 100644 --- a/waila/src/lib.rs +++ b/waila/src/lib.rs @@ -6,6 +6,7 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::{Address, Amount, Network}; use lightning::offers::offer; use lightning::offers::offer::Offer; +use lightning::offers::refund::Refund; use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription}; use lnurl::lightning_address::LightningAddress; use lnurl::lnurl::LnUrl; @@ -25,6 +26,7 @@ pub enum PaymentParams<'a> { Bip21(UnifiedUri<'a>), Bolt11(Bolt11Invoice), Bolt12(Offer), + Bolt12Refund(Refund), NodePubkey(PublicKey), LnUrl(LnUrl), LightningAddress(LightningAddress), @@ -52,6 +54,7 @@ impl PaymentParams<'_> { Bolt11InvoiceDescription::Hash(_) => None, }, PaymentParams::Bolt12(offer) => Some(offer.description().to_string()), + PaymentParams::Bolt12Refund(refund) => Some(refund.description().to_string()), PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -67,6 +70,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(uri) => Some(uri.address.network), PaymentParams::Bolt11(invoice) => Some(Network::from(invoice.currency())), PaymentParams::Bolt12(_) => None, // todo fix after https://github.com/rust-bitcoin/rust-bitcoin/pull/1675 + PaymentParams::Bolt12Refund(_) => None, // todo fix after https://github.com/rust-bitcoin/rust-bitcoin/pull/1675 PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -86,6 +90,9 @@ impl PaymentParams<'_> { PaymentParams::Bolt12(offer) => { Some(offer.supports_chain(ChainHash::using_genesis_block(network))) } + PaymentParams::Bolt12Refund(refund) => { + Some(refund.chain() == ChainHash::using_genesis_block(network)) + } PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -112,6 +119,7 @@ impl PaymentParams<'_> { offer::Amount::Bitcoin { amount_msats } => Some(*amount_msats), offer::Amount::Currency { .. } => None, }), + PaymentParams::Bolt12Refund(refund) => Some(refund.amount_msats()), PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -127,6 +135,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(uri) => Some(uri.address.clone()), PaymentParams::Bolt11(invoice) => invoice.fallback_addresses().first().cloned(), PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -142,6 +151,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(uri) => uri.extras.lightning.clone(), PaymentParams::Bolt11(invoice) => Some(invoice.clone()), PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -157,6 +167,23 @@ impl PaymentParams<'_> { PaymentParams::Bip21(_) => None, PaymentParams::Bolt11(_) => None, PaymentParams::Bolt12(offer) => Some(offer.clone()), + PaymentParams::Bolt12Refund(_) => None, + PaymentParams::NodePubkey(_) => None, + PaymentParams::LnUrl(_) => None, + PaymentParams::LightningAddress(_) => None, + PaymentParams::Nostr(_) => None, + #[cfg(feature = "rgb")] + PaymentParams::Rgb(_) => None, + } + } + + pub fn refund(&self) -> Option { + match self { + PaymentParams::OnChain(_) => None, + PaymentParams::Bip21(_) => None, + PaymentParams::Bolt11(_) => None, + PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(refund) => Some(refund.clone()), PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -176,6 +203,7 @@ impl PaymentParams<'_> { .map(|invoice| invoice.recover_payee_pub_key()), PaymentParams::Bolt11(invoice) => Some(invoice.recover_payee_pub_key()), PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(pubkey) => Some(*pubkey), PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -191,6 +219,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(_) => None, PaymentParams::Bolt11(_) => None, PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(lnurl) => Some(lnurl.clone()), PaymentParams::LightningAddress(ln_addr) => Some(LnUrl::from_url(ln_addr.lnurlp_url())), @@ -212,6 +241,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(_) => None, PaymentParams::Bolt11(_) => None, PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(ln_addr) => Some(ln_addr.clone()), @@ -227,6 +257,7 @@ impl PaymentParams<'_> { PaymentParams::Bip21(_) => None, PaymentParams::Bolt11(_) => None, PaymentParams::Bolt12(_) => None, + PaymentParams::Bolt12Refund(_) => None, PaymentParams::NodePubkey(_) => None, PaymentParams::LnUrl(_) => None, PaymentParams::LightningAddress(_) => None, @@ -269,6 +300,7 @@ impl FromStr for PaymentParams<'_> { .or_else(|_| LnUrl::from_str(str).map(PaymentParams::LnUrl)) .or_else(|_| LightningAddress::from_str(str).map(PaymentParams::LightningAddress)) .or_else(|_| Offer::from_str(str).map(PaymentParams::Bolt12)) + .or_else(|_| Refund::from_str(str).map(PaymentParams::Bolt12Refund)) .map_err(|_| ()); } else if lower.starts_with("lnurl:") { let str = lower.strip_prefix("lnurl:").unwrap(); @@ -305,6 +337,7 @@ impl FromStr for PaymentParams<'_> { .or_else(|_| LnUrl::from_str(str).map(PaymentParams::LnUrl)) .or_else(|_| PublicKey::from_str(str).map(PaymentParams::NodePubkey)) .or_else(|_| Offer::from_str(str).map(PaymentParams::Bolt12)) + .or_else(|_| Refund::from_str(str).map(PaymentParams::Bolt12Refund)) .or_else(|_| XOnlyPublicKey::from_str(str).map(PaymentParams::Nostr)) .or_else(|_| XOnlyPublicKey::from_bech32(str).map(PaymentParams::Nostr)) .map_err(|_| ()) @@ -322,6 +355,7 @@ mod tests { "03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad"; const SAMPLE_INVOICE: &str = "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq9qrsgqdfjcdk6w3ak5pca9hwfwfh63zrrz06wwfya0ydlzpgzxkn5xagsqz7x9j4jwe7yj7vaf2k9lqsdk45kts2fd0fkr28am0u4w95tt2nsq76cqw0"; const SAMPLE_OFFER: &str = "lno1qgs0v8hw8d368q9yw7sx8tejk2aujlyll8cp7tzzyh5h8xyppqqqqqqgqvqcdgq2qenxzatrv46pvggrv64u366d5c0rr2xjc3fq6vw2hh6ce3f9p7z4v4ee0u7avfynjw9q"; + const SAMPLE_REFUND: &str = "lnr1qqsqzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqg2qdnx7m6jqgp7skppq0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66"; const SAMPLE_BIP21: &str = "bitcoin:1andreas3batLhQa2FawWjeyjCqyBzypd?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz"; const SAMPLE_BIP21_WITH_INVOICE: &str = "bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign%3A%20For%20lunch%20Tuesday&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6"; const SAMPLE_BIP21_WITH_INVOICE_AND_LABEL: &str = "bitcoin:tb1p0vztr8q25czuka5u4ta5pqu0h8dxkf72mam89cpg4tg40fm8wgmqp3gv99?amount=0.000001&label=yooo&lightning=lntbs1u1pjrww6fdq809hk7mcnp4qvwggxr0fsueyrcer4x075walsv93vqvn3vlg9etesx287x6ddy4xpp5a3drwdx2fmkkgmuenpvmynnl7uf09jmgvtlg86ckkvgn99ajqgtssp5gr3aghgjxlwshnqwqn39c2cz5hw4cnsnzxdjn7kywl40rru4mjdq9qyysgqcqpcxqrpwurzjqfgtsj42x8an5zujpxvfhp9ngwm7u5lu8lvzfucjhex4pq8ysj5q2qqqqyqqv9cqqsqqqqlgqqqqqqqqfqzgl9zq04nzpxyvdr8vj3h98gvnj3luanj2cxcra0q2th4xjsxmtj8k3582l67xq9ffz5586f3nm5ax58xaqjg6rjcj2vzvx2q39v9eqpn0wx54"; @@ -386,6 +420,18 @@ mod tests { assert_eq!(parsed.lnurl(), None); } + #[test] + fn parse_refund() { + let parsed = PaymentParams::from_str(SAMPLE_REFUND).unwrap(); + + assert_eq!(parsed.amount(), Some(Amount::from_sat(1))); + assert_eq!(parsed.amount_msats(), Some(1_000)); + assert!(parsed.valid_for_network(Network::Bitcoin).unwrap_or(false)); + assert_eq!(parsed.refund().unwrap().to_string(), SAMPLE_REFUND); + assert_eq!(parsed.memo().as_deref(), Some("foo")); + assert_eq!(parsed.lnurl(), None); + } + #[test] fn parse_invoice_with_prefix() { let parsed = PaymentParams::from_str(&format!("lightning:{SAMPLE_INVOICE}")).unwrap();