> ## Documentation Index
> Fetch the complete documentation index at: https://docs.utexo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# wdk-rgb-lightning Reference

> Reference for @utexo/wdk-rgb-lightning — WDK module for RGB Lightning channels, invoices, and payments. Pre-1.0 beta.

`@utexo/wdk-rgb-lightning` is a WDK module for RGB-over-Lightning, built on `rgb-lightning-node` (RLN). It runs an LDK + `rgb-lib` node behind WDK's manager/account contract: channels, BOLT11 and RGB invoices, payments, HODL invoices, optional VSS backup, and an LSP client.

The node runs in **external-signer** mode. The BIP-39 mnemonic stays in the WDK secret manager. Channel-state crypto runs in-process through a VLS signer.

<Warning>
  Pre-1.0 beta (`0.1.0-beta` line). APIs may change between releases.
</Warning>

## Why a Separate Package

This module complements [`@utexo/wdk-wallet-rgb`](/sdk/wdk-wallet-rgb). Each owns its own `rgb-lib` SQLite state and they do **not** share asset records. Give each module a **separate** `dataDir` — `rgb-lib` takes an exclusive lock on a wallet directory.

This module holds and transfers RGB assets for channels and invoices. For issuance, use `@utexo/wdk-wallet-rgb`. Node-level issuance calls are forwarded on the account, but `wdk-wallet-rgb` is the supported path.

## Installation

```bash theme={null}
npm install @utexo/wdk-rgb-lightning

# Native binding for your runtime (optional peer deps):
npm install @utexo/rgb-lightning-node-nodejs   # Node
# or
npm install @utexo/rgb-lightning-node-bare     # Bare / React Native
```

Install only the binding for your runtime. Each `postinstall` downloads a prebuilt native artifact; no Rust toolchain is required.

On Node, `import '@utexo/wdk-rgb-lightning'` wires `@utexo/rgb-lightning-node-nodejs`. In a Bare worklet, `require('@utexo/wdk-rgb-lightning')` wires `@utexo/rgb-lightning-node-bare`. Both re-export the same manager, account, errors, and LSP surface.

## Configuration

`WalletManagerRgbLightning` takes the seed at construction. `network` and `dataDir` are required.

| Option | Type | Description |
| - | - | - |
| `network` | `string` | `'mainnet'`, `'testnet'`, `'signet'`, or `'regtest'` |
| `dataDir` | `string` | Persistent directory for RLN SQLite + LDK state |
| `daemonListeningPort` | `number` | RLN daemon port. Default `0` (ephemeral) |
| `ldkPeerListeningPort` | `number` | LDK peer port. Default `0` (ephemeral) |
| `enableVirtualChannelsV0` | `boolean` | Required for APay against a production LSP. Default `false` |
| `virtualPeerPubkeys` | `string[]` | Peer node IDs allowed to open `trusted_no_broadcast` virtual channels |
| `vssUrl` | `string` | VSS cloud backup URL. Omit to disable |
| `vssAllowHttp` | `boolean` | Allow plain `http://` for non-loopback VSS hosts. Default `false` |
| `lspBaseUrl` | `string` | LSP base URL for APay and `createLsp()` |
| `lspBearerToken` | `string` | Bearer token for LSP `/internal/*` routes |

```typescript theme={null}
import WalletManagerRgbLightning from '@utexo/wdk-rgb-lightning';

const manager = new WalletManagerRgbLightning(mnemonic, {
  network: 'regtest',
  dataDir: '/path/to/wallet-data',
});
```

## Classes

### `WalletManagerRgbLightning`

Default export. Construct with a BIP-39 mnemonic (or `Uint8Array` seed) and config.

#### Methods

| Method | Description |
| - | - |
| `getAccount(0)` | Return the single `WalletAccountRgbLightning`. Index must be `0` |
| `getAccountByPath(path)` | Same account, looked up by derivation path |
| `getFeeRates()` | `{ normal, fast }` fee rates as `bigint` sat/vB |
| `dispose()` | Shut down the node. Synchronous |

```typescript theme={null}
const account = await manager.getAccount(0);

await account.unlock({
  indexer_url: 'tcp://localhost:50001',
  proxy_endpoint: 'rpc://localhost:3000/json-rpc',
  announce_addresses: [],
  announce_alias: 'my-node',
});
```

Unlock takes **exactly one** chain backend: `indexer_url`, or all four `bitcoind_rpc_*` fields (`bitcoind_rpc_username`, `bitcoind_rpc_password`, `bitcoind_rpc_host`, `bitcoind_rpc_port`). Mixing both is rejected. `proxy_endpoint`, `announce_addresses`, and `announce_alias` are always required.

