@jinn-network/client 0.1.6 → 0.1.7-canary.17a8ecb8

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 (351) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +67 -1
  3. package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
  4. package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
  5. package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
  6. package/dist/adapters/mech/adapter.d.ts +38 -1
  7. package/dist/adapters/mech/adapter.js +268 -57
  8. package/dist/adapters/mech/adapter.js.map +1 -1
  9. package/dist/adapters/mech/contracts.d.ts +17 -4
  10. package/dist/adapters/mech/contracts.js +8 -2
  11. package/dist/adapters/mech/contracts.js.map +1 -1
  12. package/dist/adapters/mech/safe-revert.d.ts +20 -0
  13. package/dist/adapters/mech/safe-revert.js +12 -4
  14. package/dist/adapters/mech/safe-revert.js.map +1 -1
  15. package/dist/adapters/mech/safe.d.ts +6 -2
  16. package/dist/adapters/mech/safe.js +32 -11
  17. package/dist/adapters/mech/safe.js.map +1 -1
  18. package/dist/adapters/mech/types.d.ts +6 -1
  19. package/dist/adapters/mech/types.js.map +1 -1
  20. package/dist/adapters/mech/verdict-code.d.ts +1 -0
  21. package/dist/adapters/mech/verdict-code.js +18 -0
  22. package/dist/adapters/mech/verdict-code.js.map +1 -1
  23. package/dist/api/activity-events-endpoint.d.ts +14 -0
  24. package/dist/api/activity-events-endpoint.js +59 -0
  25. package/dist/api/activity-events-endpoint.js.map +1 -0
  26. package/dist/api/admin-endpoint.d.ts +15 -3
  27. package/dist/api/admin-endpoint.js +24 -2
  28. package/dist/api/admin-endpoint.js.map +1 -1
  29. package/dist/api/bootstrap-endpoint.d.ts +1 -2
  30. package/dist/api/bootstrap-endpoint.js +49 -1
  31. package/dist/api/bootstrap-endpoint.js.map +1 -1
  32. package/dist/api/codex-doctor-endpoint.d.ts +73 -0
  33. package/dist/api/codex-doctor-endpoint.js +177 -0
  34. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  35. package/dist/api/discovery-endpoint.d.ts +1 -0
  36. package/dist/api/discovery-endpoint.js +26 -0
  37. package/dist/api/discovery-endpoint.js.map +1 -1
  38. package/dist/api/fleet-build.d.ts +1 -0
  39. package/dist/api/fleet-build.js +2 -1
  40. package/dist/api/fleet-build.js.map +1 -1
  41. package/dist/api/gather-status.d.ts +14 -0
  42. package/dist/api/gather-status.js +494 -19
  43. package/dist/api/gather-status.js.map +1 -1
  44. package/dist/api/hermes-doctor-endpoint.d.ts +117 -0
  45. package/dist/api/hermes-doctor-endpoint.js +229 -23
  46. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  47. package/dist/api/launcher-status.d.ts +22 -17
  48. package/dist/api/launcher-status.js +13 -11
  49. package/dist/api/launcher-status.js.map +1 -1
  50. package/dist/api/launcher-tasks.d.ts +1 -1
  51. package/dist/api/launcher-tasks.js +12 -8
  52. package/dist/api/launcher-tasks.js.map +1 -1
  53. package/dist/api/portfolio-v0-build.d.ts +10 -0
  54. package/dist/api/portfolio-v0-build.js +24 -5
  55. package/dist/api/portfolio-v0-build.js.map +1 -1
  56. package/dist/api/prediction-v1-build.d.ts +10 -0
  57. package/dist/api/prediction-v1-build.js +7 -1
  58. package/dist/api/prediction-v1-build.js.map +1 -1
  59. package/dist/api/server.d.ts +31 -1
  60. package/dist/api/server.js +72 -1
  61. package/dist/api/server.js.map +1 -1
  62. package/dist/api/setup-endpoints.d.ts +16 -0
  63. package/dist/api/setup-endpoints.js +89 -135
  64. package/dist/api/setup-endpoints.js.map +1 -1
  65. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  66. package/dist/api/setup-retry-endpoint.js +32 -0
  67. package/dist/api/setup-retry-endpoint.js.map +1 -0
  68. package/dist/api/solvernets-endpoints.d.ts +8 -0
  69. package/dist/api/solvernets-endpoints.js +71 -43
  70. package/dist/api/solvernets-endpoints.js.map +1 -1
  71. package/dist/api/status-build.d.ts +112 -0
  72. package/dist/api/status-build.js +98 -18
  73. package/dist/api/status-build.js.map +1 -1
  74. package/dist/api/task-run-routing.d.ts +7 -0
  75. package/dist/api/task-run-routing.js +12 -0
  76. package/dist/api/task-run-routing.js.map +1 -0
  77. package/dist/api/task-runs-build.d.ts +21 -0
  78. package/dist/api/task-runs-build.js +14 -1
  79. package/dist/api/task-runs-build.js.map +1 -1
  80. package/dist/build-info.json +4 -4
  81. package/dist/build-meta.json +1 -1
  82. package/dist/chain-read-errors.d.ts +10 -0
  83. package/dist/chain-read-errors.js +15 -0
  84. package/dist/chain-read-errors.js.map +1 -1
  85. package/dist/cli/commands/auth.js +1 -1
  86. package/dist/cli/commands/auth.js.map +1 -1
  87. package/dist/cli/commands/create.js +3 -2
  88. package/dist/cli/commands/create.js.map +1 -1
  89. package/dist/cli/commands/doctor.d.ts +2 -0
  90. package/dist/cli/commands/doctor.js +2 -0
  91. package/dist/cli/commands/doctor.js.map +1 -1
  92. package/dist/cli/commands/rewards.js +11 -7
  93. package/dist/cli/commands/rewards.js.map +1 -1
  94. package/dist/cli/commands/solver-nets.js +101 -15
  95. package/dist/cli/commands/solver-nets.js.map +1 -1
  96. package/dist/cli/commands/solver-plugins-block.d.ts +33 -0
  97. package/dist/cli/commands/solver-plugins-block.js +118 -0
  98. package/dist/cli/commands/solver-plugins-block.js.map +1 -0
  99. package/dist/cli/commands/solver-plugins-feedback.d.ts +72 -0
  100. package/dist/cli/commands/solver-plugins-feedback.js +262 -0
  101. package/dist/cli/commands/solver-plugins-feedback.js.map +1 -0
  102. package/dist/cli/commands/solver-plugins-read.d.ts +54 -0
  103. package/dist/cli/commands/solver-plugins-read.js +259 -0
  104. package/dist/cli/commands/solver-plugins-read.js.map +1 -0
  105. package/dist/cli/commands/solver-plugins.d.ts +35 -0
  106. package/dist/cli/commands/solver-plugins.js +399 -2
  107. package/dist/cli/commands/solver-plugins.js.map +1 -1
  108. package/dist/cli/commands/status.js +1 -1
  109. package/dist/cli/commands/status.js.map +1 -1
  110. package/dist/cli/commands/tasks.js +101 -11
  111. package/dist/cli/commands/tasks.js.map +1 -1
  112. package/dist/cli/commands/update.d.ts +10 -0
  113. package/dist/cli/commands/update.js +36 -0
  114. package/dist/cli/commands/update.js.map +1 -1
  115. package/dist/cli/introspection-context.js +5 -0
  116. package/dist/cli/introspection-context.js.map +1 -1
  117. package/dist/cli/task-native-readiness.d.ts +10 -1
  118. package/dist/cli/task-native-readiness.js +30 -6
  119. package/dist/cli/task-native-readiness.js.map +1 -1
  120. package/dist/config.d.ts +273 -235
  121. package/dist/config.js +305 -114
  122. package/dist/config.js.map +1 -1
  123. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  124. package/dist/daemon/checkpoint-loop.js +76 -0
  125. package/dist/daemon/checkpoint-loop.js.map +1 -0
  126. package/dist/daemon/creator.d.ts +1 -1
  127. package/dist/daemon/creator.js +7 -3
  128. package/dist/daemon/creator.js.map +1 -1
  129. package/dist/daemon/daemon.d.ts +22 -0
  130. package/dist/daemon/daemon.js +156 -23
  131. package/dist/daemon/daemon.js.map +1 -1
  132. package/dist/daemon/eviction-loop.d.ts +40 -0
  133. package/dist/daemon/eviction-loop.js +67 -0
  134. package/dist/daemon/eviction-loop.js.map +1 -0
  135. package/dist/daemon/gate-logger.d.ts +9 -0
  136. package/dist/daemon/gate-logger.js +2 -0
  137. package/dist/daemon/gate-logger.js.map +1 -0
  138. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  139. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  140. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  141. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  142. package/dist/daemon/jinn-claim-loop.js +77 -23
  143. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  144. package/dist/daemon/readiness-gate.d.ts +1 -4
  145. package/dist/daemon/readiness-gate.js.map +1 -1
  146. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  147. package/dist/daemon/skip-log-dedup.js +106 -0
  148. package/dist/daemon/skip-log-dedup.js.map +1 -0
  149. package/dist/daemon/spend-cap-gate.d.ts +40 -0
  150. package/dist/daemon/spend-cap-gate.js +46 -0
  151. package/dist/daemon/spend-cap-gate.js.map +1 -0
  152. package/dist/dashboard/assets/index-8yHQgi7p.js +345 -0
  153. package/dist/dashboard/assets/index-BOBhJ76-.css +32 -0
  154. package/dist/dashboard/index.html +2 -2
  155. package/dist/discovery/factory.d.ts +17 -5
  156. package/dist/discovery/factory.js +46 -18
  157. package/dist/discovery/factory.js.map +1 -1
  158. package/dist/discovery/http.js +142 -3
  159. package/dist/discovery/http.js.map +1 -1
  160. package/dist/discovery/onchain.d.ts +5 -0
  161. package/dist/discovery/onchain.js +407 -15
  162. package/dist/discovery/onchain.js.map +1 -1
  163. package/dist/discovery/types.d.ts +45 -1
  164. package/dist/discovery/types.js +8 -10
  165. package/dist/discovery/types.js.map +1 -1
  166. package/dist/discovery/with-fallback.d.ts +7 -0
  167. package/dist/discovery/with-fallback.js +10 -0
  168. package/dist/discovery/with-fallback.js.map +1 -1
  169. package/dist/earning/bootstrap.d.ts +92 -1
  170. package/dist/earning/bootstrap.js +203 -63
  171. package/dist/earning/bootstrap.js.map +1 -1
  172. package/dist/earning/contracts.d.ts +14 -0
  173. package/dist/earning/contracts.js +17 -5
  174. package/dist/earning/contracts.js.map +1 -1
  175. package/dist/earning/funding-plan.js +27 -18
  176. package/dist/earning/funding-plan.js.map +1 -1
  177. package/dist/earning/jinn-rewards.d.ts +46 -0
  178. package/dist/earning/jinn-rewards.js +32 -0
  179. package/dist/earning/jinn-rewards.js.map +1 -1
  180. package/dist/earning/safe-adapter.d.ts +2 -0
  181. package/dist/earning/safe-adapter.js +37 -11
  182. package/dist/earning/safe-adapter.js.map +1 -1
  183. package/dist/earning/store.d.ts +8 -0
  184. package/dist/earning/store.js.map +1 -1
  185. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  186. package/dist/earning/testnet-setup-migration.js +27 -1
  187. package/dist/earning/testnet-setup-migration.js.map +1 -1
  188. package/dist/earning/types.d.ts +21 -6
  189. package/dist/earning/viem-clients.d.ts +11 -4
  190. package/dist/earning/viem-clients.js +14 -5
  191. package/dist/earning/viem-clients.js.map +1 -1
  192. package/dist/erc8004/reputation.d.ts +8 -0
  193. package/dist/erc8004/reputation.js +22 -3
  194. package/dist/erc8004/reputation.js.map +1 -1
  195. package/dist/events/types.d.ts +2 -2
  196. package/dist/harnesses/cost-estimates.d.ts +145 -0
  197. package/dist/harnesses/cost-estimates.js +297 -0
  198. package/dist/harnesses/cost-estimates.js.map +1 -0
  199. package/dist/harnesses/engine/engine.d.ts +72 -0
  200. package/dist/harnesses/engine/engine.js +118 -8
  201. package/dist/harnesses/engine/engine.js.map +1 -1
  202. package/dist/harnesses/engine/persistence.d.ts +51 -1
  203. package/dist/harnesses/engine/persistence.js +118 -5
  204. package/dist/harnesses/engine/persistence.js.map +1 -1
  205. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  206. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  207. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  208. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  209. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  210. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  211. package/dist/harnesses/impls/hermes-agent/bootstrap.js +40 -6
  212. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  213. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  214. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  215. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  216. package/dist/harnesses/impls/index.d.ts +7 -0
  217. package/dist/harnesses/impls/index.js +16 -1
  218. package/dist/harnesses/impls/index.js.map +1 -1
  219. package/dist/harnesses/impls/learner/harness.d.ts +38 -4
  220. package/dist/harnesses/impls/learner/harness.js +96 -2
  221. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  222. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  223. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  224. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  225. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  226. package/dist/harnesses/impls/stub.d.ts +58 -0
  227. package/dist/harnesses/impls/stub.js +89 -0
  228. package/dist/harnesses/impls/stub.js.map +1 -0
  229. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  230. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +178 -93
  231. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  232. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  233. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  234. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  235. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +88 -4
  236. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +143 -22
  237. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  238. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  239. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  240. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  241. package/dist/harnesses/readiness-registry.js +9 -1
  242. package/dist/harnesses/readiness-registry.js.map +1 -1
  243. package/dist/main.js +413 -111
  244. package/dist/main.js.map +1 -1
  245. package/dist/observability/emit-event.d.ts +3 -2
  246. package/dist/observability/emit-event.js +22 -1
  247. package/dist/observability/emit-event.js.map +1 -1
  248. package/dist/operator-errors.d.ts +7 -0
  249. package/dist/operator-errors.js +13 -1
  250. package/dist/operator-errors.js.map +1 -1
  251. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  252. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  253. package/dist/plugins/learner/AGENTS.md +40 -0
  254. package/dist/plugins/learner/CLAUDE.md +33 -0
  255. package/dist/plugins/learner/README.md +59 -0
  256. package/dist/plugins/learner/hooks/hooks.json +16 -0
  257. package/dist/plugins/learner/hooks/session-start +38 -0
  258. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  259. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  260. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +94 -0
  261. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  262. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  263. package/dist/plugins/learner/skills/learn/promoter-prompt.md +113 -0
  264. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  265. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  266. package/dist/preflight/rpc-network.d.ts +40 -0
  267. package/dist/preflight/rpc-network.js +67 -1
  268. package/dist/preflight/rpc-network.js.map +1 -1
  269. package/dist/restart-daemon.d.ts +90 -0
  270. package/dist/restart-daemon.js +95 -0
  271. package/dist/restart-daemon.js.map +1 -0
  272. package/dist/rpc/transport.d.ts +109 -0
  273. package/dist/rpc/transport.js +220 -0
  274. package/dist/rpc/transport.js.map +1 -0
  275. package/dist/scripts/donation-consumption-acceptance.js +7 -28
  276. package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
  277. package/dist/setup/halt-mode.d.ts +14 -0
  278. package/dist/setup/halt-mode.js +17 -0
  279. package/dist/setup/halt-mode.js.map +1 -0
  280. package/dist/solver-nets/prediction-operator-ux.d.ts +1 -2
  281. package/dist/solver-nets/prediction-operator-ux.js +90 -47
  282. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  283. package/dist/solver-nets/registry.d.ts +20 -1
  284. package/dist/solver-nets/registry.js +38 -25
  285. package/dist/solver-nets/registry.js.map +1 -1
  286. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  287. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  288. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  289. package/dist/solver-types/_swe-rebench-v2-pool.d.ts +9 -2
  290. package/dist/solver-types/_swe-rebench-v2-pool.js +15 -20
  291. package/dist/solver-types/_swe-rebench-v2-pool.js.map +1 -1
  292. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  293. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  294. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  295. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +94 -1
  296. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +305 -39
  297. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  298. package/dist/solver-types/swe-rebench-v2-auto.d.ts +22 -7
  299. package/dist/solver-types/swe-rebench-v2-auto.js +45 -20
  300. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  301. package/dist/solver-types/swe-rebench-v2.d.ts +13 -2
  302. package/dist/solver-types/swe-rebench-v2.js +237 -95
  303. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  304. package/dist/solvernets/daemon-init.d.ts +10 -2
  305. package/dist/solvernets/daemon-init.js +22 -2
  306. package/dist/solvernets/daemon-init.js.map +1 -1
  307. package/dist/solvernets/launched-record-dispatcher.js +35 -7
  308. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  309. package/dist/solvernets/store.d.ts +5 -0
  310. package/dist/solvernets/store.js +1 -0
  311. package/dist/solvernets/store.js.map +1 -1
  312. package/dist/spend/credential.d.ts +8 -0
  313. package/dist/spend/credential.js +30 -0
  314. package/dist/spend/credential.js.map +1 -0
  315. package/dist/spend/daemon-config.d.ts +13 -0
  316. package/dist/spend/daemon-config.js +24 -0
  317. package/dist/spend/daemon-config.js.map +1 -0
  318. package/dist/spend/pricing.d.ts +16 -0
  319. package/dist/spend/pricing.js +26 -0
  320. package/dist/spend/pricing.js.map +1 -0
  321. package/dist/spend/record.d.ts +13 -0
  322. package/dist/spend/record.js +30 -0
  323. package/dist/spend/record.js.map +1 -0
  324. package/dist/spend/usage.d.ts +27 -0
  325. package/dist/spend/usage.js +113 -0
  326. package/dist/spend/usage.js.map +1 -0
  327. package/dist/store/store.d.ts +43 -0
  328. package/dist/store/store.js +236 -7
  329. package/dist/store/store.js.map +1 -1
  330. package/dist/tasks/sources.d.ts +18 -1
  331. package/dist/tasks/sources.js +33 -5
  332. package/dist/tasks/sources.js.map +1 -1
  333. package/dist/trajectory/transcript-parsers/types.d.ts +8 -8
  334. package/dist/tx-retry.d.ts +166 -19
  335. package/dist/tx-retry.js +310 -32
  336. package/dist/tx-retry.js.map +1 -1
  337. package/dist/types/payloads/prediction-apy-v0.d.ts +5 -5
  338. package/dist/types/payloads/prediction-v0.d.ts +5 -5
  339. package/dist/types/task-document.d.ts +392 -0
  340. package/dist/types/task-document.js +10 -0
  341. package/dist/types/task-document.js.map +1 -1
  342. package/dist/types/task.d.ts +28 -0
  343. package/dist/util/extract-tx-hash.d.ts +14 -0
  344. package/dist/util/extract-tx-hash.js +19 -0
  345. package/dist/util/extract-tx-hash.js.map +1 -0
  346. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  347. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  348. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  349. package/package.json +30 -12
  350. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  351. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
