Skip to content
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

Refactor and modularize payment APIs #270

Merged
merged 7 commits into from
May 15, 2024
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A ready-to-go Lightning node library built using [LDK][ldk] and [BDK][bdk].
LDK Node is a self-custodial Lightning node in library form. Its central goal is to provide a small, simple, and straightforward interface that enables users to easily set up and run a Lightning node with an integrated on-chain wallet. While minimalism is at its core, LDK Node aims to be sufficiently modular and configurable to be useful for a variety of use cases.

## Getting Started
The primary abstraction of the library is the [`Node`][api_docs_node], which can be retrieved by setting up and configuring a [`Builder`][api_docs_builder] to your liking and calling one of the `build` methods. `Node` can then be controlled via commands such as `start`, `stop`, `connect_open_channel`, `send_payment`, etc.
The primary abstraction of the library is the [`Node`][api_docs_node], which can be retrieved by setting up and configuring a [`Builder`][api_docs_builder] to your liking and calling one of the `build` methods. `Node` can then be controlled via commands such as `start`, `stop`, `connect_open_channel`, `send`, etc.

```rust
use ldk_node::Builder;
Expand All @@ -31,7 +31,7 @@ fn main() {

node.start().unwrap();

let funding_address = node.new_onchain_address();
let funding_address = node.onchain_payment().new_address();

// .. fund address ..

Expand All @@ -44,7 +44,7 @@ fn main() {
node.event_handled();

let invoice = Bolt11Invoice::from_str("INVOICE_STR").unwrap();
node.send_payment(&invoice).unwrap();
node.bolt11_payment().send(&invoice).unwrap();

node.stop().unwrap();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ class AndroidLibTest {
val nodeId2 = node2.nodeId()
println("Node Id 2: $nodeId2")

val address1 = node1.newOnchainAddress()
val address1 = node1.onchain_payment().newOnchainAddress()
println("Funding address 1: $address1")

val address2 = node2.newOnchainAddress()
val address2 = node2.onchain_payment().newOnchainAddress()
println("Funding address 2: $address2")

node1.stop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ class LibraryTest {
val nodeId2 = node2.nodeId()
println("Node Id 2: $nodeId2")

val address1 = node1.newOnchainAddress()
val address1 = node1.onchainPayment().newAddress()
println("Funding address 1: $address1")

val address2 = node2.newOnchainAddress()
val address2 = node2.onchainPayment().newAddress()
println("Funding address 2: $address2")

val txid1 = sendToAddress(address1, 100000u)
Expand Down Expand Up @@ -222,9 +222,9 @@ class LibraryTest {
else -> return
}

val invoice = node2.receivePayment(2500000u, "asdf", 9217u)
val invoice = node2.bolt11Payment().receive(2500000u, "asdf", 9217u)

node1.sendPayment(invoice)
node1.bolt11Payment().send(invoice)

val paymentSuccessfulEvent = node1.waitNextEvent()
println("Got event: $paymentSuccessfulEvent")
Expand Down
84 changes: 53 additions & 31 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,9 @@ interface Node {
void event_handled();
PublicKey node_id();
sequence<SocketAddress>? listening_addresses();
[Throws=NodeError]
Address new_onchain_address();
[Throws=NodeError]
Txid send_to_onchain_address([ByRef]Address address, u64 amount_msat);
[Throws=NodeError]
Txid send_all_to_onchain_address([ByRef]Address address);
Bolt11Payment bolt11_payment();
SpontaneousPayment spontaneous_payment();
OnchainPayment onchain_payment();
[Throws=NodeError]
void connect(PublicKey node_id, SocketAddress address, boolean persist);
[Throws=NodeError]
Expand All @@ -71,36 +68,51 @@ interface Node {
void update_channel_config([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, ChannelConfig channel_config);
[Throws=NodeError]
void sync_wallets();
PaymentDetails? payment([ByRef]PaymentId payment_id);
[Throws=NodeError]
PaymentHash send_payment([ByRef]Bolt11Invoice invoice);
void remove_payment([ByRef]PaymentId payment_id);
BalanceDetails list_balances();
sequence<PaymentDetails> list_payments();
sequence<PeerDetails> list_peers();
sequence<ChannelDetails> list_channels();
[Throws=NodeError]
PaymentHash send_payment_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat);
string sign_message([ByRef]sequence<u8> msg);
boolean verify_signature([ByRef]sequence<u8> msg, [ByRef]string sig, [ByRef]PublicKey pkey);
};

interface Bolt11Payment {
[Throws=NodeError]
PaymentHash send_spontaneous_payment(u64 amount_msat, PublicKey node_id);
PaymentId send([ByRef]Bolt11Invoice invoice);
[Throws=NodeError]
void send_payment_probes([ByRef]Bolt11Invoice invoice);
PaymentId send_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat);
[Throws=NodeError]
void send_spontaneous_payment_probes(u64 amount_msat, PublicKey node_id);
void send_probes([ByRef]Bolt11Invoice invoice);
[Throws=NodeError]
void send_payment_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat);
void send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat);
[Throws=NodeError]
Bolt11Invoice receive_payment(u64 amount_msat, [ByRef]string description, u32 expiry_secs);
Bolt11Invoice receive(u64 amount_msat, [ByRef]string description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_payment([ByRef]string description, u32 expiry_secs);
Bolt11Invoice receive_variable_amount([ByRef]string description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_payment_via_jit_channel(u64 amount_msat, [ByRef]string description, u32 expiry_secs, u64? max_lsp_fee_limit_msat);
Bolt11Invoice receive_via_jit_channel(u64 amount_msat, [ByRef]string description, u32 expiry_secs, u64? max_lsp_fee_limit_msat);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_payment_via_jit_channel([ByRef]string description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat);
PaymentDetails? payment([ByRef]PaymentHash payment_hash);
Bolt11Invoice receive_variable_amount_via_jit_channel([ByRef]string description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat);
};

interface SpontaneousPayment {
[Throws=NodeError]
void remove_payment([ByRef]PaymentHash payment_hash);
BalanceDetails list_balances();
sequence<PaymentDetails> list_payments();
sequence<PeerDetails> list_peers();
sequence<ChannelDetails> list_channels();
PaymentId send(u64 amount_msat, PublicKey node_id);
[Throws=NodeError]
string sign_message([ByRef]sequence<u8> msg);
boolean verify_signature([ByRef]sequence<u8> msg, [ByRef]string sig, [ByRef]PublicKey pkey);
void send_probes(u64 amount_msat, PublicKey node_id);
};

interface OnchainPayment {
[Throws=NodeError]
Address new_address();
[Throws=NodeError]
Txid send_to_address([ByRef]Address address, u64 amount_msat);
[Throws=NodeError]
Txid send_all_to_address([ByRef]Address address);
};

[Error]
Expand All @@ -127,6 +139,7 @@ enum NodeError {
"InvalidSocketAddress",
"InvalidPublicKey",
"InvalidSecretKey",
"InvalidPaymentId",
"InvalidPaymentHash",
"InvalidPaymentPreimage",
"InvalidPaymentSecret",
Expand Down Expand Up @@ -173,9 +186,9 @@ enum BuildError {

[Enum]
interface Event {
PaymentSuccessful(PaymentHash payment_hash, u64? fee_paid_msat);
PaymentFailed(PaymentHash payment_hash, PaymentFailureReason? reason);
PaymentReceived(PaymentHash payment_hash, u64 amount_msat);
PaymentSuccessful(PaymentId? payment_id, PaymentHash payment_hash, u64? fee_paid_msat);
PaymentFailed(PaymentId? payment_id, PaymentHash payment_hash, PaymentFailureReason? reason);
PaymentReceived(PaymentId? payment_id, PaymentHash payment_hash, u64 amount_msat);
ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo);
ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id);
ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason);
Expand Down Expand Up @@ -207,6 +220,14 @@ interface ClosureReason {
HTLCsTimedOut();
};

[Enum]
interface PaymentKind {
Onchain();
Bolt11(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret);
Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, LSPFeeLimits lsp_fee_limits);
Spontaneous(PaymentHash hash, PaymentPreimage? preimage);
};

enum PaymentDirection {
"Inbound",
"Outbound",
Expand All @@ -224,13 +245,11 @@ dictionary LSPFeeLimits {
};

dictionary PaymentDetails {
PaymentHash hash;
PaymentPreimage? preimage;
PaymentSecret? secret;
PaymentId id;
PaymentKind kind;
u64? amount_msat;
PaymentDirection direction;
PaymentStatus status;
LSPFeeLimits? lsp_fee_limits;
};

[NonExhaustive]
Expand Down Expand Up @@ -352,6 +371,9 @@ typedef string Address;
[Custom]
typedef string Bolt11Invoice;

[Custom]
typedef string PaymentId;

[Custom]
typedef string PaymentHash;

Expand Down
8 changes: 4 additions & 4 deletions bindings/python/src/ldk_node/test_ldk_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ def test_channel_full_cycle(self):
node_id_2 = node_2.node_id()
print("Node ID 2:", node_id_2)

address_1 = node_1.new_onchain_address()
address_1 = node_1.onchain_payment().new_address()
txid_1 = send_to_address(address_1, 100000)
address_2 = node_2.new_onchain_address()
address_2 = node_2.onchain_payment().new_address()
txid_2 = send_to_address(address_2, 100000)

wait_for_tx(esplora_endpoint, txid_1)
Expand Down Expand Up @@ -185,8 +185,8 @@ def test_channel_full_cycle(self):
print("EVENT:", channel_ready_event_2)
node_2.event_handled()

invoice = node_2.receive_payment(2500000, "asdf", 9217)
node_1.send_payment(invoice)
invoice = node_2.bolt11_payment().receive(2500000, "asdf", 9217)
node_1.bolt11_payment().send(invoice)

payment_successful_event_1 = node_1.wait_next_event()
assert isinstance(payment_successful_event_1, Event.PAYMENT_SUCCESSFUL)
Expand Down
2 changes: 1 addition & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::io::sqlite_store::SqliteStore;
use crate::liquidity::LiquiditySource;
use crate::logger::{log_error, log_info, FilesystemLogger, Logger};
use crate::message_handler::NodeCustomMessageHandler;
use crate::payment_store::PaymentStore;
use crate::payment::store::PaymentStore;
use crate::peer_store::PeerStore;
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub enum Error {
InvalidPublicKey,
/// The given secret key is invalid.
InvalidSecretKey,
/// The given payment id is invalid.
InvalidPaymentId,
/// The given payment hash is invalid.
InvalidPaymentHash,
/// The given payment pre-image is invalid.
Expand Down Expand Up @@ -100,6 +102,7 @@ impl fmt::Display for Error {
Self::InvalidSocketAddress => write!(f, "The given network address is invalid."),
Self::InvalidPublicKey => write!(f, "The given public key is invalid."),
Self::InvalidSecretKey => write!(f, "The given secret key is invalid."),
Self::InvalidPaymentId => write!(f, "The given payment id is invalid."),
Self::InvalidPaymentHash => write!(f, "The given payment hash is invalid."),
Self::InvalidPaymentPreimage => write!(f, "The given payment preimage is invalid."),
Self::InvalidPaymentSecret => write!(f, "The given payment secret is invalid."),
Expand Down
Loading
Loading