safehands-pharos 1.4.0 → 2.6.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.
Files changed (571) hide show
  1. package/.agents/policies/default.json +15 -0
  2. package/.env.example +81 -64
  3. package/README.md +301 -333
  4. package/SECURITY.md +112 -0
  5. package/SKILL.md +59 -0
  6. package/contracts/SafeHandsAttestation.sol +182 -0
  7. package/contracts/SafeHandsRegistry.sol +149 -0
  8. package/dist/agent/SafeHandsGuardianAgent.d.ts +39 -0
  9. package/dist/agent/SafeHandsGuardianAgent.d.ts.map +1 -0
  10. package/dist/agent/SafeHandsGuardianAgent.js +98 -0
  11. package/dist/agent/SafeHandsGuardianAgent.js.map +1 -0
  12. package/dist/agent/agentDecisionFormatter.d.ts +43 -0
  13. package/dist/agent/agentDecisionFormatter.d.ts.map +1 -0
  14. package/dist/agent/agentDecisionFormatter.js +96 -0
  15. package/dist/agent/agentDecisionFormatter.js.map +1 -0
  16. package/dist/agent/agentEnrich.d.ts +28 -0
  17. package/dist/agent/agentEnrich.d.ts.map +1 -0
  18. package/dist/agent/agentEnrich.js +99 -0
  19. package/dist/agent/agentEnrich.js.map +1 -0
  20. package/dist/agent/agentIntentClassifier.d.ts +44 -0
  21. package/dist/agent/agentIntentClassifier.d.ts.map +1 -0
  22. package/dist/agent/agentIntentClassifier.js +77 -0
  23. package/dist/agent/agentIntentClassifier.js.map +1 -0
  24. package/dist/agent/agentPolicyResolver.d.ts +44 -0
  25. package/dist/agent/agentPolicyResolver.d.ts.map +1 -0
  26. package/dist/agent/agentPolicyResolver.js +94 -0
  27. package/dist/agent/agentPolicyResolver.js.map +1 -0
  28. package/dist/agent/agentRuntime.d.ts +12 -0
  29. package/dist/agent/agentRuntime.d.ts.map +1 -0
  30. package/dist/agent/agentRuntime.js +31 -0
  31. package/dist/agent/agentRuntime.js.map +1 -0
  32. package/dist/agent/agentToolRouter.d.ts +24 -0
  33. package/dist/agent/agentToolRouter.d.ts.map +1 -0
  34. package/dist/agent/agentToolRouter.js +89 -0
  35. package/dist/agent/agentToolRouter.js.map +1 -0
  36. package/dist/agent/guardianOperator.d.ts +35 -0
  37. package/dist/agent/guardianOperator.d.ts.map +1 -0
  38. package/dist/agent/guardianOperator.js +65 -0
  39. package/dist/agent/guardianOperator.js.map +1 -0
  40. package/dist/agent/index.d.ts +8 -0
  41. package/dist/agent/index.d.ts.map +1 -0
  42. package/dist/agent/index.js +14 -0
  43. package/dist/agent/index.js.map +1 -0
  44. package/dist/api/activityRoutes.d.ts +70 -0
  45. package/dist/api/activityRoutes.d.ts.map +1 -0
  46. package/dist/api/activityRoutes.js +100 -0
  47. package/dist/api/activityRoutes.js.map +1 -0
  48. package/dist/api/agentRoutes.d.ts +16 -0
  49. package/dist/api/agentRoutes.d.ts.map +1 -0
  50. package/dist/api/agentRoutes.js +37 -0
  51. package/dist/api/agentRoutes.js.map +1 -0
  52. package/dist/api/broadcastRoutes.d.ts +34 -0
  53. package/dist/api/broadcastRoutes.d.ts.map +1 -0
  54. package/dist/api/broadcastRoutes.js +147 -0
  55. package/dist/api/broadcastRoutes.js.map +1 -0
  56. package/dist/api/consolePage.d.ts +2 -0
  57. package/dist/api/consolePage.d.ts.map +1 -0
  58. package/dist/api/consolePage.js +206 -0
  59. package/dist/api/consolePage.js.map +1 -0
  60. package/dist/api/httpHardening.d.ts +75 -0
  61. package/dist/api/httpHardening.d.ts.map +1 -0
  62. package/dist/api/httpHardening.js +122 -0
  63. package/dist/api/httpHardening.js.map +1 -0
  64. package/dist/api/indexerRoutes.d.ts +46 -0
  65. package/dist/api/indexerRoutes.d.ts.map +1 -0
  66. package/dist/api/indexerRoutes.js +75 -0
  67. package/dist/api/indexerRoutes.js.map +1 -0
  68. package/dist/api/paidRoutes.d.ts +8 -0
  69. package/dist/api/paidRoutes.d.ts.map +1 -0
  70. package/dist/api/paidRoutes.js +175 -0
  71. package/dist/api/paidRoutes.js.map +1 -0
  72. package/dist/api/prepareRoutes.d.ts +58 -0
  73. package/dist/api/prepareRoutes.d.ts.map +1 -0
  74. package/dist/api/prepareRoutes.js +90 -0
  75. package/dist/api/prepareRoutes.js.map +1 -0
  76. package/dist/api/response.d.ts +39 -0
  77. package/dist/api/response.d.ts.map +1 -0
  78. package/dist/api/response.js +53 -0
  79. package/dist/api/response.js.map +1 -0
  80. package/dist/api/routes.d.ts +175 -0
  81. package/dist/api/routes.d.ts.map +1 -0
  82. package/dist/api/routes.js +276 -0
  83. package/dist/api/routes.js.map +1 -0
  84. package/dist/api/schemas.d.ts +147 -0
  85. package/dist/api/schemas.d.ts.map +1 -0
  86. package/dist/api/schemas.js +81 -0
  87. package/dist/api/schemas.js.map +1 -0
  88. package/dist/api/server.d.ts +11 -0
  89. package/dist/api/server.d.ts.map +1 -0
  90. package/dist/api/server.js +505 -0
  91. package/dist/api/server.js.map +1 -0
  92. package/dist/api/toolRoutes.d.ts +14 -0
  93. package/dist/api/toolRoutes.d.ts.map +1 -0
  94. package/dist/api/toolRoutes.js +138 -0
  95. package/dist/api/toolRoutes.js.map +1 -0
  96. package/dist/api/walletPrepareRoutes.d.ts +74 -0
  97. package/dist/api/walletPrepareRoutes.d.ts.map +1 -0
  98. package/dist/api/walletPrepareRoutes.js +127 -0
  99. package/dist/api/walletPrepareRoutes.js.map +1 -0
  100. package/dist/api/x402Gate.d.ts +51 -0
  101. package/dist/api/x402Gate.d.ts.map +1 -0
  102. package/dist/api/x402Gate.js +184 -0
  103. package/dist/api/x402Gate.js.map +1 -0
  104. package/dist/cli.d.ts +5 -5
  105. package/dist/cli.d.ts.map +1 -1
  106. package/dist/cli.js +154 -124
  107. package/dist/cli.js.map +1 -1
  108. package/dist/data/ecosystemRegistry.data.d.ts +3 -0
  109. package/dist/data/ecosystemRegistry.data.d.ts.map +1 -0
  110. package/dist/data/ecosystemRegistry.data.js +582 -0
  111. package/dist/data/ecosystemRegistry.data.js.map +1 -0
  112. package/dist/demo.d.ts +1 -1
  113. package/dist/demo.d.ts.map +1 -1
  114. package/dist/demo.js +206 -171
  115. package/dist/demo.js.map +1 -1
  116. package/dist/index.d.ts +2 -2
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +249 -164
  119. package/dist/index.js.map +1 -1
  120. package/dist/init.d.ts +1 -1
  121. package/dist/init.d.ts.map +1 -1
  122. package/dist/init.js +127 -65
  123. package/dist/init.js.map +1 -1
  124. package/dist/lib/analysis/approval.d.ts +29 -0
  125. package/dist/lib/analysis/approval.d.ts.map +1 -0
  126. package/dist/lib/analysis/approval.js +162 -0
  127. package/dist/lib/analysis/approval.js.map +1 -0
  128. package/dist/lib/analysis/calldata.d.ts +60 -0
  129. package/dist/lib/analysis/calldata.d.ts.map +1 -0
  130. package/dist/lib/analysis/calldata.js +349 -0
  131. package/dist/lib/analysis/calldata.js.map +1 -0
  132. package/dist/lib/analysis/contractIntel.d.ts +65 -0
  133. package/dist/lib/analysis/contractIntel.d.ts.map +1 -0
  134. package/dist/lib/analysis/contractIntel.js +320 -0
  135. package/dist/lib/analysis/contractIntel.js.map +1 -0
  136. package/dist/lib/analysis/evm.d.ts +42 -0
  137. package/dist/lib/analysis/evm.d.ts.map +1 -0
  138. package/dist/lib/analysis/evm.js +185 -0
  139. package/dist/lib/analysis/evm.js.map +1 -0
  140. package/dist/lib/analysis/gas.d.ts +4 -0
  141. package/dist/lib/analysis/gas.d.ts.map +1 -0
  142. package/dist/lib/analysis/gas.js +13 -0
  143. package/dist/lib/analysis/gas.js.map +1 -0
  144. package/dist/lib/analysis/index.d.ts +11 -0
  145. package/dist/lib/analysis/index.d.ts.map +1 -0
  146. package/dist/lib/analysis/index.js +16 -0
  147. package/dist/lib/analysis/index.js.map +1 -0
  148. package/dist/lib/analysis/pharosTokens.d.ts +31 -0
  149. package/dist/lib/analysis/pharosTokens.d.ts.map +1 -0
  150. package/dist/lib/analysis/pharosTokens.js +78 -0
  151. package/dist/lib/analysis/pharosTokens.js.map +1 -0
  152. package/dist/lib/analysis/safeTx.d.ts +27 -0
  153. package/dist/lib/analysis/safeTx.d.ts.map +1 -0
  154. package/dist/lib/analysis/safeTx.js +118 -0
  155. package/dist/lib/analysis/safeTx.js.map +1 -0
  156. package/dist/lib/analysis/token.d.ts +21 -0
  157. package/dist/lib/analysis/token.d.ts.map +1 -0
  158. package/dist/lib/analysis/token.js +151 -0
  159. package/dist/lib/analysis/token.js.map +1 -0
  160. package/dist/lib/analysis/types.d.ts +49 -0
  161. package/dist/lib/analysis/types.d.ts.map +1 -0
  162. package/dist/lib/analysis/types.js +10 -0
  163. package/dist/lib/analysis/types.js.map +1 -0
  164. package/dist/lib/analysis/x402.d.ts +24 -0
  165. package/dist/lib/analysis/x402.d.ts.map +1 -0
  166. package/dist/lib/analysis/x402.js +60 -0
  167. package/dist/lib/analysis/x402.js.map +1 -0
  168. package/dist/lib/auditLog.d.ts +1 -0
  169. package/dist/lib/auditLog.d.ts.map +1 -1
  170. package/dist/lib/auditLog.js +0 -0
  171. package/dist/lib/auditLog.js.map +1 -1
  172. package/dist/lib/config.d.ts +77 -0
  173. package/dist/lib/config.d.ts.map +1 -0
  174. package/dist/lib/config.js +120 -0
  175. package/dist/lib/config.js.map +1 -0
  176. package/dist/lib/constants.d.ts +452 -291
  177. package/dist/lib/constants.d.ts.map +1 -1
  178. package/dist/lib/constants.js +509 -292
  179. package/dist/lib/constants.js.map +1 -1
  180. package/dist/lib/dodoApi.d.ts +101 -78
  181. package/dist/lib/dodoApi.d.ts.map +1 -1
  182. package/dist/lib/dodoApi.js +259 -196
  183. package/dist/lib/dodoApi.js.map +1 -1
  184. package/dist/lib/ecosystemRegistry.d.ts +116 -0
  185. package/dist/lib/ecosystemRegistry.d.ts.map +1 -0
  186. package/dist/lib/ecosystemRegistry.js +178 -0
  187. package/dist/lib/ecosystemRegistry.js.map +1 -0
  188. package/dist/lib/envLoader.d.ts +2 -0
  189. package/dist/lib/envLoader.d.ts.map +1 -0
  190. package/dist/lib/envLoader.js +65 -0
  191. package/dist/lib/envLoader.js.map +1 -0
  192. package/dist/lib/goldsky.d.ts +58 -0
  193. package/dist/lib/goldsky.d.ts.map +1 -0
  194. package/dist/lib/goldsky.js +275 -0
  195. package/dist/lib/goldsky.js.map +1 -0
  196. package/dist/lib/guardian/decision.d.ts +23 -0
  197. package/dist/lib/guardian/decision.d.ts.map +1 -0
  198. package/dist/lib/guardian/decision.js +40 -0
  199. package/dist/lib/guardian/decision.js.map +1 -0
  200. package/dist/lib/http.d.ts +13 -14
  201. package/dist/lib/http.d.ts.map +1 -1
  202. package/dist/lib/http.js +383 -118
  203. package/dist/lib/http.js.map +1 -1
  204. package/dist/lib/managedExecution.d.ts +19 -0
  205. package/dist/lib/managedExecution.d.ts.map +1 -0
  206. package/dist/lib/managedExecution.js +64 -0
  207. package/dist/lib/managedExecution.js.map +1 -0
  208. package/dist/lib/merkleBatcher.d.ts +23 -0
  209. package/dist/lib/merkleBatcher.d.ts.map +1 -0
  210. package/dist/lib/merkleBatcher.js +62 -0
  211. package/dist/lib/merkleBatcher.js.map +1 -0
  212. package/dist/lib/networks.d.ts +48 -0
  213. package/dist/lib/networks.d.ts.map +1 -0
  214. package/dist/lib/networks.js +103 -0
  215. package/dist/lib/networks.js.map +1 -0
  216. package/dist/lib/observability/accessContext.d.ts +29 -0
  217. package/dist/lib/observability/accessContext.d.ts.map +1 -0
  218. package/dist/lib/observability/accessContext.js +50 -0
  219. package/dist/lib/observability/accessContext.js.map +1 -0
  220. package/dist/lib/observability/activityStore.d.ts +70 -0
  221. package/dist/lib/observability/activityStore.d.ts.map +1 -0
  222. package/dist/lib/observability/activityStore.js +149 -0
  223. package/dist/lib/observability/activityStore.js.map +1 -0
  224. package/dist/lib/observability/apiKey.d.ts +55 -0
  225. package/dist/lib/observability/apiKey.d.ts.map +1 -0
  226. package/dist/lib/observability/apiKey.js +141 -0
  227. package/dist/lib/observability/apiKey.js.map +1 -0
  228. package/dist/lib/observability/logger.d.ts +30 -0
  229. package/dist/lib/observability/logger.d.ts.map +1 -0
  230. package/dist/lib/observability/logger.js +30 -0
  231. package/dist/lib/observability/logger.js.map +1 -0
  232. package/dist/lib/observability/quota.d.ts +33 -0
  233. package/dist/lib/observability/quota.d.ts.map +1 -0
  234. package/dist/lib/observability/quota.js +49 -0
  235. package/dist/lib/observability/quota.js.map +1 -0
  236. package/dist/lib/observability/requestId.d.ts +8 -0
  237. package/dist/lib/observability/requestId.d.ts.map +1 -0
  238. package/dist/lib/observability/requestId.js +24 -0
  239. package/dist/lib/observability/requestId.js.map +1 -0
  240. package/dist/lib/observability/sanitize.d.ts +77 -0
  241. package/dist/lib/observability/sanitize.d.ts.map +1 -0
  242. package/dist/lib/observability/sanitize.js +228 -0
  243. package/dist/lib/observability/sanitize.js.map +1 -0
  244. package/dist/lib/observability/scopes.d.ts +20 -0
  245. package/dist/lib/observability/scopes.d.ts.map +1 -0
  246. package/dist/lib/observability/scopes.js +77 -0
  247. package/dist/lib/observability/scopes.js.map +1 -0
  248. package/dist/lib/okxDexApi.d.ts +106 -0
  249. package/dist/lib/okxDexApi.d.ts.map +1 -0
  250. package/dist/lib/okxDexApi.js +221 -0
  251. package/dist/lib/okxDexApi.js.map +1 -0
  252. package/dist/lib/persistentJsonStore.d.ts +5 -0
  253. package/dist/lib/persistentJsonStore.d.ts.map +1 -0
  254. package/dist/lib/persistentJsonStore.js +39 -0
  255. package/dist/lib/persistentJsonStore.js.map +1 -0
  256. package/dist/lib/pharos/attestationPublisher.d.ts +50 -0
  257. package/dist/lib/pharos/attestationPublisher.d.ts.map +1 -0
  258. package/dist/lib/pharos/attestationPublisher.js +262 -0
  259. package/dist/lib/pharos/attestationPublisher.js.map +1 -0
  260. package/dist/lib/pharos/ecosystem.d.ts +52 -0
  261. package/dist/lib/pharos/ecosystem.d.ts.map +1 -0
  262. package/dist/lib/pharos/ecosystem.js +431 -0
  263. package/dist/lib/pharos/ecosystem.js.map +1 -0
  264. package/dist/lib/pharos/ecosystemEvidence.d.ts +53 -0
  265. package/dist/lib/pharos/ecosystemEvidence.d.ts.map +1 -0
  266. package/dist/lib/pharos/ecosystemEvidence.js +133 -0
  267. package/dist/lib/pharos/ecosystemEvidence.js.map +1 -0
  268. package/dist/lib/pharos/rpc.d.ts +44 -0
  269. package/dist/lib/pharos/rpc.d.ts.map +1 -0
  270. package/dist/lib/pharos/rpc.js +90 -0
  271. package/dist/lib/pharos/rpc.js.map +1 -0
  272. package/dist/lib/pharos/rpcEvidence.d.ts +49 -0
  273. package/dist/lib/pharos/rpcEvidence.d.ts.map +1 -0
  274. package/dist/lib/pharos/rpcEvidence.js +46 -0
  275. package/dist/lib/pharos/rpcEvidence.js.map +1 -0
  276. package/dist/lib/pharos/rpcMethods.d.ts +46 -0
  277. package/dist/lib/pharos/rpcMethods.d.ts.map +1 -0
  278. package/dist/lib/pharos/rpcMethods.js +176 -0
  279. package/dist/lib/pharos/rpcMethods.js.map +1 -0
  280. package/dist/lib/pharos/spvVerifier.d.ts +47 -0
  281. package/dist/lib/pharos/spvVerifier.d.ts.map +1 -0
  282. package/dist/lib/pharos/spvVerifier.js +105 -0
  283. package/dist/lib/pharos/spvVerifier.js.map +1 -0
  284. package/dist/lib/pharos/userSignedBroadcaster.d.ts +10 -0
  285. package/dist/lib/pharos/userSignedBroadcaster.d.ts.map +1 -0
  286. package/dist/lib/pharos/userSignedBroadcaster.js +50 -0
  287. package/dist/lib/pharos/userSignedBroadcaster.js.map +1 -0
  288. package/dist/lib/pharosClient.d.ts +53 -58
  289. package/dist/lib/pharosClient.d.ts.map +1 -1
  290. package/dist/lib/pharosClient.js +56 -63
  291. package/dist/lib/pharosClient.js.map +1 -1
  292. package/dist/lib/policy/actionPolicyEngine.d.ts +89 -53
  293. package/dist/lib/policy/actionPolicyEngine.d.ts.map +1 -1
  294. package/dist/lib/policy/actionPolicyEngine.js +373 -212
  295. package/dist/lib/policy/actionPolicyEngine.js.map +1 -1
  296. package/dist/lib/policy/agentPolicy.d.ts +29 -0
  297. package/dist/lib/policy/agentPolicy.d.ts.map +1 -0
  298. package/dist/lib/policy/agentPolicy.js +154 -0
  299. package/dist/lib/policy/agentPolicy.js.map +1 -0
  300. package/dist/lib/policy/policyPresets.d.ts +30 -0
  301. package/dist/lib/policy/policyPresets.d.ts.map +1 -0
  302. package/dist/lib/policy/policyPresets.js +124 -0
  303. package/dist/lib/policy/policyPresets.js.map +1 -0
  304. package/dist/lib/policy/writeExecutionGate.d.ts +23 -0
  305. package/dist/lib/policy/writeExecutionGate.d.ts.map +1 -0
  306. package/dist/lib/policy/writeExecutionGate.js +65 -0
  307. package/dist/lib/policy/writeExecutionGate.js.map +1 -0
  308. package/dist/lib/preparedTxStore.d.ts +21 -0
  309. package/dist/lib/preparedTxStore.d.ts.map +1 -0
  310. package/dist/lib/preparedTxStore.js +90 -0
  311. package/dist/lib/preparedTxStore.js.map +1 -0
  312. package/dist/lib/price/chainlinkPushProvider.d.ts +34 -0
  313. package/dist/lib/price/chainlinkPushProvider.d.ts.map +1 -0
  314. package/dist/lib/price/chainlinkPushProvider.js +36 -0
  315. package/dist/lib/price/chainlinkPushProvider.js.map +1 -0
  316. package/dist/lib/price/feedRegistry.d.ts +26 -0
  317. package/dist/lib/price/feedRegistry.d.ts.map +1 -0
  318. package/dist/lib/price/feedRegistry.js +67 -0
  319. package/dist/lib/price/feedRegistry.js.map +1 -0
  320. package/dist/lib/price/priceResolver.d.ts +35 -0
  321. package/dist/lib/price/priceResolver.d.ts.map +1 -0
  322. package/dist/lib/price/priceResolver.js +246 -0
  323. package/dist/lib/price/priceResolver.js.map +1 -0
  324. package/dist/lib/price/supraProvider.d.ts +9 -0
  325. package/dist/lib/price/supraProvider.d.ts.map +1 -0
  326. package/dist/lib/price/supraProvider.js +17 -0
  327. package/dist/lib/price/supraProvider.js.map +1 -0
  328. package/dist/lib/price/types.d.ts +67 -0
  329. package/dist/lib/price/types.d.ts.map +1 -0
  330. package/dist/lib/price/types.js +7 -0
  331. package/dist/lib/price/types.js.map +1 -0
  332. package/dist/lib/productionGuards.d.ts +16 -0
  333. package/dist/lib/productionGuards.d.ts.map +1 -0
  334. package/dist/lib/productionGuards.js +93 -0
  335. package/dist/lib/productionGuards.js.map +1 -0
  336. package/dist/lib/recipientSafety.d.ts +5 -0
  337. package/dist/lib/recipientSafety.d.ts.map +1 -0
  338. package/dist/lib/recipientSafety.js +28 -0
  339. package/dist/lib/recipientSafety.js.map +1 -0
  340. package/dist/lib/riskEngine.d.ts +45 -26
  341. package/dist/lib/riskEngine.d.ts.map +1 -1
  342. package/dist/lib/riskEngine.js +346 -283
  343. package/dist/lib/riskEngine.js.map +1 -1
  344. package/dist/lib/riskInclusion.d.ts +72 -0
  345. package/dist/lib/riskInclusion.d.ts.map +1 -0
  346. package/dist/lib/riskInclusion.js +252 -0
  347. package/dist/lib/riskInclusion.js.map +1 -0
  348. package/dist/lib/safeHandsRegistry.d.ts +32 -0
  349. package/dist/lib/safeHandsRegistry.d.ts.map +1 -0
  350. package/dist/lib/safeHandsRegistry.js +151 -0
  351. package/dist/lib/safeHandsRegistry.js.map +1 -0
  352. package/dist/lib/signer/index.d.ts +24 -24
  353. package/dist/lib/signer/index.d.ts.map +1 -1
  354. package/dist/lib/signer/index.js +110 -88
  355. package/dist/lib/signer/index.js.map +1 -1
  356. package/dist/lib/spendAccumulator.d.ts +24 -1
  357. package/dist/lib/spendAccumulator.d.ts.map +1 -1
  358. package/dist/lib/spendAccumulator.js +76 -6
  359. package/dist/lib/spendAccumulator.js.map +1 -1
  360. package/dist/lib/toolResponse.d.ts +30 -25
  361. package/dist/lib/toolResponse.d.ts.map +1 -1
  362. package/dist/lib/toolResponse.js +57 -53
  363. package/dist/lib/toolResponse.js.map +1 -1
  364. package/dist/lib/validation.d.ts +7 -0
  365. package/dist/lib/validation.d.ts.map +1 -0
  366. package/dist/lib/validation.js +62 -0
  367. package/dist/lib/validation.js.map +1 -0
  368. package/dist/lib/wallet/index.d.ts +33 -37
  369. package/dist/lib/wallet/index.d.ts.map +1 -1
  370. package/dist/lib/wallet/index.js +141 -128
  371. package/dist/lib/wallet/index.js.map +1 -1
  372. package/dist/lib/x402ReplayStore.d.ts +6 -0
  373. package/dist/lib/x402ReplayStore.d.ts.map +1 -0
  374. package/dist/lib/x402ReplayStore.js +79 -0
  375. package/dist/lib/x402ReplayStore.js.map +1 -0
  376. package/dist/safehands.zip +0 -0
  377. package/dist/sdk.d.ts +14 -0
  378. package/dist/sdk.d.ts.map +1 -0
  379. package/dist/sdk.js +25 -0
  380. package/dist/sdk.js.map +1 -0
  381. package/dist/tools/approveToken.d.ts +66 -45
  382. package/dist/tools/approveToken.d.ts.map +1 -1
  383. package/dist/tools/approveToken.js +152 -85
  384. package/dist/tools/approveToken.js.map +1 -1
  385. package/dist/tools/assessRisk.d.ts +66 -79
  386. package/dist/tools/assessRisk.d.ts.map +1 -1
  387. package/dist/tools/assessRisk.js +63 -104
  388. package/dist/tools/assessRisk.js.map +1 -1
  389. package/dist/tools/checkAllowance.d.ts +49 -43
  390. package/dist/tools/checkAllowance.d.ts.map +1 -1
  391. package/dist/tools/checkAllowance.js +78 -56
  392. package/dist/tools/checkAllowance.js.map +1 -1
  393. package/dist/tools/checkTokenSecurity.d.ts +103 -46
  394. package/dist/tools/checkTokenSecurity.d.ts.map +1 -1
  395. package/dist/tools/checkTokenSecurity.js +240 -95
  396. package/dist/tools/checkTokenSecurity.js.map +1 -1
  397. package/dist/tools/createAgentWallet.d.ts +30 -26
  398. package/dist/tools/createAgentWallet.d.ts.map +1 -1
  399. package/dist/tools/createAgentWallet.js +87 -58
  400. package/dist/tools/createAgentWallet.js.map +1 -1
  401. package/dist/tools/estimateGas.d.ts +84 -79
  402. package/dist/tools/estimateGas.d.ts.map +1 -1
  403. package/dist/tools/estimateGas.js +130 -124
  404. package/dist/tools/estimateGas.js.map +1 -1
  405. package/dist/tools/executeSwap.d.ts +109 -61
  406. package/dist/tools/executeSwap.d.ts.map +1 -1
  407. package/dist/tools/executeSwap.js +289 -141
  408. package/dist/tools/executeSwap.js.map +1 -1
  409. package/dist/tools/explainRisk.d.ts +29 -29
  410. package/dist/tools/explainRisk.d.ts.map +1 -1
  411. package/dist/tools/explainRisk.js +33 -32
  412. package/dist/tools/explainRisk.js.map +1 -1
  413. package/dist/tools/getAgentPolicy.d.ts +15 -0
  414. package/dist/tools/getAgentPolicy.d.ts.map +1 -0
  415. package/dist/tools/getAgentPolicy.js +16 -0
  416. package/dist/tools/getAgentPolicy.js.map +1 -0
  417. package/dist/tools/getAgentReputation.d.ts +31 -0
  418. package/dist/tools/getAgentReputation.d.ts.map +1 -0
  419. package/dist/tools/getAgentReputation.js +44 -0
  420. package/dist/tools/getAgentReputation.js.map +1 -0
  421. package/dist/tools/getAgentWallet.d.ts +21 -21
  422. package/dist/tools/getAgentWallet.d.ts.map +1 -1
  423. package/dist/tools/getAgentWallet.js +37 -27
  424. package/dist/tools/getAgentWallet.js.map +1 -1
  425. package/dist/tools/getAgentWalletBalance.d.ts +11 -11
  426. package/dist/tools/getAgentWalletBalance.d.ts.map +1 -1
  427. package/dist/tools/getAgentWalletBalance.js +102 -70
  428. package/dist/tools/getAgentWalletBalance.js.map +1 -1
  429. package/dist/tools/getExecutionHistory.d.ts +49 -49
  430. package/dist/tools/getExecutionHistory.d.ts.map +1 -1
  431. package/dist/tools/getExecutionHistory.js +148 -154
  432. package/dist/tools/getExecutionHistory.js.map +1 -1
  433. package/dist/tools/getGasPrice.d.ts +43 -43
  434. package/dist/tools/getGasPrice.d.ts.map +0 -0
  435. package/dist/tools/getGasPrice.js +59 -59
  436. package/dist/tools/getGasPrice.js.map +1 -1
  437. package/dist/tools/getPoolInfo.d.ts +75 -75
  438. package/dist/tools/getPoolInfo.d.ts.map +1 -1
  439. package/dist/tools/getPoolInfo.js +142 -137
  440. package/dist/tools/getPoolInfo.js.map +1 -1
  441. package/dist/tools/getSpvProof.d.ts +24 -0
  442. package/dist/tools/getSpvProof.d.ts.map +1 -0
  443. package/dist/tools/getSpvProof.js +64 -0
  444. package/dist/tools/getSpvProof.js.map +1 -0
  445. package/dist/tools/getTokenPrice.d.ts +56 -113
  446. package/dist/tools/getTokenPrice.d.ts.map +1 -1
  447. package/dist/tools/getTokenPrice.js +110 -117
  448. package/dist/tools/getTokenPrice.js.map +1 -1
  449. package/dist/tools/getTransactionStatus.d.ts +43 -43
  450. package/dist/tools/getTransactionStatus.d.ts.map +0 -0
  451. package/dist/tools/getTransactionStatus.js +59 -59
  452. package/dist/tools/getTransactionStatus.js.map +0 -0
  453. package/dist/tools/getWalletBalance.d.ts +103 -68
  454. package/dist/tools/getWalletBalance.d.ts.map +1 -1
  455. package/dist/tools/getWalletBalance.js +127 -87
  456. package/dist/tools/getWalletBalance.js.map +1 -1
  457. package/dist/tools/publishRiskScore.d.ts +85 -63
  458. package/dist/tools/publishRiskScore.d.ts.map +1 -1
  459. package/dist/tools/publishRiskScore.js +136 -88
  460. package/dist/tools/publishRiskScore.js.map +1 -1
  461. package/dist/tools/queryGoldsky.d.ts +20 -0
  462. package/dist/tools/queryGoldsky.d.ts.map +1 -0
  463. package/dist/tools/queryGoldsky.js +29 -0
  464. package/dist/tools/queryGoldsky.js.map +1 -0
  465. package/dist/tools/queryRiskRegistry.d.ts +38 -38
  466. package/dist/tools/queryRiskRegistry.d.ts.map +1 -1
  467. package/dist/tools/queryRiskRegistry.js +59 -55
  468. package/dist/tools/queryRiskRegistry.js.map +1 -1
  469. package/dist/tools/safehandsPreflightCheck.d.ts +92 -77
  470. package/dist/tools/safehandsPreflightCheck.d.ts.map +1 -1
  471. package/dist/tools/safehandsPreflightCheck.js +174 -47
  472. package/dist/tools/safehandsPreflightCheck.js.map +1 -1
  473. package/dist/tools/safehandsRiskReport.d.ts +96 -81
  474. package/dist/tools/safehandsRiskReport.d.ts.map +1 -1
  475. package/dist/tools/safehandsRiskReport.js +48 -28
  476. package/dist/tools/safehandsRiskReport.js.map +1 -1
  477. package/dist/tools/safehandsSafeExecute.d.ts +20 -20
  478. package/dist/tools/safehandsSafeExecute.d.ts.map +1 -1
  479. package/dist/tools/safehandsSafeExecute.js +164 -81
  480. package/dist/tools/safehandsSafeExecute.js.map +1 -1
  481. package/dist/tools/safehandsWalletHealth.d.ts +28 -14
  482. package/dist/tools/safehandsWalletHealth.d.ts.map +1 -1
  483. package/dist/tools/safehandsWalletHealth.js +145 -103
  484. package/dist/tools/safehandsWalletHealth.js.map +1 -1
  485. package/dist/tools/safehandsX402Preflight.d.ts +26 -26
  486. package/dist/tools/safehandsX402Preflight.d.ts.map +1 -1
  487. package/dist/tools/safehandsX402Preflight.js +86 -65
  488. package/dist/tools/safehandsX402Preflight.js.map +1 -1
  489. package/dist/tools/sendPayment.d.ts +63 -57
  490. package/dist/tools/sendPayment.d.ts.map +1 -1
  491. package/dist/tools/sendPayment.js +144 -117
  492. package/dist/tools/sendPayment.js.map +1 -1
  493. package/dist/tools/setAgentPolicy.d.ts +75 -0
  494. package/dist/tools/setAgentPolicy.d.ts.map +1 -0
  495. package/dist/tools/setAgentPolicy.js +80 -0
  496. package/dist/tools/setAgentPolicy.js.map +1 -0
  497. package/dist/tools/simulateTransaction.d.ts +64 -60
  498. package/dist/tools/simulateTransaction.d.ts.map +1 -1
  499. package/dist/tools/simulateTransaction.js +116 -83
  500. package/dist/tools/simulateTransaction.js.map +1 -1
  501. package/dist/tools/tokenRegistryStatus.d.ts +46 -26
  502. package/dist/tools/tokenRegistryStatus.d.ts.map +1 -1
  503. package/dist/tools/tokenRegistryStatus.js +126 -96
  504. package/dist/tools/tokenRegistryStatus.js.map +1 -1
  505. package/dist/tools/verifyRiskInclusion.d.ts +59 -0
  506. package/dist/tools/verifyRiskInclusion.d.ts.map +1 -0
  507. package/dist/tools/verifyRiskInclusion.js +40 -0
  508. package/dist/tools/verifyRiskInclusion.js.map +1 -0
  509. package/dist/tools/x402PayAndFetch.d.ts +87 -81
  510. package/dist/tools/x402PayAndFetch.d.ts.map +1 -1
  511. package/dist/tools/x402PayAndFetch.js +295 -152
  512. package/dist/tools/x402PayAndFetch.js.map +1 -1
  513. package/dist/worker.d.ts +3 -0
  514. package/dist/worker.d.ts.map +1 -0
  515. package/dist/worker.js +39 -0
  516. package/dist/worker.js.map +1 -0
  517. package/dist/x402Server.d.ts +1 -1
  518. package/dist/x402Server.d.ts.map +1 -1
  519. package/dist/x402Server.js +409 -252
  520. package/dist/x402Server.js.map +1 -1
  521. package/docs/REVIEWER_QUICKSTART.md +113 -0
  522. package/docs/SAFEHANDS_REVIEWER_DEMO_SCRIPT.md +228 -0
  523. package/package.json +130 -83
  524. package/contracts/RiskRegistry.json +0 -223
  525. package/contracts/RiskRegistry.sol +0 -58
  526. package/dist/lib/testDodoLive.d.ts +0 -2
  527. package/dist/lib/testDodoLive.d.ts.map +0 -1
  528. package/dist/lib/testDodoLive.js +0 -105
  529. package/dist/lib/testDodoLive.js.map +0 -1
  530. package/dist/lib/testLiveSafehands.d.ts +0 -2
  531. package/dist/lib/testLiveSafehands.d.ts.map +0 -1
  532. package/dist/lib/testLiveSafehands.js +0 -93
  533. package/dist/lib/testLiveSafehands.js.map +0 -1
  534. package/dist/lib/testRpc.d.ts +0 -2
  535. package/dist/lib/testRpc.d.ts.map +0 -1
  536. package/dist/lib/testRpc.js +0 -30
  537. package/dist/lib/testRpc.js.map +0 -1
  538. package/dist/lib/testRpcLive.d.ts +0 -2
  539. package/dist/lib/testRpcLive.d.ts.map +0 -1
  540. package/dist/lib/testRpcLive.js +0 -89
  541. package/dist/lib/testRpcLive.js.map +0 -1
  542. package/dist/lib/testTools.d.ts +0 -2
  543. package/dist/lib/testTools.d.ts.map +0 -1
  544. package/dist/lib/testTools.js +0 -398
  545. package/dist/lib/testTools.js.map +0 -1
  546. package/dist/lib/testX402Live.d.ts +0 -2
  547. package/dist/lib/testX402Live.d.ts.map +0 -1
  548. package/dist/lib/testX402Live.js +0 -160
  549. package/dist/lib/testX402Live.js.map +0 -1
  550. package/dist/scripts/checkDeploy.d.ts +0 -2
  551. package/dist/scripts/checkDeploy.d.ts.map +0 -1
  552. package/dist/scripts/checkDeploy.js +0 -25
  553. package/dist/scripts/checkDeploy.js.map +0 -1
  554. package/dist/scripts/deployRegistry.d.ts +0 -2
  555. package/dist/scripts/deployRegistry.d.ts.map +0 -1
  556. package/dist/scripts/deployRegistry.js +0 -101
  557. package/dist/scripts/deployRegistry.js.map +0 -1
  558. package/dist/scripts/testRegistry.d.ts +0 -2
  559. package/dist/scripts/testRegistry.d.ts.map +0 -1
  560. package/dist/scripts/testRegistry.js +0 -44
  561. package/dist/scripts/testRegistry.js.map +0 -1
  562. package/examples/dashboard/index.html +0 -337
  563. package/examples/pharos-skill-engine/SKILL.safehands.md +0 -85
  564. package/examples/pharos-skill-engine/assets/safehands/example-actions.json +0 -49
  565. package/examples/pharos-skill-engine/assets/safehands/policy-defaults.json +0 -11
  566. package/examples/pharos-skill-engine/references/safehands.md +0 -345
  567. package/examples/scenario-hack.ts +0 -38
  568. package/skill/SKILL.md +0 -133
  569. package/skill/assets/safehands/example-actions.json +0 -49
  570. package/skill/assets/safehands/policy-defaults.json +0 -11
  571. package/skill/references/safehands.md +0 -345
