Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ log = { version = "0.4.22", default-features = false, features = ["std"]}

vss-client = "0.3"
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.5" }
bitcoin-payment-instructions = { git = "https://github.com/chuksys/bitcoin-payment-instructions", branch = "bump-ldk-deps" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
Expand Down Expand Up @@ -147,4 +149,4 @@ check-cfg = [
"cfg(tokio_unstable)",
"cfg(cln_test)",
"cfg(lnd_test)",
]
]
20 changes: 14 additions & 6 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ interface Node {
Bolt12Payment bolt12_payment();
SpontaneousPayment spontaneous_payment();
OnchainPayment onchain_payment();
UnifiedQrPayment unified_qr_payment();
UnifiedPayment unified_payment();
LSPS1Liquidity lsps1_liquidity();
[Throws=NodeError]
void connect(PublicKey node_id, SocketAddress address, boolean persist);
Expand Down Expand Up @@ -203,7 +203,7 @@ interface Bolt12Payment {
[Throws=NodeError]
PaymentId send([ByRef]Offer offer, u64? quantity, string? payer_note);
[Throws=NodeError]
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note);
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note, HumanReadableName? hrn);
[Throws=NodeError]
Offer receive(u64 amount_msat, [ByRef]string description, u32? expiry_secs, u64? quantity);
[Throws=NodeError]
Expand Down Expand Up @@ -252,11 +252,11 @@ interface FeeRate {
u64 to_sat_per_vb_ceil();
};

interface UnifiedQrPayment {
interface UnifiedPayment {
[Throws=NodeError]
string receive(u64 amount_sats, [ByRef]string message, u32 expiry_sec);
[Throws=NodeError]
QrPaymentResult send([ByRef]string uri_str);
[Throws=NodeError, Async]
UnifiedPaymentResult send([ByRef]string uri_str, u64? amount_msat);
};

interface LSPS1Liquidity {
Expand Down Expand Up @@ -322,6 +322,7 @@ enum NodeError {
"LiquidityFeeTooHigh",
"InvalidBlindedPaths",
"AsyncPaymentServicesDisabled",
"HrnParsingFailed",
};

dictionary NodeStatus {
Expand Down Expand Up @@ -431,7 +432,7 @@ interface PaymentKind {
};

[Enum]
interface QrPaymentResult {
interface UnifiedPaymentResult {
Onchain(Txid txid);
Bolt11(PaymentId payment_id);
Bolt12(PaymentId payment_id);
Expand Down Expand Up @@ -783,6 +784,13 @@ interface Offer {
PublicKey? issuer_signing_pubkey();
};

interface HumanReadableName {
[Throws=NodeError, Name=from_encoded]
constructor([ByRef] string encoded);
string user();
string domain();
};

[Traits=(Debug, Display, Eq)]
interface Refund {
[Throws=NodeError, Name=from_str]
Expand Down
14 changes: 12 additions & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use bip39::Mnemonic;
use bitcoin::bip32::{ChildNumber, Xpriv};
use bitcoin::secp256k1::PublicKey;
use bitcoin::{BlockHash, Network};
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
use lightning::chain::{chainmonitor, BestBlock, Watch};
use lightning::io::Cursor;
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs};
Expand Down Expand Up @@ -1536,6 +1537,8 @@ fn build_with_store_internal(
})?;
}

let hrn_resolver = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));

// Initialize the PeerManager
let onion_messenger: Arc<OnionMessenger> =
if let Some(AsyncPaymentsRole::Server) = async_payments_role {
Expand All @@ -1547,7 +1550,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
IgnoringMessageHandler {},
Arc::clone(&hrn_resolver),
IgnoringMessageHandler {},
))
} else {
Expand All @@ -1559,7 +1562,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
IgnoringMessageHandler {},
Arc::clone(&hrn_resolver),
IgnoringMessageHandler {},
))
};
Expand Down Expand Up @@ -1691,6 +1694,12 @@ fn build_with_store_internal(
Arc::clone(&keys_manager),
));

let peer_manager_clone = Arc::clone(&peer_manager);

hrn_resolver.register_post_queue_action(Box::new(move || {
peer_manager_clone.process_events();
}));

liquidity_source.as_ref().map(|l| l.set_peer_manager(Arc::clone(&peer_manager)));

gossip_source.set_gossip_verifier(
Expand Down Expand Up @@ -1797,6 +1806,7 @@ fn build_with_store_internal(
node_metrics,
om_mailbox,
async_payments_role,
hrn_resolver,
})
}

Expand Down
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ pub enum Error {
InvalidBlindedPaths,
/// Asynchronous payment services are disabled.
AsyncPaymentServicesDisabled,
/// Parsing a Human-Readable Name has failed.
HrnParsingFailed,
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -202,6 +204,9 @@ impl fmt::Display for Error {
Self::AsyncPaymentServicesDisabled => {
write!(f, "Asynchronous payment services are disabled.")
},
Self::HrnParsingFailed => {
write!(f, "Failed to parse a human-readable name.")
},
}
}
}
Expand Down
57 changes: 56 additions & 1 deletion src/ffi/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,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;

pub use lightning::onion_message::dns_resolution::HumanReadableName as LdkHumanReadableName;

use crate::{hex_utils, SocketAddress, UniffiCustomTypeConverter, UserChannelId};

impl UniffiCustomTypeConverter for PublicKey {
Expand Down Expand Up @@ -267,6 +270,58 @@ impl std::fmt::Display for Offer {
}
}

pub struct HumanReadableName {
pub(crate) inner: LdkHumanReadableName,
}

