β¦ β¦βββββββ¬ β¬β¬β¬ ββββββ€βββββββββ ββ©ββ΄ β΄βββ ββ β΄β΄ββ
A visual GUI wrapper for Foundry's Anvil
wanvil (Wrapped Anvil) gives your local anvil node a real-time web dashboard.
Browse blocks, transactions, and addresses β start, stop, and restart your node β all from the browser.
Your terminal still works exactly like before.
| Feature | Description | |
|---|---|---|
| π | Block Explorer | Live view of blocks, transactions, and address balances with search |
| β‘ | Node Controls | Start / stop / restart anvil directly from the web UI |
| π | Live Logs | Real-time anvil stdout/stderr streamed into a built-in terminal |
| π | Preset Manager | Save and load encrypted mnemonics β no more copy-pasting seed phrases |
| π | Run History | See all past runs, reload any old config with one click |
| π | Light and Dark Mode | Auto-detected from your system preferences |
| π₯οΈ | Terminal Pass-through | Opt-in with --anvil-logs β everything anvil prints goes to your terminal too |
You need: Node.js 20+ and Foundry (
anvilon your PATH).
npm i -g wanvilNo extra build steps. No postinstall. Ready to go.
wanvilThat's it. Three things happen:
- anvil starts β exactly like running
anvildirectly - GUI available at http://localhost:4269 β the full dashboard
- Terminal stays clean β pass
--anvil-logsto mirror anvil output
Your terminal behaves the same as
anvil. wanvil just adds a browser UI on top.
wanvil accepts all anvil flags directly β no -- separator needed.
wanvil's own flags are silently consumed; everything else goes straight to anvil.
# These are equivalent:
anvil --fork-url https://... --accounts 20
wanvil --fork-url https://... --accounts 20Fork Ethereum mainnet:
wanvil --fork-url https://eth-mainnet.g.alchemy.com/v2/YOUR_KEYFork at a specific block:
wanvil --fork-url https://... --fork-block-number 19000000Fork with more accounts:
wanvil --fork-url https://... --accounts 20Use a custom mnemonic:
wanvil --mnemonic "test test test test test test test test test test test junk"Change the GUI port:
wanvil --gui-port 5000No browser at all (headless, terminal only):
wanvil --no-guiStart GUI and auto-open the browser:
wanvil --open-browser
# or
wanvil -OMirror anvil output to the terminal:
wanvil --anvil-logs
# or
wanvil -ALGUI-only mode (anvil already running externally):
wanvil --no-anvil
# or
wanvil -NIn this mode wanvil won't spawn anvil. It assumes anvil is already running on the standard port.
Print version:
wanvil --version
# or
wanvil -vThese are consumed by wanvil itself. Anvil never sees them.
| Flag | Short | Description | Default |
|---|---|---|---|
--gui-port <port> |
Port for the web dashboard | 4269 |
|
--no-gui |
Disable the web dashboard entirely | false |
|
--open-browser |
-O |
Auto-open the browser on startup | false |
--anvil-logs |
-AL |
Mirror anvil stdout/stderr to the terminal | false |
--no-anvil |
-N |
Don't spawn anvil; assume itβs already running | false |
--version |
-v |
Print wanvil version and exit | β |
--preset <id> |
-p |
Load an encrypted mnemonic preset by ID | β |
--save-preset |
Interactive: encrypt and save a new mnemonic | β | |
--log-level <level> |
Server log level (info, debug, trace, etc.) |
info |
Everything else (like
--fork-url,--accounts,--block-time) passes through to anvil untouched.
When you open the GUI, you land on the Explorer Dashboard. Here's what each page gives you:
The home page shows a quick overview:
- Last Block number
- Recent Transactions count
- Network info (RPC URL, chain ID)
- Latest 5 Blocks with transaction counts
- Latest 5 Transactions with from/to addresses
- Search bar β paste a tx hash, address, or block number to jump straight to it
A paginated table of all blocks on your local chain. Click any block number to see:
- Block hash, parent hash, timestamp
- Gas used / gas limit
- Full list of transactions in that block
List of all transactions. Click any tx hash to see:
- From / To addresses
- Value transferred
- Gas price, gas used
- Input data (calldata)
- Block number where it was mined
Lists the default anvil accounts with their ETH balances. Click any address to see:
- Current balance
- Transaction count (nonce)
- Full transaction history for that address
The node management page. This only shows up when you're connected to a local node and the control server is running. From here you can:
- View live logs in a terminal emulator
- Stop the running node
- Manage presets β save, load, delete encrypted mnemonics
Tired of copy-pasting the same seed phrase? Presets let you save mnemonics locally, encrypted with a password.
Save a preset (interactive prompt):
wanvil --save-presetIt will ask for:
- A label (e.g. "mainnet-fork-dev")
- Your mnemonic phrase
- A password (typed hidden, like
sudo) - Password confirmation
Use a saved preset:
wanvil --preset 1It prompts for your password, decrypts the mnemonic, and injects --mnemonic <decrypted> into the anvil args automatically.
π Encryption: AES-256-GCM with PBKDF2 key derivation. Presets are stored at
~/.config/wanvil/presets.json. Even if someone reads the file, they can't get your mnemonic without the password.
Every time you start anvil through wanvil (either CLI or the web UI), the config is saved to a local SQLite database.
- Open the GUI when anvil is offline β you'll see a "Run History" tab
- Click Load on any past run to pre-fill the config form
- Hit Launch Node to start with that exact config again
This means you never have to remember long fork URLs or block numbers.
If you open the dashboard and anvil isn't running yet, you'll see the "Anvil is not running" screen. From there you can:
- Fill in Fork URL, Fork Block, Mnemonic, and Extra Arguments
- Click Launch Node
- Watch the live logs stream in while the node boots
This requires the control server to be running (it always is when you use
wanvil). If you're usingnpm run devfor the client only, you neednpm run dev:serverin another terminal.
All wanvil data lives in ~/.config/wanvil/:
| File | What it stores |
|---|---|
data.db |
Run history and last-used configuration (SQLite) |
presets.json |
AES-256-GCM encrypted mnemonic presets |
This directory is created automatically on first run. Deleting it resets everything.
wanvil [flags] [...anvil-args]
β
βββ cli/ β parses args, spawns anvil, owns the process
βββ server/ β HTTP + Socket.io control plane (passive)
βββ client/ β React web dashboard
- The CLI owns the anvil child process. It's the single source of truth for process lifecycle.
- The Server is a passive consumer β it receives an
IAnvilBridgeinterface, never spawns anything. - The Client talks to the server over Socket.io and reads the chain directly via JSON-RPC (viem).
Want to hack on wanvil? Here's how to get started.
git clone https://github.com/MrBns/wanvil.git
cd wanvil
npm install
npx prisma generate| Command | What it does |
|---|---|
npm run dev |
Starts the Vite client only at http://localhost:5173 |
npm run dev:server |
Starts the control server only (Socket.io + HTTP) |
npm run dev:cli |
Runs the full CLI with tsx (spawns anvil + server) |
npm run dev:full |
Runs client + CLI together β recommended |
npm run dev:fullThis runs Vite (hot reload on :5173) and the CLI (anvil + control server on :4269) side by side.
Tip: If you only want to work on the UI and already have
anvilrunning separately,npm run devis enough.
βββ shared/ Pure TypeScript interfaces (the contract)
β βββ bridge.ts IAnvilBridge, IPresetManager, IServerConfig
β βββ events.ts Socket.io event types
β βββ args.ts CLI flag definitions
β
βββ cli/ Node.js CLI (process owner)
β βββ src/
β βββ boot.ts Orchestrator
β βββ anvil-bridge.ts IAnvilBridge implementation
β βββ parse-args.ts Smart arg splitter
β βββ preset-manager.ts AES-256-GCM encryption
β
βββ server/ Passive HTTP + Socket.io backend
β βββ src/
β βββ index.ts bootServer() + standalone dev mode
β βββ socket/ Socket event handlers
β βββ services/ DbService (Prisma), RpcHealthService
β βββ http/ Static file server + health probes
β
βββ client/ React 19 SPA
β βββ src/
β βββ pages/ Dashboard, Blocks, Txs, Addresses, Manager
β βββ components/ Sidebar, AnvilProvider, UI primitives
β βββ lib/ Socket client, RPC context, Zustand store
β βββ services/ Blockchain service (viem)
β
βββ prisma/ Database schema (SQLite)
TypeScript Project References compile in order: shared then server then cli. Client is built separately with Vite.
npm run build # prisma generate β tsc --build β vite buildUses Biome (replaces ESLint + Prettier):
npm run lint # check for issues
npm run format # auto-format
npm run check # fix + format in one goserver/must never import fromcli/β that would create a circular dependency.- All cross-layer types go through
shared/βbridge.tsandevents.tsare the contract. - Zero shadows in the UI β the design uses borders and backgrounds, never
shadow-*. - The CLI owns the process β the server is passive, reads from the bridge only.
Client (dev only)
| Variable | Default |
|---|---|
VITE_ANVIL_SOCKET_URL |
http://127.0.0.1:4269 |
In production the client auto-detects from
window.location.
Server
| Variable | Description | Default |
|---|---|---|
PORT |
Server listen port | 3001 |
CORS_ORIGINS |
Comma-separated allowed origins | dev defaults |
LOG_LEVEL |
Pino log level | info |
ANVIL_LOG_BUFFER_SIZE |
Max retained log lines | 1000 |
RPC_PROBE_TIMEOUT_MS |
Health check timeout | 2000 |
HTTP Probes: GET /health Β· GET /live Β· GET /ready
MIT