browser-rpc 0.0.1 → 0.0.3

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 +155 -0
  2. package/dist/index.js +5 -6
  3. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # Browser RPC Proxy
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 script 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 viem
56
+
57
+ ```typescript
58
+ import { createWalletClient, http } from 'viem'
59
+ import { base } from 'viem/chains'
60
+
61
+ const client = createWalletClient({
62
+ chain: base,
63
+ transport: http('http://localhost:8545', {
64
+ timeout: 1000 * 60, // Viem default timeout is 10 seconds
65
+ }),
66
+ })
67
+
68
+ // This will open your browser for approval
69
+ const hash = await client.sendTransaction({
70
+ account: null,
71
+ to: '0x...',
72
+ value: parseEther('0.01'),
73
+ })
74
+ ```
75
+
76
+ ### With Foundry (not tested)
77
+
78
+ ```bash
79
+ # Start the proxy
80
+ browser-rpc --rpc https://mainnet.base.org
81
+
82
+ # In another terminal, run your script
83
+ forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast
84
+ ```
85
+
86
+ ### With Hardhat (not tested)
87
+
88
+ ```javascript
89
+ // hardhat.config.js
90
+ module.exports = {
91
+ networks: {
92
+ browserRpc: {
93
+ url: 'http://localhost:8545',
94
+ },
95
+ },
96
+ }
97
+ ```
98
+
99
+ ```bash
100
+ npx hardhat run scripts/deploy.js --network browserRpc
101
+ ```
102
+
103
+ ## CLI Options
104
+
105
+ | Flag | Default | Description |
106
+ | -------------- | ---------- | -------------------------------- |
107
+ | `--rpc`, `-r` | (required) | Upstream RPC URL for read calls |
108
+ | `--port`, `-p` | `8545` | Port for the proxy server |
109
+ | `--no-open` | `false` | Disable auto-opening the browser |
110
+
111
+ ## How It Works
112
+
113
+ 1. Your script sends `eth_sendTransaction` to the proxy
114
+ 2. The proxy holds the connection open and opens a browser UI
115
+ 3. You connect your wallet and review the transaction
116
+ 4. Click "Execute" to sign and send via your wallet
117
+ 5. The transaction hash is returned to your script
118
+
119
+ Read-only calls (`eth_call`, `eth_getBalance`, etc.) pass through directly to the upstream RPC.
120
+
121
+ ## Supported Methods
122
+
123
+ | Method | Behavior |
124
+ | ---------------------- | ------------------------------ |
125
+ | `eth_sendTransaction` | Opens browser for signing |
126
+ | `eth_signTypedData_v4` | Opens browser for signing |
127
+ | `eth_sign` | Opens browser for signing |
128
+ | Everything else | Passes through to upstream RPC |
129
+
130
+ ## Chain Support
131
+
132
+ The proxy automatically detects the chain from your upstream RPC and configures the UI accordingly. Any EVM-compatible chain is supported.
133
+
134
+ If your wallet is connected to the wrong chain, the UI will prompt you to switch.
135
+
136
+ ## Development
137
+
138
+ ```bash
139
+ # Clone the repo
140
+ git clone https://github.com/gskril/browser-rpc.git
141
+ cd browser-rpc
142
+
143
+ # Install dependencies
144
+ bun install
145
+
146
+ # Build everything
147
+ bun run build
148
+
149
+ # Start the dev server
150
+ bun run dev:server -- --rpc https://mainnet.base.org
151
+ ```
152
+
153
+ ## License
154
+
155
+ 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.3",
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",