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
package/README.md CHANGED
@@ -1,333 +1,301 @@
1
- <p align="center">
2
- <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
3
- <img src="https://img.shields.io/badge/MCP_Skill-000000?style=for-the-badge" />
4
- <img src="https://img.shields.io/badge/Pharos_Atlantic-688689-blueviolet?style=for-the-badge" />
5
- <img src="https://img.shields.io/badge/Tools-27-orange?style=for-the-badge" />
6
- <img src="https://img.shields.io/badge/Testnet_Only-SAFE-blue?style=for-the-badge" />
7
- </p>
8
-
9
- # SafeHands-Pharos Transaction Safety Firewall for AI Agents
10
-
11
- SafeHands is a **Pharos Skill Engine-compatible MCP package** that acts as a safety layer before your AI agent executes any on-chain action payments, swaps, token approvals, or x402 paid requests.
12
-
13
- Every action goes through a preflight check first:
14
-
15
- ```
16
- Agent wants to act
17
-
18
- safehands_preflight_check
19
-
20
- ALLOW → safe, proceed
21
- WARN → proceed with caution
22
- BLOCK → stop, reason explained
23
- ```
24
-
25
- > **Testnet only.** SafeHands targets Pharos Atlantic Testnet (Chain ID 688689). Not audited for mainnet use.
26
-
27
- ---
28
-
29
- ## Getting Started
30
-
31
- ### Install via Pharos Skill Engine
32
-
33
- ```bash
34
- npx skills add SZtch/safehands-pharos
35
- ```
36
-
37
- ### Connect to Claude Desktop
38
-
39
- Add to `claude_desktop_config.json`:
40
-
41
- ```json
42
- {
43
- "mcpServers": {
44
- "safehands": {
45
- "command": "npx",
46
- "args": ["safehands-pharos"]
47
- }
48
- }
49
- }
50
- ```
51
-
52
- Restart Claude Desktop — SafeHands tools appear automatically in every conversation.
53
-
54
- ### Connect to Anvita Flow
55
-
56
- Add as MCP server in Anvita Flow settings:
57
-
58
- ```json
59
- {
60
- "command": "npx",
61
- "args": ["safehands-pharos"]
62
- }
63
- ```
64
-
65
- ### First-time setup
66
-
67
- ```bash
68
- npx safehands-pharos init
69
- ```
70
-
71
- Interactive wizard that configures your `.env` — wallet mode, spend limits, write gates.
72
-
73
- ### Run the demo
74
-
75
- ```bash
76
- npx safehands-pharos --demo
77
- ```
78
-
79
- Non-destructive demo: shows ALLOW, BLOCK, wallet health, token registry, x402 preflight, and risk report — no real transactions.
80
-
81
- ---
82
-
83
- ## Start with These 3 Tools
84
-
85
- | Goal | Tool |
86
- |------|------|
87
- | Check if an action is safe | `safehands_preflight_check` |
88
- | Check wallet / signer readiness | `safehands_wallet_health` |
89
- | Execute with built-in safety gate | `safehands_safe_execute` |
90
-
91
- ---
92
-
93
- ## Calling Tools from the CLI
94
-
95
- ```bash
96
- # Short form (recommended)
97
- npx safehands-pharos skill <tool> '<json>'
98
-
99
- # With flag
100
- npx safehands-pharos skill <tool> -i '<json>'
101
-
102
- # Explicit flag
103
- npx safehands-pharos skill <tool> --input-json '<json>'
104
- ```
105
-
106
- Examples:
107
-
108
- ```bash
109
- # Preflight check before a swap
110
- npx safehands-pharos skill safehands_preflight_check \
111
- '{"actionType":"execute_swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","chainId":688689,"isMainnet":false}'
112
-
113
- # Check wallet balance
114
- npx safehands-pharos skill get_wallet_balance \
115
- '{"walletAddress":"0xYourWallet"}'
116
-
117
- # Assess risk score
118
- npx safehands-pharos skill assess_risk \
119
- '{"action":"swap","tokenIn":"PHRS","tokenOut":"USDC","amount":"0.01","walletAddress":"0xYourWallet"}'
120
-
121
- # Classify a token address
122
- npx safehands-pharos skill token_registry_status \
123
- '{"tokenAddress":"0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8"}'
124
- ```
125
-
126
- ---
127
-
128
- ## All 27 Tools
129
-
130
- All tools return the same response envelope:
131
-
132
- ```json
133
- {
134
- "success": true,
135
- "data": { ... },
136
- "error": null,
137
- "timestamp": "2026-06-13T00:00:00.000Z"
138
- }
139
- ```
140
-
141
- On failure: `success: false`, `data: null`, `error: { code, message, retryable }`.
142
-
143
- ### SafeHands Guardrail Tools
144
-
145
- | Tool | What it does | CLI |
146
- |------|-------------|-----|
147
- | `safehands_preflight_check` | ALLOW / WARN / BLOCK before any action | ✓ |
148
- | `safehands_safe_execute` | Preflight + execute in one call | ✓ |
149
- | `safehands_wallet_health` | Wallet, signer, gas, x402 readiness | |
150
- | `safehands_x402_preflight` | URL safety + payment check before x402 | ✓ |
151
- | `safehands_risk_report` | Human-readable risk summary | ✓ |
152
- | `explain_risk` | Translate ALLOW/WARN/BLOCK into plain English | ✓ |
153
- | `token_registry_status` | Canonical / custom / unknown token check | |
154
-
155
- ### Safety & Analysis Tools
156
-
157
- | Tool | What it does | CLI |
158
- |------|-------------|-----|
159
- | `assess_risk` | 5-dimension risk score (0–100) | ✓ |
160
- | `check_token_security` | GoPlus token security profile | ✓ |
161
- | `simulate_transaction` | Dry-run before broadcasting | |
162
- | `estimate_gas` | Gas estimate + sufficiency check | ✓ |
163
- | `check_allowance` | ERC-20 allowance check | MCP |
164
-
165
- ### Market & Chain Data
166
-
167
- | Tool | What it does | CLI |
168
- |------|-------------|-----|
169
- | `get_wallet_balance` | PHRS / USDC / USDT balances | ✓ |
170
- | `get_token_price` | Token price via DODO | ✓ |
171
- | `get_gas_price` | Current network gas price | MCP |
172
- | `get_pool_info` | FaroSwap / DODO pool info | MCP |
173
- | `get_transaction_status` | TX status by hash | ✓ |
174
- | `get_execution_history` | Wallet transfer history (ERC-20 + native) | MCP |
175
-
176
- ### Write Tools *(require `WRITE_TOOLS_ENABLED=true`)*
177
-
178
- | Tool | What it does | CLI |
179
- |------|-------------|-----|
180
- | `execute_swap` | Swap tokens via FaroSwap / DODO | MCP |
181
- | `send_payment` | Send native PHRS | MCP |
182
- | `approve_token` | ERC-20 approval (unlimited blocked by default) | MCP |
183
- | `publish_risk_score` | Publish risk score to RiskRegistry contract | MCP |
184
- | `x402_pay_and_fetch` | Fetch x402 resource, pay only after HTTP 402 | MCP |
185
-
186
- ### Risk Registry
187
-
188
- | Tool | What it does | CLI |
189
- |------|-------------|-----|
190
- | `query_risk_registry` | Read on-chain risk score | ✓ |
191
-
192
- ### Managed Wallet Tools
193
-
194
- | Tool | What it does | CLI |
195
- |------|-------------|-----|
196
- | `create_agent_wallet` | Create testnet wallet (AES-256-GCM encrypted) | ✓ |
197
- | `get_agent_wallet` | Wallet address + metadata (no private key) | ✓ |
198
- | `get_agent_wallet_balance` | Managed wallet balances | ✓ |
199
-
200
- > **CLI** = callable via `npx safehands-pharos skill <tool> '<json>'`
201
- > **MCP** = available via Claude Desktop / Anvita Flow only
202
-
203
- ---
204
-
205
- ## Configuration
206
-
207
- Copy the example file:
208
-
209
- ```bash
210
- cp .env.example .env
211
- ```
212
-
213
- Key settings:
214
-
215
- ```env
216
- # Wallet mode
217
- WALLET_MODE=none # none | env | managed-testnet
218
- PRIVATE_KEY= # required when WALLET_MODE=env
219
- WALLET_STORE_PATH= # optional: persist managed wallets to disk
220
-
221
- # Write gates (all off by default)
222
- WRITE_TOOLS_ENABLED=false
223
- ALLOW_UNLIMITED_APPROVAL=false
224
-
225
- # Spend limits
226
- MAX_TX_AMOUNT_PHRS=0.1 # max PHRS per transaction
227
- MAX_DAILY_SPEND_USD=10 # daily cap across all wallets
228
- PHRS_USD_PRICE=1.0 # used for daily spend accounting
229
-
230
- # DODO API (required for swaps and price data)
231
- DODO_API_KEY=
232
- ```
233
-
234
- ### Wallet modes explained
235
-
236
- | Mode | How it works |
237
- |------|-------------|
238
- | `none` | No signer read-only tools only (safe default) |
239
- | `env` | Reads `PRIVATE_KEY` from `.env` |
240
- | `managed-testnet` | Uses wallet created via `create_agent_wallet` |
241
-
242
- ### Persistent managed wallets
243
-
244
- By default, wallets created with `create_agent_wallet` are in-memory and lost on restart. To persist them:
245
-
246
- ```env
247
- WALLET_STORE_PATH=./.agents/wallets.json
248
- WALLET_ENCRYPTION_KEY=your-strong-secret
249
- ```
250
-
251
- Private keys are AES-256-GCM encrypted on disk. The `.agents/` folder is gitignored.
252
-
253
- ---
254
-
255
- ## Security Defaults
256
-
257
- SafeHands ships safe by default nothing is enabled without explicit opt-in:
258
-
259
- - `WRITE_TOOLS_ENABLED=false` no on-chain writes without opt-in
260
- - `WALLET_MODE=none` — no signer loaded on startup
261
- - Unlimited token approvals blocked
262
- - Mainnet actions blocked
263
- - SSRF-sensitive x402 URLs blocked
264
- - Private keys never returned in responses or logs
265
- - Daily spend cap enforced in-memory per wallet
266
-
267
- ---
268
-
269
- ## Why AI Agents Need This
270
-
271
- Generic Web3 tools answer: *"Can this transaction be sent?"*
272
- SafeHands answers: **"Should this action be allowed at all?"**
273
-
274
- | Risk | What goes wrong | SafeHands guardrail |
275
- |------|----------------|---------------------|
276
- | Unlimited approval | Agent approves malicious spender forever | Blocked by default |
277
- | Wrong chain | Agent signs on mainnet | Blocked |
278
- | Risky x402 URL | Agent pays a localhost/private IP | Blocked |
279
- | Overspending | Agent drains wallet | Daily cap enforced |
280
- | Unknown token | Agent swaps unverified token | Warns or requires review |
281
- | Missing signer | Agent tries write without wallet | Structured error returned |
282
-
283
- ---
284
-
285
- ## x402 Support
286
-
287
- SafeHands acts as both an x402 client and server.
288
-
289
- **Client** (`x402_pay_and_fetch`): Fetches a resource normally first. If the server returns HTTP 402, SafeHands runs a preflight check, requests the signer, pays, and retries all in one tool call. Payment proofs are never logged.
290
-
291
- **Server** (`npm run x402-server`): Exposes paid endpoints:
292
-
293
- | Endpoint | Type | Price |
294
- |----------|------|-------|
295
- | `GET /supported` | Free | |
296
- | `GET /health` | Free | — |
297
- | `GET /assess-risk` | Paid | 0.001 USDC |
298
- | `GET /check-token-security` | Paid | 0.001 USDC |
299
- | `GET /simulate-transaction` | Paid | 0.001 USDC |
300
-
301
- ---
302
-
303
- ## Network Info
304
-
305
- | Item | Value |
306
- |------|-------|
307
- | Chain ID | `688689` |
308
- | RPC | `https://atlantic.dplabs-internal.com` |
309
- | Explorer | `https://atlantic.pharosscan.xyz` |
310
- | USDC | `0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8` |
311
- | RiskRegistry | `0x61962a6c812ee9f57b207e1ea47c19ae70bb7141` |
312
-
313
- ---
314
-
315
- ## Testing
316
-
317
- ```bash
318
- npm run build
319
- npm run test:all # 43-point smoke test (no network needed)
320
- npm run test:rpc:live # live RPC connectivity check
321
- npm run test:live:safehands # 7 CLI safety checks against built dist
322
- npm run test:dodo:live # DODO API check (skips if DODO_API_KEY not set)
323
- ```
324
-
325
- ---
326
-
327
- ## Known Limitations
328
-
329
- - Testnet-only — not audited for mainnet
330
- - Managed wallet encryption is AES-256-GCM but not KMS/Vault grade
331
- - `get_token_price` and swap routing require a DODO API key
332
- - GoPlus token security does not support Pharos testnet (Chain 688689) — `check_token_security` returns a clear error
333
- - DODO reverse routes (e.g. USDT → PHRS) have no liquidity on testnet
1
+ <p align="center">
2
+ <img src="assets/banner.svg" alt="SafeHands: the transaction firewall for AI agent finance on Pharos Pacific Mainnet" width="100%">
3
+ </p>
4
+
5
+ # SafeHands
6
+
7
+ **The transaction firewall for AI agent finance on Pharos: deterministic `ALLOW` / `REQUIRE_CONFIRMATION` / `BLOCK` verdicts *before* a wallet signs.**
8
+
9
+ *No custody. No blind signing. Policy first, execution second.*
10
+
11
+ AI agents are starting to run real financial workflows on Pharos: payments, treasury actions, swaps, bridges, liquidity operations, and interactions with tokenized real-world assets. An agent doing that work can sign almost anything: an unlimited token approval, a swap on the wrong chain, a payment to a malicious x402 endpoint, a transfer of a tokenized asset to an unvetted counterparty. SafeHands is the firewall that stands *before* the signature. A deterministic policy engine analyzes each intent (calldata, token, spender, counterparty, amount, chain) and returns one of four verdicts (`ALLOW`, `BLOCK`, `REQUIRE_CONFIRMATION`, `PREPARE_ONLY`) with a plain-English reason. You act on your own wallet; SafeHands never holds keys and never signs for you.
12
+
13
+ In **hosted Anvita mode**, SafeHands provides no-custody, read-only safety verdicts; it does not sign, broadcast, or execute transactions today. In **self-hosted integrations**, the same policy model can gate execution itself. It ships as an MCP server, an HTTP API, and a CLI, exposing 33 tools that any agent in the Pharos ecosystem can call against Pharos Pacific Mainnet (chain `1672`).
14
+
15
+ [![CI](https://github.com/SZtch/safehands-pharos/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/SZtch/safehands-pharos/actions/workflows/ci.yml)
16
+ ![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white)
17
+ ![Pharos Pacific Mainnet](https://img.shields.io/badge/Pharos_Pacific_Mainnet-1672-6d28d9)
18
+ ![33 tools](https://img.shields.io/badge/tools-33-0891b2)
19
+ ![Hosted mode: no-custody verdict](https://img.shields.io/badge/hosted-no--custody_verdict-16a34a)
20
+ ![License: MIT](https://img.shields.io/badge/license-MIT-black)
21
+
22
+ ### Which SafeHands is for me?
23
+
24
+ One deterministic policy engine, delivered where you need the verdict: from a zero-infra hosted call to a self-hosted integration:
25
+
26
+ | You are… | Use | What it is |
27
+ |---|---|---|
28
+ | A **user or Steward agent** that wants a pre-execution verdict | the **Anvita Flow hosted skill** | Zero-infra, no keys, no custody: you get the verdict *before* you sign. The hosted deliverable in [`anvita/safehands/`](anvita/safehands/), live on Anvita Flow as `safehands`. |
29
+ | A **developer** wiring safety into your own agent | the **npm package**: MCP server, CLI & SDK | `npx … --demo`, drop it into any MCP client, or `import { evaluateActionPolicy } from "safehands-pharos"`. The verdict path is the product; write tools are reference-only and stay gated behind env flags + a signer + the same verdict. |
30
+ | An **operator** who wants the HTTP API | the **self-hosted reference backend** | `node dist/api/server.js` → `http://localhost:4022`; free verdict endpoints plus the optional x402-gated `/paid/*` bundle. |
31
+
32
+ > **Read-only hosted mode is a security property, not a tier.** Because the hosted verdict layer holds no keys and signs nothing, every other agent can safely put it *in front of* their transactions: a firewall that can't move funds is one nobody has to trust with funds. Signing stays with you.
33
+
34
+ The compact hosted engine returns an `allow / warn / block` risk recommendation; the full policy engine (npm/API) returns the four-value decision. They map cleanly but score independently, and their thresholds intentionally differ: see [`docs/DECISION_CONTRACT.md`](docs/DECISION_CONTRACT.md), and never compare raw scores across them.
35
+
36
+ ## SafeHands on Anvita Flow
37
+
38
+ SafeHands is live on [Anvita Flow](https://flow.anvita.xyz/home) as **`safehands`**, a fully hosted, non-custodial Service Agent for the Pharos Agent Carnival.
39
+
40
+ Users can ask their Steward Agent to find **`safehands`** and evaluate a blockchain action before signing. The verdict is computed by a deterministic risk engine, not guessed by an LLM.
41
+
42
+ No external server, private keys, or wallet custody are required.
43
+
44
+ Hosted package: [`anvita/safehands/`](anvita/safehands/)
45
+ Integration guide: **[docs/ANVITA_FLOW.md](docs/ANVITA_FLOW.md)**
46
+ Building an agent that should call SafeHands before signing? Start at **[docs/AGENT_INTEGRATION.md](docs/AGENT_INTEGRATION.md)**.
47
+
48
+ ---
49
+ ## Try it in 10 seconds
50
+
51
+ **One command, zero infrastructure**: no config, no wallet, no keys, no transactions:
52
+
53
+ ```bash
54
+ npx -y github:SZtch/safehands-pharos --demo
55
+ # (after npm publish: npx safehands-pharos --demo · or locally: git clone → npm install → node dist/index.js --demo)
56
+ ```
57
+
58
+ Watch the deterministic policy engine issue real safety decisions (`ALLOW`, `BLOCK`, `REQUIRE_CONFIRMATION`) against Pharos Pacific Mainnet. It runs twelve deterministic safety checks in your terminal (wallet health, policy decisions, token-registry lookups, x402 preflight, SSRF blocking, risk scoring, RWA transfer-compliance and settlement-cap scenarios) and touches nothing on-chain. The full check list and expected outputs are in [docs/REVIEWER_QUICKSTART.md](docs/REVIEWER_QUICKSTART.md).
59
+
60
+ <details>
61
+ <summary>Sample output: one of the twelve checks</summary>
62
+
63
+ ```text
64
+ $ npx safehands-pharos --demo
65
+
66
+ 🛡️ SafeHands-Pharos Deterministic Demo
67
+ Environment: pacific-mainnet
68
+ Chain ID: 1672
69
+ Mode: non-destructive demo, no real transactions broadcast
70
+
71
+ 3. Unlimited Approval Preflight: BLOCK
72
+
73
+ safehands_preflight_check
74
+ {
75
+ "success": true,
76
+ "data": {
77
+ "decision": "BLOCK",
78
+ "riskLevel": "HIGH",
79
+ "safeToExecute": false,
80
+ "reasons": ["Unlimited approval requested."],
81
+ "requiredActions": ["Use a limited approval amount."]
82
+ },
83
+ "error": null
84
+ }
85
+ ```
86
+
87
+ </details>
88
+
89
+ ## Run the API yourself (optional self-host)
90
+
91
+ To exercise the HTTP API directly, self-host the zero-custody reference backend locally against Pharos Pacific Mainnet; no API key needed for the public surface:
92
+
93
+ ```bash
94
+ npm install --include=dev && npm run build
95
+ node dist/api/server.js # read-only API on http://localhost:4022 (PORT env to change)
96
+ ```
97
+
98
+ ```bash
99
+ # Health + network config
100
+ curl -s http://localhost:4022/health
101
+ curl -s http://localhost:4022/public-config
102
+
103
+ # Real preflight decision from the live policy engine
104
+ curl -s -X POST http://localhost:4022/tools/safehands_preflight_check \
105
+ -H "content-type: application/json" \
106
+ -d '{"actionType":"approve_token","chainId":1672,"approvalToken":"USDC","spender":"0x000000000000000000000000000000000000dEaD","approvalAmount":"max"}'
107
+
108
+ # On-chain reputation read (live attestation contract)
109
+ curl -s -X POST http://localhost:4022/tools/get_agent_reputation \
110
+ -H "content-type: application/json" \
111
+ -d '{"address":"0x6730d3a2A217108AB53CCFe60ffdAd05D3C124e5"}'
112
+
113
+ # x402-gated endpoint. Fail-closed by default: without x402 config this returns 503.
114
+ # With X402_PAY_TO and a reachable external X402_FACILITATOR_URL set, it returns a
115
+ # real HTTP 402 challenge (mainnet USDC, eip155:1672).
116
+ curl -s -i http://localhost:4022/paid/risk-report
117
+ ```
118
+
119
+ Interactive browser demo (while the local API runs): **http://localhost:4022/demo**. Full curl walkthrough: [docs/SAFEHANDS_REVIEWER_DEMO_SCRIPT.md](docs/SAFEHANDS_REVIEWER_DEMO_SCRIPT.md).
120
+
121
+ ---
122
+
123
+ ## What it does
124
+
125
+ SafeHands sits between an agent's *intent* and the *signature*. Before any action, the agent calls `safehands_preflight_check` (or one of the specialized preflight tools) and gets back a decision:
126
+
127
+ <p align="center">
128
+ <img src="assets/architecture.svg" alt="SafeHands architecture: agent intent flows through the deterministic policy engine to a four-value decision; the user signs with their own wallet; Pharos mainnet records the attestation audit trail, risk registry, and composable reputation" width="100%">
129
+ </p>
130
+
131
+ The decision is **deterministic**: the policy engine decides, not a model. An LLM can advise, but it cannot override a policy it dislikes.
132
+
133
+ ### What it catches
134
+
135
+ | Risk | Without SafeHands | With SafeHands |
136
+ |------|-------------------|----------------|
137
+ | Unlimited token approval | Agent grants a malicious spender forever | `BLOCK`: unlimited approvals off by default |
138
+ | Unsupported chain | Agent targets a non-Pharos network (e.g. Ethereum) | `BLOCK`: chain-ID guard |
139
+ | Malicious x402 endpoint | Agent pays a localhost / private-IP URL | `BLOCK`: SSRF + redirect guard |
140
+ | Wallet drain | Agent overspends in one session | `BLOCK`: per-agent + daily spend cap |
141
+ | Unknown token | Agent swaps an unverified contract | `REQUIRE_CONFIRMATION` |
142
+ | Arbitrary contract call | Agent calls an unknown contract | `REQUIRE_CONFIRMATION` |
143
+ | Bad input | Agent passes `-1` or the zero address | `VALIDATION_ERROR` |
144
+ | Unregistered tokenized asset | Agent approves an unknown asset contract to an unverified spender | `REQUIRE_CONFIRMATION`: human review required |
145
+ | Oversized settlement | Agent settles a real-world invoice above the policy cap | `BLOCK`: deterministic spend limit |
146
+
147
+ ## Why this matters for Real-Fi & RWA
148
+
149
+ Pharos is a Real-Fi chain: the environment where agent-driven payments, treasury operations, and tokenized real-world assets settle. Those assets carry obligations memecoins do not (asset legitimacy, transfer restrictions, audit trails, settlement discipline, counterparty trust), and an agent can repeat a mistake a thousand times. SafeHands is the pre-execution safety layer for exactly those obligations: the read/policy path is live on mainnet today, and the write-side attestation path is a working opt-in. Demo scenarios 11-12 show the RWA flows end-to-end; the full live-vs-roadmap mapping is in **[docs/REALFI_RWA_ALIGNMENT.md](docs/REALFI_RWA_ALIGNMENT.md)**.
150
+
151
+ ## What it is, and is not
152
+
153
+ SafeHands is a **transaction firewall**, not a wallet. It is not a custody service, a private-key manager, a signer, a DEX, or a bridge. It does not issue tokenized assets, does not manage real-world assets, and is not a compliance authority: it is the deterministic checkpoint agent-finance flows run through before execution. It renders the verdict; you keep the signature.
154
+
155
+ **Today, hosted (Anvita Flow):** a read-only, zero-custody pre-execution verdict. It holds no keys, signs nothing, broadcasts nothing, and executes nothing. You always sign and send with your own wallet.
156
+
157
+ **Advanced, self-hosted integration (MCP / CLI / SDK / HTTP API):** the same verdict engine, embeddable in your own agent. Execution tools (`execute_swap`, `send_payment`, `approve_token`, …) exist in the codebase as a **reference** for how a signing path binds to the verdict: every write is gated by the policy engine plus the write-execution gate (`actionPolicyEngine` is the sole ALLOW/BLOCK decider; `writeExecutionGate` refuses to proceed without a passing verdict wired in). They are **OFF by default, experimental, and unaudited**, run **self-hosted and single-tenant only**, and the public server refuses to enable them: a boot guard fails fast if managed execution is configured on a public host. The audited, production surface is the read-only verdict layer.
158
+
159
+ ## Execution modes
160
+
161
+ | Mode | Key / wallet | Where it runs | Use for |
162
+ |------|--------------|---------------|---------|
163
+ | **Read-only preflight** *(default)* | none | hosted or local | Safety checks, risk analysis, demos |
164
+ | **User-signed** | your own wallet | anywhere | SafeHands validates; you sign externally, then it verifies + relays the broadcast |
165
+ | **Managed execution** | local encrypted wallet | self-hosted only | Full agent autonomy on mainnet, opt-in |
166
+ | **Env wallet** *(advanced)* | `PRIVATE_KEY` in env | local dev | Local mainnet development |
167
+
168
+ Read-only usage needs no `.env`, no private key, and no authorization.
169
+
170
+ ---
171
+
172
+ ## Install
173
+
174
+ ```bash
175
+ npx skills add SZtch/safehands-pharos
176
+ ```
177
+
178
+ ### Claude Desktop (or any MCP client)
179
+
180
+ Add to `claude_desktop_config.json` and restart. The default is read-only, with no keys, wallet, or setup:
181
+
182
+ ```json
183
+ {
184
+ "mcpServers": {
185
+ "safehands": {
186
+ "command": "npx",
187
+ "args": ["-y", "github:SZtch/safehands-pharos"]
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ Then ask: *"Run a SafeHands preflight on this payment."*
194
+
195
+ To run **self-hosted managed execution** on your own machine, add an `env` block (`WALLET_MODE=managed-mainnet`, `WRITE_TOOLS_ENABLED=true`). SafeHands creates a local AES-256-GCM-encrypted wallet on first run; you fund it from a faucet and authorize it before write tools unlock. See [.env.example](.env.example) and [docs/PRODUCTION_BACKEND.md](docs/PRODUCTION_BACKEND.md).
196
+
197
+ ### CLI
198
+
199
+ ```bash
200
+ npx github:SZtch/safehands-pharos skill safehands_preflight_check \
201
+ '{"actionType":"approve_token","chainId":1672,"approvalToken":"USDC","spender":"0x000000000000000000000000000000000000dEaD","approvalAmount":"max"}'
202
+ ```
203
+
204
+ Every tool returns the same envelope: `{ "success": true, "data": { … }, "error": null, "timestamp": "…" }`.
205
+
206
+ ## The 33 tools
207
+
208
+ One policy engine behind MCP, HTTP, and CLI. The safety-preflight, risk, and market/chain tools are public and keyless; execution tools are OFF by default behind env gates plus the policy verdict. Full catalog: **[docs/TOOLS.md](docs/TOOLS.md)**.
209
+
210
+ ## Per-agent policy
211
+
212
+ Different agents can carry different risk thresholds (`conservative` / `balanced` (default) / `advanced` / `custom`). Hard safety rules (mainnet guard, zero address, SSRF, unauthorized managed execution) are never overridable by any profile. Policies live in `.agents/policies/`; raising a limit requires an explicit saved config, so runtime or prompt injection cannot silently widen it. Profile limits: **[docs/POLICY_PROFILES.md](docs/POLICY_PROFILES.md)**.
213
+
214
+ ## x402
215
+
216
+ SafeHands makes agent-driven x402 payments safer by validating the HTTP 402 requirement before anything is signed or settled:
217
+
218
+ - `safehands_x402_preflight`: no payment, no auth, URL + amount safety
219
+ - `x402_pay_and_fetch`: gated execution behind policy limits
220
+ - SSRF and redirect-SSRF are blocked; payment amount, token, and per-agent caps are enforced
221
+ - Replay/idempotency is backed by a durable store (Upstash Redis when configured, local JSON fallback)
222
+
223
+ ## On-chain registry + attestation
224
+
225
+ SafeHands deploys two contracts to Pharos Pacific Mainnet: a **registry** (authorized operators/agents, Merkle risk roots, `verifyRiskRecord` view) and an **attestation** contract (privacy-preserving verified-safe records + reputation).
226
+
227
+ | | |
228
+ |---|---|
229
+ | Registry | [`0x428e02bf85412e7242d991cd6725ec59e8b06c8d`](https://www.pharosscan.xyz/address/0x428e02bf85412e7242d991cd6725ec59e8b06c8d) |
230
+ | Attestation | [`0x71a7a87b3b1ab6d86204cad691bb32fd75b4588c`](https://www.pharosscan.xyz/address/0x71a7a87b3b1ab6d86204cad691bb32fd75b4588c) |
231
+ | Network | Pharos Pacific Mainnet (chain `1672`) |
232
+ | Source | `contracts/SafeHandsRegistry.sol`, `contracts/SafeHandsAttestation.sol` |
233
+
234
+ When the attested-broadcast path is enabled and a user-signed transaction is broadcast successfully, SafeHands writes an attestation on-chain: hashed context only (`preparedTransactionHash`, `policyHash`, `metadataHash`) plus the `txHash`, never raw calldata, keys, amounts, recipients, or intent. Attestation gas is paid by a dedicated `SAFEHANDS_ATTESTER_PRIVATE_KEY` separate from any user wallet. The backend reads the contract addresses from `SAFEHANDS_REGISTRY_ADDRESS` / `SAFEHANDS_ATTESTATION_ADDRESS`, so you can point at your own redeploy without touching code.
235
+
236
+ ## Network
237
+
238
+ | | Pharos Pacific Mainnet |
239
+ |---|---|
240
+ | Chain ID | `1672` |
241
+ | Native token | `PROS` |
242
+ | RPC | `https://rpc.pharos.xyz` |
243
+ | Explorer | `https://www.pharosscan.xyz` |
244
+
245
+ Pharos Atlantic Testnet (`688689`) remains readable for legacy checks but is deprecated for execution.
246
+
247
+ ## Security defaults
248
+
249
+ SafeHands ships closed. Nothing runs without an explicit opt-in:
250
+
251
+ - `WRITE_TOOLS_ENABLED=false`: no write tools
252
+ - `WALLET_MODE=none`: no wallet created (`managed-mainnet` is opt-in, self-hosted only)
253
+ - Unlimited approvals blocked
254
+ - Mainnet execution disabled until write/signing env gates are set
255
+ - SSRF-sensitive URLs blocked
256
+ - Private keys never returned in responses or logs
257
+ - Per-agent policy limits and daily spend caps enforced
258
+ - Managed execution gated by on-chain registry authorization
259
+ - A boot guard refuses managed/write execution on a public host
260
+
261
+ ---
262
+
263
+ ## Testing
264
+
265
+ ```bash
266
+ npm run build # compile
267
+ npm test # hermetic deterministic suite (policy, x402 gate, write-auth, risk-inclusion; no network)
268
+ npm run demo # live safety checks in the terminal
269
+ npm run test:contracts # Hardhat contract tests (offline smoke fallback)
270
+ npm run test:all # build + test + demo + contracts
271
+ ```
272
+
273
+ `npm test` needs no wallet, key, or network and never broadcasts. Live read-only RPC checks run separately via `npm run test:live`. The live user-signed broadcast path is opt-in (`SAFEHANDS_USER_SIGNED_BROADCAST_ENABLED=true SAFEHANDS_LIVE_BROADCAST_TEST=true npm run test:live-broadcast`).
274
+
275
+ ## Configuration
276
+
277
+ Read-only preflight works with **no `.env` at all**. Every write/execution/attestation capability is opt-in behind an env flag. The full annotated reference (network, safety gates, managed execution, attestation, x402, production hosting) is in **[.env.example](.env.example)**; self-host operations are in **[docs/PRODUCTION_BACKEND.md](docs/PRODUCTION_BACKEND.md)**.
278
+
279
+ ## Known limitations
280
+
281
+ - Managed-wallet encryption is AES-256-GCM, not KMS/Vault-grade; not intended for custody of large amounts.
282
+ - User-signed broadcast (`POST /broadcast/signed`) is live but disabled by default; without `SAFEHANDS_USER_SIGNED_BROADCAST_ENABLED=true` it runs verify-only.
283
+ - GoPlus token security does not cover Pharos testnet (`688689`). On Pacific Mainnet (`1672`) GoPlus coverage is still new: tokens it has not yet indexed return a fail-closed `UNVERIFIED` result (never "safe").
284
+ - Canonical token prices come from Chainlink Push Engine feeds on Pharos Pacific Mainnet. If the public RPC is temporarily rate-limited, SafeHands may serve a clearly flagged bounded cached oracle value; stale feeds fail closed.
285
+ - DODO / FaroSwap route checks can occasionally lack liquidity for exotic pairs; this affects pool/route/swap tooling, not canonical `get_token_price`.
286
+
287
+ ## Roadmap
288
+
289
+ The goal: be the safety decision every AI agent consults *before* it acts on-chain. One rule holds throughout: **the safety verdict stays deterministic. The model advises; the policy engine decides.** The arc is a single verdict engine moving from *advising* an action (hosted, today) to *gating* it (verdict-bound signing) without the safety logic ever changing.
290
+
291
+ **Shipped (v2.6.0):** 33-tool agent surface across MCP, HTTP, and CLI; hosted Anvita engine at read-path capability parity (offline calldata/approval decoding, dangerous-admin recognition, MultiSend aggregation, operator recipient denylist), plus registry-only name resolution (`resolve_alias`), wallet balance and portfolio reads valued via live Chainlink with a holdings-exposure factor on fund-moving intents, EIP-1967 proxy inspection, and ERC-4626 vault / AMM pool safety probes with escalate-only composition; deterministic policy engine (mainnet guard, approval limits, SSRF guard, spend caps); `execute_swap` with a second, registry-verified venue (OKX DEX aggregator; reference write path, off by default); registry + attestation contracts live on Pharos Pacific Mainnet; GoPlus token-security and Goldsky indexing; x402 preflight and gated `pay_and_fetch`.
292
+
293
+ **Next:** L1 risk-root committer automation, a data-availability serving endpoint, broader cross-agent reputation reads, and compliance-provider integrations for RWA flows (TRM Labs screening, Circle CCTP settlement; currently roadmap, not integrated).
294
+
295
+ **Contracts v2 (designed, not scheduled):** committed-root history, content-addressed data availability (IPFS CID instead of a mutable URL), verdict revocation, reproducible verdicts, and intent tickets that bind a verdict to one exact transaction. Full reasoning: **[docs/CONTRACTS_V2_DESIGN.md](docs/CONTRACTS_V2_DESIGN.md)**.
296
+
297
+ ---
298
+
299
+ ## License
300
+
301
+ MIT © [SZtch](https://github.com/SZtch)