WDK logoWDK documentation

Use an LSP, Lightning Address, and APay

Use the beta.15 LSP client, composed RGB flows, LNURL-pay helpers, Lightning Address, and asynchronous payments.

The package exposes a standalone HTTP client, account-bound helpers, and a composed UtexoLsp flow object.

Community modules are developed and maintained independently by third-party contributors.

Tether and the WDK Team do not endorse or assume responsibility for their code, security, or maintenance. Use your own judgment and proceed at your own risk.

Configure a secure LSP endpoint

const manager = new WalletManagerRgbLightning(seedPhrase, {
  network: 'mainnet',
  dataDir: '/app-private/wdk/rgb-lightning',
  lspBaseUrl: 'https://lsp.example.com',
  lspBearerToken: await loadLspToken(),
})

Treat the bearer token as a secret. Public HTTP is rejected by default. Enable HTTP only for an explicitly accepted loopback/development environment.

Use the standalone client

import { LspClient } from '@utexo/wdk-rgb-lightning'

const client = new LspClient({
  baseUrl: 'https://lsp.example.com',
})

const [health, info] = await Promise.all([
  client.health(),
  client.getInfo(),
])

The client also exposes LNURL discovery/callback, Lightning Address resolution, RGB on-chain send bridging, and Lightning receive bridging. Validate native response objects.

Use composed RGB flows

With lspBaseUrl configured, the no-argument form discovers the peer:

const lsp = await account.createLsp()

await lsp.connect()

const receive = await lsp.receiveAsset({
  assetId,
  amountRgb: 100,
})

const settlement = await lsp.awaitReceiveSettlement(receive.lnInvoice)

UtexoLsp also exposes waitForChannel(), waitForOutboundLiquidity(), sendAsset(), payAddress(), enableLightningAddress(), and claimPendingPayments().

In beta.15, sendAsset() requires ln.amtMsat and ln.expirySec at runtime even though the public declaration marks ln and those fields optional.

const sent = await lsp.sendAsset({
  rgbInvoice,
  ln: {
    amtMsat: 5_000_000,
    expirySec: 3_600,
  },
})

Bound every wait with a timeout or AbortSignal. Handle LspChannelTimeoutError, LspLiquidityTimeoutError, and LspSettlementError separately.

Pay a Lightning Address

const paid = await lsp.payAddress({
  address: 'alice@example.com',
  amtMsat: 5_000_000,
})

The lower-level payLightningAddress() and LNURL helpers are also exported from the package root.

LNURL callbacks must remain on the discovery host by default. Set allowCrossHostCallback: true only after reviewing the delegated host and redirect threat model.

Inputs such as $alice@example.com are normalized as UMA-style address syntax. This release does not implement UMA signing, compliance, currency negotiation, or exchange-rate semantics.

Enable a Lightning Address

const address = await lsp.enableLightningAddress()
console.log(address.address)

The LSP owns availability and name assignment. Do not present the address as durable until the LSP confirms it and your application stores the returned mapping.

Configure production APay

APay receives payments while the wallet is offline. Construct the manager with:

const manager = new WalletManagerRgbLightning(seedPhrase, {
  network: 'mainnet',
  dataDir: '/app-private/wdk/rgb-lightning',
  lspBaseUrl: 'https://lsp.example.com',
  lspBearerToken,
  enableVirtualChannelsV0: true,
  virtualPeerPubkeys: [lspNodeId],
})

Then bootstrap the authenticated LSP peer:

const result = await account.bootstrapLsp({
  peerPubkeyAndAddr: `${lspNodeId}@${lspHost}:${lspPort}`,
  hostNodeId: lspNodeId,
  waitForPeerMs: 15_000,
  pollIntervalMs: 250,
})

bootstrapLsp() connects the peer, waits for visibility, then calls apayNew() when hostNodeId is supplied.

A failed bootstrap can leave a connected peer even when APay registration did not finish. Inspect listPeers() and APay state before retrying; do not assume rollback.

Production APay requires mutual trust for trusted_no_broadcast virtual channels. Authenticate the LSP node ID independently.

Next steps

On this page