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

@zill-protocol/rn-sdk

v0.2.3

Published

React Native focused SDK for Zill/Nocturne. It re-exports the shared protocol logic from `@zill-protocol/client` and adds React Native helpers for sync, storage, and proving.

Readme

@zill-protocol/rn-sdk

React Native focused SDK for Zill/Nocturne. It re-exports the shared protocol logic from @zill-protocol/client and adds React Native helpers for sync, storage, and proving.

This package is internal-only for now and is opinionated toward the Zill stack.

What this SDK does

  • Syncs public chain data from /v0/sync and maintains local note state.
  • Decrypts notes on-device using the viewer keys.
  • Maintains a local sparse Merkle prover in MMKV.
  • Prepares, signs, and proves operations (joinsplit).
  • Tracks operation status via the bundler endpoint.
  • Exposes optional activity and tx-status HTTP clients.

How it works (high level)

  1. createHttpSyncAdapter polls /v0/sync and yields insertions + nullifiers.
  2. The client decrypts notes locally and stores state in NocturneDB.
  3. The merkle prover is updated in MMKV.
  4. prepareOperation builds a pre-sign operation from local notes.
  5. signOperation and proveOperation generate a submittable operation.
  6. Your app submits the operation to the bundler and tracks status.

Quick start (recommended)

import { createReactNativeClientFromConfig } from "@zill-protocol/rn-sdk";

const { client } = createReactNativeClientFromConfig({
  namespace: walletId,
  syncBaseUrl: "https://insertion-writer.up.railway.app",
  bundlerBaseUrl: "https://bundler.up.railway.app",
  viewer,
  provider,
  config: "citrea-testnet",
  tokenConverter,
  syncOptions: {
    expectedChainId: "5115",
    expectedHandlerAddress: "0x...",
  },
});

Sync

await client.sync();
const latestIndex = await client.getLatestSyncedMerkleIndex();

createHttpSyncAdapter ships with a built-in MMKV cursor store for nullifier pagination. If you omit nullifierCursorStore, it persists the cursor under <namespace>::sync (default namespace is default).

Retry/backoff is supported via the retry option on the sync adapter. Chain and handler validation can be enforced via expectedChainId and expectedHandlerAddress.

Sync adapter options (summary)

  • baseUrl (required): sync API base URL.
  • fetch: custom fetch implementation.
  • insertionLimit / nullifierLimit: page sizes.
  • pollIntervalMs: sleep interval when idle.
  • namespace: used by the built-in cursor store.
  • nullifierCursorKey: override the cursor key name.
  • nullifierCursorStore: custom store implementation.
  • expectedChainId / expectedHandlerAddress: fail fast on misconfigured URLs.
  • retry: retry/backoff settings for transient failures.

Retry options

{
  maxRetries: 3,
  baseDelayMs: 500,
  maxDelayMs: 5000,
  jitterRatio: 0.2,
  retryOnStatuses: [429, 502, 503, 504],
  timeoutMs: 10000,
}

Custom cursor store

const syncAdapter = createHttpSyncAdapter({
  baseUrl: "...",
  nullifierCursorStore: {
    get: async () => Number(await storage.getItem("nfCursor") ?? 0),
    set: async (cursor) => storage.setItem("nfCursor", cursor.toString()),
  },
});

Operation flow (prepare -> sign -> prove)

import { createHttpBundlerClient } from "@zill-protocol/rn-sdk";
import { signOperation, proveOperation } from "@zill-protocol/client";

const preSignOp = await client.prepareOperation(opRequest, 1.1);
const signedOp = signOperation(nocturneSigner, preSignOp);
const provenOp = await proveOperation(joinSplitProver, signedOp);

const bundler = createHttpBundlerClient("https://bundler.up.railway.app");
const { id } = await bundler.submitOperation(provenOp);
const status = await bundler.getOperationStatus(id);

Notes:

  • joinSplitProver is typically ReactNativeJoinSplitProver.
  • You can submit via createHttpBundlerClient or your own network layer.

Submitting operations

Bundler accepts a JSON payload of the form { operation } at POST /relay and returns { id }, where id is the operation digest string. The SDK provides a simple client wrapper:

import { createHttpBundlerClient } from "@zill-protocol/rn-sdk";

