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

solana-privacy-devtools

v0.1.1

Published

Developer tools for Solana privacy: static code analysis, transaction simulation, test matchers, and CI/CD integration

Readme

solana-privacy-scanner-ci-tools

CI/CD integration tools for Solana privacy scanning. Test privacy in your development workflow with transaction simulation, testing matchers, and automated checks.

npm License: MIT

Features

  • 🧪 Transaction Simulator - Test privacy before sending to mainnet
  • Testing Matchers - Privacy assertions in Vitest/Jest tests
  • ⚙️ Config System - Project-level privacy policies
  • 🔗 GitHub Actions - Automated PR privacy checks
  • 🪝 Pre-commit Hooks - Catch issues before commit
  • 🐳 Docker Support - Containerized scanning for CI/CD

Quick Start

Installation

npm install --save-dev solana-privacy-scanner-ci-tools

Setup Wizard

Run the interactive setup:

npx privacy-scanner-init

This will:

  • Create .privacyrc configuration
  • Set up GitHub Actions (optional)
  • Install pre-commit hooks (optional)
  • Configure testing matchers (optional)

Transaction Simulator

Analyze privacy before sending transactions to the network.

Basic Usage

import { simulateTransactionPrivacy } from 'solana-privacy-scanner-ci-tools/simulator';
import { Connection, Transaction } from '@solana/web3.js';

const connection = new Connection('https://api.devnet.solana.com');
const tx = new Transaction().add(/* your instruction */);

// Simulate privacy impact (doesn't send transaction)
const report = await simulateTransactionPrivacy(tx, connection);

console.log(`Risk Level: ${report.overallRisk}`);
console.log(`Signals: ${report.signals.length}`);

if (report.overallRisk === 'HIGH') {
  console.warn('High privacy risks detected!');
  // Don't send the transaction
} else {
  // Safe to send
  await sendAndConfirmTransaction(connection, tx, [signer]);
}

Flow Analysis

Analyze multiple transactions as a user flow:

import { simulateTransactionFlow } from 'solana-privacy-scanner-ci-tools/simulator';

const flow = [
  createDepositTx(),
  createSwapTx(),
  createWithdrawTx()
];

const flowReport = await simulateTransactionFlow(flow, connection);

console.log(`Cumulative Risk: ${flowReport.cumulativeRisk}`);
console.log(`Emergent Patterns: ${flowReport.emergentPatterns.length}`);

// Check for patterns that only appear across multiple transactions
for (const pattern of flowReport.emergentPatterns) {
  console.log(`- ${pattern.type}: ${pattern.description}`);
}

Implementation Comparison

Compare two implementations to choose the most private:

import { compareImplementations } from 'solana-privacy-scanner-ci-tools/simulator';

const directTransfer = createDirectTransfer(user, recipient, amount);
const intermediaryTransfer = createIntermediaryTransfer(user, recipient, amount);

const comparison = await compareImplementations(
  directTransfer,
  intermediaryTransfer,
  connection
);

console.log(`Winner: Implementation ${comparison.winner}`);
console.log(`Privacy improvement: ${comparison.difference} points`);
console.log(`Recommendation: ${comparison.recommendation}`);

Testing Matchers

Add privacy assertions to your tests.

Setup

// tests/setup.ts
import 'solana-privacy-scanner-ci-tools/matchers';

Usage

import { expect } from 'vitest';
import { simulateTransactionPrivacy } from 'solana-privacy-scanner-ci-tools/simulator';

