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,284 +1,347 @@
1
- // ─── Risk Scoring Engine ───────────────────────────────────────────────
2
- // 5-dimension risk assessment engine for SafeHands.
3
- // Weights: liquidity 25%, slippage 25%, counterparty 20%,
4
- // balance 15%, market conditions 15%
5
- // ────────────────────────────────────────────────────────────────────────
6
- import { publicClient } from "./pharosClient.js";
7
- import { getDodoRoute, isNativeToken, resolveTokenAddress, resolveTokenDecimals, toWei, } from "./dodoApi.js";
8
- import { RISK_WEIGHTS, RISK_BLOCK_THRESHOLD, MAX_SLIPPAGE_PCT, MAX_BALANCE_USAGE_PCT, ERC20_ABI, } from "./constants.js";
9
- import { formatEther, isAddress, parseEther } from "viem";
10
- // ─── Helpers ───────────────────────────────────────────────────────────
11
- function clamp(value, min = 0, max = 100) {
12
- return Math.max(min, Math.min(max, value));
13
- }
14
- function computeRiskLevel(score) {
15
- if (score <= 30)
16
- return "low";
17
- if (score <= 60)
18
- return "medium";
19
- if (score <= 80)
20
- return "high";
21
- return "critical";
22
- }
23
- function computeRecommendation(score) {
24
- if (score <= 30)
25
- return "proceed";
26
- if (score <= RISK_BLOCK_THRESHOLD)
27
- return "caution";
28
- return "block";
29
- }
30
- function weightedAverage(breakdown) {
31
- const w = RISK_WEIGHTS;
32
- return Math.round(breakdown.liquidityRisk * w.liquidityRisk +
33
- breakdown.slippageRisk * w.slippageRisk +
34
- breakdown.counterpartyRisk * w.counterpartyRisk +
35
- breakdown.balanceRisk * w.balanceRisk +
36
- breakdown.marketConditionRisk * w.marketConditionRisk);
37
- }
38
- // ─── Individual Risk Scorers ───────────────────────────────────────────
39
- async function scoreLiquidity(input) {
40
- const reasons = [];
41
- if (input.action !== "swap")
42
- return { score: 0, reasons };
43
- try {
44
- const quote = await getDodoRoute({
45
- fromToken: input.tokenIn,
46
- toToken: input.tokenOut,
47
- amountHuman: input.amount,
48
- walletAddress: input.walletAddress,
49
- });
50
- if (!quote.routeAvailable) {
51
- reasons.push("No swap route available — liquidity may be exhausted");
52
- return { score: 100, reasons };
53
- }
54
- const impact = Math.abs(quote.priceImpact);
55
- if (impact > 5) {
56
- reasons.push(`High price impact: ${impact.toFixed(2)}%`);
57
- return { score: clamp(80 + impact), reasons };
58
- }
59
- if (impact > 2) {
60
- reasons.push(`Moderate price impact: ${impact.toFixed(2)}%`);
61
- return { score: clamp(40 + impact * 10), reasons };
62
- }
63
- reasons.push(`Price impact acceptable: ${impact.toFixed(2)}%`);
64
- return { score: clamp(impact * 15), reasons };
65
- }
66
- catch (err) {
67
- reasons.push(`Failed to fetch liquidity data: ${err.message}`);
68
- return { score: 70, reasons };
69
- }
70
- }
71
- async function scoreSlippage(input) {
72
- const reasons = [];
73
- if (input.action !== "swap")
74
- return { score: 0, reasons };
75
- try {
76
- const quote = await getDodoRoute({
77
- fromToken: input.tokenIn,
78
- toToken: input.tokenOut,
79
- amountHuman: input.amount,
80
- walletAddress: input.walletAddress,
81
- });
82
- if (!quote.routeAvailable) {
83
- reasons.push("Cannot estimate slippage — no route");
84
- return { score: 90, reasons };
85
- }
86
- const impact = Math.abs(quote.priceImpact);
87
- if (impact > MAX_SLIPPAGE_PCT) {
88
- reasons.push(`Slippage exceeds max ${MAX_SLIPPAGE_PCT}%: estimated ${impact.toFixed(2)}%`);
89
- return { score: clamp(80 + (impact - MAX_SLIPPAGE_PCT) * 5), reasons };
90
- }
91
- reasons.push(`Estimated slippage: ${impact.toFixed(2)}%`);
92
- return { score: clamp(impact * 16), reasons };
93
- }
94
- catch {
95
- reasons.push("Slippage estimation failed");
96
- return { score: 60, reasons };
97
- }
98
- }
99
- async function scoreCounterparty(input) {
100
- const reasons = [];
101
- if (input.action === "swap") {
102
- // For swaps, counterparty is the DODO protocol — trusted
103
- reasons.push("Swap routed through DODO protocol (known)");
104
- return { score: 5, reasons };
105
- }
106
- // For transfers, check the recipient address
107
- const to = input.toAddress;
108
- if (!to) {
109
- reasons.push("No recipient address provided");
110
- return { score: 100, reasons };
111
- }
112
- if (!isAddress(to)) {
113
- reasons.push("Invalid EVM address format");
114
- return { score: 100, reasons };
115
- }
116
- // Zero address check
117
- if (to === "0x0000000000000000000000000000000000000000") {
118
- reasons.push("Sending to zero address — tokens will be burned");
119
- return { score: 95, reasons };
120
- }
121
- // Self-send check
122
- if (to.toLowerCase() === input.walletAddress.toLowerCase()) {
123
- reasons.push("Sending to own address — likely unintended");
124
- return { score: 50, reasons };
125
- }
126
- // Check if address has code (is a contract)
127
- try {
128
- const code = await publicClient.getCode({ address: to });
129
- if (code && code !== "0x") {
130
- reasons.push("Recipient is a contract address — verify intent");
131
- return { score: 40, reasons };
132
- }
133
- }
134
- catch {
135
- // RPC error, non-critical
136
- }
137
- // Check if address has any transaction history (has balance)
138
- try {
139
- const balance = await publicClient.getBalance({ address: to });
140
- if (balance === 0n) {
141
- reasons.push("Recipient has zero balance — new or unused address");
142
- return { score: 30, reasons };
143
- }
144
- }
145
- catch {
146
- // Non-critical
147
- }
148
- reasons.push("Recipient address looks valid");
149
- return { score: 10, reasons };
150
- }
151
- async function scoreBalance(input) {
152
- const reasons = [];
153
- try {
154
- const walletAddr = input.walletAddress;
155
- if (input.action === "transfer" || (input.action === "swap" && isNativeToken(input.tokenIn || "PHRS"))) {
156
- // Check native PHRS balance
157
- const balance = await publicClient.getBalance({ address: walletAddr });
158
- const amountWei = parseEther(input.amount);
159
- const gasBuffer = parseEther("0.01"); // ~0.01 PHRS for gas
160
- if (balance < amountWei + gasBuffer) {
161
- const balanceHuman = formatEther(balance);
162
- reasons.push(`Insufficient PHRS balance: have ${balanceHuman}, need ${input.amount} + gas`);
163
- return { score: 100, reasons };
164
- }
165
- const usagePct = Number((amountWei * 100n) / balance);
166
- if (usagePct > MAX_BALANCE_USAGE_PCT) {
167
- reasons.push(`Using ${usagePct}% of wallet balance — high exposure`);
168
- return { score: clamp(60 + (usagePct - MAX_BALANCE_USAGE_PCT)), reasons };
169
- }
170
- reasons.push(`Balance sufficient, using ${usagePct}% of wallet`);
171
- return { score: clamp(usagePct / 3), reasons };
172
- }
173
- // ERC-20 token balance check
174
- if (input.tokenIn) {
175
- const tokenAddress = resolveTokenAddress(input.tokenIn);
176
- const decimals = resolveTokenDecimals(input.tokenIn);
177
- const amountWei = BigInt(toWei(input.amount, decimals));
178
- const balance = (await publicClient.readContract({
179
- address: tokenAddress,
180
- abi: ERC20_ABI,
181
- functionName: "balanceOf",
182
- args: [walletAddr],
183
- }));
184
- if (balance < amountWei) {
185
- reasons.push(`Insufficient ${input.tokenIn} balance`);
186
- return { score: 100, reasons };
187
- }
188
- // Also check gas balance
189
- const ethBalance = await publicClient.getBalance({ address: walletAddr });
190
- if (ethBalance < parseEther("0.005")) {
191
- reasons.push("Very low PHRS balance for gas fees");
192
- return { score: 80, reasons };
193
- }
194
- reasons.push("Token and gas balance sufficient");
195
- return { score: 5, reasons };
196
- }
197
- return { score: 0, reasons: ["Balance check skipped"] };
198
- }
199
- catch (err) {
200
- reasons.push(`Balance check failed: ${err.message}`);
201
- return { score: 50, reasons };
202
- }
203
- }
204
- async function scoreMarketCondition(_input) {
205
- const reasons = [];
206
- try {
207
- // Check recent block production rate as a proxy for chain health
208
- const latestBlock = await publicClient.getBlock({ blockTag: "latest" });
209
- const prevBlock = await publicClient.getBlock({
210
- blockNumber: latestBlock.number - 10n,
211
- });
212
- const timeDiff = Number(latestBlock.timestamp - prevBlock.timestamp);
213
- const avgBlockTime = timeDiff / 10;
214
- if (avgBlockTime > 30) {
215
- reasons.push(`Slow block production: ~${avgBlockTime.toFixed(1)}s/block — chain may be congested`);
216
- return { score: 60, reasons };
217
- }
218
- if (avgBlockTime > 15) {
219
- reasons.push(`Slightly elevated block times: ~${avgBlockTime.toFixed(1)}s/block`);
220
- return { score: 30, reasons };
221
- }
222
- // Check gas price
223
- const gasPrice = await publicClient.getGasPrice();
224
- const gasPriceGwei = Number(gasPrice) / 1e9;
225
- if (gasPriceGwei > 100) {
226
- reasons.push(`High gas price: ${gasPriceGwei.toFixed(1)} Gwei`);
227
- return { score: 50, reasons };
228
- }
229
- reasons.push(`Chain healthy: ~${avgBlockTime.toFixed(1)}s/block, ${gasPriceGwei.toFixed(1)} Gwei gas`);
230
- return { score: 5, reasons };
231
- }
232
- catch {
233
- reasons.push("Could not assess market conditions");
234
- return { score: 20, reasons };
235
- }
236
- }
237
- // ─── Main Risk Assessment ──────────────────────────────────────────────
238
- export async function assessRisk(input) {
239
- const [liquidity, slippage, counterparty, balance, market] = await Promise.all([
240
- scoreLiquidity(input),
241
- scoreSlippage(input),
242
- scoreCounterparty(input),
243
- scoreBalance(input),
244
- scoreMarketCondition(input),
245
- ]);
246
- const breakdown = {
247
- liquidityRisk: liquidity.score,
248
- slippageRisk: slippage.score,
249
- counterpartyRisk: counterparty.score,
250
- balanceRisk: balance.score,
251
- marketConditionRisk: market.score,
252
- };
253
- const riskScore = clamp(weightedAverage(breakdown));
254
- const riskLevel = computeRiskLevel(riskScore);
255
- const recommendation = computeRecommendation(riskScore);
256
- const reasons = [
257
- ...liquidity.reasons,
258
- ...slippage.reasons,
259
- ...counterparty.reasons,
260
- ...balance.reasons,
261
- ...market.reasons,
262
- ];
263
- let suggestion;
264
- if (recommendation === "proceed") {
265
- suggestion = "Risk is within acceptable range. Proceed with the transaction.";
266
- }
267
- else if (recommendation === "caution") {
268
- suggestion =
269
- "Moderate risk detected. Review the risk breakdown carefully before proceeding. Consider reducing the amount or adjusting parameters.";
270
- }
271
- else {
272
- suggestion =
273
- "High risk detected execution blocked for safety. Review the reasons and adjust your transaction parameters significantly before retrying.";
274
- }
275
- return {
276
- riskScore,
277
- riskLevel,
278
- recommendation,
279
- breakdown,
280
- reasons,
281
- suggestion,
282
- };
283
- }
1
+ // ─── Risk Scoring Engine (ADVISORY) ────────────────────────────────────
2
+ // 5-dimension risk assessment engine for SafeHands.
3
+ // Weights: liquidity 25%, slippage 25%, counterparty 20%,
4
+ // balance 15%, market conditions 15%
5
+ //
6
+ // This engine never gates execution. Its output is advisory: published
7
+ // on-chain as part of the assessment record (publish_risk_score) and fed to
8
+ // the actionPolicyEngine as evidence (riskEvidenceFromAssessment) the
9
+ // policy engine is the sole ALLOW/BLOCK decider on write paths
10
+ // (docs/DECISION_CONTRACT.md).
11
+ // ────────────────────────────────────────────────────────────────────────
12
+ import { publicClient } from "./pharosClient.js";
13
+ import { getDodoRoute, isNativeToken, resolveTokenAddress, resolveTokenDecimals, toWei, DodoNotConfiguredError, } from "./dodoApi.js";
14
+ import { RISK_WEIGHTS, RISK_BLOCK_THRESHOLD, COUNTERPARTY_CRITICAL_THRESHOLD, MAX_SLIPPAGE_PCT, MAX_BALANCE_USAGE_PCT, ERC20_ABI, CHAIN_ID, } from "./constants.js";
15
+ import { addressTrustEvidence } from "./ecosystemRegistry.js";
16
+ import { formatEther, isAddress, parseEther } from "viem";
17
+ // ─── Helpers ───────────────────────────────────────────────────────────
18
+ function clamp(value, min = 0, max = 100) {
19
+ return Math.max(min, Math.min(max, value));
20
+ }
21
+ function computeRiskLevel(score) {
22
+ if (score <= 30)
23
+ return "low";
24
+ if (score <= 60)
25
+ return "medium";
26
+ if (score <= 80)
27
+ return "high";
28
+ return "critical";
29
+ }
30
+ function computeRecommendation(score) {
31
+ if (score <= 30)
32
+ return "proceed";
33
+ if (score <= RISK_BLOCK_THRESHOLD)
34
+ return "caution";
35
+ return "block";
36
+ }
37
+ function weightedAverage(breakdown) {
38
+ const w = RISK_WEIGHTS;
39
+ return Math.round(breakdown.liquidityRisk * w.liquidityRisk +
40
+ breakdown.slippageRisk * w.slippageRisk +
41
+ breakdown.counterpartyRisk * w.counterpartyRisk +
42
+ breakdown.balanceRisk * w.balanceRisk +
43
+ breakdown.marketConditionRisk * w.marketConditionRisk);
44
+ }
45
+ // ─── Individual Risk Scorers ───────────────────────────────────────────
46
+ /**
47
+ * Pre-fetches the DODO route quote once for swap actions.
48
+ * Both scoreLiquidity and scoreSlippage use this cached result.
49
+ * `notConfigured` distinguishes the structural provider-not-configured state
50
+ * (SWAP_LIQUIDITY_NOT_CONFIGURED) from a transient fetch failure.
51
+ */
52
+ async function fetchSwapQuote(input) {
53
+ if (input.action !== "swap")
54
+ return { quote: null, notConfigured: false };
55
+ try {
56
+ const quote = await getDodoRoute({
57
+ fromToken: input.tokenIn,
58
+ toToken: input.tokenOut,
59
+ amountHuman: input.amount,
60
+ walletAddress: input.walletAddress,
61
+ });
62
+ return { quote, notConfigured: false };
63
+ }
64
+ catch (err) {
65
+ return { quote: null, notConfigured: err instanceof DodoNotConfiguredError };
66
+ }
67
+ }
68
+ function scoreLiquidity(input, quote, notConfigured) {
69
+ const reasons = [];
70
+ if (input.action !== "swap")
71
+ return { score: 0, reasons };
72
+ if (!quote) {
73
+ reasons.push(notConfigured
74
+ ? `Swap liquidity provider is not configured for chainId ${CHAIN_ID} (SWAP_LIQUIDITY_NOT_CONFIGURED); liquidity cannot be verified on this network.`
75
+ : "Failed to fetch liquidity data: route provider unavailable.");
76
+ return { score: 70, reasons };
77
+ }
78
+ if (!quote.routeAvailable) {
79
+ reasons.push("No swap route available; liquidity may be exhausted");
80
+ return { score: 100, reasons };
81
+ }
82
+ const impact = Math.abs(quote.priceImpact);
83
+ if (impact > 5) {
84
+ reasons.push(`High price impact: ${impact.toFixed(2)}%`);
85
+ return { score: clamp(80 + impact), reasons };
86
+ }
87
+ if (impact > 2) {
88
+ reasons.push(`Moderate price impact: ${impact.toFixed(2)}%`);
89
+ return { score: clamp(40 + impact * 10), reasons };
90
+ }
91
+ reasons.push(`Price impact acceptable: ${impact.toFixed(2)}%`);
92
+ return { score: clamp(impact * 15), reasons };
93
+ }
94
+ function scoreSlippage(input, quote, notConfigured) {
95
+ const reasons = [];
96
+ if (input.action !== "swap")
97
+ return { score: 0, reasons };
98
+ if (!quote) {
99
+ reasons.push(notConfigured
100
+ ? `Slippage cannot be estimated: swap route provider not configured for chainId ${CHAIN_ID} (SWAP_LIQUIDITY_NOT_CONFIGURED).`
101
+ : "Slippage estimation failed: route provider unavailable.");
102
+ return { score: 60, reasons };
103
+ }
104
+ if (!quote.routeAvailable) {
105
+ reasons.push("Cannot estimate slippage: no route");
106
+ return { score: 90, reasons };
107
+ }
108
+ const impact = Math.abs(quote.priceImpact);
109
+ if (impact > MAX_SLIPPAGE_PCT) {
110
+ reasons.push(`Slippage exceeds max ${MAX_SLIPPAGE_PCT}%: estimated ${impact.toFixed(2)}%`);
111
+ return { score: clamp(80 + (impact - MAX_SLIPPAGE_PCT) * 5), reasons };
112
+ }
113
+ reasons.push(`Estimated slippage: ${impact.toFixed(2)}%`);
114
+ return { score: clamp(impact * 16), reasons };
115
+ }
116
+ async function scoreCounterparty(input, quote) {
117
+ const reasons = [];
118
+ if (input.action === "swap") {
119
+ // Registry-driven counterparty trust ONLY. The former unconditional
120
+ // "DODO protocol (known) → 5" relaxed risk with a testnet-provenance claim
121
+ // that holds on no network per the ecosystem registry.
122
+ const router = quote?.routeAvailable && isAddress(quote.to) ? quote.to : null;
123
+ if (!router) {
124
+ reasons.push("Swap counterparty (router) could not be determined; no route data to evaluate.");
125
+ return { score: 55, reasons };
126
+ }
127
+ const evidence = addressTrustEvidence(router, CHAIN_ID);
128
+ if (evidence.verifiedCanonical) {
129
+ reasons.push(`Swap router ${evidence.contractLabel ?? router} is VERIFIED in the SafeHands ecosystem registry.`);
130
+ return { score: 5, reasons };
131
+ }
132
+ if (evidence.recognized) {
133
+ reasons.push(`Swap router matches ecosystem-registry entry "${evidence.contractLabel}" (${evidence.verificationStatus}); recognition only, not a safety signal.`);
134
+ return { score: 40, reasons };
135
+ }
136
+ reasons.push(`Swap router ${router} is not in the SafeHands ecosystem registry: unverified counterparty (the execution allowlist still constrains which router may execute at write time).`);
137
+ return { score: 55, reasons };
138
+ }
139
+ // For transfers, check the recipient address
140
+ const to = input.toAddress;
141
+ if (!to) {
142
+ reasons.push("No recipient address provided");
143
+ return { score: 100, reasons };
144
+ }
145
+ if (!isAddress(to)) {
146
+ reasons.push("Invalid EVM address format");
147
+ return { score: 100, reasons };
148
+ }
149
+ // Zero address check
150
+ if (to === "0x0000000000000000000000000000000000000000") {
151
+ reasons.push("Sending to zero address; tokens will be burned");
152
+ return { score: 95, reasons };
153
+ }
154
+ // Self-send check
155
+ if (to.toLowerCase() === input.walletAddress.toLowerCase()) {
156
+ reasons.push("Sending to own address; likely unintended");
157
+ return { score: 50, reasons };
158
+ }
159
+ // Check if address has code (is a contract)
160
+ try {
161
+ const code = await publicClient.getCode({ address: to });
162
+ if (code && code !== "0x") {
163
+ reasons.push("Recipient is a contract address; verify intent");
164
+ return { score: 40, reasons };
165
+ }
166
+ }
167
+ catch {
168
+ // RPC error, non-critical
169
+ }
170
+ // Check if address has any transaction history (has balance)
171
+ try {
172
+ const balance = await publicClient.getBalance({ address: to });
173
+ if (balance === 0n) {
174
+ reasons.push("Recipient has zero balance; new or unused address");
175
+ return { score: 30, reasons };
176
+ }
177
+ }
178
+ catch {
179
+ // Non-critical
180
+ }
181
+ reasons.push("Recipient address looks valid");
182
+ return { score: 10, reasons };
183
+ }
184
+ async function scoreBalance(input) {
185
+ const reasons = [];
186
+ try {
187
+ const walletAddr = input.walletAddress;
188
+ if (input.action === "transfer" || (input.action === "swap" && isNativeToken(input.tokenIn || "PROS"))) {
189
+ // Check native PROS balance
190
+ const balance = await publicClient.getBalance({ address: walletAddr });
191
+ const amountWei = parseEther(input.amount);
192
+ const gasBuffer = parseEther("0.01"); // ~0.01 PROS for gas
193
+ if (balance < amountWei + gasBuffer) {
194
+ const balanceHuman = formatEther(balance);
195
+ reasons.push(`Insufficient PROS balance: have ${balanceHuman}, need ${input.amount} + gas`);
196
+ return { score: 100, reasons };
197
+ }
198
+ const usagePct = Number((amountWei * 100n) / balance);
199
+ if (usagePct > MAX_BALANCE_USAGE_PCT) {
200
+ reasons.push(`Using ${usagePct}% of wallet balance; high exposure`);
201
+ return { score: clamp(60 + (usagePct - MAX_BALANCE_USAGE_PCT)), reasons };
202
+ }
203
+ reasons.push(`Balance sufficient, using ${usagePct}% of wallet`);
204
+ return { score: clamp(usagePct / 3), reasons };
205
+ }
206
+ // ERC-20 token balance check
207
+ if (input.tokenIn) {
208
+ const tokenAddress = resolveTokenAddress(input.tokenIn);
209
+ const decimals = resolveTokenDecimals(input.tokenIn);
210
+ const amountWei = BigInt(toWei(input.amount, decimals));
211
+ const balance = (await publicClient.readContract({
212
+ address: tokenAddress,
213
+ abi: ERC20_ABI,
214
+ functionName: "balanceOf",
215
+ args: [walletAddr],
216
+ }));
217
+ if (balance < amountWei) {
218
+ reasons.push(`Insufficient ${input.tokenIn} balance`);
219
+ return { score: 100, reasons };
220
+ }
221
+ // Also check gas balance
222
+ const ethBalance = await publicClient.getBalance({ address: walletAddr });
223
+ if (ethBalance < parseEther("0.005")) {
224
+ reasons.push("Very low PROS balance for gas fees");
225
+ return { score: 80, reasons };
226
+ }
227
+ reasons.push("Token and gas balance sufficient");
228
+ return { score: 5, reasons };
229
+ }
230
+ return { score: 0, reasons: ["Balance check skipped"] };
231
+ }
232
+ catch (err) {
233
+ reasons.push(`Balance check failed: ${err.message}`);
234
+ return { score: 50, reasons, degraded: true };
235
+ }
236
+ }
237
+ async function scoreMarketCondition(_input) {
238
+ const reasons = [];
239
+ try {
240
+ // Check recent block production rate as a proxy for chain health
241
+ const latestBlock = await publicClient.getBlock({ blockTag: "latest" });
242
+ const prevBlock = await publicClient.getBlock({
243
+ blockNumber: latestBlock.number - 10n,
244
+ });
245
+ const timeDiff = Number(latestBlock.timestamp - prevBlock.timestamp);
246
+ const avgBlockTime = timeDiff / 10;
247
+ if (avgBlockTime > 30) {
248
+ reasons.push(`Slow block production: ~${avgBlockTime.toFixed(1)}s/block; chain may be congested`);
249
+ return { score: 60, reasons };
250
+ }
251
+ if (avgBlockTime > 15) {
252
+ reasons.push(`Slightly elevated block times: ~${avgBlockTime.toFixed(1)}s/block`);
253
+ return { score: 30, reasons };
254
+ }
255
+ // Check gas price
256
+ const gasPrice = await publicClient.getGasPrice();
257
+ const gasPriceGwei = Number(gasPrice) / 1e9;
258
+ if (gasPriceGwei > 100) {
259
+ reasons.push(`High gas price: ${gasPriceGwei.toFixed(1)} Gwei`);
260
+ return { score: 50, reasons };
261
+ }
262
+ reasons.push(`Chain healthy: ~${avgBlockTime.toFixed(1)}s/block, ${gasPriceGwei.toFixed(1)} Gwei gas`);
263
+ return { score: 5, reasons };
264
+ }
265
+ catch {
266
+ reasons.push("Could not assess market conditions");
267
+ return { score: 20, reasons };
268
+ }
269
+ }
270
+ // ─── Main Risk Assessment ──────────────────────────────────────────────
271
+ export async function assessRisk(input) {
272
+ // Fetch DODO route once and share between liquidity + slippage + counterparty scorers
273
+ const { quote: swapQuote, notConfigured: swapProviderNotConfigured } = await fetchSwapQuote(input);
274
+ const [counterparty, balance, market] = await Promise.all([
275
+ scoreCounterparty(input, swapQuote),
276
+ scoreBalance(input),
277
+ scoreMarketCondition(input),
278
+ ]);
279
+ const liquidity = scoreLiquidity(input, swapQuote, swapProviderNotConfigured);
280
+ const slippage = scoreSlippage(input, swapQuote, swapProviderNotConfigured);
281
+ const breakdown = {
282
+ liquidityRisk: liquidity.score,
283
+ slippageRisk: slippage.score,
284
+ counterpartyRisk: counterparty.score,
285
+ balanceRisk: balance.score,
286
+ marketConditionRisk: market.score,
287
+ };
288
+ const riskScore = clamp(weightedAverage(breakdown));
289
+ const riskLevel = computeRiskLevel(riskScore);
290
+ let recommendation = computeRecommendation(riskScore);
291
+ // Fail-closed on missing CRITICAL data. A swap whose route/liquidity could
292
+ // not be fetched, or any action whose balance check threw, must NOT be scored as
293
+ // safe on degraded inputs. Mark degraded and refuse to "proceed" silently.
294
+ const degradedReasons = [];
295
+ if (input.action === "swap" && swapQuote === null) {
296
+ degradedReasons.push(swapProviderNotConfigured
297
+ ? `Swap liquidity provider is not configured for chainId ${CHAIN_ID} (SWAP_LIQUIDITY_NOT_CONFIGURED); this is a permanent configuration state on this network, not a transient outage.`
298
+ : "Liquidity/slippage could not be assessed: swap route fetch failed.");
299
+ }
300
+ if (balance.degraded) {
301
+ degradedReasons.push("Wallet balance could not be verified; RPC unavailable.");
302
+ }
303
+ const degraded = degradedReasons.length > 0;
304
+ if (degraded && recommendation === "proceed") {
305
+ recommendation = "caution";
306
+ }
307
+ // Advisory escalation mirroring the policy engine's `risk_counterparty`
308
+ // check (the actual block mechanism). Kept so the published recommendation
309
+ // stays honest for critically-risky transfers (missing / invalid / zero
310
+ // recipient): weighted heuristics alone can never cross the block threshold
311
+ // for a transfer, so without this the on-chain record would say "caution"
312
+ // where the policy engine blocks.
313
+ if (input.action === "transfer" && counterparty.score >= COUNTERPARTY_CRITICAL_THRESHOLD) {
314
+ recommendation = "block";
315
+ }
316
+ const reasons = [
317
+ ...liquidity.reasons,
318
+ ...slippage.reasons,
319
+ ...counterparty.reasons,
320
+ ...balance.reasons,
321
+ ...market.reasons,
322
+ ];
323
+ let suggestion;
324
+ if (recommendation === "proceed") {
325
+ suggestion = "Risk is within acceptable range. Proceed with the transaction.";
326
+ }
327
+ else if (recommendation === "caution") {
328
+ suggestion =
329
+ "Moderate risk detected. Review the risk breakdown carefully before proceeding. Consider reducing the amount or adjusting parameters.";
330
+ }
331
+ else {
332
+ suggestion =
333
+ "High risk detected: execution blocked for safety. Review the reasons and adjust your transaction parameters significantly before retrying.";
334
+ }
335
+ return {
336
+ riskScore,
337
+ riskLevel,
338
+ recommendation,
339
+ breakdown,
340
+ reasons,
341
+ suggestion,
342
+ degraded,
343
+ degradedReasons,
344
+ ...(input.action === "swap" ? { swapProviderNotConfigured } : {}),
345
+ };
346
+ }
284
347
  //# sourceMappingURL=riskEngine.js.map