***

### `WalletAccountRgbLightning`

Returned by `getAccount(0)`. RGB Lightning is single-account; RLN owns one LDK node per `dataDir`.

#### Lifecycle

| Method | Description |
| - | - |
| `unlock(request)` | Bring the node online. Returns `{ ok: true }` |
| `getBootstrap()` | Signer/node identity material |
| `shutdown()` | Shut down the native node. Returns `{ ok: true }` |
| `dispose()` | No-op on the account. Call `manager.dispose()` to release the node |

#### Node Info

| Method | Description |
| - | - |
| `getNodeInfo()` | Node pubkey, channel counts, sync status |
| `getNetworkInfo()` | Bitcoin network and chain info |
| `refreshWalletSnapshot(options?)` | Production refresh. `options.mode` is `'routine'` (default) or `'recovery'` |
| `sync()` | Deprecated. Colored FastSync only — do not use for portfolio state |
| `getAddress()` | Current receive address. Throws `AccountLockedError` before unlock |
| `getAddressState()` | `{ status: 'ready', address }` or `{ status: 'locked', address: null }` |
| `rotateAddress()` | Advance the receive address. Returns the new address |

#### Peers

| Method | Description |
| - | - |
| `connectPeer(peerPubkeyAndAddr)` | Connect. String form: `'pubkey@host:port'`. Returns `{ ok: true }` |
| `disconnectPeer({ peer_pubkey })` | Disconnect a peer. Returns `{ ok: true }` |
| `listPeers()` | Connected peers |

#### Channels

| Method | Description |
| - | - |
| `openChannel({ peer_pubkey_and_opt_addr, capacity_sat, push_msat?, public?, with_anchors?, asset_id?, asset_amount?, virtual_open_mode? })` | Open a BTC or RGB channel |
| `closeChannel({ channel_id })` | Close a channel. Returns `{ ok: true }` |
| `listChannels()` | Open channels |
| `getChannelId(temporaryChannelIdHex)` | Resolve a temporary channel ID |

Set `virtual_open_mode: 'trusted_no_broadcast'` for APay virtual channels. Requires `enableVirtualChannelsV0: true` and the peer in `virtualPeerPubkeys`.

#### Invoices & Payments

| Method | Description |
| - | - |
| `createInvoice({ amt_msat?, expiry_sec, asset_id?, asset_amount? })` | Create a BOLT11 invoice (native snake\_case) |
| `createLightningInvoice({ amountMsat?, expirySec, assetId?, assetAmount? })` | Same call, camelCase alias |
| `decodeInvoice(invoice)` | Decode a BOLT11 invoice |
| `getInvoiceStatus(invoice)` | Invoice status |
| `sendPayment({ invoice, amt_msat?, asset_id?, asset_amount?, max_total_routing_fee_msat? })` | Pay a BOLT11 invoice |
| `keysend({ dest_pubkey, amt_msat, asset_id?, asset_amount? })` | Spontaneous keysend |
| `listPayments()` | Payment history |
| `getPayment(paymentHash, type)` | One payment. `type` is `'Outbound'`, `'InboundAutoClaim'`, or `'InboundHodl'` |

#### HODL Invoices

| Method | Description |
| - | - |
| `createHodlInvoice({ paymentHash, expirySec, amtMsat?, assetId?, assetAmount? })` | Returns `{ bolt11, paymentHash }` |
| `cancelHodlInvoice({ payment_hash })` | Cancel. Returns `{ ok: true }` |
| `claimHodlInvoice({ payment_hash, preimage })` | Claim an inbound HODL payment |

#### RGB Assets

RGB receive supports two invoice styles:

* **Blinded invoice** — most common. The receiver creates a blinded endpoint; the sender pays the invoice directly.
* **Witness invoice** — the receiver binds the transfer to witness data. The sender must provide `witnessData` (at minimum `amountSats`) in `transfer()`.

```typescript theme={null}
// Blinded invoice
await receiver.createRgbInvoice({
  min_confirmations: 1,
  witness: false,
  asset_id: assetId,
  assignment_amount: 100,
});

await sender.transfer({
  recipient: blindedInvoice,
  amount: 100,
  token: assetId,
});

// Witness invoice
await receiver.createRgbInvoice({
  min_confirmations: 1,
  witness: true,
  asset_id: assetId,
  assignment_amount: 100,
});

await sender.transfer({
  recipient: witnessInvoice,
  amount: 100,
  token: assetId,
  witnessData: { amountSats: 1000 },
});
```

