Skip to content

Commit

Permalink
Implement LSPS2 API methods
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull committed Jan 9, 2024
1 parent 6cfa4ef commit 8d69393
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
4 changes: 4 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ interface LDKNode {
Bolt11Invoice receive_payment(u64 amount_msat, [ByRef]string description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_payment([ByRef]string description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_payment_via_jit_channel(u64 amount_msat, [ByRef]string description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_payment_via_jit_channel([ByRef]string description, u32 expiry_secs);
PaymentDetails? payment([ByRef]PaymentHash payment_hash);
[Throws=NodeError]
void remove_payment([ByRef]PaymentHash payment_hash);
Expand Down
82 changes: 82 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,88 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
Ok(invoice)
}

/// Returns a payable invoice that can be used to request a payment of the amount given and
/// receive it via a newly created just-in-time (JIT) channel.
///
/// When the returned invoice is paid, the configured [LSPS2]-compliant LSP will open a channel
/// to us, supplying just-in-time inbound liquidity.
///
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
pub fn receive_payment_via_jit_channel(
&self, amount_msat: u64, description: &str, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
self.receive_payment_via_jit_channel_inner(Some(amount_msat), description, expiry_secs)
}

/// Returns a payable invoice that can be used to request a variable amount payment (also known
/// as "zero-amount" invoice) and receive it via a newly created just-in-time (JIT) channel.
///
/// When the returned invoice is paid, the configured [LSPS2]-compliant LSP will open a channel
/// to us, supplying just-in-time inbound liquidity.
///
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
pub fn receive_variable_amount_payment_via_jit_channel(
&self, description: &str, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
self.receive_payment_via_jit_channel_inner(None, description, expiry_secs)
}

fn receive_payment_via_jit_channel_inner(
&self, amount_msat: Option<u64>, description: &str, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let (node_id, address) = self
.liquidity_source
.get_liquidity_source_details()
.ok_or(Error::LiquiditySourceUnavailable)?;

let rt_lock = self.runtime.read().unwrap();
let runtime = rt_lock.as_ref().unwrap();

let peer_info = PeerInfo { node_id, address };

let con_node_id = peer_info.node_id;
let con_addr = peer_info.address.clone();
let con_logger = Arc::clone(&self.logger);
let con_pm = Arc::clone(&self.peer_manager);

// We need to use our main runtime here as a local runtime might not be around to poll
// connection futures going forward.
tokio::task::block_in_place(move || {
runtime.block_on(async move {
connect_peer_if_necessary(con_node_id, con_addr, con_pm, con_logger).await
})
})?;

log_info!(self.logger, "Connected to LSP {}@{}. ", peer_info.node_id, peer_info.address);

let liquidity_source = Arc::clone(&self.liquidity_source);
let invoice = tokio::task::block_in_place(move || {
runtime.block_on(async move {
liquidity_source
.lsps2_receive_to_jit_channel(amount_msat, description, expiry_secs)
.await
})
})?;

// Register payment in payment store.
let payment_hash = PaymentHash(invoice.payment_hash().to_byte_array());
let payment = PaymentDetails {
hash: payment_hash,
preimage: None,
secret: Some(invoice.payment_secret().clone()),
amount_msat,
direction: PaymentDirection::Inbound,
status: PaymentStatus::Pending,
};

self.payment_store.insert(payment)?;

// Persist LSP peer to make sure we reconnect on restart.
self.peer_store.add_peer(peer_info)?;

Ok(invoice)
}

/// Retrieve the details of a specific payment with the given hash.
///
/// Returns `Some` if the payment was known and `None` otherwise.
Expand Down
7 changes: 7 additions & 0 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ where
}
}

pub(crate) fn get_liquidity_source_details(&self) -> Option<(PublicKey, SocketAddress)> {
match self {
Self::None => None,
Self::LSPS2 { node_id, address, .. } => Some((*node_id, address.clone())),
}
}

pub(crate) async fn handle_next_event(&self) {
match self {
Self::None => {}
Expand Down

0 comments on commit 8d69393

Please sign in to comment.