@@ -1,253 +1,410 @@
1
- // ─── SafeHands x402 Server ──────────────────────────────────────────────
2
- // Exposes SafeHands risk endpoints. /supported and /health are free and do
3
- // not require user private keys. Paid routes are gated only when receiver +
4
- // facilitator signer config is present.
5
- // ────────────────────────────────────────────────────────────────────────
6
- import express from "express";
7
- import { join } from "path";
8
- import { readFileSync } from "fs";
9
- import { defineChain, createWalletClient, http, publicActions } from "viem";
10
- import { privateKeyToAccount } from "viem/accounts";
11
- import { x402Facilitator } from "@x402/core/facilitator";
12
- import { toFacilitatorEvmSigner } from "@x402/evm";
13
- import { ExactEvmScheme as FacilitatorExactEvmScheme } from "@x402/evm/exact/facilitator";
14
- import { ExactEvmScheme as ServerExactEvmScheme } from "@x402/evm/exact/server";
15
- import { HTTPFacilitatorClient } from "@x402/core/server";
16
- import { paymentMiddleware, x402ResourceServer } from "@x402/express";
17
- import { handleAssessRisk } from "./tools/assessRisk.js";
18
- import { handleCheckTokenSecurity } from "./tools/checkTokenSecurity.js";
19
- import { handleSimulateTransaction } from "./tools/simulateTransaction.js";
20
- import { CHAIN_ID, PHAROS_ENVIRONMENT, RPC_URL, X402_PAYMENT_TOKEN_ADDRESS } from "./lib/constants.js";
21
- import { fail, ok } from "./lib/toolResponse.js";
22
- function loadEnv() {
23
- try {
24
- const f = readFileSync(join(process.cwd(), ".env"), "utf-8");
25
- for (const l of f.split("\n")) {
26
- const t = l.trim();
27
- if (!t || t.startsWith("#"))
28
- continue;
29
- const i = t.indexOf("=");
30
- if (i === -1)
31
- continue;
32
- const key = t.slice(0, i).trim();
33
- if (process.env[key] === undefined)
34
- process.env[key] = t.slice(i + 1).trim();
35
- }
36
- }
37
- catch { }
38
- }
39
- loadEnv();
40
- const receiverAddress = (process.env.X402_PAY_TO || process.env.WALLET_ADDRESS || "");
41
- const facilitatorPrivateKey = process.env.X402_FACILITATOR_PRIVATE_KEY || "";
42
- const port = parseInt(process.env.X402_SERVER_PORT || process.env.X402_PORT || "4021", 10);
43
- const rpcUrl = process.env.PHAROS_RPC_URL || RPC_URL;
44
- const usdcAddress = X402_PAYMENT_TOKEN_ADDRESS;
45
- const priceUsdc = process.env.X402_PRICE_USDC || "0.001";
46
- const isPaidConfigured = Boolean(receiverAddress && facilitatorPrivateKey);
47
- const pharos = defineChain({
48
- id: CHAIN_ID,
49
- name: `Pharos ${PHAROS_ENVIRONMENT}`,
50
- nativeCurrency: { name: "PHRS", symbol: "PHRS", decimals: 18 },
51
- rpcUrls: { default: { http: [rpcUrl] } },
52
- testnet: true,
53
- });
54
- const app = express();
55
- app.disable("x-powered-by");
56
- app.use((req, res, next) => {
57
- req.setTimeout(15_000);
58
- res.setHeader("X-Content-Type-Options", "nosniff");
59
- res.setHeader("Referrer-Policy", "no-referrer");
60
- next();
61
- });
62
- app.use(express.json({ limit: "64kb" }));
63
- const rateLimitWindowMs = 60_000;
64
- const rateLimitMax = 120;
65
- const rateLimitBuckets = new Map();
66
- app.use((req, res, next) => {
67
- const key = req.ip || "unknown";
68
- const now = Date.now();
69
- const bucket = rateLimitBuckets.get(key);
70
- if (!bucket || bucket.resetAt <= now) {
71
- rateLimitBuckets.set(key, { count: 1, resetAt: now + rateLimitWindowMs });
72
- return next();
73
- }
74
- bucket.count += 1;
75
- if (bucket.count > rateLimitMax) {
76
- return res.status(429).json(fail("RATE_LIMITED", "Too many requests", true, "x402_server"));
77
- }
78
- return next();
79
- });
80
- let facilitator = null;
81
- let resourceServer = null;
82
- if (isPaidConfigured) {
83
- const account = privateKeyToAccount(facilitatorPrivateKey);
84
- const walletClient = createWalletClient({
85
- account,
86
- chain: pharos,
87
- transport: http(undefined, { timeout: 30_000 }),
88
- }).extend(publicActions);
89
- const evmSigner = toFacilitatorEvmSigner({
90
- address: account.address,
91
- getCode: (args) => walletClient.getCode(args),
92
- readContract: (args) => walletClient.readContract({ ...args, args: args.args || [] }),
93
- verifyTypedData: (args) => walletClient.verifyTypedData(args),
94
- writeContract: (args) => walletClient.writeContract({ ...args, args: args.args || [] }),
95
- sendTransaction: (args) => walletClient.sendTransaction(args),
96
- waitForTransactionReceipt: (args) => walletClient.waitForTransactionReceipt(args),
97
- });
98
- facilitator = new x402Facilitator();
99
- facilitator.register(`eip155:${CHAIN_ID}`, new FacilitatorExactEvmScheme(evmSigner, {}));
100
- const facilitatorClient = new HTTPFacilitatorClient({ url: `http://localhost:${port}` });
101
- resourceServer = new x402ResourceServer(facilitatorClient);
102
- const evmScheme = new ServerExactEvmScheme();
103
- evmScheme.registerMoneyParser(async (amount, network) => {
104
- if (network === `eip155:${CHAIN_ID}`) {
105
- return {
106
- amount: Math.round(amount * 1e6).toString(),
107
- asset: usdcAddress,
108
- extra: { token: "USDC", name: "USDC", version: "2" },
109
- };
110
- }
111
- return null;
112
- });
113
- resourceServer.register(`eip155:${CHAIN_ID}`, evmScheme);
114
- }
115
- app.post("/verify", async (req, res) => {
116
- if (!facilitator) {
117
- return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "x402 facilitator is not configured. Set X402_PAY_TO/WALLET_ADDRESS and X402_FACILITATOR_PRIVATE_KEY for paid endpoints. Client PRIVATE_KEY is not used for server receiver config.", false, "x402_server"));
118
- }
119
- try {
120
- const { paymentPayload, paymentRequirements } = req.body;
121
- const result = await facilitator.verify(paymentPayload, paymentRequirements);
122
- res.json(result);
123
- }
124
- catch (e) {
125
- res.status(500).json(fail("X402_PAYMENT_FAILED", e.message, true, "x402_server"));
126
- }
127
- });
128
- app.post("/settle", async (req, res) => {
129
- if (!facilitator) {
130
- return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "x402 facilitator is not configured. Set X402_PAY_TO/WALLET_ADDRESS and X402_FACILITATOR_PRIVATE_KEY for paid endpoints. Client PRIVATE_KEY is not used for server receiver config.", false, "x402_server"));
131
- }
132
- try {
133
- const { paymentPayload, paymentRequirements } = req.body;
134
- const result = await facilitator.settle(paymentPayload, paymentRequirements);
135
- res.json(result);
136
- }
137
- catch (e) {
138
- res.status(500).json(fail("X402_PAYMENT_FAILED", e.message, true, "x402_server"));
139
- }
140
- });
141
- app.get("/supported", (_req, res) => {
142
- if (facilitator)
143
- return res.json(facilitator.getSupported());
144
- return res.json(ok({
145
- configured: false,
146
- network: `eip155:${CHAIN_ID}`,
147
- scheme: "exact",
148
- asset: usdcAddress,
149
- priceUsdc,
150
- freeEndpoints: ["GET /supported", "GET /health"],
151
- paidEndpoints: ["GET /assess-risk", "GET /check-token-security", "GET /simulate-transaction"],
152
- configError: {
153
- code: "X402_SERVER_RECEIVER_CONFIG_MISSING",
154
- message: "Paid endpoints require receiver/payTo plus facilitator signer config. Free endpoints remain available.",
155
- },
156
- }));
157
- });
158
- app.get("/health", (_req, res) => {
159
- res.json(ok({
160
- status: "ok",
161
- service: "SafeHands x402 Resource Server",
162
- network: `Pharos ${PHAROS_ENVIRONMENT} (Chain ID ${CHAIN_ID})`,
163
- environment: PHAROS_ENVIRONMENT,
164
- isMainnet: false,
165
- receiverConfigured: Boolean(receiverAddress),
166
- paidEndpointsConfigured: isPaidConfigured,
167
- receiver: receiverAddress || null,
168
- asset: usdcAddress,
169
- freeEndpoints: ["/supported", "/health"],
170
- }));
171
- });
172
- function paidConfigError(req, res, next) {
173
- if (isPaidConfigured)
174
- return next();
175
- return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "Paid endpoint receiver/payTo or facilitator signer config is missing. Free endpoints do not require a client signer/private key.", false, "x402_server"));
176
- }
177
- if (isPaidConfigured && resourceServer) {
178
- app.use(paymentMiddleware({
179
- "GET /assess-risk": {
180
- accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
181
- description: `Assess transaction risk (USDC ${priceUsdc})`,
182
- mimeType: "application/json",
183
- },
184
- "GET /check-token-security": {
185
- accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
186
- description: `Verify contract token security profile (USDC ${priceUsdc})`,
187
- mimeType: "application/json",
188
- },
189
- "GET /simulate-transaction": {
190
- accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
191
- description: `Simulate EVM execution trace before broadcasting (USDC ${priceUsdc})`,
192
- mimeType: "application/json",
193
- },
194
- }, resourceServer));
195
- }
196
- else {
197
- app.use(["/assess-risk", "/check-token-security", "/simulate-transaction"], paidConfigError);
198
- }
199
- app.get("/assess-risk", async (req, res) => {
200
- try {
201
- const { action, tokenIn, tokenOut, amount, toAddress, walletAddress } = req.query;
202
- const result = await handleAssessRisk({
203
- action: action,
204
- tokenIn: tokenIn,
205
- tokenOut: tokenOut,
206
- amount: amount,
207
- toAddress: toAddress,
208
- walletAddress: walletAddress,
209
- });
210
- res.json(result);
211
- }
212
- catch (e) {
213
- res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
214
- }
215
- });
216
- app.get("/check-token-security", async (req, res) => {
217
- try {
218
- const { tokenAddress, chainId } = req.query;
219
- const cid = chainId ? parseInt(chainId, 10) : CHAIN_ID;
220
- const result = await handleCheckTokenSecurity({ tokenAddress: tokenAddress, chainId: cid });
221
- res.json(result);
222
- }
223
- catch (e) {
224
- res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
225
- }
226
- });
227
- app.get("/simulate-transaction", async (req, res) => {
228
- try {
229
- const { action, tokenIn, tokenOut, amount, toAddress, walletAddress } = req.query;
230
- const result = await handleSimulateTransaction({
231
- action: action,
232
- tokenIn: tokenIn,
233
- tokenOut: tokenOut,
234
- amount: amount,
235
- toAddress: toAddress,
236
- walletAddress: walletAddress,
237
- });
238
- res.json(result);
239
- }
240
- catch (e) {
241
- res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
242
- }
243
- });
244
- app.listen(port, () => {
245
- console.log(`✅ SafeHands x402 Server listening on http://localhost:${port}`);
246
- console.log(`📡 Network: eip155:${CHAIN_ID} (Pharos ${PHAROS_ENVIRONMENT})`);
247
- console.log(`💰 Paid endpoints configured: ${isPaidConfigured ? "yes" : "no"}`);
248
- if (receiverAddress)
249
- console.log(`💰 Paid recipient address: ${receiverAddress}`);
250
- console.log(`🪙 x402 payment token: ${usdcAddress}`);
251
- console.log(`🆓 Free APIs: /supported, /health`);
252
- });
1
+ // ─── SafeHands x402 Server ──────────────────────────────────────────────
2
+ // Exposes SafeHands risk endpoints. /supported and /health are free and do
3
+ // not require user private keys. Paid routes are gated only when receiver +
4
+ // facilitator signer config is present.
5
+ // ────────────────────────────────────────────────────────────────────────
6
+ import "./lib/envLoader.js";
7
+ import express from "express";
8
+ import { defineChain, createWalletClient, http, publicActions } from "viem";
9
+ import { privateKeyToAccount } from "viem/accounts";
10
+ import { x402Facilitator } from "@x402/core/facilitator";
11
+ import { toFacilitatorEvmSigner } from "@x402/evm";
12
+ import { ExactEvmScheme as FacilitatorExactEvmScheme } from "@x402/evm/exact/facilitator";
13
+ import { ExactEvmScheme as ServerExactEvmScheme } from "@x402/evm/exact/server";
14
+ import { HTTPFacilitatorClient } from "@x402/core/server";
15
+ import { paymentMiddleware, x402ResourceServer } from "@x402/express";
16
+ import { handleAssessRisk } from "./tools/assessRisk.js";
17
+ import { handleCheckTokenSecurity } from "./tools/checkTokenSecurity.js";
18
+ import { handleSimulateTransaction } from "./tools/simulateTransaction.js";
19
+ import { handleSafeHandsPreflightCheck } from "./tools/safehandsPreflightCheck.js";
20
+ import { handleGetTokenPrice } from "./tools/getTokenPrice.js";
21
+ import { handleGetPoolInfo } from "./tools/getPoolInfo.js";
22
+ import { getDodoRoute } from "./lib/dodoApi.js";
23
+ import { CHAIN_ID, PHAROS_ENVIRONMENT, RPC_URL, X402_PAYMENT_TOKEN_ADDRESS, PACIFIC_WPROS_ADDRESS, WPROS_ADDRESS, activeTokenDecimals, IS_MAINNET } from "./lib/constants.js";
24
+ import { fail, ok } from "./lib/toolResponse.js";
25
+ import { checkAndRecordX402Replay } from "./lib/x402ReplayStore.js";
26
+ import { assertProductionPosture } from "./lib/productionGuards.js";
27
+ import { replayStoreUnavailableMessage } from "./api/x402Gate.js";
28
+ // Fail-fast posture check (active only when NODE_ENV=production). This
29
+ // standalone server is the DEV / self-hosted single-tenant profile: it signs
30
+ // settlements locally with X402_FACILITATOR_PRIVATE_KEY (custody). In
31
+ // production it refuses to start unless SAFEHANDS_ALLOW_LOCAL_FACILITATOR=true
32
+ // is set explicitly — the zero-custody path is the Guardian API /paid/* gate
33
+ // with an external facilitator (X402_FACILITATOR_URL).
34
+ assertProductionPosture();
35
+ // Never leak internal error detail to clients on a 5xx in production; the raw
36
+ // message may contain RPC URLs, signer state, or stack fragments.
37
+ function serverErrorMessage(e) {
38
+ if (process.env.NODE_ENV === "production")
39
+ return "Internal x402 server error.";
40
+ return e instanceof Error ? e.message : String(e);
41
+ }
42
+ const receiverAddress = (process.env.X402_PAY_TO || process.env.WALLET_ADDRESS || "");
43
+ const facilitatorPrivateKey = process.env.X402_FACILITATOR_PRIVATE_KEY || "";
44
+ const port = parseInt(process.env.PORT || process.env.X402_SERVER_PORT || process.env.X402_PORT || "4021", 10);
45
+ const rpcUrl = process.env.PHAROS_RPC_URL || RPC_URL;
46
+ const paymentTokenAddress = X402_PAYMENT_TOKEN_ADDRESS;
47
+ const priceUsdc = process.env.X402_PRICE_USDC || "0.01";
48
+ const isPaidConfigured = Boolean(receiverAddress && facilitatorPrivateKey);
49
+ const pharos = defineChain({
50
+ id: CHAIN_ID,
51
+ name: `Pharos ${PHAROS_ENVIRONMENT}`,
52
+ nativeCurrency: { name: IS_MAINNET ? "PROS" : "PROS", symbol: IS_MAINNET ? "PROS" : "PROS", decimals: 18 },
53
+ rpcUrls: { default: { http: [rpcUrl] } },
54
+ testnet: !IS_MAINNET,
55
+ });
56
+ const app = express();
57
+ app.disable("x-powered-by");
58
+ app.use((req, res, next) => {
59
+ res.setHeader("Access-Control-Allow-Origin", "*");
60
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
61
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-PAYMENT, Accept");
62
+ if (req.method === "OPTIONS")
63
+ return res.sendStatus(200);
64
+ req.setTimeout(15_000);
65
+ res.setHeader("X-Content-Type-Options", "nosniff");
66
+ res.setHeader("Referrer-Policy", "no-referrer");
67
+ next();
68
+ });
69
+ app.use(express.json({ limit: "64kb" }));
70
+ const rateLimitWindowMs = 60_000;
71
+ const rateLimitMax = 120;
72
+ const rateLimitBuckets = new Map();
73
+ app.use((req, res, next) => {
74
+ const key = req.ip || "unknown";
75
+ const now = Date.now();
76
+ const bucket = rateLimitBuckets.get(key);
77
+ if (!bucket || bucket.resetAt <= now) {
78
+ rateLimitBuckets.set(key, { count: 1, resetAt: now + rateLimitWindowMs });
79
+ return next();
80
+ }
81
+ bucket.count += 1;
82
+ if (bucket.count > rateLimitMax) {
83
+ return res.status(429).json(fail("RATE_LIMITED", "Too many requests", true, "x402_server"));
84
+ }
85
+ return next();
86
+ });
87
+ let facilitator = null;
88
+ let resourceServer = null;
89
+ if (isPaidConfigured) {
90
+ const account = privateKeyToAccount(facilitatorPrivateKey);
91
+ const walletClient = createWalletClient({
92
+ account,
93
+ chain: pharos,
94
+ transport: http(undefined, { timeout: 30_000 }),
95
+ }).extend(publicActions);
96
+ const evmSigner = toFacilitatorEvmSigner({
97
+ address: account.address,
98
+ getCode: (args) => walletClient.getCode(args),
99
+ readContract: (args) => walletClient.readContract({ ...args, args: args.args || [] }),
100
+ verifyTypedData: (args) => walletClient.verifyTypedData(args),
101
+ writeContract: (args) => walletClient.writeContract({ ...args, args: args.args || [] }),
102
+ sendTransaction: (args) => walletClient.sendTransaction(args),
103
+ waitForTransactionReceipt: (args) => walletClient.waitForTransactionReceipt(args),
104
+ });
105
+ facilitator = new x402Facilitator();
106
+ facilitator.register(`eip155:${CHAIN_ID}`, new FacilitatorExactEvmScheme(evmSigner, {}));
107
+ const facilitatorClient = new HTTPFacilitatorClient({ url: `http://localhost:${port}` });
108
+ resourceServer = new x402ResourceServer(facilitatorClient);
109
+ const evmScheme = new ServerExactEvmScheme();
110
+ evmScheme.registerMoneyParser(async (amount, network) => {
111
+ if (network === `eip155:${CHAIN_ID}`) {
112
+ const decimals = activeTokenDecimals()[paymentTokenAddress.toLowerCase()] || 6;
113
+ const multiplier = Math.pow(10, decimals);
114
+ const isWpros = paymentTokenAddress.toLowerCase() === PACIFIC_WPROS_ADDRESS.toLowerCase() || paymentTokenAddress.toLowerCase() === WPROS_ADDRESS.toLowerCase();
115
+ const symbol = isWpros ? "WPROS" : "USDC";
116
+ return {
117
+ amount: Math.round(amount * multiplier).toString(),
118
+ asset: paymentTokenAddress,
119
+ extra: { token: symbol, name: symbol, version: "2" },
120
+ };
121
+ }
122
+ return null;
123
+ });
124
+ resourceServer.register(`eip155:${CHAIN_ID}`, evmScheme);
125
+ }
126
+ app.post("/verify", async (req, res) => {
127
+ if (!facilitator) {
128
+ return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "x402 facilitator is not configured. Set X402_PAY_TO/WALLET_ADDRESS and X402_FACILITATOR_PRIVATE_KEY for paid endpoints. Client PRIVATE_KEY is not used for server receiver config.", false, "x402_server"));
129
+ }
130
+ try {
131
+ const { paymentPayload, paymentRequirements } = req.body ?? {};
132
+ if (!paymentPayload || !paymentRequirements) {
133
+ return res.status(400).json(fail("BAD_REQUEST", "Missing required fields: paymentPayload and paymentRequirements.", false, "x402_server"));
134
+ }
135
+ const result = await facilitator.verify(paymentPayload, paymentRequirements);
136
+ res.json(result);
137
+ }
138
+ catch (e) {
139
+ res.status(500).json(fail("X402_PAYMENT_FAILED", serverErrorMessage(e), true, "x402_server"));
140
+ }
141
+ });
142
+ app.post("/settle", async (req, res) => {
143
+ if (!facilitator) {
144
+ return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "x402 facilitator is not configured. Set X402_PAY_TO/WALLET_ADDRESS and X402_FACILITATOR_PRIVATE_KEY for paid endpoints. Client PRIVATE_KEY is not used for server receiver config.", false, "x402_server"));
145
+ }
146
+ try {
147
+ const { paymentPayload, paymentRequirements } = req.body ?? {};
148
+ if (!paymentPayload || !paymentRequirements) {
149
+ return res.status(400).json(fail("BAD_REQUEST", "Missing required fields: paymentPayload and paymentRequirements.", false, "x402_server"));
150
+ }
151
+ const result = await facilitator.settle(paymentPayload, paymentRequirements);
152
+ res.json(result);
153
+ }
154
+ catch (e) {
155
+ res.status(500).json(fail("X402_PAYMENT_FAILED", serverErrorMessage(e), true, "x402_server"));
156
+ }
157
+ });
158
+ app.get("/supported", (_req, res) => {
159
+ if (facilitator)
160
+ return res.json(facilitator.getSupported());
161
+ return res.json(ok({
162
+ configured: false,
163
+ network: `eip155:${CHAIN_ID}`,
164
+ scheme: "exact",
165
+ asset: paymentTokenAddress,
166
+ priceUsdc,
167
+ freeEndpoints: ["GET /supported", "GET /health"],
168
+ paidEndpoints: ["GET /assess-risk", "GET /check-token-security", "GET /simulate-transaction", "GET /token-price", "GET /pool-info", "GET /swap-route"],
169
+ configError: {
170
+ code: "X402_SERVER_RECEIVER_CONFIG_MISSING",
171
+ message: "Paid endpoints require receiver/payTo plus facilitator signer config. Free endpoints remain available.",
172
+ },
173
+ }));
174
+ });
175
+ app.get("/health", (_req, res) => {
176
+ res.json(ok({
177
+ status: "ok",
178
+ service: "SafeHands x402 Resource Server",
179
+ network: `Pharos ${PHAROS_ENVIRONMENT} (Chain ID ${CHAIN_ID})`,
180
+ environment: PHAROS_ENVIRONMENT,
181
+ isMainnet: IS_MAINNET,
182
+ receiverConfigured: Boolean(receiverAddress),
183
+ paidEndpointsConfigured: isPaidConfigured,
184
+ receiver: receiverAddress || null,
185
+ asset: paymentTokenAddress,
186
+ freeEndpoints: ["/supported", "/health"],
187
+ }));
188
+ });
189
+ function paidConfigError(req, res, next) {
190
+ if (isPaidConfigured)
191
+ return next();
192
+ return res.status(503).json(fail("X402_SERVER_RECEIVER_CONFIG_MISSING", "Paid endpoint receiver/payTo or facilitator signer config is missing. Free endpoints do not require a client signer/private key.", false, "x402_server"));
193
+ }
194
+ // ─── x402 Replay Protection (durable idempotency cache) ────────────────
195
+ const REPLAY_WINDOW_MS = Number(process.env.SAFEHANDS_X402_REPLAY_WINDOW_MS || 10 * 60 * 1000); // default 10 minutes
196
+ function replayProtectionMiddleware(req, res, next) {
197
+ const paymentHeader = req.headers["x-payment"];
198
+ if (typeof paymentHeader !== "string" || paymentHeader.length <= 10)
199
+ return next();
200
+ checkAndRecordX402Replay(paymentHeader, REPLAY_WINDOW_MS)
201
+ .then((result) => {
202
+ res.setHeader("X-SafeHands-X402-Replay-Store", result.backend);
203
+ if (!result.allowed) {
204
+ return res.status(402).json(fail("REPLAY_ATTACK_DETECTED", "This x402 payment signature has already been used.", false, "x402_server"));
205
+ }
206
+ return next();
207
+ })
208
+ .catch((err) => {
209
+ // Raw store errors (Upstash detail, Redis hostname, fs paths) stay in
210
+ // server logs; production clients get a generic message.
211
+ console.error("[SafeHands x402] replay store unavailable:", err instanceof Error ? err.message : String(err));
212
+ return res.status(503).json(fail("X402_REPLAY_STORE_UNAVAILABLE", replayStoreUnavailableMessage(err), true, "x402_server"));
213
+ });
214
+ }
215
+ // ────────────────────────────────────────────────────────────────────────
216
+ if (isPaidConfigured && resourceServer) {
217
+ app.use(["/assess-risk", "/check-token-security", "/simulate-transaction", "/token-price", "/pool-info", "/swap-route"], replayProtectionMiddleware);
218
+ app.use(paymentMiddleware({
219
+ "GET /assess-risk": {
220
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
221
+ description: `Assess transaction risk (USDC ${priceUsdc})`,
222
+ mimeType: "application/json",
223
+ },
224
+ "GET /check-token-security": {
225
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
226
+ description: `Verify contract token security profile (USDC ${priceUsdc})`,
227
+ mimeType: "application/json",
228
+ },
229
+ "GET /simulate-transaction": {
230
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
231
+ description: `Simulate EVM execution trace before broadcasting (USDC ${priceUsdc})`,
232
+ mimeType: "application/json",
233
+ },
234
+ "GET /token-price": {
235
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
236
+ description: `Real-time token price via DODO/FaroSwap (USDC ${priceUsdc})`,
237
+ mimeType: "application/json",
238
+ },
239
+ "GET /pool-info": {
240
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
241
+ description: `DODO/FaroSwap pool data: price ratio, impact, fees (USDC ${priceUsdc})`,
242
+ mimeType: "application/json",
243
+ },
244
+ "GET /swap-route": {
245
+ accepts: { scheme: "exact", price: priceUsdc, network: `eip155:${CHAIN_ID}`, payTo: receiverAddress },
246
+ description: `Swap route with estimated output via DODO (USDC ${priceUsdc})`,
247
+ mimeType: "application/json",
248
+ },
249
+ }, resourceServer));
250
+ }
251
+ else {
252
+ app.use(["/assess-risk", "/check-token-security", "/simulate-transaction", "/token-price", "/pool-info", "/swap-route"], paidConfigError);
253
+ }
254
+ app.get("/assess-risk", async (req, res) => {
255
+ try {
256
+ const { action, tokenIn, tokenOut, amount, toAddress, walletAddress } = req.query;
257
+ const result = await handleAssessRisk({
258
+ action: action,
259
+ tokenIn: tokenIn,
260
+ tokenOut: tokenOut,
261
+ amount: amount,
262
+ toAddress: toAddress,
263
+ walletAddress: walletAddress,
264
+ });
265
+ res.json(result);
266
+ }
267
+ catch (e) {
268
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
269
+ }
270
+ });
271
+ app.get("/check-token-security", async (req, res) => {
272
+ try {
273
+ const { tokenAddress, chainId } = req.query;
274
+ const cid = chainId ? parseInt(chainId, 10) : CHAIN_ID;
275
+ const result = await handleCheckTokenSecurity({ tokenAddress: tokenAddress, chainId: cid });
276
+ res.json(result);
277
+ }
278
+ catch (e) {
279
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
280
+ }
281
+ });
282
+ app.get("/simulate-transaction", async (req, res) => {
283
+ try {
284
+ const { action, tokenIn, tokenOut, amount, toAddress, walletAddress } = req.query;
285
+ const result = await handleSimulateTransaction({
286
+ action: action,
287
+ tokenIn: tokenIn,
288
+ tokenOut: tokenOut,
289
+ amount: amount,
290
+ toAddress: toAddress,
291
+ walletAddress: walletAddress,
292
+ });
293
+ res.json(result);
294
+ }
295
+ catch (e) {
296
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
297
+ }
298
+ });
299
+ app.get("/token-price", async (req, res) => {
300
+ try {
301
+ const { token } = req.query;
302
+ if (!token || typeof token !== "string") {
303
+ return res.status(400).json(fail("BAD_REQUEST", "Missing required query parameter: token (PROS, USDC, or USDT)", false, "x402_server"));
304
+ }
305
+ const result = await handleGetTokenPrice({ token: token });
306
+ res.json(result);
307
+ }
308
+ catch (e) {
309
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
310
+ }
311
+ });
312
+ app.get("/pool-info", async (req, res) => {
313
+ try {
314
+ const { tokenA, tokenB } = req.query;
315
+ if (!tokenA || !tokenB || typeof tokenA !== "string" || typeof tokenB !== "string") {
316
+ return res.status(400).json(fail("BAD_REQUEST", "Missing required query parameters: tokenA and tokenB (PROS, USDC, or USDT)", false, "x402_server"));
317
+ }
318
+ const result = await handleGetPoolInfo({ tokenA: tokenA, tokenB: tokenB });
319
+ res.json(result);
320
+ }
321
+ catch (e) {
322
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
323
+ }
324
+ });
325
+ app.get("/swap-route", async (req, res) => {
326
+ try {
327
+ const { tokenIn, tokenOut, amount } = req.query;
328
+ if (!tokenIn || !tokenOut || !amount || typeof tokenIn !== "string" || typeof tokenOut !== "string" || typeof amount !== "string") {
329
+ return res.status(400).json(fail("BAD_REQUEST", "Missing required query parameters: tokenIn, tokenOut, amount", false, "x402_server"));
330
+ }
331
+ const amountNum = Number(amount);
332
+ if (!Number.isFinite(amountNum) || amountNum <= 0) {
333
+ return res.status(400).json(fail("BAD_REQUEST", "amount must be a positive number", false, "x402_server"));
334
+ }
335
+ const quote = await getDodoRoute({
336
+ fromToken: tokenIn,
337
+ toToken: tokenOut,
338
+ amountHuman: amount,
339
+ walletAddress: "0x0000000000000000000000000000000000000001",
340
+ });
341
+ res.json(ok({
342
+ tokenIn,
343
+ tokenOut,
344
+ amountIn: amount,
345
+ estimatedOutput: quote.routeAvailable ? quote.amountOut : null,
346
+ priceImpact: quote.priceImpact,
347
+ routeAvailable: quote.routeAvailable,
348
+ gasEstimate: quote.gasLimit,
349
+ wasSubstituted: quote.wasSubstituted,
350
+ substitutionNote: quote.substitutionNote || null,
351
+ source: "DODO/FaroSwap route API",
352
+ chainId: CHAIN_ID,
353
+ environment: PHAROS_ENVIRONMENT,
354
+ isMainnet: IS_MAINNET,
355
+ }));
356
+ }
357
+ catch (e) {
358
+ const message = e instanceof Error ? e.message : String(e);
359
+ if (message.includes("SWAP_LIQUIDITY_NOT_CONFIGURED")) {
360
+ return res.status(503).json(fail("SWAP_LIQUIDITY_NOT_CONFIGURED", message, false, "x402_server"));
361
+ }
362
+ res.status(400).json(fail("BAD_REQUEST", message, false, "x402_server"));
363
+ }
364
+ });
365
+ // Free endpoints for live dashboard
366
+ app.get("/preflight", async (req, res) => {
367
+ try {
368
+ const { actionType, chainId, amount, tokenAddress, spender, approvalAmount, recipient } = req.query;
369
+ const result = await handleSafeHandsPreflightCheck({
370
+ actionType: actionType,
371
+ chainId: chainId ? parseInt(chainId, 10) : CHAIN_ID,
372
+ amount: amount,
373
+ tokenAddress: tokenAddress,
374
+ spender: spender,
375
+ approvalAmount: approvalAmount,
376
+ recipient: recipient,
377
+ });
378
+ res.json(result);
379
+ }
380
+ catch (e) {
381
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
382
+ }
383
+ });
384
+ app.get("/risk", async (req, res) => {
385
+ try {
386
+ const { action, tokenIn, tokenOut, amount, toAddress, walletAddress } = req.query;
387
+ const result = await handleAssessRisk({
388
+ action: action,
389
+ tokenIn: tokenIn,
390
+ tokenOut: tokenOut,
391
+ amount: amount,
392
+ toAddress: toAddress,
393
+ walletAddress: walletAddress,
394
+ });
395
+ res.json(result);
396
+ }
397
+ catch (e) {
398
+ res.status(400).json(fail("BAD_REQUEST", e.message, false, "x402_server"));
399
+ }
400
+ });
401
+ app.listen(port, () => {
402
+ console.log(`✅ SafeHands x402 Server listening on http://localhost:${port}`);
403
+ console.log(`📡 Network: eip155:${CHAIN_ID} (Pharos ${PHAROS_ENVIRONMENT})`);
404
+ console.log(`💰 Paid endpoints configured: ${isPaidConfigured ? "yes" : "no"}`);
405
+ if (receiverAddress)
406
+ console.log(`💰 Paid recipient address: ${receiverAddress}`);
407
+ console.log(`🪙 x402 payment token: ${paymentTokenAddress}`);
408
+ console.log(`🆓 Free APIs: /supported, /health`);
409
+ });
253
410
  //# sourceMappingURL=x402Server.js.map