@@ -1,21 +1,24 @@
1
1
  /**
2
2
  * Best-effort status collection for GET /v1/status (RPC + earning store + SQLite).
3
3
  */
4
- import { createPublicClient, http } from 'viem';
4
+ import { createPublicClient, getAddress, http, parseAbiItem } from 'viem';
5
5
  import { existsSync, readFileSync } from 'node:fs';
6
6
  import { join } from 'node:path';
7
7
  import { base, baseSepolia } from 'viem/chains';
8
+ import { isOverSpendCap } from '../daemon/spend-cap-gate.js';
8
9
  import { FleetStateStore } from '../earning/store.js';
9
- import { getChainConfig } from '../earning/contracts.js';
10
+ import { DEFAULT_TESTNET_ARTIFACTS, getChainConfig, loadJinnMviConfig, } from '../earning/contracts.js';
11
+ import { createJinnL1PublicClient } from '../earning/viem-clients.js';
10
12
  import { stage1MinMasterEth } from '../earning/bootstrap.js';
11
13
  import { JINN_STAKING_ABI } from '../earning/jinn-rewards.js';
12
14
  import { displayFleetServiceIndex } from '../earning/fleet-display-index.js';
13
- import { assembleStatusV1, resolveMasterDailyEstimateWei, } from './status-build.js';
15
+ import { assembleStatusV1, pendingTjinnStatus, TJINN_PUBLIC_INVALID_SAFE_ERROR, TJINN_PUBLIC_PARTIAL_ERROR, TJINN_PUBLIC_READ_ERROR, resolveMasterDailyEstimateWei, } from './status-build.js';
14
16
  import { listStolasClaimTargets } from '../earning/stolas-claim.js';