describe('Token Transfer', () => {
  it('should maintain user privacy', async () => {
    const tx = await createTransfer(user, recipient, amount);
    const report = await simulateTransactionPrivacy(tx, connection);

    // Privacy-specific assertions
    expect(report).toHavePrivacyRisk('LOW');
    expect(report).toNotLeakUserRelationships();
    expect(report).toHaveNoHighRiskSignals();
    expect(report).toHaveAtMostSignals(2);
  });

  it('should not interact with exchanges', async () => {
    const tx = await createSwap(tokenA, tokenB);
    const report = await simulateTransactionPrivacy(tx, connection);

    expect(report).toNotInteractWith('exchange');
    expect(report).toHaveNoKnownEntities();
  });

  it('should avoid specific signals', async () => {
    const tx = await createComplexOperation();
    const report = await simulateTransactionPrivacy(tx, connection);

    expect(report).toNotHaveSignal('counterparty-reuse');
    expect(report).toNotHaveSignal('timing-pattern');
  });
});

Available Matchers

| Matcher | Description | |---------|-------------| | toHavePrivacyRisk(level) | Assert specific risk level | | toHaveNoHighRiskSignals() | No HIGH severity signals | | toNotLeakUserRelationships() | No relationship linkage | | toHaveSignal(type) | Has specific signal | | toNotHaveSignal(type) | Doesn't have specific signal | | toHavePrivacyScore(min) | Minimum privacy score | | toHaveAtMostSignals(max) | Maximum signal count | | toHaveNoKnownEntities() | No labeled entities | | toNotInteractWith(type) | Avoid entity type |


Configuration

Create .privacyrc in your project root:

{
  "maxRiskLevel": "MEDIUM",
  "enforceInCI": true,
  "testWallets": {
    "devnet": "YOUR_TEST_WALLET_ADDRESS"
  },
  "thresholds": {
    "maxHighSeverity": 0,
    "maxMediumSeverity": 3,
    "minPrivacyScore": 70
  },
  "excludePatterns": [
    "test/**",
    "scripts/**"
  ]
}

Configuration Options

interface PrivacyConfig {
  // Maximum acceptable risk level
  maxRiskLevel: 'LOW' | 'MEDIUM' | 'HIGH';
  
  // Enforce in CI/CD environments
  enforceInCI: boolean;
  
  // Block operations on violations
  blockOnFailure: boolean;
  
  // Test wallets per environment
  testWallets?: {
    devnet?: string;
    testnet?: string;
    mainnet?: string;
  };
  
  // Privacy thresholds
  thresholds?: {
    maxSignals?: number;
    maxHighSeverity?: number;
    maxMediumSeverity?: number;
    minPrivacyScore?: number; // 0-100
  };
  
  // Patterns to exclude from scanning
  excludePatterns?: string[];
}

Presets

import { STRICT_CONFIG, PERMISSIVE_CONFIG } from 'solana-privacy-scanner-ci-tools/config';

// Strict (for production)
{
  "maxRiskLevel": "LOW",
  "enforceInCI": true,
  "blockOnFailure": true,
  "thresholds": {
    "maxHighSeverity": 0,
    "maxMediumSeverity": 2,
    "minPrivacyScore": 80
  }
}

// Permissive (for development)
{
  "maxRiskLevel": "HIGH",
  "enforceInCI": false,
  "blockOnFailure": false
}

GitHub Actions

Basic Setup

Create .github/workflows/privacy-check.yml:

name: Privacy Check

