This file provides context for AI assistants working on this project.
browser-rpc is a local RPC proxy server that intercepts Ethereum transactions from development tools (Foundry, Hardhat) and routes them through a browser wallet for signing. This eliminates the need for developers to manage separate deployer keys with private keys in .env files.
Status: MVP feature-complete, tested with viem scripts and Hardhat
All core components are built and working. The proxy has been tested with Hardhat Ignition deployments.
- Server starts and serves both RPC endpoint and web UI on a single port
- Transaction interception logic is implemented
- Web UI builds and renders
- Wallet connection with custom multi-wallet selector (wagmi v3)
- API endpoints for pending transactions exist
- Full end-to-end flow: script → server → browser → wallet → back to script
- The transfer test script in
packages/scripts/src/transfer.tsis ready to use - Hardhat integration with
--fromflag for account handling
# Terminal 1: Build web UI and start the server
bun run dev:web
bun run dev:server -- --rpc https://mainnet.base.org --from 0xYourWalletAddress
# Terminal 2: Run the test transfer script
bun run packages/scripts/src/transfer.tsNote: The --from flag specifies your wallet address. This is returned for eth_accounts calls, which Hardhat needs for nonce lookups and gas estimation.
When the script runs, it should:
- Call
eth_sendTransactionto localhost:8545 - Server intercepts and opens browser to http://localhost:8545/tx/{uuid}
- User connects wallet and approves transaction
- Transaction hash returns to the script
packages/server/src/index.ts- CLI entry pointpackages/server/src/server.ts- Hono app setup, static file servingpackages/server/src/rpc/handler.ts- RPC request routingpackages/server/src/rpc/methods.ts- Which methods to intercept vs pass-throughpackages/server/src/pending/store.ts- In-memory store for pending transactions
packages/web/src/App.tsx- Main app with providers, async chain loading,useProxyChainhook, color scheme detectionpackages/web/src/components/ConnectButton.tsx- Custom wallet selector with inline multi-wallet supportpackages/web/src/pages/Transaction.tsx- Transaction review/execute page with chain/address mismatch detectionpackages/web/src/lib/wagmi.ts- Dynamic wagmi config (fetches chain from proxy)packages/web/src/hooks/usePendingTransaction.ts- Fetch pending tx datapackages/web/src/hooks/useServerConfig.ts- Fetch server config (--from address)packages/web/src/index.css- Theme variables, light/dark mode via prefers-color-scheme
packages/scripts/src/transfer.ts- Simple ETH transfer for testing
-
Single-port architecture: The server serves both the RPC endpoint (POST /) and the static web UI (GET /*) on the same port (default 8545). No separate dev server needed.
-
No private keys on server: The server never touches private keys. It just forwards the transaction request to the browser, where the wallet handles signing.
-
Wallet executes via proxy: When the user clicks "Execute" in the web UI, the wallet sends the transaction through the proxy server (
http('/')). This ensures all RPC calls go through the same endpoint. -
Promise-based pending store: The server holds the HTTP connection open using a Promise that resolves when the web UI calls
/api/complete/{id}. -
Extensible method routing: To add new intercepted methods, edit
packages/server/src/rpc/methods.ts. -
Dynamic chain detection: The web UI fetches the chain ID from the proxy via
eth_chainIdon startup, then looks up chain metadata from viem's chain list. No hardcoded chains. -
Chain mismatch prevention: The UI compares the proxy's chain with the wallet's connected chain and blocks execution if they don't match, offering a "Switch Chain" button.
-
Account handling: The
--fromflag specifies the wallet address returned foreth_accountsandeth_requestAccountscalls. This is required for Hardhat, which queries the account for nonce lookups and gas estimation before submitting transactions. The address must match the wallet used in the browser. -
UI Design System: Industrial developer-tool aesthetic with sharp edges (no border-radius), system fonts (monospace for addresses/data), and automatic light/dark theming via CSS
prefers-color-scheme. Teal accent color (#00E599 dark, #00A86B light). Custom wallet selector lists all detected injected wallets with inline display. -
Address mismatch warning: The UI fetches
--fromaddress via/api/configand warns if the connected wallet differs. This helps catch configuration errors before transaction submission.
The server package (browser-rpc) is the only published package. Web and scripts are marked private.
Publishing is automated via .github/workflows/publish.yml using npm trusted publishers:
- Create a GitHub release
- The workflow builds and publishes with provenance automatically
First-time setup requires manual publish to create the package on npm, then configure trusted publishers at https://www.npmjs.com/package/browser-rpc/access.
# Dry run (test without publishing)
bun run build && cd packages/server && npm publish --dry-run
# Publish to npm (builds web, bundles into server, publishes with provenance)
bun run publish:serverThe publish script:
- Builds the web package
- Copies
packages/web/disttopackages/server/web-dist - Builds the server package
- Publishes with
--provenance --access public
Note: packages/server/web-dist is gitignored but included in the npm tarball via the files list.
-
Large bundle size: The web UI bundle is large (~1MB) due to wallet connector dependencies and viem's chain list. Could be optimized with code splitting.
-
No persistent config: Users must pass
--rpcevery time. Could add a config file. -
Single chain per session: The upstream RPC is fixed at startup. Multi-chain switching would require changes.
# Install dependencies
bun install
# Build web UI (required before running server)
bun run --filter @browser-rpc/web build
# Run server (serves both RPC and web UI)
bun run packages/server/src/index.ts -- --rpc https://mainnet.base.org --from 0xYourWalletAddress
# Build everything
bun run build
# Run transfer test script
bun run packages/scripts/src/transfer.ts
# Publish to npm
bun run publish:server
# Format code (run after major code changes)
bun run format- Bun: 1.2.8
- Hono: 4.x
- React: 19.2
- Vite: 7.3
- Wagmi: 3.3.2
- viem: 2.44.0
- Tailwind CSS: 4.1
The web UI uses wagmi v3 with a custom wallet selector that:
- Automatically detects all injected browser wallets (MetaMask, Coinbase Wallet, Rabby, etc.)
- Shows an inline list when multiple wallets are detected
- Displays wallet icons and names for easy identification
- Connects directly if only one wallet is installed
- Provides a simple "Back" button to return to the connect state