-
Notifications
You must be signed in to change notification settings - Fork 114
Refactor unified_qr.rs to use bitcoin-payment-instructions #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
bff7bc1
34dc64d
43fb5f4
0eff43b
56e77d0
b6890ca
60b938b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,7 +55,10 @@ pub use crate::logger::{LogLevel, LogRecord, LogWriter}; | |
| pub use crate::payment::store::{ | ||
| ConfirmationStatus, LSPFeeLimits, PaymentDirection, PaymentKind, PaymentStatus, | ||
| }; | ||
| pub use crate::payment::QrPaymentResult; | ||
| pub use crate::payment::UnifiedPaymentResult; | ||
|
|
||
| use lightning::onion_message::dns_resolution::HumanReadableName as LdkHumanReadableName; | ||
|
|
||
| use crate::{hex_utils, SocketAddress, UniffiCustomTypeConverter, UserChannelId}; | ||
|
|
||
| impl UniffiCustomTypeConverter for PublicKey { | ||
|
|
@@ -284,6 +287,72 @@ impl std::fmt::Display for Offer { | |
| } | ||
| } | ||
|
|
||
| /// A struct containing the two parts of a BIP 353 Human-Readable Name - the user and domain parts. | ||
| /// | ||
| /// The `user` and `domain` parts combined cannot exceed 231 bytes in length; | ||
| /// each DNS label within them must be non-empty and no longer than 63 bytes. | ||
| /// | ||
| /// If you intend to handle non-ASCII `user` or `domain` parts, you must handle [Homograph Attacks] | ||
| /// and do punycode en-/de-coding yourself. This struct will always handle only plain ASCII `user` | ||
| /// and `domain` parts. | ||
| /// | ||
| /// This struct can also be used for LN-Address recipients. | ||
| /// | ||
| /// [Homograph Attacks]: https://en.wikipedia.org/wiki/IDN_homograph_attack | ||
| pub struct HumanReadableName { | ||
| pub(crate) inner: LdkHumanReadableName, | ||
| } | ||
|
|
||
| impl HumanReadableName { | ||
| /// Constructs a new [`HumanReadableName`] from the standard encoding - `user`@`domain`. | ||
| /// | ||
| /// If `user` includes the standard BIP 353 ₿ prefix it is automatically removed as required by | ||
| /// BIP 353. | ||
| pub fn from_encoded(encoded: &str) -> Result<Self, Error> { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide docs on all public methods. Feel free to copy them over from the LDK counterpart. |
||
| let hrn = match LdkHumanReadableName::from_encoded(encoded) { | ||
| Ok(hrn) => Ok(hrn), | ||
| Err(_) => Err(Error::HrnParsingFailed), | ||
| }?; | ||
|
|
||
| Ok(Self { inner: hrn }) | ||
| } | ||
|
|
||
| /// Gets the `user` part of this Human-Readable Name | ||
| pub fn user(&self) -> String { | ||
| self.inner.user().to_string() | ||
| } | ||
|
|
||
| /// Gets the `domain` part of this Human-Readable Name | ||
| pub fn domain(&self) -> String { | ||
| self.inner.domain().to_string() | ||
| } | ||
| } | ||
|
|
||
| impl From<LdkHumanReadableName> for HumanReadableName { | ||
| fn from(ldk_hrn: LdkHumanReadableName) -> Self { | ||
| HumanReadableName { inner: ldk_hrn } | ||
| } | ||
| } | ||
|
|
||
| impl From<HumanReadableName> for LdkHumanReadableName { | ||
| fn from(wrapper: HumanReadableName) -> Self { | ||
| wrapper.inner | ||
| } | ||
| } | ||
|
|
||
| impl Deref for HumanReadableName { | ||
| type Target = LdkHumanReadableName; | ||
| fn deref(&self) -> &Self::Target { | ||
| &self.inner | ||
| } | ||
| } | ||
|
|
||
| impl AsRef<LdkHumanReadableName> for HumanReadableName { | ||
| fn as_ref(&self) -> &LdkHumanReadableName { | ||
| self.deref() | ||
| } | ||
| } | ||
|
|
||
| /// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`]. | ||
| /// | ||
| /// Typically, after an invoice is paid, the recipient may publish a refund allowing the sender to | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; | |
|
|
||
| use lightning::blinded_path::message::BlindedMessagePath; | ||
| use lightning::ln::channelmanager::{OptionalOfferPaymentParams, PaymentId, Retry}; | ||
| use lightning::offers::offer::{Amount, Offer as LdkOffer, Quantity}; | ||
| use lightning::offers::offer::{Amount, Offer as LdkOffer, OfferFromHrn, Quantity}; | ||
| use lightning::offers::parse::Bolt12SemanticError; | ||
| use lightning::routing::router::RouteParametersConfig; | ||
| #[cfg(feature = "uniffi")] | ||
|
|
@@ -45,6 +45,11 @@ type Refund = lightning::offers::refund::Refund; | |
| #[cfg(feature = "uniffi")] | ||
| type Refund = Arc<crate::ffi::Refund>; | ||
|
|
||
| #[cfg(not(feature = "uniffi"))] | ||
| type HumanReadableName = lightning::onion_message::dns_resolution::HumanReadableName; | ||
| #[cfg(feature = "uniffi")] | ||
| type HumanReadableName = Arc<crate::ffi::HumanReadableName>; | ||
|
|
||
| /// A payment handler allowing to create and pay [BOLT 12] offers and refunds. | ||
| /// | ||
| /// Should be retrieved by calling [`Node::bolt12_payment`]. | ||
|
|
@@ -193,6 +198,37 @@ impl Bolt12Payment { | |
| pub fn send_using_amount( | ||
| &self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>, | ||
| route_parameters: Option<RouteParametersConfig>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let payment_id = self.send_using_amount_inner( | ||
| offer, | ||
| amount_msat, | ||
| quantity, | ||
| payer_note, | ||
| route_parameters, | ||
| None, | ||
| )?; | ||
| Ok(payment_id) | ||
| } | ||
|
|
||
| /// Internal helper to send a BOLT12 offer payment given an offer | ||
| /// and an amount in millisatoshi. | ||
| /// | ||
| /// This function contains the core payment logic and is called by | ||
| /// [`Self::send_using_amount`] and other internal logic that resolves | ||
| /// payment parameters (e.g. [`crate::UnifiedPayment::send`]). | ||
| /// | ||
| /// It wraps the core LDK `pay_for_offer` logic and handles necessary pre-checks, | ||
| /// payment ID generation, and payment details storage. | ||
| /// | ||
| /// The amount validation logic ensures the provided `amount_msat` is sufficient | ||
| /// based on the offer's required amount. | ||
| /// | ||
| /// If `hrn` is `Some`, the payment is initiated using [`ChannelManager::pay_for_offer_from_hrn`] | ||
| /// for offers resolved from a Human-Readable Name ([`HumanReadableName`]). | ||
| /// Otherwise, it falls back to the standard offer payment methods. | ||
| pub(crate) fn send_using_amount_inner( | ||
| &self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>, | ||
| route_parameters: Option<RouteParametersConfig>, hrn: Option<HumanReadableName>, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should change the public API here. Please create a |
||
| ) -> Result<PaymentId, Error> { | ||
| if !*self.is_running.read().unwrap() { | ||
| return Err(Error::NotRunning); | ||
|
|
@@ -228,7 +264,11 @@ impl Bolt12Payment { | |
| retry_strategy, | ||
| route_params_config: route_parameters, | ||
| }; | ||
| let res = if let Some(quantity) = quantity { | ||
| let res = if let Some(hrn) = hrn { | ||
| let hrn = maybe_deref(&hrn); | ||
| let offer = OfferFromHrn { offer: offer.clone(), hrn: *hrn }; | ||
| self.channel_manager.pay_for_offer_from_hrn(&offer, amount_msat, payment_id, params) | ||
| } else if let Some(quantity) = quantity { | ||
| self.channel_manager.pay_for_offer_with_quantity( | ||
| &offer, | ||
| Some(amount_msat), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bitcoin-payment-instructionsv0.6 has been released last week, please bump the dependency here and remove your fork.