Skip to content

lnd #5

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

Merged
merged 5 commits into from
Mar 24, 2025
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
51 changes: 50 additions & 1 deletion bindings/lni_nodejs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export interface Bolt11Resp {
paymentHash: string
serialized: string
}
export interface PhoenixPayInvoiceResp {
amountSat: number
routingFeeSat: number
paymentId: string
paymentHash: string
preimage: string
}
export interface ClnConfig {
url: string
rune: string
Expand All @@ -24,6 +31,14 @@ export interface ClnNode {
url: string
rune: string
}
export interface LndConfig {
url: string
macaroon: string
}
export interface LndNode {
url: string
macaroon: string
}
export const enum InvoiceType {
Bolt11 = 'Bolt11',
Bolt12 = 'Bolt12'
Expand Down Expand Up @@ -142,7 +157,7 @@ export interface LightningBalanceResponse {
export interface PayInvoiceResponse {
paymentHash: string
preimage: string
fee: number
feeMsats: number
}
export interface PayKeysendResponse {
fee: number
Expand All @@ -167,6 +182,11 @@ export interface CreateInvoiceParams {
description?: string
descriptionHash?: string
expiry?: number
rPreimage?: string
isBlinded?: boolean
isKeysend?: boolean
isAmp?: boolean
isPrivate?: boolean
}
export interface PayCode {
offerId: string
Expand All @@ -176,6 +196,18 @@ export interface PayCode {
singleUse?: boolean
used?: boolean
}
export interface PayInvoiceParams {
invoice: string
feeLimitMsat?: number
feeLimitPercentage?: number
timeoutSeconds?: number
amountMsats?: number
maxParts?: number
firstHopPubkey?: string
lastHopPubkey?: string
allowSelfPayment?: boolean
isAmp?: boolean
}
export interface Payment {
paymentId: string
circId: string
Expand All @@ -191,6 +223,7 @@ export declare class PhoenixdNode {
getConfig(): PhoenixdConfig
getInfo(): Promise<NodeInfo>
createInvoice(params: CreateInvoiceParams): Promise<Transaction>
payInvoice(params: PayInvoiceParams): Promise<PayInvoiceResponse>
getOffer(): Promise<PayCode>
lookupInvoice(paymentHash: string): Promise<Transaction>
payOffer(offer: string, amountMsats: number, payerNote?: string | undefined | null): Promise<PayInvoiceResponse>
Expand All @@ -203,6 +236,22 @@ export declare class ClnNode {
getConfig(): ClnConfig
getInfo(): Promise<NodeInfo>
createInvoice(params: CreateInvoiceParams): Promise<Transaction>
payInvoice(params: PayInvoiceParams): Promise<PayInvoiceResponse>
getOffer(search?: string | undefined | null): Promise<PayCode>
listOffers(search?: string | undefined | null): Promise<Array<PayCode>>
payOffer(offer: string, amountMsats: number, payerNote?: string | undefined | null): Promise<PayInvoiceResponse>
lookupInvoice(paymentHash: string): Promise<Transaction>
listTransactions(params: ListTransactionsParams): Promise<Array<Transaction>>
decode(str: string): Promise<string>
}
export declare class LndNode {
constructor(config: LndConfig)
getUrl(): string
getMacaroon(): string
getConfig(): LndConfig
getInfo(): Promise<NodeInfo>
createInvoice(params: CreateInvoiceParams): Promise<Transaction>
payInvoice(params: PayInvoiceParams): Promise<PayInvoiceResponse>
getOffer(search?: string | undefined | null): Promise<PayCode>
listOffers(search?: string | undefined | null): Promise<Array<PayCode>>
payOffer(offer: string, amountMsats: number, payerNote?: string | undefined | null): Promise<PayInvoiceResponse>
Expand Down
3 changes: 2 additions & 1 deletion bindings/lni_nodejs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,9 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

const { InvoiceType, PhoenixdNode, ClnNode } = nativeBinding
const { InvoiceType, PhoenixdNode, ClnNode, LndNode } = nativeBinding

module.exports.InvoiceType = InvoiceType
module.exports.PhoenixdNode = PhoenixdNode
module.exports.ClnNode = ClnNode
module.exports.LndNode = LndNode
61 changes: 55 additions & 6 deletions bindings/lni_nodejs/main.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PhoenixdNode, ClnNode, InvoiceType } from "./index.js";
import { PhoenixdNode, ClnNode, LndNode, InvoiceType } from "./index.js";
import dotenv from "dotenv";
dotenv.config();

Expand Down Expand Up @@ -42,6 +42,11 @@ async function phoenixd() {

const offer = await node.getOffer();
console.log("Get Offer:", offer);

// const pay_invoice_resp = await node.payInvoice({
// invoice: ""
// })
// console.log("pay_invoice_resp:", pay_invoice_resp);
}

async function cln() {
Expand All @@ -53,9 +58,6 @@ async function cln() {
const info = await node.getInfo();
console.log("Node info:", info);

// const configRes = await node.getConfig();
// console.log("Config:", configRes.url);

const invoice = await node.createInvoice({
amountMsats: 1000,
description: "test invoice",
Expand Down Expand Up @@ -93,9 +95,56 @@ async function cln() {
console.log("Transactions:", txns);
}

async function lnd() {
const config = {
url: process.env.LND_URL,
macaroon: process.env.LND_MACAROON,
};
const node = new LndNode(config);
const info = await node.getInfo();
console.log("Node info:", info);

const invoice = await node.createInvoice({
amountMsats: 1000,
description: "test invoice",
invoiceType: InvoiceType.Bolt11,
});
console.log("LND Invoice:", invoice);

const bolt11Invoice = await node.createInvoice({
amountMsats: 3000,
description: "test invoice",
invoiceType: InvoiceType.Bolt11,
});
console.log("LND bolt11 Invoice:", bolt11Invoice);


const lookupInvoice = await node.lookupInvoice(
process.env.LND_TEST_PAYMENT_HASH
);
console.log("lookupInvoice:", lookupInvoice);

const txns = await node.listTransactions({
from: 0,
limit: 10,
});
console.log("LND Transactions:", txns);
}

async function test() {
const config = {
url: process.env.PHOENIXD_URL,
password: process.env.PHOENIXD_PASSWORD,
test_hash: process.env.PHOENIXD_TEST_PAYMENT_HASH,
};
const node = new PhoenixdNode(config);
}

async function main() {
phoenixd();
cln();
// phoenixd();
// cln();
// lnd();
test();
}

main();
21 changes: 14 additions & 7 deletions bindings/lni_nodejs/src/cln.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use lni::{cln::lib::ClnConfig, CreateInvoiceParams};
use lni::{cln::lib::ClnConfig, CreateInvoiceParams, PayInvoiceParams};
use napi::bindgen_prelude::*;
use napi_derive::napi;
#[napi]
Expand Down Expand Up @@ -58,6 +58,18 @@ impl ClnNode {
Ok(txn)
}

#[napi]
pub async fn pay_invoice(
&self,
params: PayInvoiceParams,
) -> Result<lni::types::PayInvoiceResponse> {
let invoice =
lni::cln::api::pay_invoice(self.inner.url.clone(), self.inner.rune.clone(), params)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(invoice)
}

#[napi]
pub async fn get_offer(&self, search: Option<String>) -> Result<lni::types::PayCode> {
let offer = lni::cln::api::get_offer(self.inner.url.clone(), self.inner.rune.clone(), search)
Expand Down Expand Up @@ -104,12 +116,7 @@ impl ClnNode {
None,
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(
txn
.into_iter()
.next()
.ok_or_else(|| napi::Error::from_reason("No transaction found"))?,
)
Ok(txn)
}

#[napi]
Expand Down
4 changes: 4 additions & 0 deletions bindings/lni_nodejs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ extern crate napi_derive;

pub use lni::ApiError;
pub use lni::types::*;
pub use lni::utils::*;
pub use lni::types::{Transaction, InvoiceType, ListTransactionsParams, PayInvoiceResponse};

mod phoenixd;
pub use phoenixd::PhoenixdNode;

mod cln;
pub use cln::ClnNode;

mod lnd;
pub use lnd::LndNode;
135 changes: 135 additions & 0 deletions bindings/lni_nodejs/src/lnd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use lni::{lnd::lib::LndConfig, CreateInvoiceParams, PayInvoiceParams};
use napi::bindgen_prelude::*;
use napi_derive::napi;
#[napi]
pub struct LndNode {
inner: LndConfig,
}

#[napi]
impl LndNode {
#[napi(constructor)]
pub fn new(config: LndConfig) -> Self {
Self { inner: config }
}

#[napi]
pub fn get_url(&self) -> String {
self.inner.url.clone()
}

#[napi]
pub fn get_macaroon(&self) -> String {
self.inner.macaroon.clone()
}

#[napi]
pub fn get_config(&self) -> LndConfig {
LndConfig {
url: self.inner.url.clone(),
macaroon: self.inner.macaroon.clone(),
}
}

#[napi]
pub async fn get_info(&self) -> napi::Result<lni::NodeInfo> {
let info = lni::lnd::api::get_info(self.inner.url.clone(), self.inner.macaroon.clone())
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(info)
}

#[napi]
pub async fn create_invoice(
&self,
params: CreateInvoiceParams,
) -> napi::Result<lni::Transaction> {
let txn =
lni::lnd::api::create_invoice(self.inner.url.clone(), self.inner.macaroon.clone(), params)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txn)
}

#[napi]
pub async fn pay_invoice(
&self,
params: PayInvoiceParams,
) -> Result<lni::types::PayInvoiceResponse> {
let invoice =
lni::lnd::api::pay_invoice(self.inner.url.clone(), self.inner.macaroon.clone(), params)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(invoice)
}

#[napi]
pub async fn get_offer(&self, search: Option<String>) -> Result<lni::types::PayCode> {
let offer =
lni::lnd::api::get_offer(self.inner.url.clone(), self.inner.macaroon.clone(), search)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(offer)
}

#[napi]
pub async fn list_offers(&self, search: Option<String>) -> Result<Vec<lni::types::PayCode>> {
let offers =
lni::lnd::api::list_offers(self.inner.url.clone(), self.inner.macaroon.clone(), search)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(offers)
}

#[napi]
pub async fn pay_offer(
&self,
offer: String,
amount_msats: i64,
payer_note: Option<String>,
) -> napi::Result<lni::PayInvoiceResponse> {
let offer = lni::lnd::api::pay_offer(
self.inner.url.clone(),
self.inner.macaroon.clone(),
offer,
amount_msats,
payer_note,
)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(offer)
}

#[napi]
pub async fn lookup_invoice(&self, payment_hash: String) -> napi::Result<lni::Transaction> {
let txn = lni::lnd::api::lookup_invoice(
self.inner.url.clone(),
self.inner.macaroon.clone(),
Some(payment_hash),
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txn)
}

#[napi]
pub async fn list_transactions(
&self,
params: lni::types::ListTransactionsParams,
) -> napi::Result<Vec<lni::Transaction>> {
let txns = lni::lnd::api::list_transactions(
self.inner.url.clone(),
self.inner.macaroon.clone(),
params.from,
params.limit,
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txns)
}

#[napi]
pub async fn decode(&self, str: String) -> Result<String> {
let decoded = lni::lnd::api::decode(self.inner.url.clone(), self.inner.macaroon.clone(), str)
.await
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(decoded)
}
}
Loading