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

# React Native SDK Reference

> Reference for @utexo/rgb-sdk-rn — on-device Lightning node, RGB assets, and Lightning payments for iOS and Android.

The `@utexo/rgb-sdk-rn` package is the React Native SDK for iOS and Android. It embeds a full **RGB Lightning Node (RLN)** on-device — a native LDK node that runs locally.

<Warning>
  React Native (iOS and Android) only. New Architecture (TurboModule `Rgb`) is required. For Node.js use [`@utexo/wdk-rgb-lightning`](/sdk/wdk-rgb-lightning); for browsers use [`@utexo/rgb-sdk-web`](/sdk/web-sdk).

  Beta release — APIs may change between releases.
</Warning>

## What You Can Do

* Run a full Lightning node on-device via RLN
* Open Lightning channels and send/receive BTC or RGB asset payments
* LSP integration: receive RGB via Lightning, send RGB to on-chain recipients, Lightning Address
* Async payments (APay) and virtual channels
* Issue, transfer, and manage RGB assets (NIA, CFA, IFA, UDA)
* Manage UTXOs and on-chain BTC sends
* Use a hardware-wallet-style **external signer** or a **password signer**
* Restart the node on the same `UTEXOWallet` instance without recreating it
* VSS encrypted remote backup of LDK state

## Installation

```bash theme={null}
npm install @utexo/rgb-sdk-rn
```

### iOS Setup

The native framework (`RGBLightningNode.xcframework`) is downloaded during `postinstall`.

```bash theme={null}
cd ios && pod install
```

### Android Setup

Requires `minSdkVersion` 24. The native binding (`com.utexo:rgb-lightning-node-android`) resolves from Maven Central — no extra repository configuration.

At unlock time the node needs an Electrum indexer and/or bitcoind RPC, plus an RGB proxy. Known networks supply defaults.

## Primary Class: `UTEXOWallet`

`UTEXOWallet` implements `IUTEXOProtocol`, owns the on-device RLN lifecycle, and abstracts both signer types. The mnemonic and password live on the signer, not on the config object.

### Construction

```typescript theme={null}
import {
  UTEXOWallet,
  NativeExternalRLNSigner,
  PasswordRLNSigner,
  generateKeys,
  type UTEXOWalletNodeParams,
} from '@utexo/rgb-sdk-rn';

const keys = await generateKeys('regtest');

const wallet = new UTEXOWallet(
  {
    storageDirPath: '/path/to/node-storage',
    daemonListeningPort: 9735,
    ldkPeerListeningPort: 9736,
    network: 'regtest',
  },
  new NativeExternalRLNSigner(keys.mnemonic, 'regtest'),
);
```

xpubs and master fingerprint are **not** constructor fields. The signer supplies key material at `init()`.

#### `UTEXOWalletNodeParams`

| Field | Type | Description |
| - | - | - |
| `storageDirPath` | `string` | Directory where the node persists its data |
| `daemonListeningPort` | `number` | RLN daemon HTTP port |
| `ldkPeerListeningPort` | `number` | LDK peer-to-peer port |
| `network` | `string` | Bitcoin network (`'utexo'`, `'regtest'`, `'testnet'`, `'mainnet'`, …) |
| `maxMediaUploadSizeMb` | `number?` | Max media upload size in MB (default 20) |
| `enableVirtualChannelsV0` | `boolean?` | Enable virtual channels |
| `virtualPeerPubkeys` | `string[]? \| null` | Host pubkeys allowed to open inbound virtual channels. `null`/`[]` = accept from anyone |
| `vssUrl` | `string? \| null` | VSS server URL for encrypted remote backup |
| `vssAllowHttp` | `boolean?` | Allow plain HTTP VSS (default `false`) |
| `vssAllowEmptyRestore` | `boolean?` | Allow restore when no VSS backup exists yet (default `false`) |
| `lspBaseUrl` | `string? \| null` | LSP base URL for `createLsp()` and APay. Optional on `utexo` (defaults to `https://lsp-signet.utexo.com`) |
| `lspBearerToken` | `string? \| null` | LSP bearer token — required for APay |
| `reuseAddresses` | `boolean?` | Reuse on-chain addresses instead of deriving a new one per call (default `false`) |

## Signers

