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

openwallet

v0.0.1

Published

Custom Ethereum-focused CLI with encrypted local and global vaults.

Downloads

297

Readme

openwallet

openwallet is a local-first Ethereum wallet CLI with encrypted project-local and global .openwallet vaults. It uses viem for EVM wallet operations, @noble/ciphers plus @noble/hashes for vault encryption, and the OS keychain when available.

The wallet format is private to this CLI. It is not OWS-compatible and does not claim OWS conformance.

Status

MVP implementation for local development and agent workflows.

Supported:

  • Create, list, and inspect encrypted Ethereum wallets.
  • Import a BIP-39 mnemonic into an encrypted wallet.
  • Store 10 public EVM account descriptors for indexes 0..9.
  • Sign EIP-191 messages offline.
  • Sign serialized unsigned EVM transaction hex offline.
  • Use a wallet-backed EVM JSON-RPC proxy with local signing and transaction simulation.
  • Use local ./.openwallet vaults by default or ~/.openwallet with -g/--global.

Not included:

  • Direct balance commands, standalone broadcasting commands, or standalone gas/nonce commands.
  • Wallet deletion, mnemonic/private-key export, Solana, policy engines, or API keys.
  • OWS compatibility or migration support for existing OWS wallet files.
  • Recovery if the OS keychain entry for a generated vault passphrase is lost and you do not know the passphrase.

Requirements

  • Node.js 24.x
  • pnpm 10.x
  • OS keychain support for @github/keytar, or an interactive TTY for passphrase prompts

On Linux, @github/keytar depends on the Secret Service API, usually provided by libsecret and a running keyring service. If the keychain is unavailable, commands that need the vault passphrase prompt on stderr without echoing input. Non-interactive sessions that cannot prompt fail with KEYCHAIN_UNAVAILABLE; openwallet does not fall back to plaintext files, environment variables, or command-line secrets.

Install

pnpm install
pnpm build

Run the development CLI:

pnpm dev --help
pnpm dev wallet list

Run the built CLI:

node dist/bin.js --help
node dist/bin.js wallet list

If installed as a package, the binary name is openwallet:

openwallet wallet list

Vaults

Local mode is the default:

openwallet wallet create --name agent

This uses exactly the current working directory:

<cwd>/.openwallet

openwallet does not search parent directories for a vault. Running the same command from another directory uses that directory's .openwallet vault.

Global mode uses the user's home directory:

openwallet -g wallet create --name agent

This writes to:

~/.openwallet

Vault layout:

.openwallet/
└── wallets/
    └── <wallet-name>.json

Wallet names are used as filenames, so names must start with a letter or number and contain only letters, numbers, dots, underscores, or hyphens. Vault directories are created owner-only where supported, and .openwallet/ is ignored by git in this repository.

Keychain Model

When the OS keychain is available, each vault gets a generated passphrase stored under the openwallet service. The account key includes the vault scope and absolute vault path, so local and global vaults are isolated.

Wallet files remain encrypted. The keychain stores only the generated vault passphrase; it never stores mnemonics, private keys, derived keys, or wallet ciphertext directly.

If the keychain is unavailable, openwallet prompts for a vault passphrase and keeps it in memory only for that command. You must enter the same passphrase again for future commands against that vault. If a keychain entry for a generated passphrase is deleted and you do not know that passphrase, the encrypted vault is inaccessible. There is no recovery command and no plaintext fallback.

Wallet Format

Wallet files use private format openwallet-v1. Public account descriptors are readable, while the BIP-39 mnemonic is encrypted under crypto.ciphertext with scrypt plus AES-256-GCM.

The public shape is:

{
  "version": 1,
  "format": "openwallet-v1",
  "profile": "evm",
  "accounts": [
    {
      "index": 0,
      "address": "0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
      "derivationPath": "m/44'/60'/0'/0/0"
    }
  ],
  "crypto": {
    "scheme": "openwallet-secretbox-v1",
    "cipher": "aes-256-gcm",
    "kdf": "scrypt",
    "ciphertext": "..."
  }
}

Wallet creation stores 10 public EVM descriptors for derivation paths m/44'/60'/0'/0/{index}. The encrypted mnemonic is never returned by commands, logged, snapshotted, or stored outside the encrypted wallet file.

Commands

Create a wallet:

openwallet wallet create --name agent
openwallet -g wallet create --name agent

