> ## 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)