Pass a signer to the `UTEXOWallet` constructor. On the first `init()` the wallet calls `initNode`; on every later `unlock()` or `reinit()` it calls `unlockNode`.

### `NativeExternalRLNSigner` (recommended)

Native hardware-style external signer. Keys stay in the device key store. Accepts a mnemonic **or** raw BIP39 seed bytes.

```typescript theme={null}
import { NativeExternalRLNSigner } from '@utexo/rgb-sdk-rn';

const signer = new NativeExternalRLNSigner(keys.mnemonic, 'regtest');
const signer = new NativeExternalRLNSigner(seedBytes, 'regtest');
const signer = new NativeExternalRLNSigner(keys.mnemonic, 'regtest', true); // relaxed policy
```

### `PasswordRLNSigner`

Password-based auth. The mnemonic is only needed for the first `init()` (written to disk), then cleared from memory.

```typescript theme={null}
import { PasswordRLNSigner } from '@utexo/rgb-sdk-rn';

const signer = new PasswordRLNSigner('my-secure-password', keys.mnemonic);
const signer = new PasswordRLNSigner('my-secure-password'); // later unlocks
```

## Lifecycle

| Phase | Method | When to call |
| - | - | - |
| First-time setup | `init()` | Once per new wallet — writes key material to `storageDirPath` |
| Connect & unlock | `unlock(params)` | Every start — connects indexer/bitcoind and proxy |
| Graceful stop | `shutdown()` | Pause the node — state stays on disk |
| Full teardown | `destroy()` | Logout or `finally` — shutdown + destroyNode + release signer |

`initialize()` is an alias for `init()`. `reinit(params)` is `shutdown()` + `init()` + `unlock()` on the same instance. `dispose()` aliases `destroy()`.

```typescript theme={null}
const unlockParams = {
  indexerUrl: '127.0.0.1:50001',
  proxyEndpoint: 'rpc://127.0.0.1:3000/json-rpc',
};

await wallet.init();
await wallet.unlock(unlockParams);

await wallet.shutdown();
await wallet.reinit(unlockParams);

await wallet.destroy();
```

All unlock fields are optional. Omit any field to use the network default. Electrum mode does not need the bitcoind RPC fields.

#### `IRLNUnlockParams`

| Field | Type | Description |
| - | - | - |
| `bitcoindRpcUsername` | `string?` | Bitcoin RPC username |
| `bitcoindRpcPassword` | `string?` | Bitcoin RPC password |
| `bitcoindRpcHost` | `string?` | Bitcoin RPC host |
| `bitcoindRpcPort` | `number?` | Bitcoin RPC port |
| `indexerUrl` | `string?` | Electrum indexer URL (e.g. `'127.0.0.1:50001'`) |
| `proxyEndpoint` | `string?` | RGB proxy endpoint (e.g. `'rpc://host:3000/json-rpc'`) |
| `announceAddresses` | `string[]?` | Public addresses to announce |
| `announceAlias` | `string \| null?` | Node alias |
| `gossipRgsServerUrl` | `string \| null?` | RGS server URL for rapid gossip sync |