const bundler = createHttpBundlerClient("https://bundler.up.railway.app");
const { id } = await bundler.submitOperation(provenOp);

// Track status with the digest returned by the bundler.
const status = await bundler.getOperationStatus(id);

Practical guidance:

  • Keep the returned id to reconcile status updates.
  • A 400 response indicates validation failure (nullifier conflict, revert, gas).
  • A 500 response indicates bundler failure; retry with backoff.

Bundler client

createHttpBundlerClient wraps the bundler HTTP API:

  • submitOperation(op)POST /relay
  • getOperationStatus(id)GET /operations/:id
  • checkNullifier(nf)GET /nullifiers/:nullifier

Activity and tx status

import { createHttpActivityClient, createHttpTxStatusClient } from "@zill-protocol/rn-sdk";

const activityClient = createHttpActivityClient("https://insertion-writer.up.railway.app");
const page = await activityClient.fetchActivity({ limit: 100 });

const txClient = createHttpTxStatusClient("https://bundler.up.railway.app");
const status = await txClient.getOperationStatus(opDigest);

Storage adapter

The SDK ships an MMKV-backed KVStore adapter and a helper that wires both the DB and the sparse Merkle prover.

import { createReactNativeStorage } from "@zill-protocol/rn-sdk";

const { db, merkleProver } = createReactNativeStorage({
  namespace: walletId,
});

createReactNativeStorage accepts optional overrides for MMKV ids, encryption keys, or custom MMKV instances. You can also instantiate MMKVStore directly via createMMKVStore.

JoinSplit artifact manager

JoinSplit proving requires three artifacts:

  • proving key (.zkey)
  • witness calculator graph (.wcd)
  • verification key (base64)

The SDK ships JoinSplitArtifactManager to download, verify, and cache these artifacts in the app sandbox. You bring a storage adapter (e.g. RNFS) and the R2/CDN manifest (version + SHA256 hashes).

import RNFS from "react-native-fs";
import {
  JoinSplitArtifactManager,
  ReactNativeJoinSplitProver,
} from "@zill-protocol/rn-sdk";

const storage = {
  artifactDir: `${RNFS.DocumentDirectoryPath}/nocturne-artifacts`,
  ensureDir: () => RNFS.mkdir(`${RNFS.DocumentDirectoryPath}/nocturne-artifacts`),
  exists: (path: string) => RNFS.exists(path),
  readText: async (path: string) =>
    (await RNFS.exists(path)) ? RNFS.readFile(path, "utf8") : null,
  writeText: (path: string, contents: string) =>
    RNFS.writeFile(path, contents, "utf8"),
  readFileBase64: (path: string) => RNFS.readFile(path, "base64"),
  writeFileBase64: (path: string, base64: string) =>
    RNFS.writeFile(path, base64, "base64"),
};

const artifactManager = new JoinSplitArtifactManager(storage, {
  baseUrl: "https://r2.example.com/nocturne/joinsplit/",
  manifest: {
    version: "v1",
    zkey: {
      path: "joinsplit.zkey",
      sha256: "0x...",
    },
    wcd: {
      path: "joinsplit.wcd",
      sha256: "0x...",
    },
    verificationKeyBase64: "base64-vkey",
  },
  // Optional: add signed headers or tokens for private buckets.
  // getHeaders: async () => ({ Authorization: `Bearer ${token}` }),
});

const proverConfig = await artifactManager.ensureArtifacts();
const prover = new ReactNativeJoinSplitProver(proverConfig);

If you want the SDK to fetch the manifest directly:

import {
  createReactNativeJoinSplitProverFromManifestUrl,
} from "@zill-protocol/rn-sdk";

const { prover } = await createReactNativeJoinSplitProverFromManifestUrl({
  storage,
  manifestUrl: "https://bucket.example.com/joinsplit/joinsplit-artifacts.json",
});

React Native prover

ReactNativeJoinSplitProver is backed by:

  • @iden3/react-native-circom-witnesscalc
  • @iden3/react-native-rapidsnark

Privacy notes

  • The server only exposes public data (commitments, nullifiers).
  • Notes are decrypted on-device using the viewer keys.
  • Do not store decrypted note metadata server-side.

Limitations

  • Activity feed is optional and not a source of truth for private state.