@synonymdev/blocktank-lsp-ln2-client
v1.22.0
Published
Blocktank LN2 client
Downloads
262
Keywords
Readme
blocktank-lsp-ln2-client
Client to interact with the blocktank-lsp-ln2 service.
Usage
Hodl invoice
Hodl invoices are invoices that can be canceled or settled by the merchant. This is useful for example if you want to issue a refund in case the service couldn't be fulfilled.
Create HOLD invoice
import { LspLnClient, IBolt11Invoice } from '@synonymdev/blocktank-lsp-ln2-client';
const amountSat = 1000
const client = new LspLnClient()
const invoice: IBolt11Invoice = await client.createHodlInvoice(amountSat, "This is the description of the invoice")
console.log('New created invoice', invoice)
Listen for HOLDING event
import {LspLnEventListener, IBolt11InvoiceChangedEvent, LspLnClient, Bolt11InvoiceState} from "@synonymdev/blocktank-lsp-ln2-client";
const client = new LspLnClient()
const listener = new LspLnEventListener()
await listener.init()
listener.listenToInvoicesChanged(async message => {
const event: IBolt11InvoiceChangedEvent = message.content
const eventMatchesOurInvoice = event.invoiceId === invoice.id
if (!eventMatchesOurInvoice) {
// This is a general event stream, not just for our invoice.
return
}
// Pull the latest state of the invoice. You need to do this because events are not guaranteed to be in order.
const currentInvoice = await client.getInvoice(invoice.id)
const isHolding = currentInvoice.state === Bolt11InvoiceState.HOLDING && event.state.new === Bolt11InvoiceState.HOLDING // Doublecheck that the event is in the HOLDING state to not double process the event.
if (isHolding) {
// Payment arrived but is not settled yet.
const success = doWhateverYouWant()
if (success) {
// Settle the invoice.
await LnWorkerApi.settleHodlInvoice(invoice.id)
} else {
// Reject the invoice.
await LnWorkerApi.cancelHodlInvoice(invoice.id)
}
} else if (currentInvoice.state === Bolt11InvoiceState.PAID) {
// Invoice is settled.
markAsSettled()
} else if (currentInvoice.state === Bolt11InvoiceState.CANCELED) {
// Invoice is canceled.
markAsCanceled()
}
})
Bolt11 Invoice
This is a regular Lightning invoice.
Create invoice
import { LspLnClient, IBolt11Invoice } from '@synonymdev/blocktank-lsp-ln2-client';
const amountSat = 1000
const client = new LspLnClient()
const invoice: IBolt11Invoice = await client.createInvoice(amountSat, "This is the description of the invoice")
console.log('New created invoice', invoice)
Listen for PAID or CANCELED event
import {LspLnEventListener, IBolt11InvoiceChangedEvent, Bolt11InvoiceState} from "@synonymdev/blocktank-lsp-ln2-client";
const listener = new LspLnEventListener()
await listener.init()
listener.listenToInvoicesChanged(async message => {
const event: IBolt11InvoiceChangedEvent = message.content
const eventMatchesOurInvoice = event.invoiceId === invoice.id
if (!eventMatchesOurInvoice) {
// This is a general event stream, not just for our invoice.
return
}
// Pull the latest state of the invoice. You need to do this because events are not guaranteed to be in order.
if (event.state.new === Bolt11InvoiceState.PAID) {
// Invoice is settled.
markAsSettled()
} else if (currentInvoice.state === Bolt11InvoiceState.CANCELED) {
// Invoice is canceled. This happens when the invoice is expired.
markAsCanceled()
}
})
Info Regular BOLT11 invoices do not emit a HOLDING event state.
Make payment
Pay a bolt11 invoice.
Pay invoice
import { LspLnClient, IBolt11Payment, IBolt11PayCreationError } from '@synonymdev/blocktank-lsp-ln2-client';
const client = new LspLnClient()
const invoice = 'lntb1u1pwz5w78pp5e8w8cr5c30xzws9...'
try {
const payment: IBolt11Payment = await client.makePayment(invoice)
} catch (e) {
// The worker or the LND node rejected the pay request without even trying to pay.
const error: IBolt11PayCreationError = e;
console.log(`${error.type} will tell you what went wrong in a simple way. ${error.message} will give you a human error message.`)
console.log(`${error.datail?.raw} will give you the raw error. Don't rely on this though as this is can change in the future.`)
}
Listen for channel FAILED or PAID events
import {LspLnEventListener, LspLnClient, IBolt11PayChangedEvent, Bolt11PaymentState} from "@synonymdev/blocktank-lsp-ln2-client";
const listener = new LspLnEventListener()
await listener.init()
listener.listenToPaymentChanged(async message => {
const event: IBolt11PayChangedEvent = message.content
const eventMatches = event.paymentId === payment.id
if (!eventMatches) {
// This is a general event stream, not just for our payment.
return
}
setPaymentState(event.state.new);
})
Channel Open
Open a channel to a node and observe the state.
Create channel open
import { LspLnClient, IOpenChannelOrder, IOpenChannelError } from '@synonymdev/blocktank-lsp-ln2-client';
const connectionString = '[email protected]:9735'
const isPrivate = false
const localBalanceSat = 100000
try {
const open: IOpenChannelOrder = await client.orderChannel(connectionString, isPrivate, localBalanceSat)
} catch (e) {
// This is a sync channel open. If we could not connect to the peer or the open channel process failed, we will get an error here.
// error is of type IOpenChannelError.
const error: IOpenChannelError = e;
console.log(`${error.type} will tell you what went wrong in a simple way. ${error.message} will give you a human error message.`)
console.log(`${error.datail?.raw} will give you the raw error. Don't rely on this though as this is can change in the future.`)
}
Listen for channel OPEN or CLOSED events
import {LspLnEventListener, IChannelOpenEvent, LspLnClient, OpenChannelOrderState} from "@synonymdev/blocktank-lsp-ln2-client";
const client = new LspLnClient()
const listener = new LspLnEventListener()
await listener.init()
listener.listenToOpenChannelChanged(async message => {
const event: IChannelOpenEvent = message.content
const eventMatchesOurChannel = event.orderId === open.id
if (!eventMatchesOurChannel) {
// This is a general event stream, not just for our channel.
return
}
// Pull the latest state of the channel open. You need to do this because events are not guaranteed to be in order.
const currentChannel = await client.getOrderedChannel(open.id)
setChannelState(currentChannel.state);
})
Important Events can arrive in a different order than they were sent. If there is an error throw, the event will be retried. Make sure you don't process the same event twice or in the wrong order!
Info Always close your event listener with
await listener.close()
when you are done listening to events.
Versioning
- Increase version in
package.json
. - Add changes to
CHANGELOG.md
. - Commit changes.
- Tag new version:
git tag v0.1.0
. - Push tag
git push origin v0.1.0
. - Build:
npm run build
. - Publish to npm:
npm publish
.