browser-rpc 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +152 -0
  2. package/dist/index.js +5 -6
  3. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # browser-rpc
2
+
3
+ A local RPC proxy that routes Ethereum transactions through your browser wallet instead of requiring private keys in `.env` files.
4
+
5
+ ## The Problem
6
+
7
+ Deploying smart contracts requires signing transactions with a private key. Most developers use a separate "deployer" wallet with the key stored in a `.env` file, which:
8
+
9
+ - Is less secure than a browser wallet or hardware wallet
10
+ - Requires maintaining ETH balances across multiple chains
11
+ - Is tedious to set up and manage
12
+
13
+ ## The Solution
14
+
15
+ `browser-rpc` is a local proxy server that intercepts transaction requests from your development tools (Foundry, Hardhat, viem scripts) and routes them through your browser wallet for signing.
16
+
17
+ ```
18
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
19
+ │ Foundry/HH │────▶│ browser-rpc │────▶│ Upstream RPC │
20
+ │ Script │◀────│ (localhost:8545)│◀────│ (Alchemy, etc) │
21
+ └─────────────────┘ └────────┬────────┘ └─────────────────┘
22
+
23
+ │ Opens browser for signing
24
+
25
+ ┌─────────────────┐ ┌─────────────────┐
26
+ │ Web UI │────▶│ Browser Wallet │
27
+ │ (localhost:8545)│◀────│ (MetaMask) │
28
+ └─────────────────┘ └─────────────────┘
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install -g browser-rpc
35
+ ```
36
+
37
+ Or run directly with npx:
38
+
39
+ ```bash
40
+ npx browser-rpc --rpc https://mainnet.base.org
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ 1. Start the proxy server pointing to your target network:
46
+
47
+ ```bash
48
+ browser-rpc --rpc https://mainnet.base.org
49
+ ```
50
+
51
+ 2. Configure your tool to use `http://localhost:8545` as the RPC URL
52
+
53
+ 3. Run your script - when it sends a transaction, your browser will open for approval
54
+
55
+ ### With Foundry
56
+
57
+ ```bash
58
+ # Start the proxy
59
+ browser-rpc --rpc https://mainnet.base.org
60
+
61
+ # In another terminal, run your script
62
+ forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast
63
+ ```
64
+
65
+ ### With Hardhat
66
+
67
+ ```javascript
68
+ // hardhat.config.js
69
+ module.exports = {
70
+ networks: {
71
+ browserRpc: {
72
+ url: 'http://localhost:8545',
73
+ },
74
+ },
75
+ }
76
+ ```
77
+
78
+ ```bash
79
+ npx hardhat run scripts/deploy.js --network browserRpc
80
+ ```
81
+
82
+ ### With viem
83
+
84
+ ```typescript
85
+ import { createWalletClient, http } from 'viem'
86
+ import { base } from 'viem/chains'
87
+
88
+ const client = createWalletClient({
89
+ chain: base,
90
+ transport: http('http://localhost:8545'),
91
+ })
92
+
93
+ // This will open your browser for approval
94
+ const hash = await client.sendTransaction({
95
+ to: '0x...',
96
+ value: parseEther('0.01'),
97
+ })
98
+ ```
99
+
100
+ ## CLI Options
101
+
102
+ | Flag | Default | Description |
103
+ | -------------- | ---------- | -------------------------------- |
104
+ | `--rpc`, `-r` | (required) | Upstream RPC URL for read calls |
105
+ | `--port`, `-p` | `8545` | Port for the proxy server |
106
+ | `--no-open` | `false` | Disable auto-opening the browser |
107
+
108
+ ## How It Works
109
+
110
+ 1. Your script sends `eth_sendTransaction` to the proxy
111
+ 2. The proxy holds the connection open and opens a browser UI
112
+ 3. You connect your wallet and review the transaction
113
+ 4. Click "Execute" to sign and send via your wallet
114
+ 5. The transaction hash is returned to your script
115
+
116
+ Read-only calls (`eth_call`, `eth_getBalance`, etc.) pass through directly to the upstream RPC.
117
+
118
+ ## Supported Methods
119
+
120
+ | Method | Behavior |
121
+ | ---------------------- | ------------------------------ |
122
+ | `eth_sendTransaction` | Opens browser for signing |
123
+ | `eth_signTypedData_v4` | Opens browser for signing |
124
+ | `eth_sign` | Opens browser for signing |
125
+ | Everything else | Passes through to upstream RPC |
126
+
127
+ ## Chain Support
128
+
129
+ The proxy automatically detects the chain from your upstream RPC and configures the UI accordingly. Any EVM-compatible chain is supported.
130
+
131
+ If your wallet is connected to the wrong chain, the UI will prompt you to switch.
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ # Clone the repo
137
+ git clone https://github.com/gskril/browser-rpc.git
138
+ cd browser-rpc
139
+
140
+ # Install dependencies
141
+ bun install
142
+
143
+ # Build everything
144
+ bun run build
145
+
146
+ # Start the dev server
147
+ bun run dev:server -- --rpc https://mainnet.base.org
148
+ ```
149
+
150
+ ## License
151
+
152
+ MIT
package/dist/index.js CHANGED
@@ -3801,7 +3801,6 @@ function createPendingEntry(id, request) {
3801
3801
  request,
3802
3802
  resolve: resolvePromise
3803
3803
  });
3804
- console.log(`\uD83D\uDD10 Pending saved: id=${id} type=${request.type} jsonrpc=${request.jsonRpcId}`);
3805
3804
  setTimeout(() => {
3806
3805
  const entry = pending.get(id);
3807
3806
  if (entry) {
@@ -3854,10 +3853,10 @@ api.post("/tx/:id/hash", async (c) => {
3854
3853
  }
3855
3854
  const request = getPendingRequest(id);
3856
3855
  if (!request) {
3857
- console.warn(`\uD83D\uDD10 Pending missing: id=${id} hash=${body.hash}`);
3856
+ console.warn(`\x1B[31m✗ Unknown request:\x1B[0m ${id}`);
3858
3857
  return c.json({ error: "Request not found or expired" }, 404);
3859
3858
  }
3860
- console.log(`\uD83D\uDD10 Tx submitted: ${body.hash}`);
3859
+ console.log(`\x1B[32m✓ Submitted:\x1B[0m ${body.hash}`);
3861
3860
  return c.json({ ok: true });
3862
3861
  });
3863
3862
  api.post("/complete/:id", async (c) => {
@@ -4093,7 +4092,7 @@ function createServer(config) {
4093
4092
  const body = await c.req.json();
4094
4093
  if (Array.isArray(body)) {
4095
4094
  const methods = body.map((req) => req.method).join(", ");
4096
- console.log(` RPC batch: [${methods}]`);
4095
+ console.log(`\x1B[2m← [${methods}]\x1B[0m`);
4097
4096
  const responses = await Promise.all(body.map((req) => handleRpcRequest(req, {
4098
4097
  upstreamRpcUrl: config.upstreamRpcUrl,
4099
4098
  uiBaseUrl: `http://localhost:${config.port}`,
@@ -4101,7 +4100,7 @@ function createServer(config) {
4101
4100
  })));
4102
4101
  return c.json(responses);
4103
4102
  }
4104
- console.log(` RPC: ${body.method}`);
4103
+ console.log(`\x1B[2m← ${body.method}\x1B[0m`);
4105
4104
  const response = await handleRpcRequest(body, {
4106
4105
  upstreamRpcUrl: config.upstreamRpcUrl,
4107
4106
  uiBaseUrl: `http://localhost:${config.port}`,
@@ -4160,7 +4159,7 @@ var server = createServer({
4160
4159
  port,
4161
4160
  onPendingRequest: (id, url) => {
4162
4161
  console.log(`
4163
- \uD83D\uDD10 Transaction pending: ${url}`);
4162
+ \x1B[33m\u23F3 Awaiting approval:\x1B[0m ${url}`);
4164
4163
  if (options.open) {
4165
4164
  openBrowser(url);
4166
4165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-rpc",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Local RPC proxy that routes Ethereum transactions through your browser wallet",
5
5
  "type": "module",
6
6
  "repository": {
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
- "web-dist"
17
+ "web-dist",
18
+ "README.md"
18
19
  ],
19
20
  "scripts": {
20
21
  "dev": "bun run --watch src/index.ts",