safehands-pharos 1.2.6 → 1.4.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/.env.example +64 -26
- package/README.md +333 -445
- package/dist/cli.d.ts +5 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +124 -98
- package/dist/cli.js.map +1 -1
- package/dist/demo.d.ts +1 -1
- package/dist/demo.js +171 -171
- package/dist/index.d.ts +2 -2
- package/dist/index.js +138 -87
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +65 -65
- package/dist/lib/auditLog.d.ts +9 -0
- package/dist/lib/auditLog.d.ts.map +1 -0
- package/dist/lib/auditLog.js +30 -0
- package/dist/lib/auditLog.js.map +1 -0
- package/dist/lib/constants.d.ts +291 -291
- package/dist/lib/constants.js +292 -292
- package/dist/lib/dodoApi.d.ts +78 -70
- package/dist/lib/dodoApi.d.ts.map +1 -1
- package/dist/lib/dodoApi.js +196 -178
- package/dist/lib/dodoApi.js.map +1 -1
- package/dist/lib/http.d.ts +14 -14
- package/dist/lib/http.js +118 -118
- package/dist/lib/pharosClient.d.ts +58 -58
- package/dist/lib/pharosClient.d.ts.map +1 -1
- package/dist/lib/pharosClient.js +63 -53
- package/dist/lib/pharosClient.js.map +1 -1
- package/dist/lib/policy/actionPolicyEngine.d.ts +53 -53
- package/dist/lib/policy/actionPolicyEngine.js +212 -212
- package/dist/lib/policy/actionPolicyEngine.js.map +1 -1
- package/dist/lib/riskEngine.d.ts +26 -26
- package/dist/lib/riskEngine.js +283 -283
- package/dist/lib/signer/index.d.ts +24 -24
- package/dist/lib/signer/index.d.ts.map +1 -1
- package/dist/lib/signer/index.js +88 -89
- package/dist/lib/signer/index.js.map +1 -1
- package/dist/lib/spendAccumulator.d.ts +10 -0
- package/dist/lib/spendAccumulator.d.ts.map +1 -0
- package/dist/lib/spendAccumulator.js +54 -0
- package/dist/lib/spendAccumulator.js.map +1 -0
- package/dist/lib/testDodoLive.d.ts +1 -1
- package/dist/lib/testDodoLive.js +104 -104
- package/dist/lib/testLiveSafehands.d.ts +1 -1
- package/dist/lib/testLiveSafehands.js +92 -92
- package/dist/lib/testRpc.d.ts +1 -1
- package/dist/lib/testRpc.js +29 -29
- package/dist/lib/testRpcLive.d.ts +1 -1
- package/dist/lib/testRpcLive.js +88 -88
- package/dist/lib/testTools.d.ts +1 -1
- package/dist/lib/testTools.js +397 -397
- package/dist/lib/testX402Live.d.ts +1 -1
- package/dist/lib/testX402Live.js +159 -159
- package/dist/lib/toolResponse.d.ts +25 -25
- package/dist/lib/toolResponse.js +53 -53
- package/dist/lib/wallet/index.d.ts +37 -18
- package/dist/lib/wallet/index.d.ts.map +1 -1
- package/dist/lib/wallet/index.js +128 -70
- package/dist/lib/wallet/index.js.map +1 -1
- package/dist/scripts/checkDeploy.d.ts +1 -1
- package/dist/scripts/checkDeploy.js +24 -24
- package/dist/scripts/deployRegistry.d.ts +1 -1
- package/dist/scripts/deployRegistry.js +100 -100
- package/dist/scripts/testRegistry.d.ts +1 -1
- package/dist/scripts/testRegistry.js +43 -43
- package/dist/tools/approveToken.d.ts +45 -46
- package/dist/tools/approveToken.d.ts.map +1 -1
- package/dist/tools/approveToken.js +85 -83
- package/dist/tools/approveToken.js.map +1 -1
- package/dist/tools/assessRisk.d.ts +79 -79
- package/dist/tools/assessRisk.d.ts.map +1 -1
- package/dist/tools/assessRisk.js +104 -93
- package/dist/tools/assessRisk.js.map +1 -1
- package/dist/tools/checkAllowance.d.ts +43 -36
- package/dist/tools/checkAllowance.d.ts.map +1 -1
- package/dist/tools/checkAllowance.js +56 -42
- package/dist/tools/checkAllowance.js.map +1 -1
- package/dist/tools/checkTokenSecurity.d.ts +46 -46
- package/dist/tools/checkTokenSecurity.d.ts.map +1 -1
- package/dist/tools/checkTokenSecurity.js +95 -88
- package/dist/tools/checkTokenSecurity.js.map +1 -1
- package/dist/tools/createAgentWallet.d.ts +26 -26
- package/dist/tools/createAgentWallet.d.ts.map +1 -1
- package/dist/tools/createAgentWallet.js +58 -59
- package/dist/tools/createAgentWallet.js.map +1 -1
- package/dist/tools/estimateGas.d.ts +79 -79
- package/dist/tools/estimateGas.js +124 -124
- package/dist/tools/executeSwap.d.ts +61 -59
- package/dist/tools/executeSwap.d.ts.map +1 -1
- package/dist/tools/executeSwap.js +141 -129
- package/dist/tools/executeSwap.js.map +1 -1
- package/dist/tools/explainRisk.d.ts +29 -29
- package/dist/tools/explainRisk.js +32 -32
- package/dist/tools/getAgentWallet.d.ts +21 -21
- package/dist/tools/getAgentWallet.js +27 -27
- package/dist/tools/getAgentWalletBalance.d.ts +11 -11
- package/dist/tools/getAgentWalletBalance.js +70 -70
- package/dist/tools/getExecutionHistory.d.ts +49 -51
- package/dist/tools/getExecutionHistory.d.ts.map +1 -1
- package/dist/tools/getExecutionHistory.js +154 -93
- package/dist/tools/getExecutionHistory.js.map +1 -1
- package/dist/tools/getGasPrice.d.ts +43 -43
- package/dist/tools/getGasPrice.js +59 -59
- package/dist/tools/getPoolInfo.d.ts +75 -75
- package/dist/tools/getPoolInfo.js +137 -137
- package/dist/tools/getTokenPrice.d.ts +113 -113
- package/dist/tools/getTokenPrice.js +117 -117
- package/dist/tools/getTransactionStatus.d.ts +43 -57
- package/dist/tools/getTransactionStatus.d.ts.map +1 -1
- package/dist/tools/getTransactionStatus.js +59 -67
- package/dist/tools/getTransactionStatus.js.map +1 -1
- package/dist/tools/getWalletBalance.d.ts +68 -68
- package/dist/tools/getWalletBalance.js +87 -87
- package/dist/tools/publishRiskScore.d.ts +63 -63
- package/dist/tools/publishRiskScore.d.ts.map +1 -1
- package/dist/tools/publishRiskScore.js +88 -85
- package/dist/tools/publishRiskScore.js.map +1 -1
- package/dist/tools/queryRiskRegistry.d.ts +38 -48
- package/dist/tools/queryRiskRegistry.d.ts.map +1 -1
- package/dist/tools/queryRiskRegistry.js +55 -60
- package/dist/tools/queryRiskRegistry.js.map +1 -1
- package/dist/tools/safehandsPreflightCheck.d.ts +77 -77
- package/dist/tools/safehandsPreflightCheck.js +47 -47
- package/dist/tools/safehandsRiskReport.d.ts +81 -81
- package/dist/tools/safehandsRiskReport.js +28 -28
- package/dist/tools/safehandsSafeExecute.d.ts +20 -20
- package/dist/tools/safehandsSafeExecute.d.ts.map +1 -1
- package/dist/tools/safehandsSafeExecute.js +81 -75
- package/dist/tools/safehandsSafeExecute.js.map +1 -1
- package/dist/tools/safehandsWalletHealth.d.ts +14 -14
- package/dist/tools/safehandsWalletHealth.js +103 -103
- package/dist/tools/safehandsX402Preflight.d.ts +26 -26
- package/dist/tools/safehandsX402Preflight.js +65 -65
- package/dist/tools/sendPayment.d.ts +57 -58
- package/dist/tools/sendPayment.d.ts.map +1 -1
- package/dist/tools/sendPayment.js +117 -108
- package/dist/tools/sendPayment.js.map +1 -1
- package/dist/tools/simulateTransaction.d.ts +60 -81
- package/dist/tools/simulateTransaction.d.ts.map +1 -1
- package/dist/tools/simulateTransaction.js +83 -88
- package/dist/tools/simulateTransaction.js.map +1 -1
- package/dist/tools/tokenRegistryStatus.d.ts +26 -26
- package/dist/tools/tokenRegistryStatus.js +96 -96
- package/dist/tools/x402PayAndFetch.d.ts +81 -81
- package/dist/tools/x402PayAndFetch.d.ts.map +1 -1
- package/dist/tools/x402PayAndFetch.js +152 -149
- package/dist/tools/x402PayAndFetch.js.map +1 -1
- package/dist/x402Server.d.ts +1 -1
- package/dist/x402Server.js +252 -252
- package/examples/dashboard/index.html +337 -0
- package/package.json +83 -82
- package/skill/SKILL.md +133 -133
package/README.md
CHANGED
|
@@ -1,445 +1,333 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
|
|
3
|
-
<img src="https://img.shields.io/badge/MCP_Skill-000000?style=for-the-badge" />
|
|
4
|
-
<img src="https://img.shields.io/badge/Pharos_Atlantic-688689-blueviolet?style=for-the-badge" />
|
|
5
|
-
<img src="https://img.shields.io/badge/Tools-27-orange?style=for-the-badge" />
|
|
6
|
-
<img src="https://img.shields.io/badge/Testnet_Only-SAFE-blue?style=for-the-badge" />
|
|
7
|
-
</p>
|
|
8
|
-
|
|
9
|
-
# SafeHands-Pharos
|
|
10
|
-
|
|
11
|
-
SafeHands
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
###
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
|
237
|
-
|
|
238
|
-
| `
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
The reference files teach the Skill Engine how to call SafeHands through terminal commands such as:
|
|
335
|
-
|
|
336
|
-
```bash
|
|
337
|
-
npx safehands-pharos skill safehands_preflight_check --input-json '<json>'
|
|
338
|
-
npx safehands-pharos skill safehands_x402_preflight --input-json '<json>'
|
|
339
|
-
npx safehands-pharos skill safehands_wallet_health --input-json '{}'
|
|
340
|
-
npx safehands-pharos skill token_registry_status --input-json '{"tokenAddress":"0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8"}'
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
Use SafeHands before Pharos Skill Engine performs write actions. SafeHands complements the Skill Engine and should not be treated as a replacement.
|
|
344
|
-
|
|
345
|
-
---
|
|
346
|
-
|
|
347
|
-
## Security Guardrails
|
|
348
|
-
|
|
349
|
-
SafeHands defaults to defensive behavior:
|
|
350
|
-
|
|
351
|
-
- `WRITE_TOOLS_ENABLED=false` by default.
|
|
352
|
-
- `WALLET_MODE=none` by default.
|
|
353
|
-
- No wallet is created on install, import, or startup.
|
|
354
|
-
- Managed wallets are created only through `create_agent_wallet`.
|
|
355
|
-
- Private keys are never returned in MCP or CLI responses.
|
|
356
|
-
- Private keys and payment proofs are not logged.
|
|
357
|
-
- Unlimited approvals are blocked unless explicitly allowed.
|
|
358
|
-
- SSRF-sensitive x402 URLs are blocked unless local testing is explicitly enabled.
|
|
359
|
-
- Mainnet actions are blocked.
|
|
360
|
-
- External API failures return structured errors rather than crashing tool calls.
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
## Demo
|
|
365
|
-
|
|
366
|
-
Run:
|
|
367
|
-
|
|
368
|
-
```bash
|
|
369
|
-
npm run demo
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
or:
|
|
373
|
-
|
|
374
|
-
```bash
|
|
375
|
-
npx safehands-pharos --demo
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
The default demo is deterministic and non-destructive. It shows wallet health, allowed preflight, blocked approval, token registry status, x402 preflight, free x402 endpoint behavior, paid x402 without signer, SSRF blocking, write-tool blocking, and a human-readable risk explanation.
|
|
379
|
-
|
|
380
|
-
---
|
|
381
|
-
|
|
382
|
-
## Real Testnet Verification
|
|
383
|
-
|
|
384
|
-
SafeHands includes live verification commands that test against real Pharos Atlantic Testnet infrastructure:
|
|
385
|
-
|
|
386
|
-
| Command | What it does | Requires |
|
|
387
|
-
|---------|-------------|----------|
|
|
388
|
-
| `npm run test:rpc:live` | Reads chain ID, block number, optional wallet balance from live RPC | Network access |
|
|
389
|
-
| `npm run test:live:safehands` | Runs 7 CLI safety checks against built dist (no broadcast) | Built dist |
|
|
390
|
-
| `npm run test:x402:live` | Tests x402 free/paid endpoint behavior locally | Nothing |
|
|
391
|
-
| `npm run test:dodo:live` | Tests DODO API route if `DODO_API_KEY` set; skips cleanly if not | `DODO_API_KEY` (optional) |
|
|
392
|
-
|
|
393
|
-
**Important distinctions:**
|
|
394
|
-
|
|
395
|
-
1. **Live RPC checks** (`test:rpc`, `test:rpc:live`) connect to the real Pharos Atlantic Testnet RPC and read chain ID + block number.
|
|
396
|
-
2. **Live CLI checks** (`test:live:safehands`) run real CLI invocations against built dist, testing policy decisions deterministically.
|
|
397
|
-
3. **x402 behavior checks** (`test:x402:live`) use a **local test server** labeled `LOCAL_X402_SERVER_DOCS_BEHAVIOR_TEST`. They do not connect to a remote Pharos x402 endpoint.
|
|
398
|
-
4. **DODO checks** (`test:dodo:live`) performs live read-only DODO/FaroSwap checks when `DODO_API_KEY` is configured. The public API key can be provided through an environment variable. The key is not required for the normal deterministic demo. A missing key results in a clean skip. A live API pass does not automatically make router addresses docs-verified.
|
|
399
|
-
5. **Smoke tests** (`test:all`) are deterministic and do not require network connectivity (except DODO/RPC-dependent tools, which degrade gracefully).
|
|
400
|
-
6. **Address verification statuses** (DOCS_VERIFIED, DOCS_DEMO_NON_OFFICIAL, PROJECT_CONFIGURED) are sourced from `docs/reports/OFFICIAL_DOCS_ALIGNMENT_REPORT.md`.
|
|
401
|
-
7. **No real transactions are broadcast by default.** Write tools require explicit `WRITE_TOOLS_ENABLED=true`.
|
|
402
|
-
|
|
403
|
-
---
|
|
404
|
-
|
|
405
|
-
## Tests and Validation
|
|
406
|
-
|
|
407
|
-
```bash
|
|
408
|
-
npm ci
|
|
409
|
-
npm run build
|
|
410
|
-
npx tsc -p tsconfig.all.json --pretty false
|
|
411
|
-
npm run test:all # 43-point smoke test suite
|
|
412
|
-
npm audit --omit=dev --audit-level=high
|
|
413
|
-
npm pack --dry-run
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
Live verification (requires network):
|
|
417
|
-
|
|
418
|
-
```bash
|
|
419
|
-
npm run test:rpc # Basic RPC connectivity
|
|
420
|
-
npm run test:rpc:live # Full live RPC verification with structured output
|
|
421
|
-
npm run test:live:safehands # 7 CLI safety checks (read-only)
|
|
422
|
-
npm run test:x402:live # x402 behavior checks (local server)
|
|
423
|
-
npm run test:dodo:live # DODO API check (requires DODO_API_KEY, skips if missing)
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
`test:rpc` and `test:rpc:live` depend on DNS/network access to Pharos RPC and may fail in restricted environments. This should be reported honestly as a provider/network limitation, not hidden.
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
## Known Limitations and TODOs
|
|
431
|
-
|
|
432
|
-
- Testnet-only, not audited for mainnet use.
|
|
433
|
-
- Managed wallet storage is testnet-grade unless a real KMS/Vault is integrated.
|
|
434
|
-
- DODO/FaroSwap router addresses are project-configured unless official docs confirm them.
|
|
435
|
-
- GoPlus/DODO/FaroSwap availability depends on external services and API limits.
|
|
436
|
-
- `npm audit` for production dependencies is clean; full dev audit may report dev-only dependency issues depending on upstream packages.
|
|
437
|
-
- Formal unit tests with mocked RPC/DODO/GoPlus providers would improve long-term maintainability.
|
|
438
|
-
|
|
439
|
-
---
|
|
440
|
-
|
|
441
|
-
## Hackathon Summary
|
|
442
|
-
|
|
443
|
-
**Project name:** SafeHands-Pharos: Transaction Safety Firewall for AI Agents
|
|
444
|
-
|
|
445
|
-
**Short description:** SafeHands-Pharos is a Pharos Skill Engine-compatible MCP package that protects AI agents before they execute payments, token approvals, swaps, or x402 paid requests by returning ALLOW, WARN, or BLOCK decisions with human-readable risk explanations.
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
|
|
3
|
+
<img src="https://img.shields.io/badge/MCP_Skill-000000?style=for-the-badge" />
|
|
4
|
+
<img src="https://img.shields.io/badge/Pharos_Atlantic-688689-blueviolet?style=for-the-badge" />
|
|
5
|
+
<img src="https://img.shields.io/badge/Tools-27-orange?style=for-the-badge" />
|
|
6
|
+
<img src="https://img.shields.io/badge/Testnet_Only-SAFE-blue?style=for-the-badge" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
# SafeHands-Pharos — Transaction Safety Firewall for AI Agents
|
|
10
|
+
|
|
11
|
+
SafeHands is a **Pharos Skill Engine-compatible MCP package** that acts as a safety layer before your AI agent executes any on-chain action — payments, swaps, token approvals, or x402 paid requests.
|
|
12
|
+
|
|
13
|
+
Every action goes through a preflight check first:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Agent wants to act
|
|
17
|
+
↓
|
|
18
|
+
safehands_preflight_check
|
|
19
|
+
↓
|
|
20
|
+
ALLOW → safe, proceed
|
|
21
|
+
WARN → proceed with caution
|
|
22
|
+
BLOCK → stop, reason explained
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> **Testnet only.** SafeHands targets Pharos Atlantic Testnet (Chain ID 688689). Not audited for mainnet use.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Getting Started
|
|
30
|
+
|
|
31
|
+
### Install via Pharos Skill Engine
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx skills add SZtch/safehands-pharos
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Connect to Claude Desktop
|
|
38
|
+
|
|
39
|
+
Add to `claude_desktop_config.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"safehands": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["safehands-pharos"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Restart Claude Desktop — SafeHands tools appear automatically in every conversation.
|
|
53
|
+
|
|
54
|
+
### Connect to Anvita Flow
|
|
55
|
+
|
|
56
|
+
Add as MCP server in Anvita Flow settings:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"command": "npx",
|
|
61
|
+
"args": ["safehands-pharos"]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### First-time setup
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx safehands-pharos init
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Interactive wizard that configures your `.env` — wallet mode, spend limits, write gates.
|
|
72
|
+
|
|
73
|
+
### Run the demo
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx safehands-pharos --demo
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Non-destructive demo: shows ALLOW, BLOCK, wallet health, token registry, x402 preflight, and risk report — no real transactions.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Start with These 3 Tools
|
|
84
|
+
|
|
85
|
+
| Goal | Tool |
|
|
86
|
+
|------|------|
|
|
87
|
+
| Check if an action is safe | `safehands_preflight_check` |
|
|
88
|
+
| Check wallet / signer readiness | `safehands_wallet_health` |
|
|
89
|
+
| Execute with built-in safety gate | `safehands_safe_execute` |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Calling Tools from the CLI
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Short form (recommended)
|
|
97
|
+
npx safehands-pharos skill <tool> '<json>'
|
|
98
|
+
|
|
99
|
+
# With flag
|
|
100
|
+
npx safehands-pharos skill <tool> -i '<json>'
|
|
101
|
+
|
|
102
|
+
# Explicit flag
|
|
103
|
+
npx safehands-pharos skill <tool> --input-json '<json>'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Examples:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Preflight check before a swap
|
|
110
|
+
npx safehands-pharos skill safehands_preflight_check \
|
|
111
|
+
'{"actionType":"execute_swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","chainId":688689,"isMainnet":false}'
|
|
112
|
+
|
|
113
|
+
# Check wallet balance
|
|
114
|
+
npx safehands-pharos skill get_wallet_balance \
|
|
115
|
+
'{"walletAddress":"0xYourWallet"}'
|
|
116
|
+
|
|
117
|
+
# Assess risk score
|
|
118
|
+
npx safehands-pharos skill assess_risk \
|
|
119
|
+
'{"action":"swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","walletAddress":"0xYourWallet"}'
|
|
120
|
+
|
|
121
|
+
# Classify a token address
|
|
122
|
+
npx safehands-pharos skill token_registry_status \
|
|
123
|
+
'{"tokenAddress":"0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8"}'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## All 27 Tools
|
|
129
|
+
|
|
130
|
+
All tools return the same response envelope:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"success": true,
|
|
135
|
+
"data": { ... },
|
|
136
|
+
"error": null,
|
|
137
|
+
"timestamp": "2026-06-13T00:00:00.000Z"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
On failure: `success: false`, `data: null`, `error: { code, message, retryable }`.
|
|
142
|
+
|
|
143
|
+
### SafeHands Guardrail Tools
|
|
144
|
+
|
|
145
|
+
| Tool | What it does | CLI |
|
|
146
|
+
|------|-------------|-----|
|
|
147
|
+
| `safehands_preflight_check` | ALLOW / WARN / BLOCK before any action | ✓ |
|
|
148
|
+
| `safehands_safe_execute` | Preflight + execute in one call | ✓ |
|
|
149
|
+
| `safehands_wallet_health` | Wallet, signer, gas, x402 readiness | ✓ |
|
|
150
|
+
| `safehands_x402_preflight` | URL safety + payment check before x402 | ✓ |
|
|
151
|
+
| `safehands_risk_report` | Human-readable risk summary | ✓ |
|
|
152
|
+
| `explain_risk` | Translate ALLOW/WARN/BLOCK into plain English | ✓ |
|
|
153
|
+
| `token_registry_status` | Canonical / custom / unknown token check | ✓ |
|
|
154
|
+
|
|
155
|
+
### Safety & Analysis Tools
|
|
156
|
+
|
|
157
|
+
| Tool | What it does | CLI |
|
|
158
|
+
|------|-------------|-----|
|
|
159
|
+
| `assess_risk` | 5-dimension risk score (0–100) | ✓ |
|
|
160
|
+
| `check_token_security` | GoPlus token security profile | ✓ |
|
|
161
|
+
| `simulate_transaction` | Dry-run before broadcasting | ✓ |
|
|
162
|
+
| `estimate_gas` | Gas estimate + sufficiency check | ✓ |
|
|
163
|
+
| `check_allowance` | ERC-20 allowance check | MCP |
|
|
164
|
+
|
|
165
|
+
### Market & Chain Data
|
|
166
|
+
|
|
167
|
+
| Tool | What it does | CLI |
|
|
168
|
+
|------|-------------|-----|
|
|
169
|
+
| `get_wallet_balance` | PHRS / USDC / USDT balances | ✓ |
|
|
170
|
+
| `get_token_price` | Token price via DODO | ✓ |
|
|
171
|
+
| `get_gas_price` | Current network gas price | MCP |
|
|
172
|
+
| `get_pool_info` | FaroSwap / DODO pool info | MCP |
|
|
173
|
+
| `get_transaction_status` | TX status by hash | ✓ |
|
|
174
|
+
| `get_execution_history` | Wallet transfer history (ERC-20 + native) | MCP |
|
|
175
|
+
|
|
176
|
+
### Write Tools *(require `WRITE_TOOLS_ENABLED=true`)*
|
|
177
|
+
|
|
178
|
+
| Tool | What it does | CLI |
|
|
179
|
+
|------|-------------|-----|
|
|
180
|
+
| `execute_swap` | Swap tokens via FaroSwap / DODO | MCP |
|
|
181
|
+
| `send_payment` | Send native PHRS | MCP |
|
|
182
|
+
| `approve_token` | ERC-20 approval (unlimited blocked by default) | MCP |
|
|
183
|
+
| `publish_risk_score` | Publish risk score to RiskRegistry contract | MCP |
|
|
184
|
+
| `x402_pay_and_fetch` | Fetch x402 resource, pay only after HTTP 402 | MCP |
|
|
185
|
+
|
|
186
|
+
### Risk Registry
|
|
187
|
+
|
|
188
|
+
| Tool | What it does | CLI |
|
|
189
|
+
|------|-------------|-----|
|
|
190
|
+
| `query_risk_registry` | Read on-chain risk score | ✓ |
|
|
191
|
+
|
|
192
|
+
### Managed Wallet Tools
|
|
193
|
+
|
|
194
|
+
| Tool | What it does | CLI |
|
|
195
|
+
|------|-------------|-----|
|
|
196
|
+
| `create_agent_wallet` | Create testnet wallet (AES-256-GCM encrypted) | ✓ |
|
|
197
|
+
| `get_agent_wallet` | Wallet address + metadata (no private key) | ✓ |
|
|
198
|
+
| `get_agent_wallet_balance` | Managed wallet balances | ✓ |
|
|
199
|
+
|
|
200
|
+
> **CLI** = callable via `npx safehands-pharos skill <tool> '<json>'`
|
|
201
|
+
> **MCP** = available via Claude Desktop / Anvita Flow only
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Configuration
|
|
206
|
+
|
|
207
|
+
Copy the example file:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
cp .env.example .env
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Key settings:
|
|
214
|
+
|
|
215
|
+
```env
|
|
216
|
+
# Wallet mode
|
|
217
|
+
WALLET_MODE=none # none | env | managed-testnet
|
|
218
|
+
PRIVATE_KEY= # required when WALLET_MODE=env
|
|
219
|
+
WALLET_STORE_PATH= # optional: persist managed wallets to disk
|
|
220
|
+
|
|
221
|
+
# Write gates (all off by default)
|
|
222
|
+
WRITE_TOOLS_ENABLED=false
|
|
223
|
+
ALLOW_UNLIMITED_APPROVAL=false
|
|
224
|
+
|
|
225
|
+
# Spend limits
|
|
226
|
+
MAX_TX_AMOUNT_PHRS=0.1 # max PHRS per transaction
|
|
227
|
+
MAX_DAILY_SPEND_USD=10 # daily cap across all wallets
|
|
228
|
+
PHRS_USD_PRICE=1.0 # used for daily spend accounting
|
|
229
|
+
|
|
230
|
+
# DODO API (required for swaps and price data)
|
|
231
|
+
DODO_API_KEY=
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Wallet modes explained
|
|
235
|
+
|
|
236
|
+
| Mode | How it works |
|
|
237
|
+
|------|-------------|
|
|
238
|
+
| `none` | No signer — read-only tools only (safe default) |
|
|
239
|
+
| `env` | Reads `PRIVATE_KEY` from `.env` |
|
|
240
|
+
| `managed-testnet` | Uses wallet created via `create_agent_wallet` |
|
|
241
|
+
|
|
242
|
+
### Persistent managed wallets
|
|
243
|
+
|
|
244
|
+
By default, wallets created with `create_agent_wallet` are in-memory and lost on restart. To persist them:
|
|
245
|
+
|
|
246
|
+
```env
|
|
247
|
+
WALLET_STORE_PATH=./.agents/wallets.json
|
|
248
|
+
WALLET_ENCRYPTION_KEY=your-strong-secret
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Private keys are AES-256-GCM encrypted on disk. The `.agents/` folder is gitignored.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Security Defaults
|
|
256
|
+
|
|
257
|
+
SafeHands ships safe by default — nothing is enabled without explicit opt-in:
|
|
258
|
+
|
|
259
|
+
- `WRITE_TOOLS_ENABLED=false` — no on-chain writes without opt-in
|
|
260
|
+
- `WALLET_MODE=none` — no signer loaded on startup
|
|
261
|
+
- Unlimited token approvals blocked
|
|
262
|
+
- Mainnet actions blocked
|
|
263
|
+
- SSRF-sensitive x402 URLs blocked
|
|
264
|
+
- Private keys never returned in responses or logs
|
|
265
|
+
- Daily spend cap enforced in-memory per wallet
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Why AI Agents Need This
|
|
270
|
+
|
|
271
|
+
Generic Web3 tools answer: *"Can this transaction be sent?"*
|
|
272
|
+
SafeHands answers: **"Should this action be allowed at all?"**
|
|
273
|
+
|
|
274
|
+
| Risk | What goes wrong | SafeHands guardrail |
|
|
275
|
+
|------|----------------|---------------------|
|
|
276
|
+
| Unlimited approval | Agent approves malicious spender forever | Blocked by default |
|
|
277
|
+
| Wrong chain | Agent signs on mainnet | Blocked |
|
|
278
|
+
| Risky x402 URL | Agent pays a localhost/private IP | Blocked |
|
|
279
|
+
| Overspending | Agent drains wallet | Daily cap enforced |
|
|
280
|
+
| Unknown token | Agent swaps unverified token | Warns or requires review |
|
|
281
|
+
| Missing signer | Agent tries write without wallet | Structured error returned |
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## x402 Support
|
|
286
|
+
|
|
287
|
+
SafeHands acts as both an x402 client and server.
|
|
288
|
+
|
|
289
|
+
**Client** (`x402_pay_and_fetch`): Fetches a resource normally first. If the server returns HTTP 402, SafeHands runs a preflight check, requests the signer, pays, and retries — all in one tool call. Payment proofs are never logged.
|
|
290
|
+
|
|
291
|
+
**Server** (`npm run x402-server`): Exposes paid endpoints:
|
|
292
|
+
|
|
293
|
+
| Endpoint | Type | Price |
|
|
294
|
+
|----------|------|-------|
|
|
295
|
+
| `GET /supported` | Free | — |
|
|
296
|
+
| `GET /health` | Free | — |
|
|
297
|
+
| `GET /assess-risk` | Paid | 0.001 USDC |
|
|
298
|
+
| `GET /check-token-security` | Paid | 0.001 USDC |
|
|
299
|
+
| `GET /simulate-transaction` | Paid | 0.001 USDC |
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Network Info
|
|
304
|
+
|
|
305
|
+
| Item | Value |
|
|
306
|
+
|------|-------|
|
|
307
|
+
| Chain ID | `688689` |
|
|
308
|
+
| RPC | `https://atlantic.dplabs-internal.com` |
|
|
309
|
+
| Explorer | `https://atlantic.pharosscan.xyz` |
|
|
310
|
+
| USDC | `0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8` |
|
|
311
|
+
| RiskRegistry | `0x61962a6c812ee9f57b207e1ea47c19ae70bb7141` |
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Testing
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
npm run build
|
|
319
|
+
npm run test:all # 43-point smoke test (no network needed)
|
|
320
|
+
npm run test:rpc:live # live RPC connectivity check
|
|
321
|
+
npm run test:live:safehands # 7 CLI safety checks against built dist
|
|
322
|
+
npm run test:dodo:live # DODO API check (skips if DODO_API_KEY not set)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Known Limitations
|
|
328
|
+
|
|
329
|
+
- Testnet-only — not audited for mainnet
|
|
330
|
+
- Managed wallet encryption is AES-256-GCM but not KMS/Vault grade
|
|
331
|
+
- `get_token_price` and swap routing require a DODO API key
|
|
332
|
+
- GoPlus token security does not support Pharos testnet (Chain 688689) — `check_token_security` returns a clear error
|
|
333
|
+
- DODO reverse routes (e.g. USDT → PHRS) have no liquidity on testnet
|