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

nulltrace-sdk

v1.0.7

Published

NullTrace SDK - Privacy-focused Solana transactions powered by ZK compression

Downloads

797

Readme

NullTrace SDK

Standalone JavaScript SDK for NullTrace — privacy-focused Solana transactions powered by Light Protocol ZK compression. No server needed.

Install

npm install nulltrace-sdk @solana/web3.js @solana/spl-token @lightprotocol/stateless.js @lightprotocol/compressed-token

A Helius RPC endpoint is required. ZK compression depends on Helius's photon indexer. Get a free key at helius.dev.

Quick Start

import { NullTrace } from 'nulltrace-sdk';

const nt = new NullTrace('https://mainnet.helius-rpc.com/?api-key=YOUR_KEY', wallet);

// Nullify 0.5 SOL (public -> private)
await nt.nullify('So11111111111111111111111111111111111111112', '0.5');

// Reveal 0.5 SOL (private -> public)
await nt.reveal('So11111111111111111111111111111111111111112', '0.5');

// Private transfer
await nt.transfer('So11111111111111111111111111111111111111112', '1.0', 'RecipientAddress...');

// Private swap SOL -> USDT
await nt.swap('So11111111111111111111111111111111111111112', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', '1.0');

// Get all balances
const balances = await nt.getBalances();

Constructor

const nt = new NullTrace(rpcUrl, wallet);

| Param | Type | Description | |-------|------|-------------| | rpcUrl | string | Helius RPC endpoint (validated, throws if not Helius) | | walletOrKey | see below | Wallet adapter, Keypair, secret key, or private key string |

The second argument is flexible — pass whatever you have:

Option 1: Wallet Adapter (browser)

// Works with Phantom, Solflare, or any Solana wallet adapter
const nt = new NullTrace(rpcUrl, wallet);

Option 2: Keypair (Node.js)

import { Keypair } from '@solana/web3.js';

const keypair = Keypair.fromSecretKey(mySecretKey);
const nt = new NullTrace(rpcUrl, keypair);

Option 3: Secret Key bytes (Uint8Array)

const secretKey = new Uint8Array([/* 64 bytes */]);
const nt = new NullTrace(rpcUrl, secretKey);

Option 4: Base58 private key string

// As exported by Phantom, Solflare, etc.
const nt = new NullTrace(rpcUrl, '4wBqpZM9...');

All four options produce identical functionality. Options 2–4 automatically create a full wallet interface (including signMessage for private balance lookups).

Static factory methods

You can also build wallet adapters independently:

const wallet = NullTrace.fromKeypair(keypair);
const wallet = NullTrace.fromSecretKey(uint8Array);
const wallet = NullTrace.fromPrivateKey('base58string...');

API Reference

nt.nullify(mint, amount)

Convert public tokens into private ZK-compressed state.

const sigs = await nt.nullify('So11111111111111111111111111111111111111112', '0.5');
// Returns: ['5xYk...', ...]  (transaction signatures)

nt.reveal(mint, amount)

Decompress private tokens back to public state.

const sigs = await nt.reveal('So11111111111111111111111111111111111111112', '0.5');

nt.transfer(mint, amount, recipient)

Send compressed tokens privately to another address.

const sigs = await nt.transfer(
  'So11111111111111111111111111111111111111112',
  '1.0',
  '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU'
);

nt.swap(fromMint, toMint, amount, options?)

Execute a private swap via the NullTrace operator.

const result = await nt.swap(
  'So11111111111111111111111111111111111111112',  // from SOL
  'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',  // to USDT
  '1.0'
);
console.log(result.status); // 'completed'

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | onStatusChange | (s) => void | — | Called with 'signing', 'processing', 'completed' | | timeout | number | 120000 | Max wait time in ms |

// With status updates
await nt.swap(SOL, USDT, '1.0', {
  onStatusChange: (status) => console.log('Status:', status),
});

nt.quoteSwap(inputMint, outputMint, amount)

Get a swap quote without executing.

const quote = await nt.quoteSwap(
  'So11111111111111111111111111111111111111112',
  'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
  '1.0'
);
console.log(`Output: ${quote.outAmount}, Impact: ${quote.priceImpact}%`);

nt.getPublicBalances()

Fetch on-chain token balances. No signing needed.

const balances = await nt.getPublicBalances();
// [{ symbol: 'SOL', amount: '2.5', address: 'So11...', decimals: 9, ... }]

nt.getPrivateBalances()

Fetch ZK-compressed balances. Requires wallet.signMessage (prompted once, cached).

const balances = await nt.getPrivateBalances();

nt.getBalances()

Get all balances merged, with publicAmount and privateAmount fields.

const all = await nt.getBalances();
for (const t of all) {
  console.log(`${t.symbol}: ${t.publicAmount} public, ${t.privateAmount} private`);
}

nt.getTokenMetadata(mint)

Fetch token metadata (symbol, name, logo, decimals).

const meta = await nt.getTokenMetadata('Es9vMFr...');
console.log(meta.symbol, meta.decimals); // 'USDT' 6

nt.clearSignatureCache()

Clear the cached message signature so the next private balance call re-prompts.


Usage with React + Wallet Adapter

import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { NullTrace } from 'nulltrace-sdk';
import { useMemo } from 'react';

function MyComponent() {
  const wallet = useWallet();

  const nt = useMemo(() => {
    if (!wallet.publicKey) return null;
    return new NullTrace('https://mainnet.helius-rpc.com/?api-key=YOUR_KEY', wallet);
  }, [wallet.publicKey]);

  const handleNullify = async () => {
    const sigs = await nt.nullify('So11111111111111111111111111111111111111112', '0.5');
    console.log('Done:', sigs);
  };

  return <button onClick={handleNullify}>Nullify 0.5 SOL</button>;
}

Usage with Node.js

import { Keypair } from '@solana/web3.js';
import { NullTrace } from 'nulltrace-sdk';

// Pass a Keypair directly — no manual wallet wiring needed
const nt = new NullTrace(
  'https://mainnet.helius-rpc.com/?api-key=YOUR_KEY',
  Keypair.fromSecretKey(mySecretKey)
);

// Or use a base58 private key string (as exported by Phantom)
// const nt = new NullTrace(rpcUrl, '4wBqpZM9k...');

const balances = await nt.getBalances();
console.log(balances);

await nt.nullify('So11111111111111111111111111111111111111112', '0.5');

License

MIT — NullTrace