web3-tools-mcp 3.0.0 → 3.1.0
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.
- package/CHANGELOG.md +86 -2
- package/README.md +76 -52
- package/dist/chain-meta.d.ts.map +1 -1
- package/dist/chain-meta.js +19 -8
- package/dist/chain-meta.js.map +1 -1
- package/dist/clear-signing.d.ts.map +1 -1
- package/dist/clear-signing.js +17 -6
- package/dist/clear-signing.js.map +1 -1
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +9 -3
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/kv-storage.d.ts +2 -1
- package/dist/kv-storage.d.ts.map +1 -1
- package/dist/kv-storage.js +5 -2
- package/dist/kv-storage.js.map +1 -1
- package/dist/oauth.d.ts +18 -4
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +62 -26
- package/dist/oauth.js.map +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +7 -5
- package/dist/preview.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +14 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read/advanced.d.ts +9 -4
- package/dist/tools/read/advanced.d.ts.map +1 -1
- package/dist/tools/read/advanced.js +45 -33
- package/dist/tools/read/advanced.js.map +1 -1
- package/dist/tools/read/balance.d.ts.map +1 -1
- package/dist/tools/read/balance.js +17 -32
- package/dist/tools/read/balance.js.map +1 -1
- package/dist/tools/read/contract-info.d.ts +2 -0
- package/dist/tools/read/contract-info.d.ts.map +1 -1
- package/dist/tools/read/contract-info.js +53 -122
- package/dist/tools/read/contract-info.js.map +1 -1
- package/dist/tools/read/contract.d.ts.map +1 -1
- package/dist/tools/read/contract.js +2 -1
- package/dist/tools/read/contract.js.map +1 -1
- package/dist/tools/read/ens.d.ts +20 -40
- package/dist/tools/read/ens.d.ts.map +1 -1
- package/dist/tools/read/ens.js +25 -33
- package/dist/tools/read/ens.js.map +1 -1
- package/dist/tools/read/gas.d.ts.map +1 -1
- package/dist/tools/read/gas.js +13 -48
- package/dist/tools/read/gas.js.map +1 -1
- package/dist/tools/read/logs.d.ts +61 -0
- package/dist/tools/read/logs.d.ts.map +1 -1
- package/dist/tools/read/logs.js +96 -115
- package/dist/tools/read/logs.js.map +1 -1
- package/dist/tools/read/signatures.d.ts.map +1 -1
- package/dist/tools/read/signatures.js +4 -3
- package/dist/tools/read/signatures.js.map +1 -1
- package/dist/tools/read/signing.d.ts.map +1 -1
- package/dist/tools/read/signing.js +8 -2
- package/dist/tools/read/signing.js.map +1 -1
- package/dist/tools/sign/transactions.d.ts +4 -4
- package/dist/tools/sign/transactions.d.ts.map +1 -1
- package/dist/tools/sign/transactions.js +54 -9
- package/dist/tools/sign/transactions.js.map +1 -1
- package/dist/utils.d.ts +18 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +43 -1
- package/dist/utils.js.map +1 -1
- package/dist/wallet-client.d.ts +1 -0
- package/dist/wallet-client.d.ts.map +1 -1
- package/dist/wallet-client.js +16 -3
- package/dist/wallet-client.js.map +1 -1
- package/package.json +4 -7
- package/src/chain-meta.ts +16 -7
- package/src/clear-signing.ts +15 -9
- package/src/http-server.ts +8 -3
- package/src/index.ts +5 -1
- package/src/kv-storage.ts +6 -3
- package/src/oauth.ts +93 -34
- package/src/preview.ts +7 -5
- package/src/tools/index.ts +12 -1
- package/src/tools/read/advanced.ts +63 -34
- package/src/tools/read/balance.ts +18 -33
- package/src/tools/read/contract-info.ts +64 -144
- package/src/tools/read/contract.ts +2 -1
- package/src/tools/read/ens.ts +26 -33
- package/src/tools/read/gas.ts +13 -50
- package/src/tools/read/logs.ts +131 -143
- package/src/tools/read/signatures.ts +4 -4
- package/src/tools/read/signing.ts +8 -2
- package/src/tools/sign/transactions.ts +60 -9
- package/src/utils.ts +47 -1
- package/src/wallet-client.ts +17 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,75 @@
|
|
|
2
2
|
|
|
3
3
|
Notable changes per release. Dates are release dates; unreleased work sits at the top.
|
|
4
4
|
|
|
5
|
-
## [3.
|
|
5
|
+
## [3.1.0] — 2026-10-01
|
|
6
|
+
|
|
7
|
+
Mostly fixes, several of them for security — worth taking on any hosted server.
|
|
8
|
+
|
|
9
|
+
From this release `web3-wallet-relay` shares the server's version number, jumping from 2.0.0
|
|
10
|
+
to 3.1.0. The two speak one protocol that carries no version of its own, so the package
|
|
11
|
+
version is what matches them: a relay hosted on its own runs at the version of the server
|
|
12
|
+
pointing at it. `web3-tools-mcp` still pins it exactly.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- A host's `Login` can name the `credential` it checks, binding every code and token issued
|
|
17
|
+
under it so that rotating the secret revokes them, and its `page()` is told which client
|
|
18
|
+
is asking and where the code will go.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `trace_transaction`'s `traceType` is `trace`, `prestate` or `stateDiff`. `vmTrace` is gone:
|
|
23
|
+
it ran the prestate tracer under another name, and `stateDiff` asked for a tracer no node
|
|
24
|
+
has. Traces too large for an agent's context are cut short and say so.
|
|
25
|
+
- `get_logs` returns at most 1,000 logs, with `truncated` and the `nextBlock` to continue
|
|
26
|
+
from. `toBlock` is inclusive on both paths, a list in `eventArgs` is an OR filter, and an
|
|
27
|
+
invalid `address` is an error rather than a filter silently dropped.
|
|
28
|
+
- `get_balance`, `read_contract` and `batch_resolve_ens_names` take at most 25 items.
|
|
29
|
+
- ENS tools take `mainnet`, `linea` or `base` — the chains that have a resolver — and the
|
|
30
|
+
no-op `universalResolver` parameter is gone.
|
|
31
|
+
- `render.yaml` is a single service: the relay runs inside the MCP server, as on Fly.
|
|
32
|
+
- Keeping OAuth state in Upstash needs per-field hash expiry (`HEXPIRE`, Redis ≥ 7.4), so
|
|
33
|
+
expired tokens no longer pile up. The file store prunes them on write.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- `send_erc20_token` no longer assumes 18 decimals. It reads them on-chain and refuses a
|
|
38
|
+
`decimals` that disagrees; a token whose decimals cannot be read needs them passed.
|
|
39
|
+
- `write_contract` takes numeric arguments only as safe integers — pass a large uint or int
|
|
40
|
+
as a string — and coerces string arguments to their ABI types, as `read_contract` does.
|
|
41
|
+
- `sign_message` sends the browser the message hex-encoded, as the phone gets it, so both
|
|
42
|
+
sign the same bytes. The phone signs on a chain its session approved, not mainnet.
|
|
43
|
+
- Phone signing on `localhost` is refused up front: the phone has no route to that node. Use
|
|
44
|
+
the browser.
|
|
45
|
+
- The signing preview names each labelled address as `Name (0x…)`, shows token amounts with
|
|
46
|
+
the token's address, and gives an amount whose decimals are unknown as the raw integer,
|
|
47
|
+
marked so, rather than assuming 18. Its summary includes `to`.
|
|
48
|
+
- `get_logs` over Hypersync no longer drops the last block, reports a response cut short
|
|
49
|
+
by the server, or scans from genesis when `fromBlock` is omitted.
|
|
50
|
+
- `get_error_signature` hashes tuple parameters correctly.
|
|
51
|
+
- `get_gas_price` shows sub-gwei L2 prices instead of "0.00", and costs in the chain's own
|
|
52
|
+
native token.
|
|
53
|
+
- An invalid, expired or replayed OAuth code or refresh token answers `invalid_grant`, not a
|
|
54
|
+
500, so connectors re-authorise instead of retrying.
|
|
55
|
+
- Etherscan errors say why ("Invalid API Key", rate limit) rather than "NOTOK".
|
|
56
|
+
- `npx web3-wallet-relay` starts the relay.
|
|
57
|
+
|
|
58
|
+
### Security
|
|
59
|
+
|
|
60
|
+
- The provider API key no longer appears in tool output.
|
|
61
|
+
- `get_ens_avatar` returns the raw avatar record rather than fetching it server-side.
|
|
62
|
+
- Requests carry `expiresAt`, and the signing page cancels an approval that arrives after
|
|
63
|
+
the request timed out or was disconnected. A request that failed any way but an explicit
|
|
64
|
+
rejection now reports `outcome_unknown` — it may still have been broadcast — instead of
|
|
65
|
+
`rejected_or_failed`, so an agent checks before retrying rather than paying twice.
|
|
66
|
+
- The signing page is hardened against script injection and framing, with a strict CSP.
|
|
67
|
+
- OAuth refresh tokens expire, and rotating `MCP_TOKEN` revokes every token issued under
|
|
68
|
+
it — existing tokens predate the binding, so single-token deployments re-authorise once.
|
|
69
|
+
The login page names the client and where it redirects, and cannot be framed.
|
|
70
|
+
`MCP_TRUST_PROXY` lets rate limiting see client addresses behind a proxy.
|
|
71
|
+
- The hosted signer link is no longer written to the logs.
|
|
72
|
+
|
|
73
|
+
## [3.0.0] — 2026-09-26
|
|
6
74
|
|
|
7
75
|
The theme is multi-tenancy: one server can now carry several people without their wallets
|
|
8
76
|
meeting. Nothing turns that on by itself — a server still authenticates its deployment
|
|
@@ -36,6 +104,22 @@ handshake changed, so a mismatched pair cannot pair at all.
|
|
|
36
104
|
tools take `account` to choose between them, as does `disconnect_phone_wallet` — which
|
|
37
105
|
still clears everything when no account is named. With one wallet paired nothing changes,
|
|
38
106
|
and omitting `account` uses the most recently paired.
|
|
107
|
+
- **`simulate_bundle`** runs several transactions in order in one block, each on the state
|
|
108
|
+
the last left — approve then swap, deposit then borrow. Offered with an Alchemy key.
|
|
109
|
+
- **Signing requests outlive their call.** One not approved in time comes back with a
|
|
110
|
+
`requestId`, and `check_signing_request` collects it instead of a second prompt landing in
|
|
111
|
+
the wallet. A phone request returns as soon as the wallet has it, and both signers wait
|
|
112
|
+
for the receipt, reporting mined, reverted or still pending. The signing page shows every
|
|
113
|
+
request waiting, approvable in any order.
|
|
114
|
+
- A host assembling its own server can mount routes, hand a pairing made under a
|
|
115
|
+
placeholder to the address it proved, and draw the pairing QR as SVG (`qrSvg`).
|
|
116
|
+
- The server declares an icon, so a connector list shows more than a letter.
|
|
117
|
+
- `pair_phone_wallet` warns when the same wallet app is already paired, and reports a
|
|
118
|
+
pairing the wallet ended itself.
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- An ERC-721 `Transfer` reads as a token id, not as an ERC-20 transfer of nothing.
|
|
39
123
|
|
|
40
124
|
### Security
|
|
41
125
|
|
|
@@ -177,7 +261,7 @@ sign it.
|
|
|
177
261
|
`call_contract_write` is now `write_contract` — the old pair gave no hint which one
|
|
178
262
|
spent gas. The names now match viem's, and a saved prompt naming the old ones will need
|
|
179
263
|
updating.
|
|
180
|
-
- Every supported chain now lives in one table ([mcp/src/chains.ts](mcp/src/chains.ts)). Adding a
|
|
264
|
+
- Every supported chain now lives in one table ([mcp/src/chains.ts](https://github.com/hajnalben/web3-tools-mcp/blob/main/mcp/src/chains.ts)). Adding a
|
|
181
265
|
chain is a single entry; the tool schemas, RPC selection, explorer links, Hypersync
|
|
182
266
|
routing and `--help` all derive from it.
|
|
183
267
|
- Tool errors surface the underlying failure rather than a re-wrapped message that hid it.
|
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
**Your agent proposes the transaction. You approve it — in your own wallet, on your phone.** 📱
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
32 MCP tools for reading any EVM network and signing transactions in *your own* wallet.
|
|
8
8
|
Every transaction is decoded, named and simulated before you approve it.
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/web3-tools-mcp)
|
|
11
11
|
[](https://www.npmjs.com/package/web3-tools-mcp)
|
|
12
12
|
[](https://nodejs.org)
|
|
13
|
-
[](LICENSE)
|
|
13
|
+
[](https://github.com/hajnalben/web3-tools-mcp/blob/main/LICENSE)
|
|
14
14
|
|
|
15
15
|
</div>
|
|
16
16
|
|
|
@@ -22,7 +22,7 @@ One entry in that client's MCP config:
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
Each app keeps that config somewhere different —
|
|
25
|
-
[the file paths are below ↓](#-setup). You need Node.js ≥ 20; `npx` fetches the rest.
|
|
25
|
+
[the file paths are below ↓](#-setup). You need Node.js ≥ 20.19; `npx` fetches the rest.
|
|
26
26
|
|
|
27
27
|
**ChatGPT, Grok** and **claude.ai** cannot launch anything locally — they only reach a URL.
|
|
28
28
|
[Host it once ↓](#-hosting) and add it as a connector, and there is nothing running on your
|
|
@@ -91,7 +91,7 @@ npx web3-tools-mcp --walletconnect-project-id YOUR_PROJECT_ID
|
|
|
91
91
|
| 💾 | **It sticks.** The session is stored on disk (or in Redis when hosted), so it survives restarts and redeploys. Pair once, not once a day |
|
|
92
92
|
| ✍️ | **You choose each time.** Every signing tool takes a required `signWith`, so the agent asks whether this one goes to your phone or the browser. A paired phone never quietly claims a request |
|
|
93
93
|
| 🧾 | **You still see the decode.** The full preview comes back in the tool response — your wallet shows its own summary, so read ours before you approve theirs |
|
|
94
|
-
| 🔌 | **Drop it any time.** `disconnect_phone_wallet`
|
|
94
|
+
| 🔌 | **Drop it any time.** `disconnect_phone_wallet` drops the wallet you name by `account`, or every session and pairing when you name none |
|
|
95
95
|
|
|
96
96
|
Works with **MetaMask · Rabby · Trust · Coinbase Wallet** — anything speaking WalletConnect v2.
|
|
97
97
|
|
|
@@ -123,28 +123,36 @@ returns the page URL any time you want to open it yourself.
|
|
|
123
123
|
## 🧰 Tools
|
|
124
124
|
|
|
125
125
|
<details>
|
|
126
|
-
<summary><b>
|
|
126
|
+
<summary><b>32 tools</b> — reads, writes, ENS, logs, tracing</summary>
|
|
127
127
|
|
|
128
128
|
### ✍️ Transactions & signing
|
|
129
129
|
| Tool | |
|
|
130
130
|
| --- | --- |
|
|
131
|
-
| `write_contract` | Send a transaction calling a state-changing function, via your wallet |
|
|
131
|
+
| `write_contract` | Send a transaction calling a state-changing function, via your wallet. Pass large integers as strings |
|
|
132
132
|
| `send_native_token` | Send ETH or a native token |
|
|
133
|
-
| `send_erc20_token` | Send an ERC-20 |
|
|
134
|
-
| `sign_message` | Sign a message |
|
|
135
|
-
| `
|
|
133
|
+
| `send_erc20_token` | Send an ERC-20, with decimals read on-chain — a `decimals` you pass must agree |
|
|
134
|
+
| `sign_message` | Sign a message — the same bytes on either signer |
|
|
135
|
+
| `check_signing_request` | Collect a request still awaiting approval, by its `requestId` |
|
|
136
|
+
| `wallet_status` | Every signer and whether it is ready — phone wallets and the browser page |
|
|
136
137
|
| `pair_phone_wallet` | Pair a phone over WalletConnect, returns a QR |
|
|
137
|
-
| `disconnect_phone_wallet` | Drop every
|
|
138
|
+
| `disconnect_phone_wallet` | Drop one paired wallet by `account`, or every session and pairing |
|
|
138
139
|
|
|
139
140
|
The four signing tools take a required `signWith` of `phone` or `browser`. There is no
|
|
140
141
|
default on purpose — the agent has to ask you, so a request never lands on a device you are
|
|
141
|
-
not holding.
|
|
142
|
+
not holding. On `localhost` only the browser can sign; a phone has no route to your node.
|
|
143
|
+
With several phones paired, the optional `account` picks one by address;
|
|
144
|
+
omitted, the most recently paired is used.
|
|
145
|
+
|
|
146
|
+
A request not approved within the call comes back with a `requestId` instead of hanging,
|
|
147
|
+
and `check_signing_request` collects it — asking again would put a second prompt in front
|
|
148
|
+
of your wallet.
|
|
142
149
|
|
|
143
150
|
### 📜 Contracts
|
|
144
151
|
| Tool | |
|
|
145
152
|
| --- | --- |
|
|
146
|
-
| `read_contract` | Read state via view/pure functions — batched, no wallet, no gas |
|
|
153
|
+
| `read_contract` | Read state via view/pure functions — batched (up to 25 calls), no wallet, no gas |
|
|
147
154
|
| `simulate_contract` | Simulate without broadcasting, with gas |
|
|
155
|
+
| `simulate_bundle` | Simulate several transactions in order, each on the state the last left — approve → swap. Needs `ALCHEMY_API_KEY` |
|
|
148
156
|
| `get_contract_abi` | ABI, with proxy detection and verification status |
|
|
149
157
|
| `get_contract_source_code` | Verified source, proxies included |
|
|
150
158
|
| `get_contract_source_file` | One file out of the cached source |
|
|
@@ -157,14 +165,20 @@ not holding.
|
|
|
157
165
|
### ⛓️ Chain data
|
|
158
166
|
| Tool | |
|
|
159
167
|
| --- | --- |
|
|
160
|
-
| `get_balance` | Native or ERC-20 balances — batched |
|
|
161
|
-
| `get_logs` | Query and decode events,
|
|
168
|
+
| `get_balance` | Native or ERC-20 balances — batched, up to 25 queries |
|
|
169
|
+
| `get_logs` | Query and decode events; Hypersync when the RPC refuses the range. At most 1,000 logs — past that it returns `truncated` and the `nextBlock` to continue from. A list in `eventArgs` matches any of its values |
|
|
162
170
|
| `get_block_info` | Block data |
|
|
163
171
|
| `get_storage_at` | Storage slots, with type decoding |
|
|
164
172
|
| `get_gas_price` | Current gas — legacy and EIP-1559 |
|
|
165
173
|
| `estimate_gas` | Gas for any transaction |
|
|
166
|
-
| `trace_transaction` | Call tree,
|
|
167
|
-
| `debug_call` | Trace a call without broadcasting,
|
|
174
|
+
| `trace_transaction` | Call tree, prestate or state diff |
|
|
175
|
+
| `debug_call` | Trace a call without broadcasting, through a node at `ANVIL_RPC_URL` |
|
|
176
|
+
|
|
177
|
+
Tracing prefers an RPC that exposes `debug_*`, and otherwise uses a node you already run at
|
|
178
|
+
`ANVIL_RPC_URL` (default `127.0.0.1:8545`, e.g. `anvil --fork-url …`) — nothing is started
|
|
179
|
+
for you. Replaying a transaction older than the fork re-forks that node, clearing its state,
|
|
180
|
+
so it happens only with `ANVIL_ALLOW_RESET=1`. A hosted server has no default and traces only
|
|
181
|
+
through an explicit `ANVIL_RPC_URL`.
|
|
168
182
|
|
|
169
183
|
### 🏷️ ENS
|
|
170
184
|
| Tool | |
|
|
@@ -172,8 +186,10 @@ not holding.
|
|
|
172
186
|
| `resolve_ens_name` | Name → address |
|
|
173
187
|
| `reverse_resolve_ens` | Address → name |
|
|
174
188
|
| `get_ens_text_record` | Text records |
|
|
175
|
-
| `get_ens_avatar` |
|
|
176
|
-
| `batch_resolve_ens_names` |
|
|
189
|
+
| `get_ens_avatar` | The raw avatar record — URL, data URI or NFT reference, not fetched |
|
|
190
|
+
| `batch_resolve_ens_names` | Up to 25 names at once |
|
|
191
|
+
|
|
192
|
+
ENS tools take `mainnet` (ENS), `linea` (Linea Names) or `base` (Basenames).
|
|
177
193
|
|
|
178
194
|
</details>
|
|
179
195
|
|
|
@@ -196,7 +212,7 @@ not holding.
|
|
|
196
212
|
| Unichain | 130 | ✅ |
|
|
197
213
|
| Localhost | 1337 | ❌ |
|
|
198
214
|
|
|
199
|
-
Adding one is a single entry in [`mcp/src/chains.ts`](mcp/src/chains.ts).
|
|
215
|
+
Adding one is a single entry in [`mcp/src/chains.ts`](https://github.com/hajnalben/web3-tools-mcp/blob/main/mcp/src/chains.ts).
|
|
200
216
|
|
|
201
217
|
</details>
|
|
202
218
|
|
|
@@ -291,7 +307,7 @@ What you lose is reach, not stability — so here is the honest version:
|
|
|
291
307
|
| `WALLETCONNECT_PROJECT_ID` | [walletconnect](https://dashboard.walletconnect.com) | 📱 **No phone signing at all.** Browser wallet only, so a hosted instance has no way to sign |
|
|
292
308
|
| `ALCHEMY_API_KEY`<br>or `INFURA_API_KEY`<br>or `CUSTOM_RPC` | [alchemy](https://alchemy.com) · [infura](https://infura.io) | **No historical state.** Public endpoints answer `403 Archive requests require a personal token`, which takes out balances, storage and calls at a past block, event ranges, and `trace_transaction` |
|
|
293
309
|
| `ETHERSCAN_API_KEY` | [etherscan](https://etherscan.io/apis) | `get_contract_abi`, `get_contract_source_code` and `get_contract_source_file` refuse. Signing previews still decode — they try Sourcify first, then recover the ABI from bytecode |
|
|
294
|
-
| `HYPERSYNC_API_KEY` | [envio](https://envio.dev) |
|
|
310
|
+
| `HYPERSYNC_API_KEY` | [envio](https://envio.dev) | `get_logs` asks the RPC first and falls back to Hypersync when the RPC refuses the range. Without a token that fallback is gone, so wide or past ranges depend on your provider's limits |
|
|
295
311
|
|
|
296
312
|
So with nothing configured you get current balances, contract reads, gas, ENS, simulation
|
|
297
313
|
and browser signing. Add `WALLETCONNECT_PROJECT_ID` for your phone and one provider key for
|
|
@@ -299,7 +315,7 @@ history, and everything above lights up.
|
|
|
299
315
|
|
|
300
316
|
Every key has a matching flag (`--etherscan-api-key`, …), RPC selection falls back
|
|
301
317
|
Alchemy → Infura → public, and `CUSTOM_RPC` overrides all of it.
|
|
302
|
-
`npx web3-tools-mcp --help` lists them; [.env.example](.env.example) documents each one.
|
|
318
|
+
`npx web3-tools-mcp --help` lists them; [.env.example](https://github.com/hajnalben/web3-tools-mcp/blob/main/.env.example) documents each one.
|
|
303
319
|
|
|
304
320
|
```bash
|
|
305
321
|
npx web3-tools-mcp --etherscan-api-key KEY --walletconnect-project-id ID
|
|
@@ -319,26 +335,34 @@ transaction at your phone.
|
|
|
319
335
|
<a href="https://fly.io/docs/launch/"><img src="https://img.shields.io/badge/Deploy%20on-Fly.io-8b5cf6?style=for-the-badge&logo=flydotio&logoColor=white" alt="Deploy on Fly.io" height="32"></a>
|
|
320
336
|
|
|
321
337
|
**Render** reads `render.yaml`, generates `MCP_TOKEN` and asks for `WALLETCONNECT_PROJECT_ID`
|
|
322
|
-
—
|
|
338
|
+
— one click, on a paid `starter` instance with a 1 GB disk so it stays awake and keeps the
|
|
339
|
+
pairing. `MCP_PUBLIC_URL` defaults to the service's `onrender.com` address; set it only for a
|
|
340
|
+
custom domain.
|
|
323
341
|
|
|
324
342
|
**Fly** ships no deploy button, so it is four commands. Worth it for a personal instance:
|
|
325
343
|
volumes come with any plan, so the pairing survives redeploys without paying for a disk.
|
|
326
344
|
|
|
327
345
|
```bash
|
|
328
|
-
fly launch --no-deploy --copy-config
|
|
346
|
+
fly launch --no-deploy --copy-config # then set MCP_PUBLIC_URL in fly.toml to https://<app>.fly.dev
|
|
329
347
|
fly volumes create data --size 1
|
|
330
348
|
fly secrets set MCP_TOKEN=$(openssl rand -hex 24) WALLETCONNECT_PROJECT_ID=<id>
|
|
331
349
|
fly deploy
|
|
332
350
|
```
|
|
333
351
|
|
|
352
|
+
Without the right `MCP_PUBLIC_URL` the OAuth metadata and the wallet links point somewhere
|
|
353
|
+
clients cannot reach. Both `fly.toml` and `render.yaml` set `MCP_TRUST_PROXY=1`, so rate
|
|
354
|
+
limiting sees client addresses rather than the platform's proxy.
|
|
355
|
+
|
|
334
356
|
<details>
|
|
335
357
|
<summary>🐳 <b>Docker, and connecting a client</b></summary>
|
|
336
358
|
|
|
337
359
|
There is a plain `Dockerfile` too, so Railway, Cloud Run or your own box work the same way:
|
|
338
360
|
|
|
339
361
|
```bash
|
|
362
|
+
docker build -t web3-tools-mcp .
|
|
340
363
|
docker run -p 8080:8080 \
|
|
341
364
|
-e MCP_TOKEN=<long random string> \
|
|
365
|
+
-e MCP_PUBLIC_URL=https://your-host \
|
|
342
366
|
-e WALLETCONNECT_PROJECT_ID=<id> \
|
|
343
367
|
web3-tools-mcp
|
|
344
368
|
```
|
|
@@ -352,54 +376,54 @@ claude mcp add --transport http web3-tools https://your-host/mcp \
|
|
|
352
376
|
|
|
353
377
|
Clients that cannot send a header — claude.ai connectors, and the browser and phone apps —
|
|
354
378
|
use OAuth, which the server implements against the same credential: it shows a page asking
|
|
355
|
-
for `MCP_TOKEN` and issues a token once you paste it. No identity provider, no accounts.
|
|
356
|
-
`MCP_PUBLIC_URL` to the address clients reach you on, since OAuth metadata must advertise it.
|
|
379
|
+
for `MCP_TOKEN` and issues a token once you paste it. No identity provider, no accounts.
|
|
357
380
|
|
|
358
381
|
> 🔐 **`MCP_TOKEN` is mandatory** and the server refuses to start without it. Anyone who
|
|
359
382
|
> reaches `/mcp` while your phone is paired can push signing prompts at it. You would still
|
|
360
383
|
> approve each one, but that is a phishing surface, not a feature.
|
|
361
384
|
|
|
385
|
+
| Variable | |
|
|
386
|
+
| --- | --- |
|
|
387
|
+
| `MCP_HTTP_PORT` | Serve over HTTP on this port instead of stdio. Also switches on the hosted guards: no `localhost` chain, no loopback tracing node |
|
|
388
|
+
| `MCP_HTTP_HOST` | Bind address, default `0.0.0.0` |
|
|
389
|
+
| `MCP_TOKEN` | The one credential, as a bearer header or through OAuth. Changing it revokes every OAuth token issued against the old one |
|
|
390
|
+
| `MCP_PUBLIC_URL` | The address clients reach you on — advertised in OAuth metadata and used for wallet links |
|
|
391
|
+
| `MCP_TRUST_PROXY` | Reverse-proxy hops to trust for client IPs in rate limiting. `1` behind Fly or Render; off by default |
|
|
392
|
+
| `MCP_HOSTED` | The hosted guards without `MCP_HTTP_PORT`, for a host assembling its own server from the library |
|
|
393
|
+
| `XDG_CONFIG_HOME` | Where pairings, OAuth tokens and the relay token are stored, under `web3-tools-mcp/` |
|
|
394
|
+
| `UPSTASH_REDIS_REST_URL`<br>`UPSTASH_REDIS_REST_TOKEN` | Keep sessions and tokens in Redis instead. Needs per-field hash expiry (`HEXPIRE`: Upstash, or Redis ≥ 7.4) |
|
|
395
|
+
| `WALLET_TOKEN` | Relay secret. Unset, a hosted server mints one per boot |
|
|
396
|
+
| `WALLET_SERVER_URL` | A separately hosted relay, below |
|
|
397
|
+
| `ANVIL_RPC_URL`<br>`ANVIL_ALLOW_RESET` | Tracing node, and whether it may be re-forked — see Tools |
|
|
398
|
+
|
|
362
399
|
Two things decide whether the pairing survives:
|
|
363
400
|
|
|
364
401
|
- ⏰ **Keep the instance awake.** Sleeping drops the WalletConnect socket, so the first
|
|
365
402
|
transaction after an idle period waits for the host to wake — about a minute on a free tier.
|
|
366
403
|
- 💾 **Give the session somewhere durable.** Most hosts have an ephemeral filesystem, so a
|
|
367
404
|
plain file is lost on redeploy and you rescan the QR. Attach a volume and point
|
|
368
|
-
`XDG_CONFIG_HOME` at it (what `render.yaml`
|
|
369
|
-
`UPSTASH_REDIS_REST_TOKEN` ([Upstash](https://upstash.com)
|
|
405
|
+
`XDG_CONFIG_HOME` at it (what `render.yaml` and `fly.toml` do), or set
|
|
406
|
+
`UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` ([Upstash](https://upstash.com)
|
|
407
|
+
has a free plan).
|
|
370
408
|
|
|
371
409
|
Render's free Key Value instance is not an option here — no persistence, so the pairing
|
|
372
410
|
disappears at its next maintenance.
|
|
373
411
|
|
|
374
412
|
Both signers work on a hosted instance. The signing page is served from the same port as
|
|
375
413
|
`/mcp`, so `https://your-host/#t=<relay token>` is your wallet page — no second service to
|
|
376
|
-
deploy. Ask the agent for `wallet_status` to get the link; it is behind `MCP_TOKEN
|
|
377
|
-
relay
|
|
378
|
-
redeploy.
|
|
414
|
+
deploy. Ask the agent for `wallet_status` to get the link; it is behind `MCP_TOKEN` and never written to the logs. Unless
|
|
415
|
+
you set `WALLET_TOKEN`, the relay secret is minted fresh each boot rather than stored, so the
|
|
416
|
+
URL changes when you redeploy.
|
|
379
417
|
|
|
380
418
|
</details>
|
|
381
419
|
|
|
382
420
|
<details>
|
|
383
421
|
<summary>🖇️ <b>Host the signing page</b> separately</summary>
|
|
384
422
|
|
|
385
|
-
The relay is its own package, [`wallet-relay
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
```bash
|
|
390
|
-
WALLET_TOKEN=<long random string> \
|
|
391
|
-
WALLET_PUBLIC_URL=https://wallet.example.com \
|
|
392
|
-
npx web3-wallet-relay
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
Then point the server at it with `WALLET_SERVER_URL` and the same `WALLET_TOKEN`.
|
|
396
|
-
`render.yaml` deploys it as-is. Anyone holding `WALLET_TOKEN` can send your browser a
|
|
397
|
-
transaction to sign — treat it like a password, and always serve over HTTPS.
|
|
398
|
-
|
|
399
|
-
The pairing link the server prints carries a different token, derived from that one, which
|
|
400
|
-
can only answer signing requests and not make them. Sharing a pairing link is therefore not
|
|
401
|
-
the same as sharing `WALLET_TOKEN` — but it still lets whoever has it act as your wallet
|
|
402
|
-
page, so a signing request can reach them instead of you.
|
|
423
|
+
The relay is its own package, [`web3-wallet-relay`](https://github.com/hajnalben/web3-tools-mcp/tree/main/wallet-relay),
|
|
424
|
+
and runs anywhere that keeps a Node process alive and supports WebSockets. Its README covers
|
|
425
|
+
hosting it; run it at this server's version, then point the server at it with
|
|
426
|
+
`WALLET_SERVER_URL` and the same `WALLET_TOKEN`.
|
|
403
427
|
|
|
404
428
|
Locally nothing changes: the server embeds the same relay.
|
|
405
429
|
|
|
@@ -421,11 +445,11 @@ npm run typecheck
|
|
|
421
445
|
npm test
|
|
422
446
|
```
|
|
423
447
|
|
|
424
|
-
Two workspaces: [`mcp/`](mcp) is this server, [`wallet-relay/`](wallet-relay) is the signing
|
|
425
|
-
page. [CONTRIBUTING.md](CONTRIBUTING.md) covers running a checkout against a client, the
|
|
426
|
-
layout, and how to add a chain or a tool. Releases: [CHANGELOG.md](CHANGELOG.md).
|
|
448
|
+
Two workspaces: [`mcp/`](https://github.com/hajnalben/web3-tools-mcp/tree/main/mcp) is this server, [`wallet-relay/`](https://github.com/hajnalben/web3-tools-mcp/tree/main/wallet-relay) is the signing
|
|
449
|
+
page. [CONTRIBUTING.md](https://github.com/hajnalben/web3-tools-mcp/blob/main/CONTRIBUTING.md) covers running a checkout against a client, the
|
|
450
|
+
layout, and how to add a chain or a tool. Releases: [CHANGELOG.md](https://github.com/hajnalben/web3-tools-mcp/blob/main/CHANGELOG.md).
|
|
427
451
|
|
|
428
|
-
Requires Node.js ≥ 20.
|
|
452
|
+
Requires Node.js ≥ 20.19.
|
|
429
453
|
|
|
430
454
|
## 📄 License
|
|
431
455
|
|
package/dist/chain-meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-meta.d.ts","sourceRoot":"","sources":["../src/chain-meta.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,KAAK,GAAG,EAA8B,MAAM,MAAM,CAAA;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"chain-meta.d.ts","sourceRoot":"","sources":["../src/chain-meta.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,KAAK,GAAG,EAA8B,MAAM,MAAM,CAAA;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAiB3C,wBAAsB,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM;SAP1B,GAAG;YAAU,UAAU,GAAG,SAAS;YAAU,MAAM;WAAS,MAAM;GAwCtG;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM;aAxCrB,MAAM;eAAa,MAAM;GA6DlE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqBjG;AAED,wEAAwE;AACxE,eAAO,MAAM,WAAW,QAAoB,CAAA;AAC5C,eAAO,MAAM,mBAAmB,QAAmB,CAAA"}
|
package/dist/chain-meta.js
CHANGED
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
import { whatsabi } from '@shazow/whatsabi';
|
|
7
7
|
import { parseAbiItem } from 'viem';
|
|
8
8
|
import { getClientManager } from './client.js';
|
|
9
|
+
import { TtlCache } from './utils.js';
|
|
9
10
|
const ERC20_META_ABI = [
|
|
10
11
|
parseAbiItem('function decimals() view returns (uint8)'),
|
|
11
12
|
parseAbiItem('function symbol() view returns (string)')
|
|
12
13
|
];
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
// An hour covers a session's repeats while still noticing an upgraded proxy.
|
|
15
|
+
const TTL_MS = 60 * 60 * 1000;
|
|
16
|
+
const abiCache = new TtlCache(200, TTL_MS);
|
|
17
|
+
const labelCache = new TtlCache(1000, TTL_MS);
|
|
18
|
+
const metaCache = new TtlCache(1000, TTL_MS);
|
|
19
|
+
/** A local node is reset and redeployed at will, so nothing learned from it stays true. */
|
|
20
|
+
const cacheable = (chain) => chain !== 'localhost';
|
|
16
21
|
export async function loadAbi(chain, address) {
|
|
17
22
|
const key = `${chain}:${address.toLowerCase()}`;
|
|
18
23
|
const cached = abiCache.get(key);
|
|
@@ -41,7 +46,8 @@ export async function loadAbi(chain, address) {
|
|
|
41
46
|
proxy: result.address !== address ? result.address : undefined,
|
|
42
47
|
name: result.contractResult?.name ?? undefined
|
|
43
48
|
};
|
|
44
|
-
|
|
49
|
+
if (cacheable(chain))
|
|
50
|
+
abiCache.set(key, loaded);
|
|
45
51
|
return loaded;
|
|
46
52
|
}
|
|
47
53
|
export async function tokenMeta(chain, token) {
|
|
@@ -61,7 +67,9 @@ export async function tokenMeta(chain, token) {
|
|
|
61
67
|
decimals: decimals.status === 'success' ? Number(decimals.result) : undefined,
|
|
62
68
|
symbol: symbol.status === 'success' ? symbol.result : undefined
|
|
63
69
|
};
|
|
64
|
-
|
|
70
|
+
// A failed call may be a flaky RPC rather than a token without that method.
|
|
71
|
+
if (cacheable(chain) && decimals.status === 'success' && symbol.status === 'success')
|
|
72
|
+
metaCache.set(key, meta);
|
|
65
73
|
return meta;
|
|
66
74
|
}
|
|
67
75
|
/**
|
|
@@ -71,8 +79,9 @@ export async function tokenMeta(chain, token) {
|
|
|
71
79
|
*/
|
|
72
80
|
export async function addressLabel(chain, address) {
|
|
73
81
|
const key = `${chain}:${address.toLowerCase()}`;
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
const cached = labelCache.get(key);
|
|
83
|
+
if (cached)
|
|
84
|
+
return cached.label;
|
|
76
85
|
let label;
|
|
77
86
|
try {
|
|
78
87
|
const code = await getClientManager()
|
|
@@ -86,8 +95,10 @@ export async function addressLabel(chain, address) {
|
|
|
86
95
|
}
|
|
87
96
|
catch {
|
|
88
97
|
// Unknown address — show it bare rather than failing the preview.
|
|
98
|
+
return undefined;
|
|
89
99
|
}
|
|
90
|
-
|
|
100
|
+
if (cacheable(chain))
|
|
101
|
+
labelCache.set(key, { label });
|
|
91
102
|
return label;
|
|
92
103
|
}
|
|
93
104
|
/** uint256 max and anything near it means "infinite" in an approval. */
|
package/dist/chain-meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-meta.js","sourceRoot":"","sources":["../src/chain-meta.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAA0B,YAAY,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"chain-meta.js","sourceRoot":"","sources":["../src/chain-meta.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clear-signing.d.ts","sourceRoot":"","sources":["../src/clear-signing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;GAMG;AAEH,UAAU,UAAU;IAElB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CAC7E;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB;AAED,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAkCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAiBD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;
|
|
1
|
+
{"version":3,"file":"clear-signing.d.ts","sourceRoot":"","sources":["../src/clear-signing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;GAMG;AAEH,UAAU,UAAU;IAElB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CAC7E;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB;AAED,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAkCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAiBD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAqED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAKxF;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,SAAS,EAChB,EAAE,EAAE,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiBlC"}
|
package/dist/clear-signing.js
CHANGED
|
@@ -80,11 +80,22 @@ async function formatField(chain, field, root, tx) {
|
|
|
80
80
|
case 'amount': {
|
|
81
81
|
const amount = typeof raw === 'bigint' ? raw : BigInt(raw);
|
|
82
82
|
const token = field.params?.tokenAddress ?? (field.params?.tokenPath ? resolvePath(root, tx, field.params.tokenPath) : undefined);
|
|
83
|
-
const
|
|
84
|
-
|
|
83
|
+
const tokenAddress = typeof token === 'string' && isAddress(token) ? getAddress(token) : undefined;
|
|
84
|
+
const meta = tokenAddress
|
|
85
|
+
? await tokenMeta(chain, tokenAddress).catch(() => ({ symbol: undefined, decimals: undefined }))
|
|
85
86
|
: { symbol: undefined, decimals: undefined };
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
// `amount` is the native currency, which always has 18 decimals.
|
|
88
|
+
const decimals = meta.decimals ?? (format === 'amount' && !tokenAddress ? 18 : undefined);
|
|
89
|
+
// symbol() is whatever the token contract says it is, so the address always goes with it.
|
|
90
|
+
const symbol = `${meta.symbol ? ` ${meta.symbol}` : ''}${tokenAddress ? ` (${tokenAddress})` : ''}`;
|
|
91
|
+
if (tokenAddress)
|
|
92
|
+
out.address = tokenAddress;
|
|
93
|
+
if (amount > UNLIMITED_THRESHOLD)
|
|
94
|
+
out.value = `Unlimited${symbol}`;
|
|
95
|
+
else if (decimals === undefined)
|
|
96
|
+
out.value = `${amount}${symbol} (decimals unknown)`;
|
|
97
|
+
else
|
|
98
|
+
out.value = `${formatUnits(amount, decimals)}${symbol}`;
|
|
88
99
|
return out;
|
|
89
100
|
}
|
|
90
101
|
case 'addressName':
|
|
@@ -95,10 +106,10 @@ async function formatField(chain, field, root, tx) {
|
|
|
95
106
|
return out;
|
|
96
107
|
}
|
|
97
108
|
const address = getAddress(raw);
|
|
98
|
-
const name =
|
|
109
|
+
const name = lookupContract(chain, address)?.protocol;
|
|
99
110
|
out.address = address;
|
|
100
111
|
out.name = name ? protocolLabel(name) : await addressLabel(chain, address).catch(() => undefined);
|
|
101
|
-
out.value = out.name
|
|
112
|
+
out.value = out.name ? `${out.name} (${address})` : address;
|
|
102
113
|
return out;
|
|
103
114
|
}
|
|
104
115
|
default:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clear-signing.js","sourceRoot":"","sources":["../src/clear-signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAiD9C,6EAA6E;AAC7E,MAAM,eAAe,GAA2B;IAC9C,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,YAAY;IACxB,GAAG,EAAE,KAAK;CACX,CAAA;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,IAAI,KAA6C,CAAA;AAEjD,qEAAqE;AACrE,SAAS,QAAQ;IACf,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAA;YACvD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,GAAG,EAAE,CAAA;QACZ,CAAC;IACH,CAAC;IACD,OAAO,KAAmC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;AACtC,CAAC;AAED,6FAA6F;AAC7F,SAAS,SAAS,CAAC,IAAa,EAAE,IAAY;IAC5C,IAAI,OAAO,GAAY,IAAI,CAAA;IAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAI,OAAO,IAAI,IAAI;YAAE,OAAO,SAAS,CAAA;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;QAC5C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC1G,CAAC;aAAM,CAAC;YACN,OAAO,GAAI,OAAmC,CAAC,IAAI,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAQD,SAAS,WAAW,CAAC,IAAa,EAAE,EAAa,EAAE,IAAY;IAC7D,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC,EAAE,CAAA;QACxC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,OAAO,EAAE,CAAC,KAAK,CAAA;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM;YAAE,OAAO,EAAE,CAAC,IAAI,CAAA;QAC5C,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAgB,EAAE,KAAiB,EAAE,IAAa,EAAE,EAAa;IAC1F,iEAAiE;IACjE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC9G,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,MAAM,CAAA;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACtE,MAAM,GAAG,GAAsB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAE3D,mEAAmE;IACnE,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAA;QAC5B,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,aAAa,CAAC;QACnB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAsB,CAAC,CAAA;YAC7E,MAAM,KAAK,GACT,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAErH,MAAM,
|
|
1
|
+
{"version":3,"file":"clear-signing.js","sourceRoot":"","sources":["../src/clear-signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAiD9C,6EAA6E;AAC7E,MAAM,eAAe,GAA2B;IAC9C,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,YAAY;IACxB,GAAG,EAAE,KAAK;CACX,CAAA;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,IAAI,KAA6C,CAAA;AAEjD,qEAAqE;AACrE,SAAS,QAAQ;IACf,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAA;YACvD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,GAAG,EAAE,CAAA;QACZ,CAAC;IACH,CAAC;IACD,OAAO,KAAmC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;AACtC,CAAC;AAED,6FAA6F;AAC7F,SAAS,SAAS,CAAC,IAAa,EAAE,IAAY;IAC5C,IAAI,OAAO,GAAY,IAAI,CAAA;IAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAI,OAAO,IAAI,IAAI;YAAE,OAAO,SAAS,CAAA;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;QAC5C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC1G,CAAC;aAAM,CAAC;YACN,OAAO,GAAI,OAAmC,CAAC,IAAI,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAQD,SAAS,WAAW,CAAC,IAAa,EAAE,EAAa,EAAE,IAAY;IAC7D,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC,EAAE,CAAA;QACxC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,OAAO,EAAE,CAAC,KAAK,CAAA;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM;YAAE,OAAO,EAAE,CAAC,IAAI,CAAA;QAC5C,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAgB,EAAE,KAAiB,EAAE,IAAa,EAAE,EAAa;IAC1F,iEAAiE;IACjE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC9G,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,MAAM,CAAA;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACtE,MAAM,GAAG,GAAsB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAE3D,mEAAmE;IACnE,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAA;QAC5B,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,aAAa,CAAC;QACnB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAsB,CAAC,CAAA;YAC7E,MAAM,KAAK,GACT,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAErH,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAClG,MAAM,IAAI,GAAG,YAAY;gBACvB,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;gBAChG,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAA;YAC9C,iEAAiE;YACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAEzF,0FAA0F;YAC1F,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;YACnG,IAAI,YAAY;gBAAE,GAAG,CAAC,OAAO,GAAG,YAAY,CAAA;YAC5C,IAAI,MAAM,GAAG,mBAAmB;gBAAE,GAAG,CAAC,KAAK,GAAG,YAAY,MAAM,EAAE,CAAA;iBAC7D,IAAI,QAAQ,KAAK,SAAS;gBAAE,GAAG,CAAC,KAAK,GAAG,GAAG,MAAM,GAAG,MAAM,qBAAqB,CAAA;;gBAC/E,GAAG,CAAC,KAAK,GAAG,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAA;YAC5D,OAAO,GAAG,CAAA;QACZ,CAAC;QAED,KAAK,aAAa,CAAC;QACnB,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,SAAS,CAAC,GAAa,CAAC,EAAE,CAAC;gBAC9B,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;gBACvB,OAAO,GAAG,CAAA;YACZ,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAa,CAAC,CAAA;YACzC,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAA;YACrD,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;YACrB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YACjG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,CAAA;YAC3D,OAAO,GAAG,CAAA;QACZ,CAAC;QAED;YACE,GAAG,CAAC,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAClE,OAAO,GAAG,CAAA;IACd,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,KAAgB,EAAE,OAAe;IAC9D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IACpD,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAAgB,EAChB,EAAiC,EACjC,WAAoC;IAEpC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,IAAI,CAAA;IAEhD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;IACnE,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAElC,4EAA4E;IAC5E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAA;IACzE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAEnG,OAAO;QACL,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,YAAY,EAAE,MAAM,CAAC,IAAI;QACzB,MAAM;KACP,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mDAAmD,CAAA;AAE5F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAoBpD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wFAAwF;IACxF,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,eAAe,EAAE,MAAM,SAAS,CAAA;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,gGAAgG;IAChG,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAChC;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mDAAmD,CAAA;AAE5F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAoBpD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wFAAwF;IACxF,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,eAAe,EAAE,MAAM,SAAS,CAAA;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,gGAAgG;IAChG,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAChC;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkG5H"}
|
package/dist/http-server.js
CHANGED
|
@@ -25,7 +25,7 @@ export async function startHttpServer(options) {
|
|
|
25
25
|
if (!HOSTED) {
|
|
26
26
|
throw new Error('Serving over HTTP needs MCP_HOSTED=1 (or MCP_HTTP_PORT) in the environment before web3-tools-mcp is imported');
|
|
27
27
|
}
|
|
28
|
-
const port = options.port ?? Number(process.env.MCP_HTTP_PORT)
|
|
28
|
+
const port = options.port ?? (Number(process.env.MCP_HTTP_PORT) || DEFAULT_PORT);
|
|
29
29
|
const host = options.host ?? process.env.MCP_HTTP_HOST ?? '0.0.0.0';
|
|
30
30
|
const token = options.token ?? process.env.MCP_TOKEN;
|
|
31
31
|
// A reachable MCP server with a paired phone can push signing prompts at that phone. It
|
|
@@ -38,6 +38,12 @@ export async function startHttpServer(options) {
|
|
|
38
38
|
const issuer = new URL(publicUrl);
|
|
39
39
|
const provider = options.provider ?? new SingleUserOAuthProvider(token);
|
|
40
40
|
const app = express();
|
|
41
|
+
// The auth routes rate-limit per req.ip, which behind a platform proxy is the proxy's own
|
|
42
|
+
// address — every caller would share one bucket. Only trust as many hops as are really
|
|
43
|
+
// in front, or anyone could pick their own bucket with a forged X-Forwarded-For.
|
|
44
|
+
const proxyHops = Number(process.env.MCP_TRUST_PROXY);
|
|
45
|
+
if (proxyHops)
|
|
46
|
+
app.set('trust proxy', proxyHops);
|
|
41
47
|
app.use(express.json());
|
|
42
48
|
// The login form posts a token, so the authorize route needs form bodies too.
|
|
43
49
|
app.use(express.urlencoded({ extended: false }));
|
|
@@ -81,8 +87,8 @@ export async function startHttpServer(options) {
|
|
|
81
87
|
}
|
|
82
88
|
});
|
|
83
89
|
const server = await new Promise((resolve, reject) => {
|
|
84
|
-
|
|
85
|
-
listening.
|
|
90
|
+
// Express 5 hands a listen error to this callback rather than leaving it to 'error'.
|
|
91
|
+
const listening = app.listen(port, host, (error) => (error ? reject(error) : resolve(listening)));
|
|
86
92
|
});
|
|
87
93
|
// The signing page rides on this same server, so a hosted deployment can offer browser
|
|
88
94
|
// signing without a second service: one platform port serves both /mcp and the page.
|
package/dist/http-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gEAAgE,CAAA;AAElG,OAAO,EAAE,oCAAoC,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAA;AAErH,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAClG,OAAO,OAAyB,MAAM,SAAS,CAAA;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAEpD;;;;;;;;;;;;GAYG;AAEH,MAAM,YAAY,GAAG,IAAI,CAAA;AAwBzB,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA0B;IAC9D,sFAAsF;IACtF,qFAAqF;IACrF,yBAAyB;IACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8GAA8G,CAC/G,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
|