<Note>
  **Utexo Network Faucet** — Test BTC and RGB assets on the Utexo network: Telegram bot [@Utexo\_RLN\_bot](https://t.me/Utexo_RLN_bot).

  | Command | Description |
  | - | - |
  | `/getbtc` | Send your Bitcoin address to receive test satoshis |
  | `/getasset` | Send an RGB invoice to receive test RGB assets |
  | `/getinvoice` | Get an RGB Lightning invoice to test paying |
  | `/getnodeinfo` | Get the faucet node URI, asset ID, and ticker |

  Limited to 2 requests per 24 hours per user.
</Note>

## Method Reference

### Balance & Address

| Method | Description |
| - | - |
| `getBtcBalance()` | BTC balance split by `vanilla` and `colored` paths, each with `settled`, `future`, `spendable` |
| `getAddress()` | Current on-chain deposit address |
| `rotateVanillaAddress()` | Derive a fresh vanilla (BTC) address |
| `getNetwork()` | Configured network string |

`getXpub()` is not on this SDK. Use `getNodeInfo()` for node identity.

### UTXO Management

| Method | Description |
| - | - |
| `createUtxos({ upTo?, num?, size?, feeRate? })` | Create colored UTXOs for RGB operations |
| `listUnspents()` | Unspent UTXOs with RGB allocations |

<Note>
  Call `syncWallet()` after funding and again after `createUtxos()` before RGB operations.
</Note>

### RGB Assets

RGB receive supports two invoice styles:

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

`onchainReceive()` is the IUTEXOProtocol entry point (witness by default; `witness: false` for blinded). `blindReceive()` and `witnessReceive()` remain as the underlying primitives. There is no `send()` — use `onchainSend()`.

```typescript theme={null}
const blinded = await wallet.onchainReceive({
  witness: false,
  minConfirmations: 1,
  assetId,
  amount: 100,
});

await senderWallet.onchainSend({
  invoice: blinded.invoice,
  assetId,
  amount: 100,
  feeRate: 2,
  minConfirmations: 1,
});

const witness = await wallet.onchainReceive({
  witness: true,
  minConfirmations: 1,
  assetId,
  amount: 100,
});

await senderWallet.onchainSend({
  invoice: witness.invoice,
  assetId,
  amount: 100,
  feeRate: 2,
  minConfirmations: 1,
  witnessData: { amountSat: 1000 },
});
```

| Method | Description |
| - | - |
| `listAssets()` | All RGB assets (NIA, CFA, IFA, UDA) |
| `getAssetBalance(assetId)` | Balance for one asset |
| `issueAssetNia({ ticker, name, precision, amounts })` | Issue a Non-Inflationary Asset |
| `issueAssetIfa({ ticker, name, precision, amounts, inflationAmounts, rejectListUrl })` | Issue an Inflatable Asset |
| `onchainReceive({ assetId?, amount?, durationSeconds?, minConfirmations?, witness? })` | RGB invoice — witness by default. Pass `witness: false` for blinded |
| `onchainSend({ invoice, assetId, amount, donation?, feeRate?, minConfirmations?, skipSync?, witnessData? })` | RGB send. `assetId` and `amount` are required |
| `blindReceive({ assetId?, amount?, durationSeconds?, minConfirmations? })` | Blinded RGB invoice |
| `witnessReceive({ assetId?, amount?, durationSeconds?, minConfirmations? })` | Witness RGB invoice |
| `decodeRGBInvoice({ invoice })` | Decode an RGB invoice |
| `listOnchainTransfers(assetId?)` | Alias of `listTransfers()` |

### BTC Sends

| Method | Description |
| - | - |
| `sendBtc({ address, amount, feeRate, skipSync? })` | On-chain BTC send |

### Transactions & Transfers

| Method | Description |
| - | - |
| `listTransactions()` | On-chain transaction history |
| `listTransfers(assetId?)` | RGB transfer history. Statuses: `WaitingCounterparty`, `WaitingConfirmations`, `Settled`, `Failed` |
| `failTransfers(params)` | Mark pending transfers as failed |
| `refreshWallet()` | Refresh RGB transfer state |
| `syncWallet()` | Sync blockchain and UTXO state |

### Fees & Backup

| Method | Description |
| - | - |
| `estimateFeeRate(blocks)` | Fee rate estimate for a confirmation target |
| `createBackup({ backupPath, password })` | Encrypted local file backup |
| `backupNow()` | Upload a VSS snapshot now; returns the new version. Requires `vssUrl` |

### Lightning

| Method | Description |
| - | - |
| `createLightningInvoice({ amountSats?, expirySeconds?, asset? })` | Create a Lightning invoice. BTC via `amountSats`; RGB via `asset: { assetId, amount }` |
| `payLightningInvoice({ lnInvoice, amount?, assetId? })` | Pay a Lightning invoice |
| `getLightningSendStatus(paymentHash)` | Outbound status: `'Pending'`, `'Claimable'`, `'Claiming'`, `'Succeeded'`, `'Cancelled'`, `'Failed'`. `null` if unknown |
| `getLightningReceiveStatus(invoice)` | Inbound invoice status |
| `listLightningPayments()` | Lightning payments |

Do not poll Lightning with RGB transfer statuses (`WaitingCounterparty` / `Settled`).

### LSP & Async payments (APay)

`createLsp()` **must run before** `init()` / `reinit()`. The no-arg form discovers the peer from `lspBaseUrl` (or the network default) via `GET /get_info` and wires virtual channels (`enableVirtualChannelsV0: true` + LSP pubkey in `virtualPeerPubkeys`).

| Method | Description |
| - | - |
| `createLsp(peer?)` | Create an `UtexoLsp` session. Pass `LspPeer` to override discovery |
| `getLspConfig()` | `{ baseUrl, bearerToken }` this node was created with |
| `apayNewWithAddress(hostNodeId, username, domain)` | Register an attested hash pool |
| `apayNew(hostNodeId)` | Register a hash pool without address attestation |
| `createHodlInvoice(params)` | HODL invoice tied to a payment hash |
| `claimHodlInvoice(paymentHash, preimage)` | Claim an inbound HODL payment |
| `cancelHodlInvoice(paymentHash)` | Cancel a HODL invoice |

See [docs/lsp.md](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/docs/lsp.md) and [docs/async-payments.md](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/docs/async-payments.md).

### Node Info, Peers & Channels

| Method | Description |
| - | - |
| `getNodeInfo()` | Node pubkey, channel counts, sync status |
| `getNetworkInfo()` | Network-level info |
| `connectPeer(peerPubkeyAndAddr)` | Connect. Format: `'pubkey@host:port'` |
| `disconnectPeer(peerPubkey)` | Disconnect a peer |
| `listPeers()` | Connected peers |
| `openChannel({ peerPubkeyAndOptAddr, capacitySat, pushMsat, public, withAnchors, assetId?, assetAmount? })` | Open a BTC or RGB channel |
| `closeChannel(channelId, peerPubkey, force)` | Close a channel |
| `listChannels()` | Open channels |
| `getChannelId(temporaryChannelId)` | Resolve temporary → permanent channel ID |
| `keysend(destPubkey, amtMsat, assetId?, assetAmount?)` | Spontaneous keysend |
| `decodeLnInvoice(invoice)` / `invoiceStatus(invoice)` | Decode / poll a Lightning invoice |
| `checkIndexerUrl(url)` | Validate an Electrum indexer URL |
| `checkProxyEndpoint(endpoint)` | Validate an RGB proxy endpoint |

## Core Workflows

### First-Time Wallet Init

```typescript theme={null}
import {
  UTEXOWallet,
  NativeExternalRLNSigner,
  generateKeys,
} from '@utexo/rgb-sdk-rn';
import * as FileSystem from 'expo-file-system/legacy';

const network = 'utexo';
const keys = await generateKeys(network);

const storageDir = `${FileSystem.documentDirectory}my-node`.replace('file://', '');
await FileSystem.makeDirectoryAsync(storageDir, { intermediates: true });

const wallet = new UTEXOWallet(
  {
    storageDirPath: storageDir,
    daemonListeningPort: 9735,
    ldkPeerListeningPort: 9736,
    network,
  },
  new NativeExternalRLNSigner(keys.mnemonic, network),
);

const unlockParams = {
  // indexerUrl / proxyEndpoint / bitcoind* are optional — network defaults apply
};

await wallet.init();
await wallet.unlock(unlockParams);
```

### App Restart (Existing Node)

```typescript theme={null}
await wallet.reinit(unlockParams);
```

### Issue an RGB Asset

```typescript theme={null}
await wallet.syncWallet();
await wallet.createUtxos({ upTo: false, num: 10, feeRate: 1.5 });

const asset = await wallet.issueAssetNia({
  ticker: 'DEMO',
  name: 'Demo Token',
  precision: 2,
  amounts: [1000],
});
console.log('Asset ID:', asset.assetId);
```

### Open a Lightning Channel

```typescript theme={null}
await wallet.connectPeer(`${peerPubkey}@127.0.0.1:9736`);

const { temporaryChannelId } = await wallet.openChannel({
  peerPubkeyAndOptAddr: `${peerPubkey}@127.0.0.1:9736`,
  capacitySat: 500_000,
  pushMsat: 0,
  public: false,
  withAnchors: true,
  assetId: null,
  assetAmount: null,
});

let usable = false;
while (!usable) {
  await wallet.syncWallet();
  const info = await wallet.getNodeInfo();
  usable = (info.numUsableChannels ?? 0) >= 1;
  if (!usable) await new Promise((r) => setTimeout(r, 2000));
}
```

### Lightning Payment

```typescript theme={null}
const { lnInvoice } = await receiverWallet.createLightningInvoice({
  amountSats: 3000,
  expirySeconds: 900,
  asset: { assetId: '', amount: 0 },
});

const { txid: paymentHash } = await senderWallet.payLightningInvoice({ lnInvoice });

let status = null;
while (status !== 'Succeeded') {
  await senderWallet.syncWallet();
  status = await senderWallet.getLightningSendStatus(paymentHash);
  if (status === 'Failed') throw new Error('Payment failed');
  if (status !== 'Succeeded') await new Promise((r) => setTimeout(r, 2000));
}
```

BTC-only invoices can omit `asset` or pass an empty `assetId`. For RGB, pass `asset: { assetId, amount }`.

### Full Cleanup

```typescript theme={null}
try {
  // ... wallet operations ...
} finally {
  await wallet.destroy();
}
```

## VSS — Encrypted Remote Backup

Set `vssUrl` on the constructor. VSS syncs LDK state while the node runs.

Restore on a new device: same VSS URL and credentials, empty `storageDirPath`, then `vssClearFence()` **after `init()` and before `unlock()`**.

```typescript theme={null}
await walletRestored.init();
await walletRestored.vssClearFence('my-password');
await walletRestored.unlock(unlockParams);
```

`backupNow()` forces an upload and returns the new version. The web-only `configureVssBackup` / `vssBackup` / `vssBackupInfo` methods are not on this SDK.

## LSP Integration

```typescript theme={null}
const wallet = new UTEXOWallet(
  {
    ...nodeParams,
    network: 'utexo',
    lspBearerToken: 'bearer-token',
  },
  signer,
);

const lsp = await wallet.createLsp(); // before init()
await wallet.init();
await wallet.unlock(unlockParams);

await lsp.connect();
const { lnInvoice, rgbInvoice } = await lsp.receiveAsset({
  assetId: ASSET_ID,
  amountSats: 3_000,
  amountRgb: 1,
});
await lsp.awaitReceiveSettlement(lnInvoice);
```

## Standalone Helpers

| Function | Description |
| - | - |
| `generateKeys(network?)` | Generate mnemonic, xpubs, master fingerprint |
| `createWallet(network?)` | Alias for `generateKeys` |
| `deriveKeysFromMnemonic(network, mnemonic)` | Derive keys from an existing BIP39 mnemonic |
| `deriveKeysFromSeed(network, seed)` | Derive keys from BIP39 seed bytes |
| `signMessage` / `verifyMessage` | Schnorr message signing (no wallet required) |

## RLN Manager (Advanced)

`RLNManager` and `createRLNManager` expose the raw RLN node API without the `UTEXOWallet` wrapper.

```typescript theme={null}
import { createRLNManager } from '@utexo/rgb-sdk-rn';

const rln = createRLNManager();
await rln.rlnCreateNode({ storageDirPath, daemonListeningPort, ldkPeerListeningPort, network });
await rln.rlnInitNode(password, mnemonic);
await rln.rlnUnlockNode({ password, ...connectionParams });
await rln.rlnShutdown();
await rln.rlnDestroyNode();
```

## Demo App

Full demo: [rgb-sdk-rn-demo](https://github.com/UTEXO-Protocol/rgb-sdk-rn-demo). Covers `UTEXOWallet` lifecycle, both signers, `reinit()`, VSS, and APay.

```bash theme={null}
git clone https://github.com/UTEXO-Protocol/rgb-sdk-rn-demo
cd rgb-sdk-rn-demo
npm install && npm run prebuild
cd ios && LANG=en_US.UTF-8 pod install && cd ..
npm run ios:release   # or npm run android:release
```

## Further Reading

* [SDK Overview](/product-suite/sdk)
* [Web SDK](/sdk/web-sdk)
* [wdk-rgb-lightning](/sdk/wdk-rgb-lightning)
* [Architecture](/getting-started/architecture)
* [rgb-sdk-rn README](https://github.com/UTEXO-Protocol/rgb-sdk-rn/blob/dev/Readme.md)


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