Import a mnemonic:

openwallet wallet import --name agent
printf '%s\n' "$MNEMONIC" | openwallet wallet import --name agent --mnemonic-stdin

List wallets:

openwallet wallet list
openwallet -g wallet list

Inspect vault health:

openwallet wallet doctor
openwallet wallet status
openwallet -g wallet doctor

Show wallet metadata:

openwallet wallet info --name agent

wallet info returns all 10 public EVM account descriptors. The same derived EVM addresses are valid across EVM chains.

Expose a local wallet-backed EVM JSON-RPC proxy:

openwallet wallet proxy --name agent --chain eip155:8453 --rpc-target https://mainnet.base.org
openwallet wallet proxy --name agent --chain eip155:8453 --rpc-target https://mainnet.base.org --unlocked

The proxy listens on 127.0.0.1:9282. It verifies that --rpc-target serves the requested --chain, forwards non-signing JSON-RPC methods to --rpc-target, and signs eth_sign, personal_sign, eth_signTypedData*, eth_signTransaction, and eth_sendTransaction locally when the request targets a managed wallet address and uses a supported EVM transaction shape. For managed transaction signing/sending, the proxy writes a terminal notice when the request is received, simulates with eth_call, writes the simulation result, and only then signs. Anything the local proxy cannot handle is forwarded unchanged to --rpc-target. By default each signing request asks for vault/keychain access. With --unlocked, the vault is unlocked once before the server starts and signing requests reuse that in-memory session.

Sign a UTF-8 message:

openwallet sign message --wallet agent --message "hello"
openwallet sign message --wallet agent --message "hello" --index 9

Sign hex message bytes:

openwallet sign message --wallet agent --message 0x68656c6c6f --encoding hex

Sign a serialized unsigned EVM transaction:

openwallet sign tx --wallet agent --tx 0x...
openwallet sign tx --wallet agent --tx 0x... --index 1

Signing defaults to account index 0. Pass --index 0..9 to sign with one of the cached derived EVM accounts.

Use -g or --global anywhere in a wallet or signing command to select ~/.openwallet instead of the current directory's .openwallet vault.

These are equivalent:

openwallet -g wallet list
openwallet wallet -g list
openwallet wallet list -g
openwallet wallet list --global

Output

Commands return structured data through Incur. For JSON output, use either form:

openwallet wallet list --format json
openwallet wallet list --json

sign tx returns only:

  • signedTransaction
  • transactionHash

Command outputs are designed not to include mnemonics, private keys, vault passphrases, derived keys, decrypted payloads, encrypted ciphertext, or raw keychain values.

EVM Scope

The wallet and offline signing commands are EVM-chain agnostic. sign tx accepts serialized unsigned EVM transaction hex only. It does not accept JSON transaction objects, fetch chain data, estimate gas, choose nonces, or broadcast transactions. If the serialized transaction contains a chain ID, that chain ID is preserved by signing.

wallet proxy is the RPC-aware exception: it requires a canonical EVM CAIP-2 --chain such as eip155:8453, accepts JSON-RPC transaction objects for eth_signTransaction and eth_sendTransaction, asks the target RPC for missing nonce/gas/fee data, simulates with eth_call, signs locally, and forwards eth_sendRawTransaction for broadcasts.

Development

pnpm install
pnpm dev --help
pnpm format
pnpm build
pnpm typecheck
pnpm lint
pnpm test -- --coverage
pnpm audit --prod

Release

This repository uses Changesets for npm releases:

pnpm changeset
pnpm version
pnpm release

The publish workflow runs on pushes to main. It creates a Changesets version PR when changesets are present; merging that PR publishes with pnpm release.

The workflow is configured for npm trusted publishing through GitHub Actions OIDC. Configure the npm package trusted publisher for akshatmittal/openwallet and workflow .github/workflows/publish.yml, or add npm token authentication before relying on automated publishes.

Project conventions:

  • TypeScript source uses the @/* alias for internal imports.
  • Internal source imports are extensionless.
  • Tests mock keychain access and do not use the real OS keychain.
  • Tests do not require network access.

Documentation

  • docs/spec-openwallet-cli.md defines the MVP behavior and boundaries.
  • docs/plan-openwallet-cli.md explains implementation decisions and risks.
  • docs/tasks-openwallet-cli.md tracks the implementation task breakdown.