on: [pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Run Privacy Scanner
        uses: solana-privacy-scanner/action@v1
        with:
          wallet: ${{ secrets.TEST_WALLET }}
          fail-on: HIGH
          comment-pr: true

With Custom Config

- name: Run Privacy Scanner
  uses: solana-privacy-scanner/action@v1
  with:
    config: .privacyrc
    wallet: ${{ secrets.DEVNET_WALLET }}
    fail-on: MEDIUM
    output: privacy-report.json

- name: Upload Report
  uses: actions/upload-artifact@v3
  with:
    name: privacy-report
    path: privacy-report.json

Pre-commit Hooks

Using Husky

# Install husky
npm install --save-dev husky
npx husky install

# Create hook
npx husky add .husky/pre-commit "npx privacy-scanner-check"

The hook will:

  1. Load .privacyrc configuration
  2. Scan your test wallet
  3. Block commit if policy violated
  4. Show privacy report

Docker

Pull Image

docker pull solana-privacy-scanner/scanner:latest

Usage

# Basic scan
docker run solana-privacy-scanner/scanner scan-wallet <ADDRESS>

# With volume mount (save report)
docker run -v $(pwd):/workspace solana-privacy-scanner/scanner \
  scan-wallet <ADDRESS> --output /workspace/report.json

# In CI
docker run solana-privacy-scanner/scanner \
  scan-wallet $TEST_WALLET --json --output report.json

Docker Compose

version: '3'
services:
  privacy-scan:
    image: solana-privacy-scanner/scanner:latest
    command: scan-wallet ${TEST_WALLET}
    volumes:
      - ./reports:/workspace

Examples

Example 1: Test-Driven Privacy

// __tests__/privacy.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import { simulateTransactionPrivacy } from 'solana-privacy-scanner-ci-tools/simulator';

describe('Lending Protocol Privacy', () => {
  let connection: Connection;

  beforeAll(() => {
    connection = new Connection('https://api.devnet.solana.com');
  });

  it('deposit should not leak user identity', async () => {
    const depositTx = await program.methods
      .deposit(amount)
      .accounts({ user: user.publicKey, vault })
      .transaction();

    const report = await simulateTransactionPrivacy(depositTx, connection);

    expect(report).toHavePrivacyRisk('LOW');
    expect(report).toNotHaveSignal('fee-payer-reuse');
  });

  it('full borrow flow should maintain privacy', async () => {
    const flow = [
      await createCollateralDeposit(),
      await createBorrow(),
      await createRepayment()
    ];

    const flowReport = await simulateTransactionFlow(flow, connection);

    expect(flowReport.cumulativeRisk).toBe('LOW');
    expect(flowReport.emergentPatterns).toHaveLength(0);
  });
});

Example 2: Choose Best Implementation

async function chooseImplementation() {
  const directImpl = createDirectSwap(tokenA, tokenB, amount);
  const routedImpl = createRoutedSwap(tokenA, tokenB, amount);

  const comparison = await compareImplementations(
    directImpl,
    routedImpl,
    connection
  );

  return comparison.winner === 'A' ? directImpl : routedImpl;
}

Example 3: Interactive Development

// scripts/dev-helper.ts
import { simulateTransactionPrivacy } from 'solana-privacy-scanner-ci-tools/simulator';
import prompts from 'prompts';

async function devHelper() {
  const tx = buildTransaction();
  const report = await simulateTransactionPrivacy(tx, connection);

  if (report.overallRisk === 'HIGH') {
    console.warn('⚠️  High Privacy Risk!');
    console.warn(report.signals.map(s => `- ${s.type}: ${s.description}`).join('\n'));

    const { proceed } = await prompts({
      type: 'confirm',
      name: 'proceed',
      message: 'Send anyway?',
      initial: false
    });

    if (!proceed) return;
  }

  await sendTransaction(tx);
}

API Reference

Simulator

// Simulate single transaction
function simulateTransactionPrivacy(
  transaction: Transaction | VersionedTransaction,
  connection: Connection,
  options?: SimulatorOptions
): Promise<PrivacyReport>

// Simulate transaction flow
function simulateTransactionFlow(
  transactions: Transaction[],
  connection: Connection,
  options?: SimulatorOptions
): Promise<PrivacyFlowReport>

// Compare implementations
function compareImplementations(
  implA: Transaction,
  implB: Transaction,
  connection: Connection,
  options?: SimulatorOptions
): Promise<PrivacyComparison>

Config

// Load configuration
function loadConfig(cwd?: string): PrivacyConfig

// Get environment-specific config
function getEnvironmentConfig(
  config: PrivacyConfig,
  environment: string
): PrivacyConfig

// Check if enforcement enabled
function shouldEnforce(config: PrivacyConfig): boolean

Contributing

See CONTRIBUTING.md

License

MIT © Taylor Ferran

Links