impl HumanReadableName {
pub fn into_inner(&self) -> LdkHumanReadableName {
self.inner.clone()
}

pub fn from_encoded(encoded: &str) -> Result<Self, Error> {
let hrn = match LdkHumanReadableName::from_encoded(encoded) {
Ok(hrn) => Ok(hrn),
Err(_) => Err(Error::HrnParsingFailed),
}?;

Ok(Self { inner: hrn })
}

pub fn user(&self) -> String {
self.inner.user().to_string()
}

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.into_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
Expand Down
47 changes: 28 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,34 +131,34 @@ use gossip::GossipSource;
use graph::NetworkGraph;
pub use io::utils::generate_entropy_mnemonic;
use io::utils::write_node_metrics;
use lightning::chain::BestBlock;
use lightning::events::bump_transaction::Wallet as LdkWallet;
use lightning::impl_writeable_tlv_based;
use lightning::ln::channel_state::ChannelShutdownState;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::msgs::SocketAddress;
use lightning::routing::gossip::NodeAlias;
use lightning::util::persist::KVStoreSync;
use lightning_background_processor::process_events_async;
use liquidity::{LSPS1Liquidity, LiquiditySource};
use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
use payment::asynchronous::om_mailbox::OnionMessageMailbox;
use payment::asynchronous::static_invoice_store::StaticInvoiceStore;
use payment::{
Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment,
UnifiedQrPayment,
UnifiedPayment,
};
use peer_store::{PeerInfo, PeerStore};
use rand::Rng;
use runtime::Runtime;
use types::{
Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, Graph, KeysManager,
OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper, Wallet,
Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, Graph, HRNResolver,
KeysManager, OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper, Wallet,
};
pub use types::{
ChannelDetails, CustomTlvRecord, DynStore, PeerDetails, SyncAndAsyncKVStore, UserChannelId,
};

use lightning::chain::BestBlock;
use lightning::events::bump_transaction::Wallet as LdkWallet;
use lightning::impl_writeable_tlv_based;
use lightning::ln::channel_state::ChannelShutdownState;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::msgs::SocketAddress;
use lightning::routing::gossip::NodeAlias;
use lightning::util::persist::KVStoreSync;
use lightning_background_processor::process_events_async;
use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
use payment::asynchronous::om_mailbox::OnionMessageMailbox;
use rand::Rng;
pub use {
bip39, bitcoin, lightning, lightning_invoice, lightning_liquidity, lightning_types, tokio,
vss_client,
Expand Down Expand Up @@ -200,6 +200,7 @@ pub struct Node {
node_metrics: Arc<RwLock<NodeMetrics>>,
om_mailbox: Option<Arc<OnionMessageMailbox>>,
async_payments_role: Option<AsyncPaymentsRole>,
hrn_resolver: Arc<HRNResolver>,
}

impl Node {
Expand Down Expand Up @@ -927,34 +928,42 @@ impl Node {
/// Returns a payment handler allowing to create [BIP 21] URIs with an on-chain, [BOLT 11],
/// and [BOLT 12] payment options.
///
/// This handler allows you to send payments to these URIs as well as [BIP 353] HRNs.
///
/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
/// [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
/// [BIP 21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
#[cfg(not(feature = "uniffi"))]
pub fn unified_qr_payment(&self) -> UnifiedQrPayment {
UnifiedQrPayment::new(
pub fn unified_payment(&self) -> UnifiedPayment {
UnifiedPayment::new(
self.onchain_payment().into(),
self.bolt11_payment().into(),
self.bolt12_payment().into(),
Arc::clone(&self.config),
Arc::clone(&self.logger),
Arc::clone(&self.hrn_resolver),
)
}

/// Returns a payment handler allowing to create [BIP 21] URIs with an on-chain, [BOLT 11],
/// and [BOLT 12] payment options.
///
/// This handler allows you to send payments to these URIs as well as [BIP 353] HRNs.
///
/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
/// [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
/// [BIP 21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
#[cfg(feature = "uniffi")]
pub fn unified_qr_payment(&self) -> Arc<UnifiedQrPayment> {
Arc::new(UnifiedQrPayment::new(
pub fn unified_payment(&self) -> Arc<UnifiedPayment> {
Arc::new(UnifiedPayment::new(
self.onchain_payment(),
self.bolt11_payment(),
self.bolt12_payment(),
Arc::clone(&self.config),
Arc::clone(&self.logger),
Arc::clone(&self.hrn_resolver),
))
}

Expand Down
14 changes: 12 additions & 2 deletions src/payment/bolt12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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`].
Expand Down Expand Up @@ -183,6 +188,7 @@ impl Bolt12Payment {
/// response.
pub fn send_using_amount(
&self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>,
hrn: Option<HumanReadableName>,
) -> Result<PaymentId, Error> {
if !*self.is_running.read().unwrap() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -217,7 +223,11 @@ impl Bolt12Payment {
retry_strategy,
route_params_config,
};
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),
Expand Down
4 changes: 2 additions & 2 deletions src/payment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod bolt12;
mod onchain;
mod spontaneous;
pub(crate) mod store;
mod unified_qr;
mod unified;

pub use bolt11::Bolt11Payment;
pub use bolt12::Bolt12Payment;
Expand All @@ -22,4 +22,4 @@ pub use spontaneous::SpontaneousPayment;
pub use store::{
ConfirmationStatus, LSPFeeLimits, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus,
};
pub use unified_qr::{QrPaymentResult, UnifiedQrPayment};
pub use unified::{UnifiedPayment, UnifiedPaymentResult};
Loading
Loading