15
17
  import { gatherPortfolioV0Status, DEFAULT_ENGINE_WORKING_DIR_ROOT, } from './portfolio-v0-build.js';
16
18
  import { gatherPredictionV1Status, } from './prediction-v1-build.js';
17
19
  import { gatherTaskRunsStatus } from './task-runs-build.js';
18
20
  import { buildPredictionOperatorStatus, } from '../solver-nets/prediction-operator-ux.js';
21
+ import { findJoinedByName, rolesFromJoinedConfig, solverTypeFromJoinedContract, } from '../solver-nets/registry.js';
19
22
  const ERC20_BALANCE_OF_ABI = [
20
23
  {
21
24
  type: 'function',
@@ -25,6 +28,81 @@ const ERC20_BALANCE_OF_ABI = [
25
28
  outputs: [{ name: '', type: 'uint256' }],
26
29
  },
27
30
  ];
31
+ const JINN_DISTRIBUTOR_CLAIMED_ABI = [
32
+ {
33
+ type: 'function',
34
+ name: 'totalClaimedOperator',
35
+ stateMutability: 'view',
36
+ inputs: [{ name: 'serviceId', type: 'uint256' }],
37
+ outputs: [{ name: '', type: 'uint256' }],
38
+ },
39
+ ];
40
+ /**
41
+ * `Claimed` event item for `getLogs({ event, args })`. Matches the
42
+ * Solidity signature in
43
+ * `contracts/src/jinn/distribution/JinnDistributor.sol` so the operator
44
+ * 24h-minted sum can be computed without a separate indexer.
45
+ */
46
+ const JINN_DISTRIBUTOR_CLAIMED_EVENT = parseAbiItem('event Claimed(uint256 indexed serviceId, address indexed multisig, uint256 operatorMinted, uint256 daoMinted, uint256 totalEntitledOperator, uint256 totalEntitledDao)');
47
+ const TJINN_BALANCE_CACHE_TTL_MS = 30_000;
48
+ const TJINN_BALANCE_TIMEOUT_MS = 6_000;
49
+ /**
50
+ * Approximate Sepolia blocks per 24 hours. The chain produces a block every
51
+ * ~12s; 86_400 / 12 = 7_200. We pad to 7_500 to absorb the occasional
52
+ * slower block and keep the window comfortably within the common 10k-block
53
+ * `eth_getLogs` cap.
54
+ */
55
+ const SEPOLIA_BLOCKS_PER_24H = 7500n;
56
+ /**
57
+ * tJINN token address + chain id resolved from the bundled JINN MVI L1
58
+ * deployment artifact — the single source of truth. Used only when the caller
59
+ * (`main.ts`) does not thread explicit values through `StatusGatherConfig`
60
+ * (e.g. test callers, sqlite-only introspection without config). Lazy + cached
61
+ * so the artifact read happens at most once per process.
62
+ */
63
+ let cachedTjinnArtifactIdentity;
64
+ function defaultTjinnIdentity() {
65
+ if (!cachedTjinnArtifactIdentity) {
66
+ let tokenAddress;
67
+ let chainId;
68
+ try {
69
+ const mvi = loadJinnMviConfig({ l1ArtifactPath: DEFAULT_TESTNET_ARTIFACTS.jinnMviL1 });
70
+ tokenAddress = mvi.jinn;
71
+ chainId = mvi.l1ChainId;
72
+ }
73
+ catch {
74
+ // Fall through to the hard defaults below if the artifact is unreadable.
75
+ }
76
+ cachedTjinnArtifactIdentity = {
77
+ tokenAddress: tokenAddress ?? '0x0bc0B2f733bF4229FD58Baaac5ebFEf2AEc83C4A',
78
+ chainId: chainId ?? 11155111,
79
+ };
80
+ }
81
+ return cachedTjinnArtifactIdentity;
82
+ }
83
+ function resolveTjinnIdentity(status) {
84
+ const fallback = defaultTjinnIdentity();
85
+ return {
86
+ tokenAddress: status?.tjinnTokenAddress ?? fallback.tokenAddress,
87
+ chainId: status?.tjinnChainId ?? fallback.chainId,
88
+ };
89
+ }
90
+ /** Fill a fresh errors Map with `TJINN_PUBLIC_READ_ERROR` for every key. */
91
+ function errorsForAllKeys(keys) {
92
+ const errors = new Map();
93
+ for (const key of keys) {
94
+ errors.set(key, TJINN_PUBLIC_READ_ERROR);
95
+ }
96
+ return errors;
97
+ }
98
+ function errorsForAllServiceIds(serviceIds) {
99
+ const errors = new Map();
100
+ for (const serviceId of serviceIds) {
101
+ errors.set(serviceId, TJINN_PUBLIC_READ_ERROR);
102
+ }
103
+ return errors;
104
+ }
105
+ const tjinnBalanceCache = new Map();
28
106
  function readDaemonRuntime(earningDir) {
29
107
  if (!earningDir)
30
108
  return undefined;
@@ -62,6 +140,24 @@ export function invalidatePredictionOperatorStatusCache(config) {
62
140
  function chainKey(network) {
63
141
  return network === 'testnet' ? 'base-sepolia' : 'base';
64
142
  }
143
+ /**
144
+ * Derive the SolverNet name to use for the prediction operator diagnostic.
145
+ *
146
+ * Priority: (1) first joined entry's `name` field, (2) first joined entry's
147
+ * manifestCid, (3) fallback `'prediction'`.
148
+ *
149
+ * Post-issue-#421 the legacy `solverNets` config block has been retired; the
150
+ * operator's participation choices live in `joinedSolverNets` keyed by
151
+ * manifestCid.
152
+ */
153
+ function derivePredictionSolverNetName(config) {
154
+ const joinedEntries = Object.entries(config.joinedSolverNets ?? {});
155
+ if (joinedEntries.length > 0) {
156
+ const [cid, entry] = joinedEntries[0];
157
+ return entry.name ?? cid;
158
+ }
159
+ return 'prediction';
160
+ }
65
161
  function predictionOperatorCacheKey(configPath, name) {
66
162
  return `${configPath}\0${name}`;
67
163
  }
@@ -77,41 +173,42 @@ async function getCachedPredictionOperatorStatus(config, configPath, name) {
77
173
  // gather-status only runs inside a live daemon; the operator-status
78
174
  // surface should reflect that (Issue #86 §1: drop the vacuous
79
175
  // "start the daemon" copy when the daemon is already running).
80
- cached = buildPredictionOperatorStatus({ config, configPath, name, daemonRunning: true })
176
+ cached = buildPredictionOperatorStatus({ config, configPath, daemonRunning: true })
81
177
  .catch((error) => predictionOperatorUnavailable(config, configPath, name, errorMessage(error)));
82
178
  byKey.set(key, cached);
83
179
  }
84
180
  return cached;
85
181
  }
86
182
  function predictionOperatorUnavailable(config, configPath, name, message) {
87
- const net = config.solverNets[name];
183
+ // Resolve the matching joined entry by display name (or manifestCid) so
184
+ // the diagnostic can still surface the operator's configured roles when
185
+ // possible.
186
+ const joined = findJoinedByName(config.joinedSolverNets, name);
88
187
  const diagnostic = {
89
188
  code: 'prediction_operator_status_unavailable',
90
189
  severity: 'error',
91
190
  message,
92
191
  nextAction: {
93
- description: 'Inspect Prediction SolverNet configuration and restart the daemon after fixing it.',
94
- cli: `jinn solver-nets show ${name}`,
192
+ description: 'Inspect Prediction SolverNet configuration via Operator > SolverNets and restart the daemon after fixing it.',
193
+ url: '/operator#solvernets',
95
194
  },
96
195
  };
97
196
  // Roles are best-effort: an unavailable status path means the daemon
98
- // could not load the SolverNet, so we surface whatever the operator has
99
- // configured (post-migration) without trying to default further.
100
- const rawRoles = net?.roles;
101
- const netRoles = Array.isArray(rawRoles)
102
- ? rawRoles.filter((r) => r === 'solving' || r === 'evaluating')
103
- : [];
197
+ // could not load the SolverNet, so we surface whatever the operator
198
+ // joined.
199
+ const netRoles = joined ? rolesFromJoinedConfig(joined) : [];
200
+ const solverType = (joined && solverTypeFromJoinedContract(joined)) ?? 'prediction.v1';
104
201
  return {
105
202
  kind: 'prediction.v1.operatorStatus',
106
203
  ok: false,
107
204
  configPath,
108
205
  solverNet: {
109
206
  name,
110
- enabled: net?.enabled ?? false,
111
- solverType: net?.solverType ?? 'prediction.v1',
207
+ enabled: joined ? netRoles.length > 0 : false,
208
+ solverType,
112
209
  roles: netRoles,
113
- harness: net?.harness,
114
- taskGeneratorEnabled: net?.taskGenerator.enabled ?? false,
210
+ harness: joined?.harness,
211
+ taskGeneratorEnabled: false,
115
212
  },
116
213
  runtimePlugins: [],
117
214
  diagnostics: [diagnostic],
@@ -163,6 +260,8 @@ function predictionV1Unavailable(operator, operatorError) {
163
260
  solutions: 0,
164
261
  verdicts: 0,
165
262
  failed: 0,
263
+ settledFailed: 0,
264
+ localErrors: 0,
166
265
  },
167
266
  latest: {
168
267
  taskAt: null,
@@ -177,6 +276,158 @@ function predictionV1Unavailable(operator, operatorError) {
177
276
  function errorMessage(error) {
178
277
  return error instanceof Error ? error.message : String(error);
179
278
  }
279
+ function tJinnBalanceCacheKey(ethereumRpcUrl, distributorAddress, safeKeys, serviceIds) {
280
+ return [
281
+ ethereumRpcUrl,
282
+ distributorAddress ?? '',
283
+ [...safeKeys].sort().join(','),
284
+ [...serviceIds].sort((a, b) => a - b).join(','),
285
+ ].join('\0');
286
+ }
287
+ function timeoutError(message) {
288
+ const error = new Error(message);
289
+ error.name = 'TimeoutError';
290
+ return error;
291
+ }
292
+ function withTimeout(promise, timeoutMs, message) {
293
+ return new Promise((resolve, reject) => {
294
+ const timer = setTimeout(() => reject(timeoutError(message)), timeoutMs);
295
+ promise
296
+ .then(resolve, reject)
297
+ .finally(() => clearTimeout(timer));
298
+ });
299
+ }
300
+ async function readTjinnBalances(ethereumRpcUrl, tokenAddress, distributorAddress, expectedChainId, safeToAddress, serviceIds) {
301
+ const safeEntries = [...safeToAddress.entries()];
302
+ const client = createJinnL1PublicClient(ethereumRpcUrl, 'sepolia');
303
+ const chainId = await client.getChainId();
304
+ const balances = new Map();
305
+ const operatorClaimedByService = new Map();
306
+ const operatorMintedLast24hByService = new Map();
307
+ if (chainId !== expectedChainId) {
308
+ return {
309
+ chainId,
310
+ balances,
311
+ operatorClaimedByService,
312
+ operatorMintedLast24hByService,
313
+ errors: errorsForAllKeys(safeToAddress.keys()),
314
+ claimedErrors: errorsForAllServiceIds(serviceIds),
315
+ claimedLast24hError: TJINN_PUBLIC_READ_ERROR,
316
+ };
317
+ }
318
+ const errors = new Map();
319
+ // Single multicall3 round-trip (Sepolia has multicall3). `allowFailure: true`
320
+ // preserves the per-Safe partial-failure handling — a failed entry yields a
321
+ // `{ status: 'failure' }` result rather than rejecting the whole batch.
322
+ const results = await client.multicall({
323
+ allowFailure: true,
324
+ contracts: safeEntries.map(([, safeAddress]) => ({
325
+ address: tokenAddress,
326
+ abi: ERC20_BALANCE_OF_ABI,
327
+ functionName: 'balanceOf',
328
+ args: [safeAddress],
329
+ })),
330
+ });
331
+ for (let i = 0; i < results.length; i++) {
332
+ const result = results[i];
333
+ const key = safeEntries[i]?.[0];
334
+ if (!key)
335
+ continue;
336
+ if (result.status === 'success') {
337
+ balances.set(key, result.result.toString());
338
+ }
339
+ else {
340
+ errors.set(key, TJINN_PUBLIC_READ_ERROR);
341
+ }
342
+ }
343
+ const claimedErrors = new Map();
344
+ if (distributorAddress && serviceIds.length > 0) {
345
+ const claimedResults = await client.multicall({
346
+ allowFailure: true,
347
+ contracts: serviceIds.map((serviceId) => ({
348
+ address: distributorAddress,
349
+ abi: JINN_DISTRIBUTOR_CLAIMED_ABI,
350
+ functionName: 'totalClaimedOperator',
351
+ args: [BigInt(serviceId)],
352
+ })),
353
+ });
354
+ for (let i = 0; i < claimedResults.length; i++) {
355
+ const serviceId = serviceIds[i];
356
+ if (serviceId === undefined)
357
+ continue;
358
+ const result = claimedResults[i];
359
+ if (result.status === 'success') {
360
+ operatorClaimedByService.set(serviceId, result.result.toString());
361
+ }
362
+ else {
363
+ claimedErrors.set(serviceId, TJINN_PUBLIC_READ_ERROR);
364
+ }
365
+ }
366
+ }
367
+ let claimedLast24hError = null;
368
+ if (distributorAddress && serviceIds.length > 0) {
369
+ try {
370
+ const latest = await client.getBlockNumber();
371
+ const fromBlock = latest > SEPOLIA_BLOCKS_PER_24H ? latest - SEPOLIA_BLOCKS_PER_24H : 0n;
372
+ const logs = await client.getLogs({
373
+ address: distributorAddress,
374
+ event: JINN_DISTRIBUTOR_CLAIMED_EVENT,
375
+ args: { serviceId: serviceIds.map((id) => BigInt(id)) },
376
+ fromBlock,
377
+ toBlock: latest,
378
+ });
379
+ const sums = new Map();
380
+ for (const log of logs) {
381
+ const args = log.args;
382
+ if (args.serviceId === undefined || args.operatorMinted === undefined)
383
+ continue;
384
+ const id = Number(args.serviceId);
385
+ sums.set(id, (sums.get(id) ?? 0n) + args.operatorMinted);
386
+ }
387
+ for (const serviceId of serviceIds) {
388
+ operatorMintedLast24hByService.set(serviceId, (sums.get(serviceId) ?? 0n).toString());
389
+ }
390
+ }
391
+ catch {
392
+ claimedLast24hError = TJINN_PUBLIC_READ_ERROR;
393
+ }
394
+ }
395
+ return {
396
+ chainId,
397
+ balances,
398
+ operatorClaimedByService,
399
+ operatorMintedLast24hByService,
400
+ errors,
401
+ claimedErrors,
402
+ claimedLast24hError,
403
+ };
404
+ }
405
+ async function getCachedTjinnBalances(ethereumRpcUrl, tokenAddress, distributorAddress, expectedChainId, safeToAddress, serviceIds) {
406
+ const safeKeys = [...safeToAddress.keys()].sort();
407
+ const sortedServiceIds = [...serviceIds].sort((a, b) => a - b);
408
+ const cacheKey = tJinnBalanceCacheKey(ethereumRpcUrl, distributorAddress, safeKeys, sortedServiceIds);
409
+ const now = Date.now();
410
+ const cached = tjinnBalanceCache.get(cacheKey);
411
+ if (cached && cached.expiresAt > now) {
412
+ return cached.promise;
413
+ }
414
+ const promise = withTimeout(readTjinnBalances(ethereumRpcUrl, tokenAddress, distributorAddress, expectedChainId, safeToAddress, sortedServiceIds), TJINN_BALANCE_TIMEOUT_MS, 'tJINN balance collection timed out').catch(() => {
415
+ return {
416
+ chainId: expectedChainId,
417
+ balances: new Map(),
418
+ operatorClaimedByService: new Map(),
419
+ operatorMintedLast24hByService: new Map(),
420
+ errors: errorsForAllKeys(safeKeys),
421
+ claimedErrors: errorsForAllServiceIds(sortedServiceIds),
422
+ claimedLast24hError: TJINN_PUBLIC_READ_ERROR,
423
+ };
424
+ });
425
+ tjinnBalanceCache.set(cacheKey, {
426
+ expiresAt: now + TJINN_BALANCE_CACHE_TTL_MS,
427
+ promise,
428
+ });
429
+ return promise;
430
+ }
180
431
  async function sumPendingStakingRewards(rpcUrl, network, fleet) {
181
432
  const targets = listStolasClaimTargets(fleet.services);
182
433
  if (targets.length === 0) {
@@ -228,6 +479,158 @@ async function sumPendingStakingRewards(rpcUrl, network, fleet) {
228
479
  return { error: e instanceof Error ? e.message : String(e) };
229
480
  }
230
481
  }
482
+ /**
483
+ * Resolve the public error string for a tJINN status with at least one error.
484
+ *
485
+ * Flattened from a 3-deep nested ternary into guard clauses:
486
+ * - partial success (some balances read) → PARTIAL
487
+ * - only invalid-Safe errors → INVALID_SAFE
488
+ * - otherwise (RPC read failures) → READ_ERROR
489
+ *
490
+ * Caller must only invoke this when `hasInvalidSafe || hasReadError` is true.
491
+ */
492
+ function tjinnPublicError(opts) {
493
+ if (opts.hasAnyBalance)
494
+ return TJINN_PUBLIC_PARTIAL_ERROR;
495
+ if (opts.hasInvalidSafe && !opts.hasReadError)
496
+ return TJINN_PUBLIC_INVALID_SAFE_ERROR;
497
+ return TJINN_PUBLIC_READ_ERROR;
498
+ }
499
+ async function gatherTjinnStatus(ethereumRpcUrl, tokenAddress, distributorAddress, chainId, fleet) {
500
+ if (!fleet) {
501
+ return pendingTjinnStatus(tokenAddress, chainId);
502
+ }
503
+ const services = [];
504
+ const safeToAddress = new Map();
505
+ const serviceIds = new Set();
506
+ for (const svc of fleet.services) {
507
+ const index = displayFleetServiceIndex(svc);
508
+ const serviceId = svc.service_id ?? null;
509
+ if (serviceId !== null) {
510
+ serviceIds.add(serviceId);
511
+ }
512
+ const safeAddress = svc.safe_address;
513
+ if (!safeAddress) {
514
+ services.push({
515
+ index,
516
+ serviceId,
517
+ safeAddress: null,
518
+ balanceWei: null,
519
+ operatorClaimedWei: null,
520
+ state: 'pending',
521
+ error: null,
522
+ });
523
+ continue;
524
+ }
525
+ try {
526
+ const checksum = getAddress(safeAddress);
527
+ const key = checksum.toLowerCase();
528
+ services.push({
529
+ index,
530
+ serviceId,
531
+ safeAddress: checksum,
532
+ balanceWei: null,
533
+ operatorClaimedWei: null,
534
+ state: 'pending',
535
+ error: null,
536
+ });
537
+ safeToAddress.set(key, checksum);
538
+ }
539
+ catch {
540
+ services.push({
541
+ index,
542
+ serviceId,
543
+ safeAddress,
544
+ balanceWei: null,
545
+ operatorClaimedWei: null,
546
+ state: 'error',
547
+ error: TJINN_PUBLIC_INVALID_SAFE_ERROR,
548
+ });
549
+ }
550
+ }
551
+ const safeCount = safeToAddress.size;
552
+ if (safeCount === 0) {
553
+ const invalid = services.find((svc) => svc.state === 'error')?.error;
554
+ return pendingTjinnStatus(tokenAddress, chainId, {
555
+ state: invalid ? 'error' : 'pending',
556
+ safeCount,
557
+ services,
558
+ error: invalid ?? null,
559
+ });
560
+ }
561
+ if (!ethereumRpcUrl) {
562
+ return pendingTjinnStatus(tokenAddress, chainId, { safeCount, services });
563
+ }
564
+ const snapshot = await getCachedTjinnBalances(ethereumRpcUrl, tokenAddress, distributorAddress, chainId, safeToAddress, [...serviceIds]);
565
+ let total = 0n;
566
+ for (const balance of snapshot.balances.values()) {
567
+ total += BigInt(balance);
568
+ }
569
+ const allClaimedReadsAvailable = !!distributorAddress &&
570
+ serviceIds.size > 0 &&
571
+ snapshot.claimedErrors.size === 0 &&
572
+ [...serviceIds].every((serviceId) => snapshot.operatorClaimedByService.has(serviceId));
573
+ let operatorClaimedWei = null;
574
+ if (allClaimedReadsAvailable) {
575
+ let claimedTotal = 0n;
576
+ for (const serviceId of serviceIds) {
577
+ claimedTotal += BigInt(snapshot.operatorClaimedByService.get(serviceId) ?? '0');
578
+ }
579
+ operatorClaimedWei = claimedTotal.toString();
580
+ }
581
+ // 24h-window sum: null when the log query errored or there are no services.
582
+ let operatorMintedLast24hWei = null;
583
+ if (!!distributorAddress &&
584
+ serviceIds.size > 0 &&
585
+ snapshot.claimedLast24hError === null) {
586
+ let last24hTotal = 0n;
587
+ for (const serviceId of serviceIds) {
588
+ last24hTotal += BigInt(snapshot.operatorMintedLast24hByService.get(serviceId) ?? '0');
589
+ }
590
+ operatorMintedLast24hWei = last24hTotal.toString();
591
+ }
592
+ const hasInvalidSafe = services.some((svc) => svc.error === TJINN_PUBLIC_INVALID_SAFE_ERROR);
593
+ const hasReadError = snapshot.errors.size > 0;
594
+ const hasAnyError = hasInvalidSafe || hasReadError;
595
+ const hasAnyBalance = snapshot.balances.size > 0;
596
+ const publicError = hasAnyError
597
+ ? tjinnPublicError({ hasInvalidSafe, hasReadError, hasAnyBalance })
598
+ : null;
599
+ return pendingTjinnStatus(tokenAddress, snapshot.chainId, {
600
+ state: hasAnyError ? 'error' : 'ready',
601
+ safeBalanceWei: hasAnyBalance ? total.toString() : null,
602
+ operatorClaimedWei,
603
+ operatorMintedLast24hWei,
604
+ safeCount,
605
+ services: services.map((svc) => {
606
+ const operatorClaimedForService = svc.serviceId !== null
607
+ ? (snapshot.operatorClaimedByService.get(svc.serviceId) ?? null)
608
+ : null;
609
+ if (!svc.safeAddress)
610
+ return { ...svc, operatorClaimedWei: operatorClaimedForService };
611
+ if (svc.state === 'error')
612
+ return { ...svc, operatorClaimedWei: operatorClaimedForService };
613
+ const key = svc.safeAddress.toLowerCase();
614
+ const balance = snapshot.balances.get(key);
615
+ if (balance !== undefined) {
616
+ return {
617
+ ...svc,
618
+ state: 'ready',
619
+ balanceWei: balance,
620
+ operatorClaimedWei: operatorClaimedForService,
621
+ error: null,
622
+ };
623
+ }
624
+ return {
625
+ ...svc,
626
+ state: 'error',
627
+ operatorClaimedWei: operatorClaimedForService,
628
+ error: snapshot.errors.get(key) ?? TJINN_PUBLIC_READ_ERROR,
629
+ };
630
+ }),
631
+ error: publicError,
632
+ });
633
+ }
231
634
  function hasUsefulCacheValues(entry, isAgentRole) {
232
635
  if (isAgentRole)
233
636
  return entry.nativeWei != null;
@@ -350,6 +753,7 @@ export async function gatherGatheredStatusRaw(store, status) {
350
753
  }));
351
754
  const lastRewardClaimTickAt = store.getConfigValue('last_reward_claim_tick_at');
352
755
  const daily = resolveMasterDailyEstimateWei(status?.masterEthDailyEstimateWei, status?.pollIntervalMs ?? 5000);
756
+ const tjinnIdentity = resolveTjinnIdentity(status);
353
757
  // portfolio.v0 lifecycle data — best-effort, never throws
354
758
  let portfolioV0;
355
759
  try {
@@ -369,7 +773,8 @@ export async function gatherGatheredStatusRaw(store, status) {
369
773
  let predictionOperatorError;
370
774
  if (status?.config) {
371
775
  try {
372
- const raw = await getCachedPredictionOperatorStatus(status.config, status.configPath ?? '<default>', 'prediction');
776
+ const solverNetName = derivePredictionSolverNetName(status.config);
777
+ const raw = await getCachedPredictionOperatorStatus(status.config, status.configPath ?? '<default>', solverNetName);
373
778
  predictionOperator = narrowOperatorStatusForApi(raw);
374
779
  }
375
780
  catch (error) {
@@ -410,6 +815,9 @@ export async function gatherGatheredStatusRaw(store, status) {
410
815
  serviceBalances: {},
411
816
  pendingByService: {},
412
817
  claimedByService: store.getClaimedRewardsByService(),
818
+ tjinnTokenAddress: tjinnIdentity.tokenAddress,
819
+ tjinnChainId: tjinnIdentity.chainId,
820
+ tjinnDistributorAddress: status?.tjinnDistributorAddress,
413
821
  };
414
822
  if (!status) {
415
823
  return { ...baseRaw, hintsScope: 'sqlite_only' };
@@ -424,6 +832,11 @@ export async function gatherGatheredStatusRaw(store, status) {
424
832
  testnetMechDeploymentPath: status.testnetMechDeploymentPath,
425
833
  testnetStolasDeploymentPath: status.testnetStolasDeploymentPath,
426
834
  });
835
+ // Start the Sepolia tJINN read up front so it overlaps the Base-RPC fan-out
836
+ // below for free. `gatherTjinnStatus` is internally error-safe (it catches
837
+ // and returns a snapshot), so the promise never rejects — it is awaited at
838
+ // the point its result is assigned to `raw.tJinn`.
839
+ const tJinnPromise = gatherTjinnStatus(status.network === 'testnet' ? status.config?.ethereumRpcUrl : undefined, tjinnIdentity.tokenAddress, status.tjinnDistributorAddress, tjinnIdentity.chainId, fleet);
427
840
  const raw = {
428
841
  ...baseRaw,
429
842
  fleet,
@@ -503,6 +916,51 @@ export async function gatherGatheredStatusRaw(store, status) {
503
916
  else {
504
917
  raw.pendingRewardsError = pr.error;
505
918
  }
919
+ // Eviction state + inactivity — best-effort; never blocks the rest of status assembly.
920
+ try {
921
+ const evictedByServiceIndex = {};
922
+ const inactivityByServiceIndex = {};
923
+ await Promise.all(fleet.services.map(async (svc) => {
924
+ const serviceId = svc.service_id;
925
+ const stakingProxy = svc.staking_address;
926
+ if (!serviceId || !stakingProxy)
927
+ return;
928
+ const di = displayFleetServiceIndex(svc);
929
+ try {
930
+ const [state, info] = await Promise.all([
931
+ client.readContract({
932
+ address: stakingProxy,
933
+ abi: JINN_STAKING_ABI,
934
+ functionName: 'getStakingState',
935
+ args: [BigInt(serviceId)],
936
+ }),
937
+ client.readContract({
938
+ address: stakingProxy,
939
+ abi: JINN_STAKING_ABI,
940
+ functionName: 'getServiceInfo',
941
+ args: [BigInt(serviceId)],
942
+ }).catch(() => null),
943
+ ]);
944
+ // getStakingState returns uint8; 2 = Evicted enum value
945
+ evictedByServiceIndex[di] = Number(state) === 2;
946
+ // getServiceInfo returns a struct — inactivity is seconds of accumulated inactivity
947
+ if (info != null) {
948
+ const inactivity = info.inactivity;
949
+ if (typeof inactivity === 'bigint') {
950
+ inactivityByServiceIndex[di] = Number(inactivity);
951
+ }
952
+ }
953
+ }
954
+ catch {
955
+ // Transient RPC errors: skip silently; evicted defaults to false
956
+ }
957
+ }));
958
+ raw.evictedByServiceIndex = evictedByServiceIndex;
959
+ raw.inactivityByServiceIndex = inactivityByServiceIndex;
960
+ }
961
+ catch {
962
+ // Non-fatal: staking state reads should not prevent status from returning
963
+ }
506
964
  }
507
965
  if (fleet) {
508
966
  const per = {};
@@ -520,10 +978,27 @@ export async function gatherGatheredStatusRaw(store, status) {
520
978
  raw.serviceBalanceErrors = bal.errorsByDisplay;
521
979
  }
522
980
  }
981
+ // The tJINN read started up front (overlapping the Base-RPC fan-out). It is
982
+ // awaited here, as late as possible — after ALL other awaited Base-chain work
983
+ // — so the up-to-4s tJINN timeout never serializes the Base fan-out behind it.
984
+ // `gatherTjinnStatus` is internally error-safe, so a plain await is safe.
985
+ raw.tJinn = await tJinnPromise;
523
986
  return raw;
524
987
  }
525
988
  export async function gatherStatusForApi(store, status) {
526
989
  const raw = await gatherGatheredStatusRaw(store, status);
527
- return assembleStatusV1(raw);
990
+ const body = assembleStatusV1(raw);
991
+ const caps = status?.spendCaps;
992
+ if (caps && Object.keys(caps).length > 0) {
993
+ const now = new Date();
994
+ const resetsAt = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)).toISOString();
995
+ body.spend = {
996
+ credentials: Object.entries(caps).map(([credentialId, capUsd]) => {
997
+ const spentTodayUsd = store.spentTodayMicros(credentialId, now) / 1_000_000;
998
+ return { credentialId, capUsd, spentTodayUsd, paused: isOverSpendCap(spentTodayUsd, capUsd), resetsAt };
999
+ }),
1000
+ };
1001
+ }
1002
+ return body;
528
1003
  }
529
1004
  //# sourceMappingURL=gather-status.js.map