safehands-pharos 1.3.0 → 1.5.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 +444 -445
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +36 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +208 -147
- package/dist/index.js.map +1 -1
- 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 +12 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +10 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/dodoApi.d.ts +8 -0
- package/dist/lib/dodoApi.d.ts.map +1 -1
- package/dist/lib/dodoApi.js +22 -4
- package/dist/lib/dodoApi.js.map +1 -1
- package/dist/lib/envLoader.d.ts +2 -0
- package/dist/lib/envLoader.d.ts.map +1 -0
- package/dist/lib/envLoader.js +44 -0
- package/dist/lib/envLoader.js.map +1 -0
- package/dist/lib/pharosClient.d.ts.map +1 -1
- package/dist/lib/pharosClient.js +13 -3
- package/dist/lib/pharosClient.js.map +1 -1
- package/dist/lib/riskEngine.d.ts.map +1 -1
- package/dist/lib/riskEngine.js +50 -45
- package/dist/lib/riskEngine.js.map +1 -1
- package/dist/lib/signer/index.d.ts.map +1 -1
- package/dist/lib/signer/index.js +3 -4
- 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/testRpc.d.ts +1 -1
- package/dist/lib/testRpc.js +29 -29
- package/dist/lib/testTools.d.ts +1 -1
- package/dist/lib/testTools.js +4 -5
- package/dist/lib/wallet/index.d.ts +19 -0
- package/dist/lib/wallet/index.d.ts.map +1 -1
- package/dist/lib/wallet/index.js +65 -7
- package/dist/lib/wallet/index.js.map +1 -1
- package/dist/tools/approveToken.d.ts +0 -1
- package/dist/tools/approveToken.d.ts.map +1 -1
- package/dist/tools/approveToken.js +3 -1
- package/dist/tools/approveToken.js.map +1 -1
- package/dist/tools/assessRisk.d.ts.map +1 -1
- package/dist/tools/assessRisk.js +18 -7
- package/dist/tools/assessRisk.js.map +1 -1
- package/dist/tools/checkAllowance.d.ts +9 -2
- package/dist/tools/checkAllowance.d.ts.map +1 -1
- package/dist/tools/checkAllowance.js +20 -6
- package/dist/tools/checkAllowance.js.map +1 -1
- package/dist/tools/checkTokenSecurity.d.ts.map +1 -1
- package/dist/tools/checkTokenSecurity.js +7 -0
- package/dist/tools/checkTokenSecurity.js.map +1 -1
- package/dist/tools/createAgentWallet.d.ts +2 -0
- package/dist/tools/createAgentWallet.d.ts.map +1 -1
- package/dist/tools/createAgentWallet.js +30 -7
- package/dist/tools/createAgentWallet.js.map +1 -1
- package/dist/tools/executeSwap.d.ts +3 -1
- package/dist/tools/executeSwap.d.ts.map +1 -1
- package/dist/tools/executeSwap.js +13 -1
- package/dist/tools/executeSwap.js.map +1 -1
- package/dist/tools/getExecutionHistory.d.ts +15 -17
- package/dist/tools/getExecutionHistory.d.ts.map +1 -1
- package/dist/tools/getExecutionHistory.js +125 -64
- package/dist/tools/getExecutionHistory.js.map +1 -1
- package/dist/tools/getTransactionStatus.d.ts +5 -19
- package/dist/tools/getTransactionStatus.d.ts.map +1 -1
- package/dist/tools/getTransactionStatus.js +10 -18
- package/dist/tools/getTransactionStatus.js.map +1 -1
- package/dist/tools/publishRiskScore.d.ts.map +1 -1
- package/dist/tools/publishRiskScore.js +3 -0
- package/dist/tools/publishRiskScore.js.map +1 -1
- package/dist/tools/queryRiskRegistry.d.ts +3 -13
- package/dist/tools/queryRiskRegistry.d.ts.map +1 -1
- package/dist/tools/queryRiskRegistry.js +6 -11
- package/dist/tools/queryRiskRegistry.js.map +1 -1
- package/dist/tools/safehandsSafeExecute.d.ts.map +1 -1
- package/dist/tools/safehandsSafeExecute.js +12 -6
- package/dist/tools/safehandsSafeExecute.js.map +1 -1
- package/dist/tools/sendPayment.d.ts +0 -1
- package/dist/tools/sendPayment.d.ts.map +1 -1
- package/dist/tools/sendPayment.js +10 -1
- package/dist/tools/sendPayment.js.map +1 -1
- package/dist/tools/simulateTransaction.d.ts +2 -23
- package/dist/tools/simulateTransaction.d.ts.map +1 -1
- package/dist/tools/simulateTransaction.js +10 -15
- package/dist/tools/simulateTransaction.js.map +1 -1
- package/dist/tools/x402PayAndFetch.d.ts.map +1 -1
- package/dist/tools/x402PayAndFetch.js +4 -1
- package/dist/tools/x402PayAndFetch.js.map +1 -1
- package/dist/x402Server.js +51 -3
- package/dist/x402Server.js.map +1 -1
- package/package.json +73 -84
- package/.agents/skill/safehands/SKILL.md +0 -212
- package/.agents/skill/safehands/assets/networks.json +0 -24
- package/.agents/skill/safehands/assets/tokens.json +0 -66
- package/.agents/wallets.json +0 -20
- package/docs/reports/OFFICIAL_DOCS_ALIGNMENT_REPORT.md +0 -137
- package/docs/reports/final_audit_report.md +0 -307
- package/docs/reports/live_verification_report.md +0 -147
- package/docs/reports/pharos_skill_engine_alignment_report.md +0 -85
- package/examples/pharos-skill-engine/SKILL.safehands.md +0 -85
- package/examples/pharos-skill-engine/assets/safehands/example-actions.json +0 -49
- package/examples/pharos-skill-engine/assets/safehands/policy-defaults.json +0 -11
- package/examples/pharos-skill-engine/references/safehands.md +0 -345
- package/examples/scenario-hack.ts +0 -38
- package/skill/SKILL.md +0 -133
- package/skill/assets/safehands/example-actions.json +0 -49
- package/skill/assets/safehands/policy-defaults.json +0 -11
- package/skill/references/safehands.md +0 -345
package/README.md
CHANGED
|
@@ -1,445 +1,444 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
```bash
|
|
130
|
-
npx safehands-pharos
|
|
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
|
-
| `get_transaction_status` |
|
|
239
|
-
| `get_execution_history` |
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
|
390
|
-
|
|
391
|
-
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
##
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
-
|
|
435
|
-
-
|
|
436
|
-
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
**
|
|
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
|
+
# SafeHands-Pharos — Transaction Safety Firewall for AI Agents
|
|
2
|
+
|
|
3
|
+
> **Most Pharos skills let an agent *do* things — check balances, swap, pay, deploy.**
|
|
4
|
+
> **SafeHands is the one that decides whether the agent *should*.**
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx safehands-pharos skill safehands_preflight_check --input-json \
|
|
8
|
+
'{"actionType":"approve_token","chainId":688689,"tokenAddress":"0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8","spenderAddress":"0x000000000000000000000000000000000000dEaD","approvalAmount":"max"}'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Sample output:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"success": true,
|
|
16
|
+
"data": {
|
|
17
|
+
"decision": "BLOCK",
|
|
18
|
+
"riskLevel": "HIGH",
|
|
19
|
+
"safeToExecute": false,
|
|
20
|
+
"reasons": [
|
|
21
|
+
"Unlimited approval requested."
|
|
22
|
+
],
|
|
23
|
+
"requiredActions": [
|
|
24
|
+
"Use a limited approval amount."
|
|
25
|
+
],
|
|
26
|
+
"checks": [
|
|
27
|
+
{ "name": "mainnet_guard", "status": "pass", "message": "Action is not targeting mainnet." },
|
|
28
|
+
{ "name": "chain_id", "status": "pass", "message": "Chain ID is Pharos Atlantic Testnet (688689)." },
|
|
29
|
+
{ "name": "environment", "status": "pass", "message": "Environment is atlantic-testnet." },
|
|
30
|
+
{ "name": "approval_amount", "status": "fail", "message": "Unlimited approval is blocked by default." }
|
|
31
|
+
],
|
|
32
|
+
"environment": "atlantic-testnet",
|
|
33
|
+
"chainId": 688689,
|
|
34
|
+
"isMainnet": false,
|
|
35
|
+
"tokenRegistry": {
|
|
36
|
+
"symbol": "USDC",
|
|
37
|
+
"status": "SKILL_ENGINE_CANONICAL_TOKEN",
|
|
38
|
+
"verificationStatus": "DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE"
|
|
39
|
+
},
|
|
40
|
+
"source": "safehands_preflight_check"
|
|
41
|
+
},
|
|
42
|
+
"error": null,
|
|
43
|
+
"timestamp": "2026-06-14T00:00:00.000Z"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
That's the whole idea: **before** an agent approves a token, swaps, sends a payment,
|
|
48
|
+
or pays an x402 resource, SafeHands runs a policy check and returns `ALLOW`, `WARN`,
|
|
49
|
+
or `BLOCK` — with a plain-English reason. If `BLOCK`, the agent stops. No transaction,
|
|
50
|
+
no loss.
|
|
51
|
+
|
|
52
|
+
**Live preflight examples:** see [DEMO.md](DEMO.md) — real ALLOW and BLOCK outputs.
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
|
|
56
|
+
<img src="https://img.shields.io/badge/MCP_Skill-000000?style=for-the-badge" />
|
|
57
|
+
<img src="https://img.shields.io/badge/Pharos_Atlantic-688689-blueviolet?style=for-the-badge" />
|
|
58
|
+
<img src="https://img.shields.io/badge/Tools-27-orange?style=for-the-badge" />
|
|
59
|
+
<img src="https://img.shields.io/badge/Testnet_Only-SAFE-blue?style=for-the-badge" />
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
> **Testnet only.** SafeHands targets Pharos Atlantic Testnet (Chain ID 688689). Not audited for mainnet use.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Why AI Agents Need This
|
|
67
|
+
|
|
68
|
+
Generic Web3 tools answer: *"Can this transaction be sent?"*
|
|
69
|
+
SafeHands answers: **"Should this action be allowed at all?"**
|
|
70
|
+
|
|
71
|
+
| Risk | What goes wrong without SafeHands | SafeHands guardrail |
|
|
72
|
+
|------|----------------------------------|---------------------|
|
|
73
|
+
| Unlimited approval | Agent approves malicious spender forever | Blocked by default |
|
|
74
|
+
| Wrong chain | Agent signs on mainnet by mistake | Blocked |
|
|
75
|
+
| Risky x402 URL | Agent pays a localhost / private IP | Blocked (SSRF guard) |
|
|
76
|
+
| Overspending | Agent drains wallet in one session | Daily cap enforced |
|
|
77
|
+
| Unknown token | Agent swaps unverified contract | Warns, requires review |
|
|
78
|
+
| Missing signer | Agent attempts write without wallet | Structured error returned |
|
|
79
|
+
|
|
80
|
+
SafeHands is a **Pharos Skill Engine-compatible MCP package** — a composable guardrail layer that any agent can add in front of any action, without modifying existing skill logic.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Getting Started
|
|
85
|
+
|
|
86
|
+
### Step 1 — Try it now (no setup, no wallet)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx safehands-pharos --demo
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Runs 10 live safety checks in your terminal: ALLOW/BLOCK decisions, wallet health, token registry, x402 preflight, risk report. No config, no private key, no transactions.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### Step 2 — Connect to your AI agent
|
|
97
|
+
|
|
98
|
+
Pick **one** depending on how you use AI agents:
|
|
99
|
+
|
|
100
|
+
#### Claude Desktop
|
|
101
|
+
|
|
102
|
+
Add to your `claude_desktop_config.json`, then restart Claude Desktop:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"mcpServers": {
|
|
107
|
+
"safehands": {
|
|
108
|
+
"command": "npx",
|
|
109
|
+
"args": ["safehands-pharos"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All 27 SafeHands tools appear automatically in every Claude conversation.
|
|
116
|
+
|
|
117
|
+
#### Anvita Flow
|
|
118
|
+
|
|
119
|
+
Add as an MCP server in Anvita Flow settings:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{ "command": "npx", "args": ["safehands-pharos"] }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Terminal / scripts (CLI)
|
|
126
|
+
|
|
127
|
+
Call any tool directly without connecting to an AI client:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx safehands-pharos skill safehands_preflight_check \
|
|
131
|
+
'{"actionType":"send_payment","chainId":688689,"amount":"0.001","recipient":"0x1234567890123456789012345678901234567890"}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### Step 3 — (Optional) Enable write operations
|
|
137
|
+
|
|
138
|
+
By default, SafeHands is **read-only**: preflight checks, risk scoring, token registry, wallet health. No private key needed.
|
|
139
|
+
|
|
140
|
+
To unlock swaps, payments, and approvals, run the setup wizard:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx safehands-pharos init
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Or set manually in a `.env` file in your working directory:
|
|
147
|
+
|
|
148
|
+
```env
|
|
149
|
+
WALLET_MODE=env # env | managed-testnet
|
|
150
|
+
PRIVATE_KEY=0x... # testnet key only — never mainnet
|
|
151
|
+
WRITE_TOOLS_ENABLED=true
|
|
152
|
+
MAX_TX_AMOUNT_PHRS=0.1 # per-transaction cap
|
|
153
|
+
MAX_DAILY_SPEND_USD=10 # daily spend cap
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Calling Tools from the CLI
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Short form (recommended)
|
|
162
|
+
npx safehands-pharos skill <tool> '<json>'
|
|
163
|
+
|
|
164
|
+
# With flag
|
|
165
|
+
npx safehands-pharos skill <tool> -i '<json>'
|
|
166
|
+
|
|
167
|
+
# Explicit flag
|
|
168
|
+
npx safehands-pharos skill <tool> --input-json '<json>'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Examples:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Preflight check before a swap
|
|
175
|
+
npx safehands-pharos skill safehands_preflight_check \
|
|
176
|
+
'{"actionType":"execute_swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","chainId":688689,"isMainnet":false}'
|
|
177
|
+
|
|
178
|
+
# Check wallet balance
|
|
179
|
+
npx safehands-pharos skill get_wallet_balance \
|
|
180
|
+
'{"walletAddress":"0xYourWallet"}'
|
|
181
|
+
|
|
182
|
+
# Assess risk score
|
|
183
|
+
npx safehands-pharos skill assess_risk \
|
|
184
|
+
'{"action":"swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","walletAddress":"0xYourWallet"}'
|
|
185
|
+
|
|
186
|
+
# Classify a token address
|
|
187
|
+
npx safehands-pharos skill token_registry_status \
|
|
188
|
+
'{"tokenAddress":"0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8"}'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## All 27 Tools
|
|
194
|
+
|
|
195
|
+
All tools return the same response envelope:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"success": true,
|
|
200
|
+
"data": { ... },
|
|
201
|
+
"error": null,
|
|
202
|
+
"timestamp": "2026-06-13T00:00:00.000Z"
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
On failure: `success: false`, `data: null`, `error: { code, message, retryable }`.
|
|
207
|
+
|
|
208
|
+
### SafeHands Guardrail Tools
|
|
209
|
+
|
|
210
|
+
| Tool | What it does | CLI |
|
|
211
|
+
|------|-------------|-----|
|
|
212
|
+
| `safehands_preflight_check` | ALLOW / WARN / BLOCK before any action | ✓ |
|
|
213
|
+
| `safehands_safe_execute` | Preflight + execute in one call | ✓ |
|
|
214
|
+
| `safehands_wallet_health` | Wallet, signer, gas, x402 readiness | ✓ |
|
|
215
|
+
| `safehands_x402_preflight` | URL safety + payment check before x402 | ✓ |
|
|
216
|
+
| `safehands_risk_report` | Human-readable risk summary | ✓ |
|
|
217
|
+
| `explain_risk` | Translate ALLOW/WARN/BLOCK into plain English | ✓ |
|
|
218
|
+
| `token_registry_status` | Canonical / custom / unknown token check | ✓ |
|
|
219
|
+
|
|
220
|
+
### Safety & Analysis Tools
|
|
221
|
+
|
|
222
|
+
| Tool | What it does | CLI |
|
|
223
|
+
|------|-------------|-----|
|
|
224
|
+
| `assess_risk` | 5-dimension risk score (0–100) | ✓ |
|
|
225
|
+
| `check_token_security` | GoPlus token security profile | ✓ |
|
|
226
|
+
| `simulate_transaction` | Dry-run before broadcasting | ✓ |
|
|
227
|
+
| `estimate_gas` | Gas estimate + sufficiency check | ✓ |
|
|
228
|
+
| `check_allowance` | ERC-20 allowance check | MCP |
|
|
229
|
+
|
|
230
|
+
### Market & Chain Data
|
|
231
|
+
|
|
232
|
+
| Tool | What it does | CLI |
|
|
233
|
+
|------|-------------|-----|
|
|
234
|
+
| `get_wallet_balance` | PHRS / USDC / USDT balances | ✓ |
|
|
235
|
+
| `get_token_price` | Token price via DODO | ✓ |
|
|
236
|
+
| `get_gas_price` | Current network gas price | MCP |
|
|
237
|
+
| `get_pool_info` | FaroSwap / DODO pool info | MCP |
|
|
238
|
+
| `get_transaction_status` | TX status by hash | ✓ |
|
|
239
|
+
| `get_execution_history` | Wallet transfer history (ERC-20 + native) | MCP |
|
|
240
|
+
|
|
241
|
+
### Write Tools *(require `WRITE_TOOLS_ENABLED=true`)*
|
|
242
|
+
|
|
243
|
+
| Tool | What it does | CLI |
|
|
244
|
+
|------|-------------|-----|
|
|
245
|
+
| `execute_swap` | Swap tokens via FaroSwap / DODO | MCP |
|
|
246
|
+
| `send_payment` | Send native PHRS | MCP |
|
|
247
|
+
| `approve_token` | ERC-20 approval (unlimited blocked by default) | MCP |
|
|
248
|
+
| `publish_risk_score` | Publish risk score to RiskRegistry contract | MCP |
|
|
249
|
+
| `x402_pay_and_fetch` | Fetch x402 resource, pay only after HTTP 402 | MCP |
|
|
250
|
+
|
|
251
|
+
### Risk Registry
|
|
252
|
+
|
|
253
|
+
| Tool | What it does | CLI |
|
|
254
|
+
|------|-------------|-----|
|
|
255
|
+
| `query_risk_registry` | Read on-chain risk score | ✓ |
|
|
256
|
+
|
|
257
|
+
### Managed Wallet Tools
|
|
258
|
+
|
|
259
|
+
| Tool | What it does | CLI |
|
|
260
|
+
|------|-------------|-----|
|
|
261
|
+
| `create_agent_wallet` | Create testnet wallet (AES-256-GCM encrypted) | ✓ |
|
|
262
|
+
| `get_agent_wallet` | Wallet address + metadata (no private key) | ✓ |
|
|
263
|
+
| `get_agent_wallet_balance` | Managed wallet balances | ✓ |
|
|
264
|
+
|
|
265
|
+
> **CLI** = callable via `npx safehands-pharos skill <tool> '<json>'`
|
|
266
|
+
> **MCP** = available via Claude Desktop / Anvita Flow only
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Configuration
|
|
271
|
+
|
|
272
|
+
If you cloned the repo, copy the example file:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
cp .env.example .env # then edit .env with your settings
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
If you installed via `npx` or `npm install`, create a `.env` in your working directory with these settings:
|
|
279
|
+
|
|
280
|
+
```env
|
|
281
|
+
# Wallet mode
|
|
282
|
+
WALLET_MODE=none # none | env | managed-testnet
|
|
283
|
+
PRIVATE_KEY= # required when WALLET_MODE=env
|
|
284
|
+
WALLET_STORE_PATH= # optional: persist managed wallets to disk
|
|
285
|
+
|
|
286
|
+
# Write gates (all off by default)
|
|
287
|
+
WRITE_TOOLS_ENABLED=false
|
|
288
|
+
ALLOW_UNLIMITED_APPROVAL=false
|
|
289
|
+
|
|
290
|
+
# Spend limits
|
|
291
|
+
MAX_TX_AMOUNT_PHRS=0.1 # max PHRS per transaction
|
|
292
|
+
MAX_DAILY_SPEND_USD=10 # daily cap across all wallets
|
|
293
|
+
PHRS_USD_PRICE=1.0 # used for daily spend accounting
|
|
294
|
+
|
|
295
|
+
# DODO API (required for swaps and price data)
|
|
296
|
+
DODO_API_KEY=
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Wallet modes explained
|
|
300
|
+
|
|
301
|
+
| Mode | How it works |
|
|
302
|
+
|------|-------------|
|
|
303
|
+
| `none` | No signer — read-only tools only (safe default) |
|
|
304
|
+
| `env` | Reads `PRIVATE_KEY` from `.env` |
|
|
305
|
+
| `managed-testnet` | Uses wallet created via `create_agent_wallet` |
|
|
306
|
+
|
|
307
|
+
### Persistent managed wallets
|
|
308
|
+
|
|
309
|
+
By default, wallets created with `create_agent_wallet` are in-memory and lost on restart. To persist them:
|
|
310
|
+
|
|
311
|
+
```env
|
|
312
|
+
WALLET_STORE_PATH=./.agents/wallets.json
|
|
313
|
+
WALLET_ENCRYPTION_KEY=your-strong-secret
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Private keys are AES-256-GCM encrypted on disk. The `.agents/` folder is gitignored.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Security Defaults
|
|
321
|
+
|
|
322
|
+
SafeHands ships safe by default — nothing is enabled without explicit opt-in:
|
|
323
|
+
|
|
324
|
+
- `WRITE_TOOLS_ENABLED=false` — no on-chain writes without opt-in
|
|
325
|
+
- `WALLET_MODE=none` — no signer loaded on startup
|
|
326
|
+
- Unlimited token approvals blocked
|
|
327
|
+
- Mainnet actions blocked
|
|
328
|
+
- SSRF-sensitive x402 URLs blocked
|
|
329
|
+
- Private keys never returned in responses or logs
|
|
330
|
+
- Daily spend cap enforced in-memory per wallet
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## x402 Support
|
|
335
|
+
|
|
336
|
+
SafeHands acts as both an x402 client and server.
|
|
337
|
+
|
|
338
|
+
**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.
|
|
339
|
+
|
|
340
|
+
**Server** (`npm run x402-server`): Exposes paid endpoints. A live instance runs at:
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
https://safehands-pharos-production.up.railway.app
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
| Endpoint | Type | Price |
|
|
347
|
+
|----------|------|-------|
|
|
348
|
+
| `GET /supported` | Free | — |
|
|
349
|
+
| `GET /health` | Free | — |
|
|
350
|
+
| `GET /assess-risk` | Paid | 0.001 USDC |
|
|
351
|
+
| `GET /check-token-security` | Paid | 0.001 USDC |
|
|
352
|
+
| `GET /simulate-transaction` | Paid | 0.001 USDC |
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Examples
|
|
357
|
+
|
|
358
|
+
**Prompt-injection attack scenario** — SafeHands blocking an unlimited token approval triggered by a simulated prompt-injection attack:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
npx safehands-pharos skill safehands_preflight_check \
|
|
362
|
+
'{"actionType":"approve_token","chainId":688689,"approvalAmount":"max","spender":"0xBadActor12300000000000000000000000000000"}'
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Expected output: `BLOCK` — `"Unlimited approval is blocked by default."`
|
|
366
|
+
|
|
367
|
+
**Live server** — the SafeHands x402 server runs at:
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
https://safehands-pharos-production.up.railway.app
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Hit `/preflight?actionType=send_payment&amount=0.001&chainId=688689&recipient=0x1234...` for a live ALLOW/WARN/BLOCK response with no setup required.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Network Info
|
|
378
|
+
|
|
379
|
+
| Item | Value |
|
|
380
|
+
|------|-------|
|
|
381
|
+
| Chain ID | `688689` |
|
|
382
|
+
| RPC | `https://atlantic.dplabs-internal.com` |
|
|
383
|
+
| Explorer | `https://atlantic.pharosscan.xyz` |
|
|
384
|
+
| USDC | `0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8` |
|
|
385
|
+
| RiskRegistry | `0x61962a6c812ee9f57b207e1ea47c19ae70bb7141` |
|
|
386
|
+
|
|
387
|
+
**Proof of life — live on-chain tx:**
|
|
388
|
+
|
|
389
|
+
| What | Value |
|
|
390
|
+
|------|-------|
|
|
391
|
+
| Action | `publish_risk_score` → RiskRegistry |
|
|
392
|
+
| Tx Hash | [`0x6a58f636...fdefc`](https://atlantic.pharosscan.xyz/tx/0x6a58f636814458c09304db3d7c4f5f48e764f6439649fbb786cddb32c77fdefc) |
|
|
393
|
+
| Block | `24168297` |
|
|
394
|
+
| Gas Used | `140,187` |
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Testing
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
npm run build # compile TypeScript
|
|
402
|
+
npm run demo # run 10 live safety checks in terminal (no wallet needed)
|
|
403
|
+
npm run dev # run MCP server in dev mode (tsx, no build step)
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
For manual testing, use the CLI directly after building:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Build first
|
|
410
|
+
npm run build
|
|
411
|
+
|
|
412
|
+
# Then call any tool
|
|
413
|
+
node dist/index.js skill safehands_preflight_check \
|
|
414
|
+
'{"actionType":"approve_token","chainId":688689,"approvalAmount":"max"}'
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Known Limitations
|
|
420
|
+
|
|
421
|
+
- Testnet-only — not audited for mainnet
|
|
422
|
+
- Managed wallet encryption is AES-256-GCM but not KMS/Vault grade
|
|
423
|
+
- `get_token_price` and swap routing require a DODO API key
|
|
424
|
+
- GoPlus token security does not support Pharos testnet (Chain 688689) — `check_token_security` returns a clear error
|
|
425
|
+
- DODO reverse routes (e.g. USDT → PHRS) have no liquidity on testnet
|
|
426
|
+
- x402 client and server are implemented with the official `@x402/fetch` and `@x402/evm` SDKs and verified against a local x402-compatible server. They have not yet been verified against live third-party x402 endpoints on Pharos.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Roadmap
|
|
431
|
+
|
|
432
|
+
SafeHands is designed to grow from a single-project guardrail into **shared safety infrastructure** for the Pharos agent economy.
|
|
433
|
+
|
|
434
|
+
**Near-term**
|
|
435
|
+
- **Per-agent spend limits** — a `set_spend_limits` / `get_spend_limits` tool pair so each agent carries its own policy instead of a shared global cap. Stored in the existing AES-256-GCM encrypted wallet store.
|
|
436
|
+
- **x402 live endpoint verification** — validate SafeHands's x402 preflight against production third-party x402 endpoints on Pharos as they become available.
|
|
437
|
+
|
|
438
|
+
**Medium-term**
|
|
439
|
+
- **Community risk registry** — as more agents publish scores to the on-chain RiskRegistry (`0x61962a6c812ee9f57b207e1ea47c19ae70bb7141`), `query_risk_registry` becomes shared reputation infrastructure. A malicious contract blocked by one agent is flagged for all agents across the ecosystem.
|
|
440
|
+
- **Cross-chain x402 guardrails** — SafeHands's x402 preflight logic is protocol-level, not Pharos-specific. The same guardrail pattern can protect agents making x402 payments on AgentCash (Base / Solana) or any other compatible network.
|
|
441
|
+
|
|
442
|
+
**Long-term**
|
|
443
|
+
- **Mainnet support** — currently testnet-only by design. Mainnet requires a full re-audit of every safety check, formal verification of the RiskRegistry contract, and KMS/Vault-grade key management before it can be trusted with real funds.
|
|
444
|
+
- **Standardized guardrail interface** — a community spec so any Pharos skill can expose a `preflight(action) → ALLOW | WARN | BLOCK` interface and compose with SafeHands, rather than each skill reinventing safety logic independently.
|