`transfer()` rejects `witnessData` on a blinded recipient. `decodeRgbInvoice()` reports `recipient_type` as `'Blind'` or `'Witness'`.

| Method | Description |
| - | - |
| `listAssets(filterAssetSchemas?)` | List assets. Optional filter, e.g. `['Nia']` |
| `getAssetBalance(assetId)` | Balance for one asset |
| `getAssetMetadata(assetId)` | Asset metadata |
| `getTokenBalance(assetId)` | Spendable amount as `bigint` |
| `listTransfers(assetId)` | Transfer history for one asset |
| `listTransfersByTxid(txid)` | Transfers for an on-chain txid |
| `refreshTransfers(request)` / `failTransfers({ batch_transfer_idx })` | Advance or fail pending transfers |
| `createRgbInvoice({ min_confirmations, witness, asset_id?, assignment_amount?, duration_seconds? })` | On-chain RGB invoice. `witness: true` = witness receive, `false` = blinded |
| `decodeRgbInvoice(invoice)` | Decode an RGB invoice |
| `sendRgbAsset({ donation, fee_rate, min_confirmations, recipient_groups })` | Send RGB. Recipients come from `decodeRgbInvoice` |
| `importRgbContract({ contract_base64, expected_asset_id })` | Register trusted contract metadata only — no allocation |
| `importRgbTransferConsignment({ consignment_base64, offchain_txid })` | Persist metadata for a transfer the native receive path already accepted |

Issuance (`issueAssetNia`, `issueAssetUda`, `issueAssetCfa`, `issueAssetIfa`, `inflate`) is forwarded to the binding. Prefer [`@utexo/wdk-wallet-rgb`](/sdk/wdk-wallet-rgb) for issuance.

Atomic swaps are on the native binding but are **not** on the WDK account.

#### BTC

| Method | Description |
| - | - |
| `getBalance(skipSync?)` | Spendable vanilla BTC as `bigint` satoshis |
| `getBalanceDetails(skipSync?)` | Full vanilla/colored breakdown |
| `sendTransaction({ to, value, feeRate?, confirmationTarget? })` | WDK-shaped send. Returns `{ hash, fee }` |
| `sendBtc({ address, amount, fee_rate, skip_sync })` | Native RLN send. Returns `{ txid }` |
| `getTransactions(skipSync?)` / `getTransactionsByTxid(txid, skipSync?)` | On-chain history |
| `listUnspents(skipSync?)` | Unspent outputs with RGB allocations |
| `createUtxos({ up_to, num?, size?, fee_rate, skip_sync })` | Create colored UTXOs. Returns `{ ok: true }` |
| `estimateFee(blocks)` | Fee estimate for a confirmation target |

Prepare/commit/cancel variants exist for BTC sends, RGB sends, and UTXO creation (`prepareBtcSend`, `commitPreparedBtcSend`, `prepareRgbSend`, `prepareCreateUtxos`, …).

#### VSS

Requires `vssUrl` at construction. Otherwise these throw `VssNotConfiguredError`.

| Method | Description |
| - | - |
| `vssStatus()` | Local view: `{ configured, url, allowHttp, lastBackupVersion }` |
| `vssBackup()` | Flush now. Returns `{ version }` |
| `clearVssFence(password)` | Take over a stale VSS fence. Two live nodes on one store corrupt state |
| `vssDeleteAll(password)` | Delete all VSS keys. Returns `{ deleted_keys }` |

VSS replicates RLN's LDK and wallet KV state. It does not replicate the VLS signer database under `dataDir`, so same-device restarts work; cross-device recovery with open channels does not.

#### APay / LSP

Production APay needs `enableVirtualChannelsV0: true` and the LSP node ID in `virtualPeerPubkeys`.

| Method | Description |
| - | - |
| `createLsp(peer?)` | Composed `UtexoLsp`. No-arg form discovers the peer from `lspBaseUrl` |
| `getLspConfig()` | `{ baseUrl, bearerToken }` from construction |
| `getLspInfo()` | Validated LSP `GET /get_info` document |
| `bootstrapLsp({ peerPubkeyAndAddr, hostNodeId? })` | Connect, wait until the peer is in `listPeers`, optionally call `apayNew` |
| `apayNewWithAddress(hostNodeId, username, domain)` | Register an attested hash batch |
| `apayNew(hostNodeId)` | Legacy unattested registration |
| `payLightningAddress(addr, amountMsat)` | Pay a Lightning Address |
| `requestLspRgbDeposit(args)` / `payRgbViaLsp(args)` | RGB deposit / pay via the LSP |

