Skip to content

Repository files navigation

Wavelength SDK

A TypeScript SDK for embedding a self-custodial Lightning wallet directly in your app, on the web and on mobile. Your users send and receive Lightning payments with no node to run, no channels to open, and no inbound liquidity to manage, while the keys stay on their own device. The wallet runs entirely in-process: as WebAssembly in the browser, or as a native module compiled into a React Native app. There is no backend to operate and nothing listening on a socket; your app drives the wallet through a small, typed client.

Full documentation lives at wavelength.lightning.engineering.

How it fits together

The SDK is a typed client over the wavelength wallet daemon, which is compiled to WebAssembly for the browser and via gomobile for iOS and Android. The SDK loads that runtime and exposes it as the WavelengthClient contract plus a framework-agnostic WalletEngine.

Each SDK release pairs with a pinned wavelength release (the RUNTIME_MANIFEST_VERSION that @lightninglabs/wavelength-core exports). That release is where the runtime artifacts come from: the wasm asset set for the web and the native binaries for React Native. See Runtime assets and native bindings.

Packages

Package What it is
@lightninglabs/wavelength-core The contract: types, the WavelengthClient interface, the WalletEngine, errors, and enums. No DOM, no transport.
@lightninglabs/wavelength-web The browser (wasm) transport. Framework-agnostic: use it directly from vanilla JS, Vue, Svelte, or React. Re-exports core.
@lightninglabs/wavelength-react-native The React Native transport: a Turbo Module wrapping the wallet runtime compiled into the app binary. Re-exports core.
@lightninglabs/wavelength-react React provider + hooks. Transport-agnostic: the same binding runs over the web and React Native transports.

wavelength-web and wavelength-react-native each re-export every type from core, so an app imports the client and its types from one place.

Apps

None of these are published; they live in the repository as reference code and verification harnesses.

App What it is
apps/web-wallet-demo The reference web app, plus the Playwright smoke test.
apps/rn-wallet-demo The reference React Native app: an Expo dev-client demo mirroring the web demo screen for screen.
apps/docs The documentation site, published at wavelength.lightning.engineering.

Install

# React on the web (the binding + the web transport)
npm install @lightninglabs/wavelength-react @lightninglabs/wavelength-web

# React Native (the binding + the native transport)
npm install @lightninglabs/wavelength-react @lightninglabs/wavelength-react-native

# Vanilla / Vue / Svelte (web transport only)
npm install @lightninglabs/wavelength-web

You build the engine with createWebWalletEngine() from wavelength-web or createNativeWalletEngine() from wavelength-react-native. In React you pass that engine to WavelengthProvider; the provider itself is transport-agnostic and works the same way with either.

Quickstart: web

import {
  WavelengthProvider,
  useWallet,
  useWalletBalance,
  useWalletSend,
} from "@lightninglabs/wavelength-react";
import { createWebWalletEngine, defaultConfig } from "@lightninglabs/wavelength-web";

// Build the engine once. runtimeBaseUrl points at the hosted wasm runtime
// assets (see below). config + autoStart boot the embedded wallet as soon as
// the wasm runtime is ready.
const engine = createWebWalletEngine({
  runtimeBaseUrl: "https://your-host/wavewalletdk/",
  config: defaultConfig("signet"),
  autoStart: true,
});

function Root() {
  return (
    <WavelengthProvider engine={engine}>
      <Wallet />
    </WavelengthProvider>
  );
}

function Wallet() {
  const { phase } = useWallet();
  const balance = useWalletBalance();
  const { send } = useWalletSend();

  if (phase !== "ready") return <p>Loading… ({phase})</p>;

  return (
    <div>
      <p>Spendable: {balance?.confirmedSat ?? 0} sats</p>
      <button onClick={() => send({ invoice: "lnbc…" })}>Pay</button>
    </div>
  );
}

Focused hooks are available when you only need a slice. State-reading hooks like useWalletBalance() and useWalletActivity() return their value directly. Mutation hooks like useWalletSend(), useWalletReceive(), and useWalletDeposit() each expose an action plus verb-prefixed state, e.g. useWalletSend() returns { send, sendPending, sendError, sendData, resetSend }.

Using the client directly from vanilla JS, Vue, or Svelte instead of React is the same flow without the provider; see the wavelength-web README for that quickstart.

Quickstart: React Native

The same provider and hooks run over the native transport; only the engine factory changes:

import { WavelengthProvider, useWallet } from "@lightninglabs/wavelength-react";
import { createNativeWalletEngine } from "@lightninglabs/wavelength-react-native";

const engine = createNativeWalletEngine();

export default function App() {
  return (
    <WavelengthProvider engine={engine}>
      <Wallet />
    </WavelengthProvider>
  );
}

React Native has platform requirements the web does not: the package is New Architecture only, Expo apps need a development build rather than Expo Go, and the native runtime binaries are staged separately from npm. The wavelength-react-native README covers all of it.

Configuration

defaultConfig(network) returns a ready-to-use config preloaded with the canonical public endpoints for signet and testnet. Override only what you need:

import { defaultConfig } from "@lightninglabs/wavelength-web";

defaultConfig("signet");
defaultConfig("signet", { dataDir: "my-wallet" });

Each transport exports its own defaultConfig, preloaded with the endpoint flavor it speaks: on the web, arkServerAddress and swapServerAddress are REST URLs; on React Native they are gRPC endpoints. walletEsploraUrl is an HTTP Esplora endpoint on every platform.

There is no regtest preset (local ports vary per machine); build that config by hand with your stack's endpoints and the insecure-transport flags:

import type { RuntimeConfig } from "@lightninglabs/wavelength-web";

const config: RuntimeConfig = {
  network: "regtest",
  arkServerAddress: "http://127.0.0.1:7071",
  walletEsploraUrl: "http://127.0.0.1:8501",
  swapServerAddress: "http://127.0.0.1:10032",
  arkServerInsecure: true,
  swapServerInsecure: true,
};

Every field is documented on the RuntimeConfig type. mainnet has no public preset yet, so like regtest it is built by hand: supply the endpoints and allowMainnet: true yourself.

Runtime assets and native bindings

Both runtime artifacts come from the pinned wavelength release; neither ships inside an npm package.

Web: wasm runtime assets

The wasm runtime ships as a set of files (RUNTIME_ASSET_FILES) that make up the in-browser wallet. Host them together at one base URL and point runtimeBaseUrl at it:

import { RUNTIME_ASSET_FILES } from "@lightninglabs/wavelength-web";
// → wavewalletdk.wasm.gz, wasm_exec.js, sqlite-*.js, …

You host the asset set yourself. Obtain it from the wavelength release assets, or build it from a wavelength checkout. See Hosting runtime assets for the exact steps.

React Native: native binaries

The native wallet runtime (Wavewalletdk.aar for Android, Wavewalletdk.xcframework for iOS) is staged into the installed wavelength-react-native package before the first native build. Download the binaries from the wavelength release, or, from a checkout of this repository, let the package's bindings:fetch script stage them for you. See Installation for the exact steps.

Development

This is a pnpm workspace. Build before typechecking: the workspace typecheck resolves cross-package imports through each package's built dist/.

pnpm install
pnpm build
pnpm typecheck

The two demo apps are the reference integrations and the manual verification surface; each has a README covering setup and the runtime artifacts it needs (web, React Native). The docs site has its own README as well.

Releases

Packages

Contributors

Languages