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

@rail20/cli

v0.3.5

Published

Private payments for onchain agents. CLI for RAIL20 - shield, send, swap, bridge with zero-knowledge privacy on Base and Robinhood Chain.

Readme

@rail20/cli

Private payments for onchain agents. One env var or one hidden prompt, then shield / send / swap / bridge with zero-knowledge privacy on Base and Robinhood Chain. Wraps the same API docs.rail20.org/agents uses - no ZK client needed on your side.

Every command takes an optional --chain base|robinhood flag (default base). On Base the stablecoin is USDC; on Robinhood it's USDG.

Install

npm i -g @rail20/cli
# or
npx @rail20/cli help

Setup

Two ways to provide your key, depending on who's running it.

Interactive (humans / local demo) - key never shown

rail20 login
#   private key: ●●●●●●●●●●   <- hidden input, like sudo password
# ✓ wallet stored at ~/.rail20/wallet.json (chmod 600)

The key is prompted with hidden input (no echo, never enters shell history), then stored locally at ~/.rail20/wallet.json with chmod 600 (owner-only). It is never transmitted - only the derived signature is sent to the relayer.

Env var (agents / CI) - no prompt

export RAIL20_KEY=0xyour_agent_private_key
rail20 login   # detects env var, skips the prompt, stores nothing to disk

Agents pull the key from their own secret manager / vault into RAIL20_KEY. The CLI reads it directly and does not write it to disk.

Logout

rail20 logout   # removes ~/.rail20/wallet.json + config.json

Key resolution order: RAIL20_KEY env var → ~/.rail20/wallet.json → error.

Commands

rail20 balance                            # private + public balances (both pools), Base
rail20 balance --chain robinhood          # balances on Robinhood (ETH + USDG)
rail20 balance --pool eth                 # just private ETH
rail20 deposit 5 --pool usdc              # shield 5 USDC from public to private (Base)
rail20 deposit 5 --pool usdg --chain robinhood   # shield 5 USDG on Robinhood
rail20 send 0xRECIPIENT 2.5               # send 2.5 USDC privately (no gas from you)
rail20 send 0xRECIPIENT 0.01 --pool eth   # send private ETH
rail20 send 0xRECIPIENT 2.5 --chain robinhood    # send 2.5 USDG privately on Robinhood
rail20 swap 0.001 --from eth              # private same-chain swap ETH -> USDC (Uniswap V3)
rail20 swap 3 --from usdc                 # private same-chain swap USDC -> ETH
rail20 bridge arb_usdc 0xRECIPIENT 2.5    # bridge cross-chain privately to Arbitrum
rail20 bridge bsc_usdt 0xRECIPIENT 5      # bridge to BSC (destinations: rail20 assets)
rail20 assets                             # list all supported bridge destinations
rail20 recover                            # sweep any stranded funds from burner slots
rail20 recover --to 0xADDR                # sweep to a different destination

How it works

Each command follows the pattern docs.rail20.org/agents documents.

Login / balance / send / bridge - you sign once, the relayer builds the Groth16 proof server-side, and broadcasts. You pay no gas. The relayer is compensated via the protocol fee (flat + 0.35% per withdraw / swap / bridge).

Deposit - your public wallet signs and broadcasts the shield tx (this is the only step where you pay gas, because the pool must see funds coming from a public address). For ERC-20 pools (USDC), an approve runs first; the CLI polls the on-chain allowance before broadcasting the deposit (same fix as the frontend for load-balanced RPC lag).

Swap same-chain - mirrors the frontend burner flow exactly:

  1. Derive a fresh burner wallet deterministically from your signature (keccak256("rail20-burner-v2:" + keccak(sig) + ":" + nonce), scan slots 0-19).
  2. Private withdraw from your pool → burner via /api/swap-private.
  3. For USDC origin: relayer tops up burner gas via /api/burner-gas.
  4. Burner approves + swaps on Uniswap V3 (SwapRouter02, 0.01% fee tier).
  5. WETH is unwrapped to ETH if ETH is the destination.
  6. Pre-flight eth_call simulation of the reshield (catches reverts cheap).
  7. Burner reshields the swapped output back to your private balance via /api/deposit/prepare.

If any step fails between (2) and (7), funds remain on the burner (which is deterministic from your signature). Run rail20 recover to sweep them home.

Bridge cross-chain - private withdraw to a NEAR Intents 1Click solver via /api/swap, then poll /api/intent-status until SUCCESS (or REFUNDED, in which case the solver returns your funds automatically). No burner involved for bridges.

Recover - scans burner slots 0-19 for stranded USDC / ETH and sweeps them back to your public wallet (or --to <addr>). Handles the wallets swap may have left behind if a later step reverted. Uses Base-realistic gas params (0.05 gwei) so the burner's tiny ETH top-up is enough for the sweep tx.

Environment

  • RAIL20_KEY - agent private key (0x-hex). Optional if you've run rail20 login.
  • RAIL20_API - API base URL (default https://api.rail20.org).
  • RAIL20_RPC / RAIL20_BASE_RPC - Base RPC endpoint (default https://mainnet.base.org). Set to your own Alchemy / QuickNode URL for faster + more reliable gas estimation on the burner-heavy swap flow.
  • RAIL20_ROBINHOOD_RPC - Robinhood Chain RPC endpoint (default https://rpc.mainnet.chain.robinhood.com), used when --chain robinhood.

Config files

  • ~/.rail20/wallet.json - stored private key (chmod 600, only if you used rail20 login interactively).
  • ~/.rail20/config.json - cached RAIL20 signatures per wallet (chmod 600).

Verified live on Base mainnet

Every command in this CLI has been exercised end-to-end against api.rail20.org with real on-chain transactions:

  • deposit0x7ae2dde7… (3 USDC shielded)
  • send0x2108ae58… (1.49125 USDC delivered privately, fee 1.00875)
  • swap0x1bd8d68d… (0.001 ETH → 1.170797 USDC private, full reshield)
  • bridge0xdfc495fa… (2.5 USDC Base → 1.484306 USDC delivered to Arbitrum)
  • recover → 1.9895 USDC swept back from a stranded burner

Cross-chain destinations

Run rail20 assets for the full live list. Currently: Base, Ethereum, BSC, Arbitrum - ETH / WETH / USDC / USDT / cbBTC / ARB / BNB depending on the chain.

Roadmap

  • @rail20/sdk - TypeScript SDK for programmatic use inside an agent.
  • Mandate limits - human-signed spend cap per window (aligns with the "supervised agent" pattern).
  • Optional wallet encryption at rest - passphrase-protected wallet.json.

Support

Docs: docs.rail20.org/agents · Site: rail20.org