```typescript theme={null}
const lsp = await account.createLsp();
await lsp.connect();
const { lnInvoice, rgbInvoice } = await lsp.receiveAsset({
  assetId,
  amountSats: 3_000,
  amountRgb: 100,
});
await lsp.awaitReceiveSettlement(lnInvoice);
```

`UtexoLsp` also exposes `sendAsset()`, `quoteAddress()`, `payAddress()`, `enableLightningAddress()`, and `claimPendingPayments()`. Do not call `apayNew` immediately before `enableLightningAddress` — the native batch can fill the LSP hash-pool cap.

#### WDK-standard

| Method | Description |
| - | - |
| `transfer({ recipient, amount, token?, feeRate?, witnessData? })` | Routes BOLT11, LN pubkey, BTC address, or RGB invoice. `token` is an RGB asset id. Amounts are msats (LN) or sats (on-chain). Witness RGB invoices require `witnessData.amountSats` |
| `quoteTransfer(options)` / `quoteSendTransaction(tx)` | Fee quote |
| `getTransactionReceipt(hash)` | Receipt, or `null` if pending/unknown |
| `sign(message)` / `verify(message, signature)` | Lightning message sign/verify |
| `toReadOnlyAccount()` | Cached query-only account (`Promise`). No signing, channels, VSS recovery, or LSP credentials |

## Error Handling

Typed errors are exported from the package root. Branch on `err.name` / `err.code`. The original RLN message is on `cause`.

```
RgbLightningError            code: RGB_LIGHTNING_ERROR
├── UnlockError              code: UNLOCK_FAILED
├── AccountLockedError       code: ACCOUNT_LOCKED
├── VssError                 code: VSS_ERROR
│   └── VssNotConfiguredError code: VSS_NOT_CONFIGURED
├── ApayError                code: APAY_ERROR
├── WalletSyncError          code: WALLET_SYNC_FAILED
├── WalletSnapshotError      code: WALLET_SNAPSHOT_FAILED
└── NotImplementedError      code: NOT_IMPLEMENTED
```

```typescript theme={null}
import { UnlockError } from '@utexo/wdk-rgb-lightning';

try {
  await account.unlock(request);
} catch (err) {
  if (err instanceof UnlockError) {
    console.error(err.code, err.message, err.cause);
  }
}
```

LSP HTTP failures throw `LspError` / `LspProtocolError`. Channel and liquidity waits throw `LspChannelTimeoutError` and `LspLiquidityTimeoutError`.

## Usage Example

```typescript theme={null}
import WalletManagerRgbLightning from '@utexo/wdk-rgb-lightning';

const manager = new WalletManagerRgbLightning(mnemonic, {
  network: 'regtest',
  dataDir: '/path/to/wallet-data',
});

const account = await manager.getAccount(0);

await account.unlock({
  indexer_url: 'tcp://localhost:50001',
  proxy_endpoint: 'rpc://localhost:3000/json-rpc',
  announce_addresses: [],
  announce_alias: 'my-node',
});

const info = await account.getNodeInfo();
console.log('Node pubkey:', info.pubkey);

await account.connectPeer(`${peerPubkey}@127.0.0.1:9736`);
await account.openChannel({
  peer_pubkey_and_opt_addr: `${peerPubkey}@127.0.0.1:9736`,
  capacity_sat: 500_000,
  push_msat: 0,
  public: false,
  with_anchors: true,
});

const invoice = await account.createInvoice({
  amt_msat: 5_000,
  expiry_sec: 3600,
});
await account.sendPayment({ invoice: bolt11 });

manager.dispose();
```

End-to-end LSP + RGB-over-Lightning examples live in [utexo-rgb-wdk-demo](https://github.com/UTEXO-Protocol/utexo-rgb-wdk-demo).

## Using with `wdk-wallet-rgb`

Both packages use `rgb-lib`, but they do **not** share asset records. Use `@utexo/wdk-wallet-rgb` for issuance and on-chain inventory; use this module for channels, invoices, and Lightning transfers. Give each module its own `dataDir`.

## Further Reading

* [WDK Overview](/sdk/wdk-overview)
* [wdk-wallet-rgb Reference](/sdk/wdk-wallet-rgb)
* [SDK Overview](/product-suite/sdk)
* [Package README](https://github.com/UTEXO-Protocol/wdk-rgb-lightning/blob/dev/README.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.