npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@synonymdev/blocktank-lsp-ln2-client

v1.22.0

Published

Blocktank LN2 client

Downloads

262

Readme

blocktank-lsp-ln2-client

NPM version

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

  1. Increase version in package.json.
  2. Add changes to CHANGELOG.md.
  3. Commit changes.
  4. Tag new version: git tag v0.1.0.
  5. Push tag git push origin v0.1.0.
  6. Build: npm run build.
  7. Publish to npm: npm publish.