Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 161
Expose payer_note in PaymentKind::Bolt12#327
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -12,12 +12,14 @@ use crate::types::ChannelManager; | ||
| use lightning::ln::channelmanager::{PaymentId, Retry}; | ||
| use lightning::offers::invoice::Bolt12Invoice; | ||
| use lightning::offers::offer::{Amount, Offer}; | ||
| use lightning::offers::offer::{Amount, Offer, Quantity}; | ||
| use lightning::offers::parse::Bolt12SemanticError; | ||
| use lightning::offers::refund::Refund; | ||
| use lightning::util::string::UntrustedString; | ||
| use rand::RngCore; | ||
| use std::num::NonZeroU64; | ||
| use std::sync::{Arc, RwLock}; | ||
| use std::time::{Duration, SystemTime, UNIX_EPOCH}; | ||
| @@ -47,13 +49,15 @@ impl Bolt12Payment { | ||
| /// | ||
| /// If `payer_note` is `Some` it will be seen by the recipient and reflected back in the invoice | ||
| /// response. | ||
| pub fn send(&self, offer: &Offer, payer_note: Option<String>) -> Result<PaymentId, Error> { | ||
| /// | ||
| /// If `quantity` is `Some` it represents the number of items requested. | ||
| pub fn send( | ||
| &self, offer: &Offer, quantity: Option<u64>, payer_note: Option<String>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let rt_lock = self.runtime.read().unwrap(); | ||
| if rt_lock.is_none() { | ||
| return Err(Error::NotRunning); | ||
| } | ||
| let quantity = None; | ||
| let mut random_bytes = [0u8; 32]; | ||
| rand::thread_rng().fill_bytes(&mut random_bytes); | ||
| let payment_id = PaymentId(random_bytes); | ||
| @@ -76,7 +80,7 @@ impl Bolt12Payment { | ||
| &offer, | ||
| quantity, | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| None, | ||
| payer_note, | ||
| payer_note.clone(), | ||
| payment_id, | ||
| retry_strategy, | ||
| max_total_routing_fee_msat, | ||
| @@ -95,6 +99,8 @@ impl Bolt12Payment { | ||
| preimage: None, | ||
| secret: None, | ||
| offer_id: offer.id(), | ||
| payer_note: payer_note.map(UntrustedString), | ||
| quantity, | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| @@ -117,6 +123,8 @@ impl Bolt12Payment { | ||
| preimage: None, | ||
| secret: None, | ||
| offer_id: offer.id(), | ||
| payer_note: payer_note.map(UntrustedString), | ||
| quantity, | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| @@ -143,14 +151,13 @@ impl Bolt12Payment { | ||
| /// If `payer_note` is `Some` it will be seen by the recipient and reflected back in the invoice | ||
| /// response. | ||
| pub fn send_using_amount( | ||
| &self, offer: &Offer, payer_note: Option<String>, amount_msat: u64, | ||
| &self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let rt_lock = self.runtime.read().unwrap(); | ||
| if rt_lock.is_none() { | ||
| return Err(Error::NotRunning); | ||
| } | ||
| let quantity = None; | ||
| let mut random_bytes = [0u8; 32]; | ||
| rand::thread_rng().fill_bytes(&mut random_bytes); | ||
| let payment_id = PaymentId(random_bytes); | ||
| @@ -177,7 +184,7 @@ impl Bolt12Payment { | ||
| &offer, | ||
| quantity, | ||
| Some(amount_msat), | ||
| payer_note, | ||
| payer_note.clone(), | ||
| payment_id, | ||
| retry_strategy, | ||
| max_total_routing_fee_msat, | ||
| @@ -196,6 +203,8 @@ impl Bolt12Payment { | ||
| preimage: None, | ||
| secret: None, | ||
| offer_id: offer.id(), | ||
| payer_note: payer_note.map(UntrustedString), | ||
| quantity, | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| @@ -218,6 +227,8 @@ impl Bolt12Payment { | ||
| preimage: None, | ||
| secret: None, | ||
| offer_id: offer.id(), | ||
| payer_note: payer_note.map(UntrustedString), | ||
| quantity, | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| @@ -236,21 +247,32 @@ impl Bolt12Payment { | ||
| /// Returns a payable offer that can be used to request and receive a payment of the amount | ||
| /// given. | ||
| pub fn receive(&self, amount_msat: u64, description: &str) -> Result<Offer, Error> { | ||
| pub fn receive( | ||
| &self, amount_msat: u64, description: &str, quantity: Option<u64>, | ||
| ) -> Result<Offer, Error> { | ||
| let offer_builder = self.channel_manager.create_offer_builder().map_err(|e| { | ||
| log_error!(self.logger, "Failed to create offer builder: {:?}", e); | ||
| Error::OfferCreationFailed | ||
| })?; | ||
| let offer = offer_builder | ||
| .amount_msats(amount_msat) | ||
| .description(description.to_string()) | ||
| .build() | ||
| .map_err(|e| { | ||
| log_error!(self.logger, "Failed to create offer: {:?}", e); | ||
| Error::OfferCreationFailed | ||
| })?; | ||
| Ok(offer) | ||
| let mut offer = | ||
| offer_builder.amount_msats(amount_msat).description(description.to_string()); | ||
| if let Some(qty) = quantity { | ||
| if qty == 0 { | ||
| log_error!(self.logger, "Failed to create offer: quantity can't be zero."); | ||
| return Err(Error::InvalidQuantity); | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } else { | ||
| offer = offer.supported_quantity(Quantity::Bounded(NonZeroU64::new(qty).unwrap())) | ||
| }; | ||
| }; | ||
| let finalized_offer = offer.build().map_err(|e| { | ||
| log_error!(self.logger, "Failed to create offer: {:?}", e); | ||
| Error::OfferCreationFailed | ||
| })?; | ||
| Ok(finalized_offer) | ||
| } | ||
| /// Returns a payable offer that can be used to request and receive a payment for which the | ||
| @@ -281,8 +303,13 @@ impl Bolt12Payment { | ||
| let payment_hash = invoice.payment_hash(); | ||
| let payment_id = PaymentId(payment_hash.0); | ||
| let kind = | ||
| PaymentKind::Bolt12Refund { hash: Some(payment_hash), preimage: None, secret: None }; | ||
| let kind = PaymentKind::Bolt12Refund { | ||
| hash: Some(payment_hash), | ||
| preimage: None, | ||
| secret: None, | ||
| payer_note: refund.payer_note().map(|note| UntrustedString(note.0.to_string())), | ||
| quantity: refund.quantity(), | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| @@ -298,7 +325,10 @@ impl Bolt12Payment { | ||
| } | ||
| /// Returns a [`Refund`] object that can be used to offer a refund payment of the amount given. | ||
| pub fn initiate_refund(&self, amount_msat: u64, expiry_secs: u32) -> Result<Refund, Error> { | ||
| pub fn initiate_refund( | ||
| &self, amount_msat: u64, expiry_secs: u32, quantity: Option<u64>, | ||
| payer_note: Option<String>, | ||
| ) -> Result<Refund, Error> { | ||
| let mut random_bytes = [0u8; 32]; | ||
| rand::thread_rng().fill_bytes(&mut random_bytes); | ||
| let payment_id = PaymentId(random_bytes); | ||
| @@ -309,7 +339,7 @@ impl Bolt12Payment { | ||
| let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT); | ||
| let max_total_routing_fee_msat = None; | ||
| let refund = self | ||
| let mut refund_builder = self | ||
| .channel_manager | ||
| .create_refund_builder( | ||
| amount_msat, | ||
| @@ -321,17 +351,30 @@ impl Bolt12Payment { | ||
| .map_err(|e| { | ||
| log_error!(self.logger, "Failed to create refund builder: {:?}", e); | ||
| Error::RefundCreationFailed | ||
| })? | ||
| .build() | ||
| .map_err(|e| { | ||
| log_error!(self.logger, "Failed to create refund: {:?}", e); | ||
| Error::RefundCreationFailed | ||
| })?; | ||
| log_info!(self.logger, "Offering refund of {}msat", amount_msat); | ||
| if let Some(qty) = quantity { | ||
| refund_builder = refund_builder.quantity(qty); | ||
| } | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if let Some(note) = payer_note.clone() { | ||
| refund_builder = refund_builder.payer_note(note); | ||
| } | ||
| let refund = refund_builder.build().map_err(|e| { | ||
| log_error!(self.logger, "Failed to create refund: {:?}", e); | ||
| Error::RefundCreationFailed | ||
| })?; | ||
| let kind = PaymentKind::Bolt12Refund { hash: None, preimage: None, secret: None }; | ||
| log_info!(self.logger, "Offering refund of {}msat", amount_msat); | ||
| let kind = PaymentKind::Bolt12Refund { | ||
| hash: None, | ||
| preimage: None, | ||
| secret: None, | ||
| payer_note: payer_note.map(|note| UntrustedString(note)), | ||
| quantity, | ||
| }; | ||
| let payment = PaymentDetails::new( | ||
| payment_id, | ||
| kind, | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -11,6 +11,7 @@ use lightning::ln::msgs::DecodeError; | ||
| use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; | ||
| use lightning::offers::offer::OfferId; | ||
| use lightning::util::ser::{Readable, Writeable}; | ||
| use lightning::util::string::UntrustedString; | ||
| use lightning::{ | ||
| _init_and_read_len_prefixed_tlv_fields, impl_writeable_tlv_based, | ||
| impl_writeable_tlv_based_enum, write_tlv_fields, | ||
| @@ -212,6 +213,18 @@ pub enum PaymentKind { | ||
| secret: Option<PaymentSecret>, | ||
| /// The ID of the offer this payment is for. | ||
| offer_id: OfferId, | ||
| /// The payer note for the payment. | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// | ||
| /// Truncated to [`PAYER_NOTE_LIMIT`] characters. | ||
| /// | ||
| /// This will always be `None` for payments serialized with version `v0.3.0`. | ||
| /// | ||
| /// [`PAYER_NOTE_LIMIT`]: lightning::offers::invoice_request::PAYER_NOTE_LIMIT | ||
| payer_note: Option<UntrustedString>, | ||
| /// The quantity of an item requested in the offer. | ||
| /// | ||
| /// This will always be `None` for payments serialized with version `v0.3.0`. | ||
| quantity: Option<u64>, | ||
| }, | ||
| /// A [BOLT 12] 'refund' payment, i.e., a payment for a [`Refund`]. | ||
| /// | ||
| @@ -224,6 +237,14 @@ pub enum PaymentKind { | ||
| preimage: Option<PaymentPreimage>, | ||
| /// The secret used by the payment. | ||
| secret: Option<PaymentSecret>, | ||
| /// The payer note for the refund payment. | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// | ||
| /// This will always be `None` for payments serialized with version `v0.3.0`. | ||
| payer_note: Option<UntrustedString>, | ||
| /// The quantity of an item that the refund is for. | ||
| /// | ||
| /// This will always be `None` for payments serialized with version `v0.3.0`. | ||
| quantity: Option<u64>, | ||
| }, | ||
| /// A spontaneous ("keysend") payment. | ||
| Spontaneous { | ||
| @@ -249,7 +270,9 @@ impl_writeable_tlv_based_enum!(PaymentKind, | ||
| }, | ||
| (6, Bolt12Offer) => { | ||
| (0, hash, option), | ||
| (1, payer_note, option), | ||
| (2, preimage, option), | ||
| (3, quantity, option), | ||
| (4, secret, option), | ||
| (6, offer_id, required), | ||
| }, | ||
| @@ -259,7 +282,9 @@ impl_writeable_tlv_based_enum!(PaymentKind, | ||
| }, | ||
| (10, Bolt12Refund) => { | ||
| (0, hash, option), | ||
| (1, payer_note, option), | ||
| (2, preimage, option), | ||
| (3, quantity, option), | ||
| (4, secret, option), | ||
| }; | ||
| ); | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.