npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@relayprotocol/relay-lighter-wallet-adapter

v0.1.3

Published

A Lighter adapter for use in @relayprotocol/relay-sdk

Readme

Installation

yarn add @relayprotocol/relay-lighter-wallet-adapter @relayprotocol/relay-sdk viem

If you want the adapter to run its own bootstrap (fresh keygen, accountApiKey, or storage paths), you also need the Lighter SDK:

yarn add @relay-protocol/lighter-ts-sdk

It's declared as an optional peer dependency — integrators who always supply a pre-built signerClient can skip the install entirely. The adapter loads the SDK via a lazy dynamic import() and only touches it on the bootstrap path; if it's not installed and the bootstrap path runs, a clear error is thrown.

Usage

import { adaptLighterWallet } from '@relayprotocol/relay-lighter-wallet-adapter'

const account = walletClient.account
const wallet = adaptLighterWallet({
  l1Address: account.address,
  signL1Message: (message) => walletClient.signMessage({ account, message })
})

The adapter owns the full Lighter session lifecycle: it resolves the user's Lighter accountIndex, generates an in-memory API key, registers it on-chain via changeApiKey, and builds the SignerClient on demand. Construction is cheap — no network or signature prompts until the user actually initiates a transfer.

Options

| Option | Default | | | ------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | l1Address | — | The user's connected EVM address | | signL1Message | — | (message) => Promise<hex sig> — typically walletClient.signMessage({ account, message }). Optional when signerClient is supplied (the integrator owns signing). | | apiUrl | https://mainnet.zklighter.elliot.ai | Lighter HTTP API base URL. Override to point at testnet, a proxy service, or your own staging deployment. All /api/v1/* traffic (account lookup, sendTx, status polling) uses this base. | | apiKeyIndex | 2 | API key slot to (re)register | | chainId | 3586256 | Reported chain id | | wasmConfig | jsDelivr CDN | { wasmPath, wasmExecPath } | | accountApiKey | — | Hex-encoded pre-registered Lighter account API key (see below) | | signerClient + accountIndex | — | Pre-built signer with the user's Lighter account index. Must be supplied together — TypeScript enforces the pair (see below). | | storage | — | Optional persistent API-key store | | pollIntervalMs / timeoutMs | 2000 / 120000 | Confirmation polling |

API-key lifecycle strategies

The adapter supports four patterns, chosen automatically based on which options are set. Precedence: signerClient > accountApiKey > storage > fresh bootstrap.

1. Fresh bootstrap (default). Regenerates an API key every page load — key never leaves memory. Integrator pays one signature prompt (changeApiKey) on the first transfer per session.

adaptLighterWallet({ l1Address, signL1Message })

2. Persistent storage. Reuses a previously-generated key across sessions. Only the first ever session pays the signature prompt.

adaptLighterWallet({
  l1Address,
  signL1Message,
  storage: {
    get: (k) => localStorage.getItem(k),
    set: (k, v) => localStorage.setItem(k, v)
  }
})

3. Externally-managed key. Integrators who run their own API-key lifecycle (backend provisioning, wallet-level integration, HSM, etc.) can skip the bootstrap entirely by supplying a pre-registered Lighter account API key. The caller is responsible for having already registered the matching public key on the user's Lighter account at apiKeyIndex.

adaptLighterWallet({
  l1Address,
  signL1Message,
  apiKeyIndex: 2,
  accountApiKey: await fetchAccountApiKeyFromMyKeyService(userId)
})

No signature prompt fires for changeApiKey. The per-transfer L1 authorization (signL1Message) is still required.

4. Pre-built signer. For integrators with privileged access to a Lighter-provided signer (already initialized, WASM loaded, key registered). This path bypasses every bootstrap step and skips the @relay-protocol/lighter-ts-sdk dynamic import entirely — the adapter runs with zero runtime dependency on the SDK.

The adapter only needs two methods, described by the LighterSigner type:

import type { LighterSigner } from '@relayprotocol/relay-lighter-wallet-adapter'

type LighterSigner = {
  transfer: (
    params: LighterTransferParams
  ) => Promise<[unknown, string, string | null]>
  getTransaction: (txHash: string) => Promise<LighterTransaction>
}

A full SignerClient from @relay-protocol/lighter-ts-sdk satisfies this structurally and can be passed directly:

const client = await getLighterSigner() // from your Lighter integration

adaptLighterWallet({
  l1Address,
  signerClient: client,
  accountIndex: 509564 // required when `signerClient` is set
})

signerClient and accountIndex must be supplied together. TypeScript's discriminated union on AdaptLighterWalletOptions enforces the pair — you can't pass one without the other. The adapter needs accountIndex for AdaptedWallet.address() (which the Relay SDK calls when building quotes or rendering the widget); it can't pull this out of a SignerClient instance because the SDK's config is private.

When signerClient is set, apiUrl, apiKeyIndex, wasmConfig, accountApiKey, and storage are all ignored (the signer already has them baked in). signL1Message becomes optional too — if the integrator's signer handles L1 signing internally, omit it; otherwise supply it and the adapter will forward it to transfer() as ethSigner.