@fased/fased 0.1.62 → 0.1.64

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 (341) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +38 -30
  3. package/config/dependency-ownership.json +1 -1
  4. package/config/signer-policies/README.md +49 -0
  5. package/config/signer-policies/agent.json.template +32 -0
  6. package/config/signer-policies/mining.json.template +69 -0
  7. package/config/signer-policies/network.json.template +5 -0
  8. package/config/signer-policies/vault.json.template +70 -0
  9. package/config/signer-protocol-v2.json +76 -0
  10. package/config/typescript-noemit-baseline.json +680 -0
  11. package/dist/agents/auth-profiles/store.js +267 -31
  12. package/dist/agents/bash-tools.exec.js +10 -4
  13. package/dist/agents/current-model-catalog.js +3 -3
  14. package/dist/agents/memory-search.js +7 -1
  15. package/dist/agents/model-catalog-access.js +1 -2
  16. package/dist/agents/model-catalog-snapshot.js +1 -1
  17. package/dist/agents/model-catalog-source.js +1 -1
  18. package/dist/agents/model-metadata.js +1 -1
  19. package/dist/agents/model-selection.js +2 -28
  20. package/dist/agents/models-config.providers.js +6 -6
  21. package/dist/agents/pi-embedded-runner/compact.js +15 -7
  22. package/dist/agents/pi-embedded-runner/model.js +1 -1
  23. package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
  24. package/dist/agents/pi-embedded-runner/run.js +2 -0
  25. package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
  26. package/dist/agents/pi-tool-definition-adapter.js +16 -1
  27. package/dist/agents/pi-tools.js +2 -1
  28. package/dist/agents/sandbox/config.js +1 -1
  29. package/dist/agents/sandbox/context.js +27 -2
  30. package/dist/agents/skills/env-overrides.js +38 -28
  31. package/dist/agents/skills/trust.js +93 -0
  32. package/dist/agents/skills/workspace.js +128 -0
  33. package/dist/agents/skills-clawhub.js +36 -11
  34. package/dist/agents/skills-marketplace-scan.js +49 -0
  35. package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
  36. package/dist/agents/tools/mining-tool.js +1 -1
  37. package/dist/agents/tools/session-status-tool.js +1 -1
  38. package/dist/agents/tools/wallet-action-tool.js +172 -36
  39. package/dist/agents/tools/wallet-skill-policy.js +65 -23
  40. package/dist/agents/tools/wallet-tool.js +7 -11
  41. package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
  42. package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
  43. package/dist/auto-reply/reply/directive-handling.model.js +2 -1
  44. package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
  45. package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
  46. package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
  47. package/dist/auto-reply/reply/model-selection.js +7 -4
  48. package/dist/auto-reply/reply/session-reset-model.js +4 -4
  49. package/dist/brand.js +1 -1
  50. package/dist/build-info.json +3 -3
  51. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  52. package/dist/channel-web.js +2 -2
  53. package/dist/cli/gateway-cli/run.js +8 -0
  54. package/dist/cli/program/command-registry.js +1 -1
  55. package/dist/cli/program/register.onboard.js +2 -3
  56. package/dist/cli/program/register.wallet.js +16 -123
  57. package/dist/cli/providers-cli.js +1 -1
  58. package/dist/cli/sat-cli.js +129 -2
  59. package/dist/cli/update-cli/update-command.js +260 -11
  60. package/dist/commands/auth-choice.apply.api-providers.js +3 -3
  61. package/dist/commands/doctor-config-flow.js +1 -1
  62. package/dist/commands/doctor-legacy-config.js +2 -13
  63. package/dist/commands/model-picker.js +6 -6
  64. package/dist/commands/models/auth.js +1 -1
  65. package/dist/commands/onboard-auth.config-gateways.js +1 -1
  66. package/dist/commands/onboard-auth.credentials.js +32 -8
  67. package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
  68. package/dist/commands/onboard-non-interactive/local.js +5 -1
  69. package/dist/commands/wallet.js +568 -1911
  70. package/dist/config/config.js +2 -2
  71. package/dist/config/io.js +64 -2
  72. package/dist/config/schema.help.js +8 -7
  73. package/dist/config/schema.labels.js +5 -4
  74. package/dist/config/zod-schema.agent-runtime.js +1 -0
  75. package/dist/config/zod-schema.js +5 -0
  76. package/dist/control-ui/assets/{app-DLil9VO1.js → app-bR-fO5ty.js} +1511 -1555
  77. package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
  78. package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
  79. package/dist/control-ui/assets/{index-DdE_NIXo.js → index-ckCxHwjy.js} +3 -3
  80. package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
  81. package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
  82. package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
  83. package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
  84. package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/control-ui/version.json +1 -1
  87. package/dist/daemon/systemd-system.js +56 -50
  88. package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
  89. package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
  90. package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
  91. package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
  92. package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
  93. package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
  94. package/dist/federation/auto-connect.js +98 -8
  95. package/dist/federation/marketplace-capability-adapter.js +33 -7
  96. package/dist/federation/marketplace-delivery-outbox.js +196 -0
  97. package/dist/federation/marketplace-delivery.js +351 -215
  98. package/dist/federation/marketplace-direct-payment.js +272 -141
  99. package/dist/federation/marketplace-escrow.js +607 -249
  100. package/dist/federation/marketplace-settlement-ledger.js +352 -0
  101. package/dist/federation/offers.js +9 -7
  102. package/dist/federation/peer-auth-v2.js +529 -0
  103. package/dist/gateway/a2a-http.js +425 -96
  104. package/dist/gateway/a2a-settlement.js +259 -153
  105. package/dist/gateway/a2a-task-store.js +524 -0
  106. package/dist/gateway/auth.js +38 -2
  107. package/dist/gateway/config-reload.js +46 -33
  108. package/dist/gateway/durable-capacity.js +31 -0
  109. package/dist/gateway/federation-http.js +540 -135
  110. package/dist/gateway/federation-marketplace-run-store.js +397 -0
  111. package/dist/gateway/federation-marketplace.js +535 -230
  112. package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
  113. package/dist/gateway/security-path.js +1 -1
  114. package/dist/gateway/server-http.js +1084 -1205
  115. package/dist/gateway/server-methods/models.js +1 -1
  116. package/dist/gateway/server-methods/secrets.js +40 -0
  117. package/dist/gateway/server-methods.js +1 -2
  118. package/dist/gateway/server-reload-handlers.js +196 -66
  119. package/dist/gateway/server-runtime-config.js +1 -1
  120. package/dist/gateway/server-secrets-runtime.js +288 -0
  121. package/dist/gateway/server.impl.js +73 -42
  122. package/dist/gateway/sessions-patch.js +3 -5
  123. package/dist/index.js +4 -2
  124. package/dist/infra/fasedhub.js +64 -1
  125. package/dist/infra/local-source-paired-update.js +538 -0
  126. package/dist/infra/restart.js +41 -10
  127. package/dist/infra/update-runner.js +96 -0
  128. package/dist/light-update-status.js +11 -11
  129. package/dist/memory/backend-config.js +2 -1
  130. package/dist/memory/session-files.js +16 -2
  131. package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
  132. package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
  133. package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
  134. package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-BYxAt775.js} +27 -27
  135. package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
  136. package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
  137. package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
  138. package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
  139. package/dist/plugin-sdk/channel-plugin-common.js +4 -4
  140. package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
  141. package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DIRHG2gJ.js} +1 -1
  142. package/dist/plugin-sdk/command-status.d.ts +2 -2
  143. package/dist/plugin-sdk/command-status.js +27 -27
  144. package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
  145. package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
  146. package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
  147. package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-BOT7kHb6.js} +6779 -3696
  148. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  149. package/dist/plugin-sdk/discord.d.ts +6 -6
  150. package/dist/plugin-sdk/discord.js +19 -19
  151. package/dist/plugin-sdk/file-lock.js +35 -4
  152. package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
  153. package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
  154. package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
  155. package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
  156. package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
  157. package/dist/plugin-sdk/index.d.ts +21 -39
  158. package/dist/plugin-sdk/index.js +29 -29
  159. package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
  160. package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
  161. package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
  162. package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
  163. package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
  164. package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
  165. package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-BCFDaqJ-.js} +31 -31
  166. package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
  167. package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.js} +27 -27
  168. package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
  169. package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
  170. package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
  171. package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
  172. package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
  173. package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
  174. package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
  175. package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
  176. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
  177. package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
  178. package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
  179. package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
  180. package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
  181. package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
  182. package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
  183. package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
  184. package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
  185. package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
  186. package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
  187. package/dist/plugin-sdk/sat-runtime.js +29 -29
  188. package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
  189. package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
  190. package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
  191. package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
  192. package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
  193. package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
  194. package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
  195. package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BUTt8cxK.js} +39 -39
  196. package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
  197. package/dist/plugin-sdk/slack.d.ts +6 -6
  198. package/dist/plugin-sdk/slack.js +9 -9
  199. package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-D0wHVqjt.js} +3 -3
  200. package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
  201. package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
  202. package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-CC_qN4v0.js} +30 -30
  203. package/dist/plugin-sdk/telegram.d.ts +6 -6
  204. package/dist/plugin-sdk/telegram.js +8 -8
  205. package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
  206. package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
  207. package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
  208. package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
  209. package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
  210. package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -2
  211. package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
  212. package/dist/plugin-sdk/{web-CInY-lCv.js → web-BXsJ1vqe.js} +32 -32
  213. package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
  214. package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
  215. package/dist/plugin-sdk/whatsapp.d.ts +13 -13
  216. package/dist/plugin-sdk/whatsapp.js +12 -12
  217. package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
  218. package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
  219. package/dist/providers/refresh.js +1 -1
  220. package/dist/providers/registry.js +1 -1
  221. package/dist/secrets/apply.js +1 -1
  222. package/dist/secrets/runtime.js +1 -1
  223. package/dist/wallet/external-submission-ledger.js +376 -0
  224. package/dist/wallet/legacy-embedded-keystore.js +40 -0
  225. package/dist/wallet/local-socket-signer-archive.js +30 -0
  226. package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
  227. package/dist/wallet/local-socket-signer-policy.js +166 -0
  228. package/dist/wallet/local-socket-signer-protocol.js +561 -118
  229. package/dist/wallet/native-signer-wallet-id.js +25 -0
  230. package/dist/wallet/providers/alchemy-adapter.js +3 -0
  231. package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
  232. package/dist/wallet/providers/turnkey-adapter.js +292 -34
  233. package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
  234. package/dist/wallet/signer-network-admin.js +184 -0
  235. package/dist/wallet/signer-protocol-v2.generated.js +90 -0
  236. package/dist/wallet/solana-bond-signing.js +157 -69
  237. package/dist/wallet/solana-reviewed-transaction.js +375 -0
  238. package/dist/wallet/solana-swap.js +520 -64
  239. package/dist/wallet/solana-transaction-inspection.js +106 -4
  240. package/dist/wallet/solana-trigger.js +658 -320
  241. package/dist/wallet/turnkey-reviewed-state.js +370 -0
  242. package/dist/wallet/wallet-approval-auth.js +17 -28
  243. package/dist/wallet/wallet-atomic-state.js +53 -0
  244. package/dist/wallet/wallet-canary.js +0 -1
  245. package/dist/wallet/wallet-inbound-events.js +16 -11
  246. package/dist/wallet/wallet-policy-simulation.js +1 -1
  247. package/dist/wallet/wallet-policy.js +90 -36
  248. package/dist/wallet/wallet-provider-capabilities.js +28 -4
  249. package/dist/wallet/wallet-provider-registry.js +57 -44
  250. package/dist/wallet/wallet-provider-resolver.js +62 -63
  251. package/dist/wallet/wallet-runtime-config.js +28 -41
  252. package/dist/wallet/wallet-secrets-store.js +22 -0
  253. package/dist/wallet/wallet-send-approvals.js +1891 -589
  254. package/dist/wallet/wallet-send-execution-ledger.js +292 -0
  255. package/dist/wallet/wallet-settlement-links.js +14 -13
  256. package/dist/wallet/wallet-standard-review.js +353 -0
  257. package/dist/wallet/wallet-status.js +0 -9
  258. package/dist/wallet/wallet-task-ledger.js +16 -2
  259. package/dist/web/auto-reply/heartbeat-runner.js +1 -1
  260. package/dist/web/auto-reply/monitor.js +2 -2
  261. package/dist/wizard/host-security-capability.js +14 -23
  262. package/dist/wizard/onboarding.finalize.js +63 -184
  263. package/dist/wizard/onboarding.host-security.js +117 -1367
  264. package/dist/wizard/onboarding.js +172 -217
  265. package/dist/wizard/onboarding.wallet.js +232 -785
  266. package/extensions/acpx/package.json +1 -1
  267. package/extensions/bluebubbles/package.json +1 -1
  268. package/extensions/copilot-proxy/package.json +1 -1
  269. package/extensions/diagnostics-otel/package.json +1 -1
  270. package/extensions/fased-federation/package.json +1 -1
  271. package/extensions/google-gemini-cli-auth/package.json +1 -1
  272. package/extensions/imessage/package.json +1 -1
  273. package/extensions/irc/package.json +1 -1
  274. package/extensions/line/package.json +1 -1
  275. package/extensions/llm-task/package.json +1 -1
  276. package/extensions/lobster/package.json +1 -1
  277. package/extensions/matrix/CHANGELOG.md +12 -0
  278. package/extensions/matrix/package.json +1 -1
  279. package/extensions/mattermost/package.json +1 -1
  280. package/extensions/memory-core/package.json +2 -2
  281. package/extensions/memory-lancedb/package.json +1 -1
  282. package/extensions/minimax-portal-auth/package.json +1 -1
  283. package/extensions/msteams/CHANGELOG.md +12 -0
  284. package/extensions/msteams/package.json +1 -1
  285. package/extensions/nextcloud-talk/package.json +1 -1
  286. package/extensions/nostr/CHANGELOG.md +12 -0
  287. package/extensions/nostr/package.json +1 -1
  288. package/extensions/open-prose/package.json +1 -1
  289. package/extensions/sat-mining/index.ts +498 -153
  290. package/extensions/sat-mining/package.json +1 -1
  291. package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
  292. package/extensions/sat-mining/src/audit-store.ts +50 -5
  293. package/extensions/sat-mining/src/claim-service.ts +85 -14
  294. package/extensions/sat-mining/src/config.ts +9 -0
  295. package/extensions/sat-mining/src/cycle-progress.ts +16 -8
  296. package/extensions/sat-mining/src/epoch-service.ts +9 -5
  297. package/extensions/sat-mining/src/gateway-runner.ts +21 -1
  298. package/extensions/sat-mining/src/protocol-contract.ts +45 -1
  299. package/extensions/sat-mining/src/recovery-service.ts +312 -0
  300. package/extensions/sat-mining/src/round-watcher.ts +391 -81
  301. package/extensions/sat-mining/src/rpc-read.ts +330 -89
  302. package/extensions/sat-mining/src/runtime.ts +14 -0
  303. package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
  304. package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
  305. package/extensions/sat-mining/src/solana-submit.ts +1199 -428
  306. package/extensions/sat-mining/src/submission-ledger.ts +433 -0
  307. package/extensions/signal/package.json +1 -1
  308. package/extensions/synology-chat/package.json +1 -1
  309. package/extensions/tlon/package.json +1 -1
  310. package/extensions/twitch/CHANGELOG.md +12 -0
  311. package/extensions/twitch/package.json +1 -1
  312. package/extensions/voice-call/CHANGELOG.md +12 -0
  313. package/extensions/voice-call/package.json +1 -1
  314. package/extensions/zalo/CHANGELOG.md +12 -0
  315. package/extensions/zalo/package.json +1 -1
  316. package/extensions/zalouser/CHANGELOG.md +12 -0
  317. package/extensions/zalouser/package.json +1 -1
  318. package/install.sh +4955 -0
  319. package/package.json +23 -5
  320. package/scripts/fased-host-updater.mjs +1421 -0
  321. package/scripts/fased-host-updaterctl.mjs +186 -0
  322. package/scripts/fased-managed-service.sh +36 -0
  323. package/scripts/fased-managed-updater.mjs +3065 -156
  324. package/scripts/fased-signer-enroll-hosting.sh +275 -0
  325. package/scripts/fased-signer-network-hosting.sh +143 -0
  326. package/scripts/fased-signer-owner-policy.mjs +1430 -0
  327. package/scripts/fased-signer-policy-hosting.sh +50 -0
  328. package/scripts/fased-signer-policy-local.sh +26 -0
  329. package/scripts/hosted-release-manifest.mjs +185 -0
  330. package/scripts/install-fased-signerd.sh +183 -108
  331. package/scripts/install-managed-runtime.mjs +212 -10
  332. package/scripts/managed-runtime-layout.mjs +75 -3
  333. package/scripts/migrate-hosted-signer-v2.mjs +58 -0
  334. package/scripts/start-managed.sh +169 -360
  335. package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
  336. package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
  337. package/dist/wallet/local-socket-signer-broker.js +0 -224
  338. package/dist/wallet/local-socket-signer-custody.js +0 -42
  339. package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
  340. package/dist/wallet/providers/privy-adapter.js +0 -80
  341. package/dist/wallet/wallet-custody.js +0 -1836
@@ -90,13 +90,16 @@ import {
90
90
  plannerPolicyVersion,
91
91
  scorePlannerOutcome,
92
92
  } from "./src/planner-policy.js";
93
+ import { SAT_PROTOCOL_CONSTANTS } from "./src/protocol-contract.js";
93
94
  import { createSatRecoveryService } from "./src/recovery-service.js";
94
95
  import { readSatValidatorArtifact, recomputeSatValidatorArtifact } from "./src/replay.js";
95
96
  import { createSatRoundWatcherService } from "./src/round-watcher.js";
96
97
  import {
97
98
  invalidateSatReadCaches,
99
+ inspectSatCycle,
98
100
  inspectSatEpoch,
99
101
  inspectSatClaimReceipt,
102
+ inspectSatBondStakingDistributor,
100
103
  inspectCurrentSatRoundBucket,
101
104
  inspectSatMinerCapitalAccountStatus,
102
105
  inspectSatMinerCycleByAddress,
@@ -133,36 +136,44 @@ import {
133
136
  withSatServiceReadTimeout,
134
137
  } from "./src/service-read-timeout.js";
135
138
  import {
136
- submitSatBootstrap,
137
139
  submitSatClaimProtocolDistributorSat,
138
140
  submitSatClaimProtocolTreasury,
141
+ submitSatClaimUnallocatedStakingRewards,
139
142
  submitSatClaimCycleRewards,
140
143
  submitSatClaimCycleRewardsBatch,
144
+ submitSatAbortEmptyCycle,
141
145
  submitSatCompactPendingCycleRange,
142
146
  submitSatCloseResolvedCycleArtifacts,
143
147
  submitSatCloseResolvedCleanupBatch,
144
148
  submitSatCloseResolvedCycleRegistryPage,
145
149
  submitSatCloseResolvedMinerCycleState,
146
- submitSatCycle,
150
+ submitSatCloseCommitPhase,
151
+ submitSatCommitCycle,
147
152
  submitSatDepositMinerCapital,
148
153
  submitSatFinalizeCycleSettlement,
149
154
  submitSatInitMinerCapital,
150
155
  submitSatOpenCycle,
151
156
  submitSatOpenDispute,
157
+ submitSatReleaseUnrevealedCommit,
152
158
  submitSatRepublishEpochRoots,
159
+ submitSatRevealCycle,
153
160
  submitSatRefillRegistryReserveFromTreasury,
154
161
  submitSatScoreCyclePage,
155
162
  submitSatSetActiveCommit,
156
- submitSatSetProtocolRecipients,
163
+ submitSatSealCycleEntropy,
164
+ submitSatTopUpRegistryReserve,
157
165
  submitSatRetargetUnlock,
158
166
  submitSatResolveDispute,
159
167
  submitSatDistributeCyclePage,
160
168
  submitSatSettleCyclePage,
169
+ submitSatSyncBondStakingRewards,
161
170
  submitSatWithdrawMinerCapital,
162
171
  resolveSatValidatorAuthority,
163
172
  submitSatValidatorAttestation,
173
+ runWithSatSubmissionWorkflow,
164
174
  } from "./src/solana-submit.js";
165
175
  import { computeMiningStrategy } from "./src/strategy-engine.js";
176
+ import { digestSatSubmissionIntent } from "./src/submission-ledger.js";
166
177
  import {
167
178
  buildSatValidatorArtifact,
168
179
  findSatValidatorArtifact,
@@ -492,8 +503,7 @@ function resolveWalletSolanaRpcUrl(env: NodeJS.ProcessEnv, walletId?: string): s
492
503
  const perWalletKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix}` : "";
493
504
  const value =
494
505
  (perWalletKey ? String(env[perWalletKey] ?? "").trim() : "") ||
495
- String(env.FASED_WALLET_SOLANA_RPC_URL ?? "").trim() ||
496
- String(env.FASED_WALLET_EMBEDDED_KEYSTORE_RPC_URL ?? "").trim();
506
+ String(env.FASED_WALLET_SOLANA_RPC_URL ?? "").trim();
497
507
  return value || undefined;
498
508
  }
499
509
 
@@ -1200,9 +1210,9 @@ const satMiningPlugin = {
1200
1210
  disputes:
1201
1211
  "usage: /satdisputesonchain <validator-authority> <epoch-id> <round-id> [reasonCode=..] [requireNonzeroSlashPenalty=true] [sortBy=targetAuthority|reasonCode|slashPenaltyOwed|openedAt] [sortOrder=asc|desc]",
1202
1212
  resolve:
1203
- "usage: /satresolvedispute <dispute-authority> <target-authority> <epoch-id> <round-id> <dismissed|upheld>",
1213
+ "usage: /satresolvedispute <dispute-authority> <target-authority> <epoch-id> <round-id> <dismissed|upheld> [idempotencyKey=<key>]",
1204
1214
  republish:
1205
- "usage: /satrepublishroots <epoch-id> <bucket-root> <score-root> <coordination-root> # returns preflight rejection reasons instead of submitting when invalid",
1215
+ "usage: /satrepublishroots <epoch-id> <bucket-root> <score-root> <coordination-root> [idempotencyKey=<key>] # returns preflight rejection reasons instead of submitting when invalid",
1206
1216
  recovery: "usage: /satrecoverysummary <validator-authority> <epoch-id> <round-id>",
1207
1217
  };
1208
1218
  const satUsageWithCheatsheet = (usage: string) =>
@@ -1435,11 +1445,14 @@ const satMiningPlugin = {
1435
1445
  description: "Resolve a SAT dispute as dismissed or upheld.",
1436
1446
  acceptsArgs: true,
1437
1447
  handler: async (ctx) => {
1438
- const [disputeAuthority, targetAuthority, epochRaw, microRoundRaw, statusRaw] = (
1439
- ctx.args ?? ""
1440
- )
1441
- .split(/\s+/)
1442
- .filter(Boolean);
1448
+ const [
1449
+ disputeAuthority,
1450
+ targetAuthority,
1451
+ epochRaw,
1452
+ microRoundRaw,
1453
+ statusRaw,
1454
+ ...optionParts
1455
+ ] = (ctx.args ?? "").split(/\s+/).filter(Boolean);
1443
1456
  if (!disputeAuthority || !targetAuthority || !epochRaw || !microRoundRaw || !statusRaw) {
1444
1457
  return { text: satUsageWithCheatsheet(satUsageText.resolve) };
1445
1458
  }
@@ -1449,6 +1462,13 @@ const satMiningPlugin = {
1449
1462
  if (!Number.isFinite(statusFlag)) {
1450
1463
  return { text: satUsageWithCheatsheet(satUsageText.resolve) };
1451
1464
  }
1465
+ const idempotencyMatch =
1466
+ optionParts.length === 1
1467
+ ? optionParts[0]?.match(/^idempotency(?:Key|-key)=(.+)$/u)
1468
+ : null;
1469
+ if (optionParts.length > 0 && !idempotencyMatch) {
1470
+ return { text: satUsageWithCheatsheet(satUsageText.resolve) };
1471
+ }
1452
1472
  const request = state.client.buildResolveDisputeRequest({
1453
1473
  disputeAuthority,
1454
1474
  targetAuthority,
@@ -1456,7 +1476,10 @@ const satMiningPlugin = {
1456
1476
  microRoundId: Number(microRoundRaw),
1457
1477
  statusFlag,
1458
1478
  });
1459
- const submitted = await submitSatResolveDispute(state.activeConfig, request.params);
1479
+ const submitted = await runWithSatSubmissionWorkflow(
1480
+ `command:satresolvedispute:${idempotencyMatch?.[1] ?? digestSatSubmissionIntent(request.params)}`,
1481
+ async () => await submitSatResolveDispute(state.activeConfig, request.params),
1482
+ );
1460
1483
  return { text: JSON.stringify({ request, submitted }, null, 2) };
1461
1484
  },
1462
1485
  });
@@ -1465,12 +1488,19 @@ const satMiningPlugin = {
1465
1488
  description: "Republish corrected SAT epoch roots after upheld dispute review.",
1466
1489
  acceptsArgs: true,
1467
1490
  handler: async (ctx) => {
1468
- const [epochRaw, bucketRoot, scoreRoot, coordinationRoot] = (ctx.args ?? "")
1491
+ const [epochRaw, bucketRoot, scoreRoot, coordinationRoot, ...optionParts] = (ctx.args ?? "")
1469
1492
  .split(/\s+/)
1470
1493
  .filter(Boolean);
1471
1494
  if (!epochRaw || !bucketRoot || !scoreRoot || !coordinationRoot) {
1472
1495
  return { text: satUsageWithCheatsheet(satUsageText.republish) };
1473
1496
  }
1497
+ const idempotencyMatch =
1498
+ optionParts.length === 1
1499
+ ? optionParts[0]?.match(/^idempotency(?:Key|-key)=(.+)$/u)
1500
+ : null;
1501
+ if (optionParts.length > 0 && !idempotencyMatch) {
1502
+ return { text: satUsageWithCheatsheet(satUsageText.republish) };
1503
+ }
1474
1504
  const request = state.client.buildRepublishEpochRootsRequest({
1475
1505
  epochId: Number(epochRaw),
1476
1506
  bucketRoot,
@@ -1484,7 +1514,10 @@ const satMiningPlugin = {
1484
1514
  if (!preflight.canRepublish) {
1485
1515
  return { text: JSON.stringify({ request, preflight }, null, 2) };
1486
1516
  }
1487
- const submitted = await submitSatRepublishEpochRoots(state.activeConfig, request.params);
1517
+ const submitted = await runWithSatSubmissionWorkflow(
1518
+ `command:satrepublishroots:${idempotencyMatch?.[1] ?? digestSatSubmissionIntent(request.params)}`,
1519
+ async () => await submitSatRepublishEpochRoots(state.activeConfig, request.params),
1520
+ );
1488
1521
  return { text: JSON.stringify({ request, preflight, submitted }, null, 2) };
1489
1522
  },
1490
1523
  });
@@ -1905,7 +1938,10 @@ const satMiningPlugin = {
1905
1938
  parameters: SatResolveDisputeToolSchema,
1906
1939
  async execute(_toolCallId, params) {
1907
1940
  const request = state.client.buildResolveDisputeRequest(params);
1908
- const submitted = await submitSatResolveDispute(state.activeConfig, request.params);
1941
+ const submitted = await runWithSatSubmissionWorkflow(
1942
+ `tool:sat_resolve_dispute:${_toolCallId}`,
1943
+ async () => await submitSatResolveDispute(state.activeConfig, request.params),
1944
+ );
1909
1945
  return {
1910
1946
  content: [
1911
1947
  { type: "text" as const, text: JSON.stringify({ request, submitted }, null, 2) },
@@ -1933,7 +1969,10 @@ const satMiningPlugin = {
1933
1969
  details: { request, preflight },
1934
1970
  };
1935
1971
  }
1936
- const submitted = await submitSatRepublishEpochRoots(state.activeConfig, request.params);
1972
+ const submitted = await runWithSatSubmissionWorkflow(
1973
+ `tool:sat_republish_epoch_roots:${_toolCallId}`,
1974
+ async () => await submitSatRepublishEpochRoots(state.activeConfig, request.params),
1975
+ );
1937
1976
  return {
1938
1977
  content: [
1939
1978
  {
@@ -1952,7 +1991,10 @@ const satMiningPlugin = {
1952
1991
  parameters: SatValidatorToolSchema,
1953
1992
  async execute(_toolCallId, params) {
1954
1993
  const request = state.client.buildSubmitValidatorAttestationRequest(params);
1955
- const submitted = await submitSatValidatorAttestation(state.activeConfig, request.params);
1994
+ const submitted = await runWithSatSubmissionWorkflow(
1995
+ `tool:sat_submit_validator_attestation:${_toolCallId}`,
1996
+ async () => await submitSatValidatorAttestation(state.activeConfig, request.params),
1997
+ );
1956
1998
  const response = await buildValidatorSubmissionSummary({
1957
1999
  epochId: request.params.epochId,
1958
2000
  microRoundId: request.params.microRoundId,
@@ -1973,7 +2015,10 @@ const satMiningPlugin = {
1973
2015
  parameters: SatDisputeToolSchema,
1974
2016
  async execute(_toolCallId, params) {
1975
2017
  const request = state.client.buildOpenDisputeRequest(params);
1976
- const submitted = await submitSatOpenDispute(state.activeConfig, request.params);
2018
+ const submitted = await runWithSatSubmissionWorkflow(
2019
+ `tool:sat_open_dispute:${_toolCallId}`,
2020
+ async () => await submitSatOpenDispute(state.activeConfig, request.params),
2021
+ );
1977
2022
  const response = await buildValidatorSubmissionSummary({
1978
2023
  epochId: request.params.epochId,
1979
2024
  microRoundId: request.params.microRoundId,
@@ -2037,7 +2082,7 @@ const satMiningPlugin = {
2037
2082
  "depositMinerCapital",
2038
2083
  "withdrawMinerCapital",
2039
2084
  "setActiveCommit",
2040
- "bootstrapRegistryReserve",
2085
+ "topUpRegistryReserve",
2041
2086
  "openCycle",
2042
2087
  "submitCycle",
2043
2088
  "claimCycleRewards",
@@ -2051,6 +2096,7 @@ const satMiningPlugin = {
2051
2096
  const isInternalSatMaintenanceAction = (action: string | null | undefined) =>
2052
2097
  new Set([
2053
2098
  "bootstrapRegistryReserve",
2099
+ "topUpRegistryReserve",
2054
2100
  "openCycle",
2055
2101
  "setActiveCommit",
2056
2102
  "closeResolvedMinerCycleState",
@@ -2928,6 +2974,7 @@ const satMiningPlugin = {
2928
2974
  cycleId?: number | null;
2929
2975
  txHash: string | null;
2930
2976
  status: "success" | "failure";
2977
+ complete?: boolean;
2931
2978
  message?: string | null;
2932
2979
  }) => {
2933
2980
  mergeRecentActionTail([
@@ -2986,6 +3033,34 @@ const satMiningPlugin = {
2986
3033
  );
2987
3034
  void persistRecentActions();
2988
3035
  };
3036
+ const markClaimActionResult = (params: {
3037
+ action: "claimCycleRewards" | "claimCycleRewardsBatch";
3038
+ txHash: string | null | undefined;
3039
+ cycleIds: readonly number[];
3040
+ resolvedCycleIds: readonly number[];
3041
+ }) => {
3042
+ invalidateMiningReadCaches();
3043
+ state.lastAction = params.action;
3044
+ state.lastActionTxHash = params.txHash ?? null;
3045
+ state.lastFailure = null;
3046
+ const resolved = new Set(params.resolvedCycleIds);
3047
+ const actionAt = new Date().toISOString();
3048
+ mergeRecentActionTail(
3049
+ [...new Set(params.cycleIds)]
3050
+ .filter((cycleId) => Number.isFinite(cycleId) && cycleId >= 0)
3051
+ .map((cycleId) => ({
3052
+ action: params.action,
3053
+ cycleId,
3054
+ txHash: params.txHash ?? null,
3055
+ status: "success" as const,
3056
+ complete: resolved.has(cycleId),
3057
+ message: resolved.has(cycleId)
3058
+ ? "Cycle rewards fully claimed."
3059
+ : "Bounded SAT claim chunk submitted; rewards remain claimable.",
3060
+ at: actionAt,
3061
+ })),
3062
+ );
3063
+ };
2989
3064
  const markActionFailure = (action: string, error: unknown, cycleId?: number | null) => {
2990
3065
  const message = sanitizeMiningActionMessage(error);
2991
3066
  state.lastAction = action;
@@ -3121,19 +3196,61 @@ const satMiningPlugin = {
3121
3196
  const claimableRebate =
3122
3197
  BigInt(minerCycle.claimableDetRebateLamports ?? "0") +
3123
3198
  BigInt(minerCycle.claimablePerfRebateLamports ?? "0");
3124
- const claimedSat = BigInt(minerCycle.claimedSatRaw ?? "0");
3125
- const claimedRebate =
3126
- BigInt(minerCycle.claimedDetRebateLamports ?? "0") +
3127
- BigInt(minerCycle.claimedPerfRebateLamports ?? "0");
3128
- if (
3129
- minerCycle.capitalLockReleased &&
3130
- (claimedSat > 0n || claimedRebate > 0n || (claimableSat === 0n && claimableRebate === 0n))
3131
- ) {
3199
+ if (minerCycle.capitalLockReleased && claimableSat === 0n && claimableRebate === 0n) {
3132
3200
  resolved.push(cycleId);
3133
3201
  }
3134
3202
  }
3135
3203
  return resolved;
3136
3204
  };
3205
+ const resolveClaimCompletion = async (cycleIds: readonly number[]) => {
3206
+ const authority = state.activeWalletAddress;
3207
+ if (!authority) {
3208
+ throw new Error("Mining wallet authority is unavailable after claim confirmation.");
3209
+ }
3210
+ invalidateMiningReadCaches();
3211
+ const resolvedCycleIds: number[] = [];
3212
+ const pendingCycleIds: number[] = [];
3213
+ for (const cycleId of [...new Set(cycleIds)]) {
3214
+ const minerCycle = await satOps
3215
+ .inspectSatMinerCycle(state.activeConfig, { authority, cycleId })
3216
+ .catch(() => null);
3217
+ const claimableSat = BigInt(minerCycle?.claimableSatRaw ?? "0");
3218
+ const claimableRebate =
3219
+ BigInt(minerCycle?.claimableDetRebateLamports ?? "0") +
3220
+ BigInt(minerCycle?.claimablePerfRebateLamports ?? "0");
3221
+ if (
3222
+ minerCycle?.capitalLockReleased === true &&
3223
+ claimableSat === 0n &&
3224
+ claimableRebate === 0n
3225
+ ) {
3226
+ resolvedCycleIds.push(cycleId);
3227
+ } else {
3228
+ pendingCycleIds.push(cycleId);
3229
+ }
3230
+ }
3231
+ return { resolvedCycleIds, pendingCycleIds };
3232
+ };
3233
+ const applyClaimCompletion = (params: {
3234
+ action: "claimCycleRewards" | "claimCycleRewardsBatch";
3235
+ txHash: string | null | undefined;
3236
+ cycleIds: readonly number[];
3237
+ resolvedCycleIds: readonly number[];
3238
+ pendingCycleIds: readonly number[];
3239
+ }) => {
3240
+ for (const cycleId of params.resolvedCycleIds) {
3241
+ getOrCreateRoundExecutionState(state, cycleId, 0).claimSubmitted = true;
3242
+ }
3243
+ for (const cycleId of params.pendingCycleIds) {
3244
+ getOrCreateRoundExecutionState(state, cycleId, 0).claimSubmitted = false;
3245
+ }
3246
+ markSatClaimBacklogClaimed(state, params.resolvedCycleIds, params.txHash);
3247
+ markSatClaimBacklogReady(
3248
+ state,
3249
+ params.pendingCycleIds,
3250
+ "bounded SAT claim chunk submitted; rewards remain claimable",
3251
+ );
3252
+ markClaimActionResult(params);
3253
+ };
3137
3254
  const capturePendingPlannerCycle = async (cycleId: number): Promise<void> => {
3138
3255
  const plannerSnapshot =
3139
3256
  state.lastPlannerDecision?.cycleId === cycleId ? state.lastPlannerDecision.snapshot : null;
@@ -3234,7 +3351,10 @@ const satMiningPlugin = {
3234
3351
  }
3235
3352
  }
3236
3353
  for (const execution of state.roundExecution.values()) {
3237
- if (execution.participationSubmitted && !execution.claimSubmitted) {
3354
+ if (
3355
+ (execution.commitSubmitted || execution.participationSubmitted) &&
3356
+ !execution.claimSubmitted
3357
+ ) {
3238
3358
  return true;
3239
3359
  }
3240
3360
  }
@@ -3242,7 +3362,12 @@ const satMiningPlugin = {
3242
3362
  if (entry.status !== "success" || typeof entry.cycleId !== "number" || entry.cycleId <= 0) {
3243
3363
  return false;
3244
3364
  }
3245
- if (entry.action !== "openCycle" && entry.action !== "submitCycle") {
3365
+ if (
3366
+ entry.action !== "openCycle" &&
3367
+ entry.action !== "submitCycle" &&
3368
+ entry.action !== "commitCycle" &&
3369
+ entry.action !== "revealCycle"
3370
+ ) {
3246
3371
  return false;
3247
3372
  }
3248
3373
  return !hasSuccessfulClaimOrCloseRecentAction(entry.cycleId);
@@ -3288,6 +3413,7 @@ const satMiningPlugin = {
3288
3413
  strategyExecution:
3289
3414
  state.activeConfig.strategyExecution ??
3290
3415
  strategyModeToExecution(state.activeConfig.strategyMode),
3416
+ cycleCadence: state.activeConfig.cycleCadence ?? 1,
3291
3417
  claimMode: "auto",
3292
3418
  payout: state.activeConfig.payout ?? true,
3293
3419
  strategyMode: state.activeConfig.strategyMode ?? "base",
@@ -3392,6 +3518,10 @@ const satMiningPlugin = {
3392
3518
  state.activeConfig.strategyExecution = strategyModeToExecution(
3393
3519
  state.activeConfig.strategyMode,
3394
3520
  );
3521
+ state.activeConfig.cycleCadence =
3522
+ profile.cycleCadence === 2 || profile.cycleCadence === 6 || profile.cycleCadence === 12
3523
+ ? profile.cycleCadence
3524
+ : 1;
3395
3525
  state.activeConfig.claimMode = "auto";
3396
3526
  state.activeConfig.payout =
3397
3527
  typeof profile.payout === "boolean" ? profile.payout : state.activeConfig.payout;
@@ -3641,8 +3771,7 @@ const satMiningPlugin = {
3641
3771
  const perWalletKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix.toUpperCase()}` : "";
3642
3772
  return Boolean(
3643
3773
  (perWalletKey ? String(effectiveEnv[perWalletKey] ?? "").trim() : "") ||
3644
- String(effectiveEnv.FASED_WALLET_SOLANA_RPC_URL ?? "").trim() ||
3645
- String(effectiveEnv.FASED_WALLET_EMBEDDED_KEYSTORE_RPC_URL ?? "").trim(),
3774
+ String(effectiveEnv.FASED_WALLET_SOLANA_RPC_URL ?? "").trim(),
3646
3775
  );
3647
3776
  };
3648
3777
  const normalizeAddressValue = (value?: string) => {
@@ -4182,7 +4311,7 @@ const satMiningPlugin = {
4182
4311
  remediation:
4183
4312
  wallet?.signerCapability === "background-ready"
4184
4313
  ? undefined
4185
- : "Use the built-in local signer or embedded keystore for unattended mining automation.",
4314
+ : "Use the local native signer for unattended Mining. Wallet Standard and Turnkey are reviewed/manual wallet paths, not background Mining signers.",
4186
4315
  },
4187
4316
  {
4188
4317
  key: "rpcReady",
@@ -4235,13 +4364,13 @@ const satMiningPlugin = {
4235
4364
  ? "SAT miner capital account has an invalid owner"
4236
4365
  : "Fund Mining capital first"
4237
4366
  : capitalFreeLamports >= capitalEntryThreshold
4238
- ? "Meets 0.25 SOL funded minimum entry"
4239
- : "Below 0.25 SOL funded minimum entry",
4367
+ ? "Meets 0.25 SOL minimum eligibility capital"
4368
+ : "Below 0.25 SOL minimum eligibility capital",
4240
4369
  remediation: !minerCapitalInitialized
4241
4370
  ? minerCapitalRemediation
4242
4371
  : capitalFreeLamports >= capitalEntryThreshold
4243
4372
  ? undefined
4244
- : "Deposit at least 0.25 SOL into miner capital to participate in SAT cycles.",
4373
+ : "Deposit at least 0.25 SOL plus reveal collateral into miner capital to participate in SAT cycles.",
4245
4374
  },
4246
4375
  {
4247
4376
  key: "ataReady",
@@ -4471,7 +4600,9 @@ const satMiningPlugin = {
4471
4600
  return undefined;
4472
4601
  }
4473
4602
  })();
4474
- const totalCommittedLamports = currentExecution?.participationSubmitted ? 250_000_000 : 0;
4603
+ const totalCommittedLamports = currentExecution?.commitSubmitted
4604
+ ? (currentExecution.commitLamports ?? 250_000_000)
4605
+ : 0;
4475
4606
  const unlockRatio = Math.min(1, totalCommittedLamports / currentUnlockTargetLamports);
4476
4607
  const claimableSatRaw = snapshot.walletEpoch
4477
4608
  ? (
@@ -4481,7 +4612,11 @@ const satMiningPlugin = {
4481
4612
  : undefined;
4482
4613
  const slashPenaltyOwed = BigInt(snapshot.stake?.slashPenaltyOwed ?? "0");
4483
4614
  const hasClaimableSat = claimableSatRaw ? BigInt(claimableSatRaw) > 0n : false;
4484
- const lastParticipation = latestRecentAction("submitCycle");
4615
+ const lastParticipation = latestRecentActionAny([
4616
+ "revealCycle",
4617
+ "commitCycle",
4618
+ "submitCycle",
4619
+ ]);
4485
4620
  const lastMiningCrank =
4486
4621
  latestRecentAction("distributeCyclePage") ??
4487
4622
  latestRecentAction("scoreCyclePage") ??
@@ -4620,6 +4755,8 @@ const satMiningPlugin = {
4620
4755
  (action) =>
4621
4756
  action.status === "success" &&
4622
4757
  (action.action === "submitCycle" ||
4758
+ action.action === "commitCycle" ||
4759
+ action.action === "revealCycle" ||
4623
4760
  action.action === "setActiveCommit" ||
4624
4761
  action.action === "depositCapital" ||
4625
4762
  action.action === "withdrawCapital" ||
@@ -4636,6 +4773,8 @@ const satMiningPlugin = {
4636
4773
  (state.running ||
4637
4774
  state.activeConfig.enabled ||
4638
4775
  state.activeConfig.drainOnly ||
4776
+ currentExecution?.commitSubmitted ||
4777
+ previousExecution?.commitSubmitted ||
4639
4778
  currentExecution?.participationSubmitted ||
4640
4779
  previousExecution?.participationSubmitted ||
4641
4780
  hasPositiveLamportsValue(cachedStatus?.currentCapitalFundedLamports) ||
@@ -4654,6 +4793,39 @@ const satMiningPlugin = {
4654
4793
  globalState?.minimumEntryLamports ??
4655
4794
  "250000000";
4656
4795
  const cycleErosionPpm = resolveSatEffectiveCycleErosionPpm(globalState);
4796
+ const cycleCadence = state.activeConfig.cycleCadence ?? 1;
4797
+ const runway = (() => {
4798
+ try {
4799
+ const funded = BigInt(currentCapitalFundedLamports);
4800
+ const commit = BigInt(activeCommitLamports);
4801
+ const erosion = (commit * cycleErosionPpm) / 1_000_000n;
4802
+ const missedRevealPenalty =
4803
+ (commit * BigInt(SAT_PROTOCOL_CONSTANTS.cycleNonRevealPenaltyBps)) / 10_000n;
4804
+ const collateral = missedRevealPenalty > erosion ? missedRevealPenalty : erosion;
4805
+ const requiredToEnter = commit + collateral;
4806
+ const participations =
4807
+ funded < requiredToEnter
4808
+ ? 0n
4809
+ : erosion === 0n
4810
+ ? null
4811
+ : (funded - requiredToEnter) / erosion + 1n;
4812
+ const calendarCycles =
4813
+ participations == null ? null : participations * BigInt(cycleCadence);
4814
+ const days =
4815
+ calendarCycles == null
4816
+ ? null
4817
+ : Number(calendarCycles * BigInt(SAT_CYCLE_SECONDS)) / 86_400;
4818
+ return {
4819
+ commitCollateralLamports: collateral.toString(),
4820
+ estimatedParticipations: participations?.toString() ?? null,
4821
+ estimatedCalendarCycles: calendarCycles?.toString() ?? null,
4822
+ estimatedDays: days,
4823
+ excludesNetworkFees: true,
4824
+ };
4825
+ } catch {
4826
+ return null;
4827
+ }
4828
+ })();
4657
4829
  const liveCycleErosionLamports = (() => {
4658
4830
  try {
4659
4831
  return ((BigInt(liveCycleCommittedLamports) * cycleErosionPpm) / 1_000_000n).toString();
@@ -4776,7 +4948,7 @@ const satMiningPlugin = {
4776
4948
  const liveCycleTotalCommittedLamports =
4777
4949
  currentCycleState?.totalCommittedLamports ??
4778
4950
  currentMinerCycleState?.committedLamports ??
4779
- (currentExecution?.participationSubmitted ? liveCycleCommittedLamports : null);
4951
+ (currentExecution?.commitSubmitted ? liveCycleCommittedLamports : null);
4780
4952
  const liveCycleUnlockTargetLamports =
4781
4953
  currentCycleState?.unlockTargetLamports ?? globalState?.currentUnlockSolLamports ?? null;
4782
4954
  const liveCycleUnlockRatioFp =
@@ -4830,10 +5002,10 @@ const satMiningPlugin = {
4830
5002
  const latestSettledCycleId = settledHistory[0]?.cycleId ?? null;
4831
5003
  const latestSubmittedCycleId = (() => {
4832
5004
  const cycleIds = new Set<number>();
4833
- if (currentExecution?.participationSubmitted) {
5005
+ if (currentExecution?.commitSubmitted || currentExecution?.participationSubmitted) {
4834
5006
  cycleIds.add(currentCycleId);
4835
5007
  }
4836
- if (previousExecution?.participationSubmitted) {
5008
+ if (previousExecution?.commitSubmitted || previousExecution?.participationSubmitted) {
4837
5009
  cycleIds.add(previousCycleId);
4838
5010
  }
4839
5011
  for (const pendingCycleId of pendingCycleIds) {
@@ -4842,7 +5014,9 @@ const satMiningPlugin = {
4842
5014
  for (const entry of allUserFacingRecentActions) {
4843
5015
  if (
4844
5016
  entry.status === "success" &&
4845
- entry.action === "submitCycle" &&
5017
+ (entry.action === "submitCycle" ||
5018
+ entry.action === "commitCycle" ||
5019
+ entry.action === "revealCycle") &&
4846
5020
  typeof entry.cycleId === "number" &&
4847
5021
  Number.isFinite(entry.cycleId)
4848
5022
  ) {
@@ -5092,6 +5266,8 @@ const satMiningPlugin = {
5092
5266
  strategyExecution:
5093
5267
  state.activeConfig.strategyExecution ??
5094
5268
  strategyModeToExecution(state.activeConfig.strategyMode),
5269
+ cycleCadence,
5270
+ runway,
5095
5271
  strategyMode: state.activeConfig.strategyMode ?? "base",
5096
5272
  network: state.activeConfig.network,
5097
5273
  riskMode: state.activeConfig.riskMode,
@@ -6661,7 +6837,30 @@ const satMiningPlugin = {
6661
6837
  return generated;
6662
6838
  };
6663
6839
 
6664
- api.registerGatewayMethod("sat.openCycle", async ({ params, respond }) => {
6840
+ type SatGatewayHandler = Parameters<typeof api.registerGatewayMethod>[1];
6841
+ const registerSatSubmissionMethod = (method: string, handler: SatGatewayHandler) => {
6842
+ api.registerGatewayMethod(method, async (context) => {
6843
+ const source =
6844
+ context.params && typeof context.params === "object" && !Array.isArray(context.params)
6845
+ ? (context.params as Record<string, unknown>)
6846
+ : {};
6847
+ const { idempotencyKey: rawIdempotencyKey, ...intentParams } = source;
6848
+ const idempotencyKey =
6849
+ typeof rawIdempotencyKey === "string" && rawIdempotencyKey.trim()
6850
+ ? rawIdempotencyKey.trim()
6851
+ : `derived:${digestSatSubmissionIntent(intentParams)}`;
6852
+ try {
6853
+ await runWithSatSubmissionWorkflow(
6854
+ `gateway:${method}:${idempotencyKey}`,
6855
+ async () => await handler(context),
6856
+ );
6857
+ } catch (error) {
6858
+ respondGatewayError(context.respond, error);
6859
+ }
6860
+ });
6861
+ };
6862
+
6863
+ registerSatSubmissionMethod("sat.openCycle", async ({ params, respond }) => {
6665
6864
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
6666
6865
  try {
6667
6866
  const request = state.client.buildOpenCycleRequest({ cycleId });
@@ -6679,51 +6878,23 @@ const satMiningPlugin = {
6679
6878
  }
6680
6879
  });
6681
6880
 
6682
- api.registerGatewayMethod("sat.bootstrapRegistryReserve", async ({ params, respond }) => {
6683
- try {
6684
- const authority =
6685
- typeof (params as { authority?: string })?.authority === "string"
6686
- ? String((params as { authority?: string }).authority).trim()
6687
- : (state.activeWalletAddress ?? "");
6688
- const initialStake =
6689
- typeof (params as { initialStake?: number })?.initialStake === "number"
6690
- ? Number((params as { initialStake?: number }).initialStake)
6691
- : 0;
6692
- const submitted = await submitSatBootstrap(state.activeConfig, {
6693
- authority,
6694
- initialStake,
6695
- });
6696
- markActionSuccess("bootstrapRegistryReserve", submitted.txHash, null);
6697
- respond(true, jsonOk({ submitted, status: await getMiningStatus() }));
6698
- } catch (error) {
6699
- markActionFailure("bootstrapRegistryReserve", error, null);
6700
- respondGatewayError(respond, error);
6701
- }
6702
- });
6703
-
6704
- api.registerGatewayMethod("sat.setProtocolRecipients", async ({ params, respond }) => {
6881
+ registerSatSubmissionMethod("sat.topUpRegistryReserve", async ({ params, respond }) => {
6705
6882
  try {
6706
- const treasuryRecipient =
6707
- typeof (params as { treasuryRecipient?: string })?.treasuryRecipient === "string"
6708
- ? String((params as { treasuryRecipient?: string }).treasuryRecipient).trim()
6709
- : "";
6710
- const distributorRecipient =
6711
- typeof (params as { distributorRecipient?: string })?.distributorRecipient === "string"
6712
- ? String((params as { distributorRecipient?: string }).distributorRecipient).trim()
6713
- : "";
6714
- const submitted = await submitSatSetProtocolRecipients(state.activeConfig, {
6715
- treasuryRecipient,
6716
- distributorRecipient,
6883
+ const targetBalanceLamports = Number(
6884
+ (params as { targetBalanceLamports?: number })?.targetBalanceLamports ?? 0,
6885
+ );
6886
+ const submitted = await submitSatTopUpRegistryReserve(state.activeConfig, {
6887
+ targetBalanceLamports,
6717
6888
  });
6718
- markActionSuccess("setProtocolRecipients", submitted.txHash, null);
6889
+ markActionSuccess("topUpRegistryReserve", submitted.txHash, null);
6719
6890
  respond(true, jsonOk({ submitted, status: await getMiningStatus() }));
6720
6891
  } catch (error) {
6721
- markActionFailure("setProtocolRecipients", error, null);
6892
+ markActionFailure("topUpRegistryReserve", error, null);
6722
6893
  respondGatewayError(respond, error);
6723
6894
  }
6724
6895
  });
6725
6896
 
6726
- api.registerGatewayMethod("sat.claimProtocolTreasury", async ({ params, respond }) => {
6897
+ registerSatSubmissionMethod("sat.claimProtocolTreasury", async ({ params, respond }) => {
6727
6898
  try {
6728
6899
  const recipientOwner =
6729
6900
  typeof (params as { recipientOwner?: string })?.recipientOwner === "string"
@@ -6740,7 +6911,7 @@ const satMiningPlugin = {
6740
6911
  }
6741
6912
  });
6742
6913
 
6743
- api.registerGatewayMethod("sat.claimProtocolDistributorSat", async ({ params, respond }) => {
6914
+ registerSatSubmissionMethod("sat.claimProtocolDistributorSat", async ({ params, respond }) => {
6744
6915
  try {
6745
6916
  const recipientOwner =
6746
6917
  typeof (params as { recipientOwner?: string })?.recipientOwner === "string"
@@ -6757,7 +6928,7 @@ const satMiningPlugin = {
6757
6928
  }
6758
6929
  });
6759
6930
 
6760
- api.registerGatewayMethod(
6931
+ registerSatSubmissionMethod(
6761
6932
  "sat.refillRegistryReserveFromTreasury",
6762
6933
  async ({ params, respond }) => {
6763
6934
  try {
@@ -6815,7 +6986,7 @@ const satMiningPlugin = {
6815
6986
  .slice(0, Math.max(0, Math.min(limit, SAT_MAINTENANCE_RECENT_CLEANUP_CYCLE_LIMIT)));
6816
6987
  };
6817
6988
 
6818
- api.registerGatewayMethod("sat.runProtocolMaintenanceOnce", async ({ params, respond }) => {
6989
+ registerSatSubmissionMethod("sat.runProtocolMaintenanceOnce", async ({ params, respond }) => {
6819
6990
  const submitted: Array<{
6820
6991
  lane: SatMaintenanceLane;
6821
6992
  action: string;
@@ -6891,18 +7062,20 @@ const satMiningPlugin = {
6891
7062
  };
6892
7063
  const readFresh = async () => {
6893
7064
  invalidateSatReadCaches();
6894
- const [global, treasuryState, registryReserve, rent] = await Promise.all([
6895
- satOps.inspectSatGlobalState(state.activeConfig).catch(() => null),
6896
- satOps.inspectSatTreasuryState(state.activeConfig).catch(() => null),
6897
- satOps.inspectSatRegistryReserveLamports(state.activeConfig).catch(() => null),
6898
- satOps.inspectSatRentExemptionLamports(state.activeConfig).catch(() => null),
6899
- ]);
7065
+ const [global, treasuryState, registryReserve, rent, stakingDistributor] =
7066
+ await Promise.all([
7067
+ satOps.inspectSatGlobalState(state.activeConfig).catch(() => null),
7068
+ satOps.inspectSatTreasuryState(state.activeConfig).catch(() => null),
7069
+ satOps.inspectSatRegistryReserveLamports(state.activeConfig).catch(() => null),
7070
+ satOps.inspectSatRentExemptionLamports(state.activeConfig).catch(() => null),
7071
+ inspectSatBondStakingDistributor(state.activeConfig).catch(() => null),
7072
+ ]);
6900
7073
  const target =
6901
7074
  targetBalanceLamports !== undefined
6902
7075
  ? BigInt(targetBalanceLamports)
6903
7076
  : BigInt(rent?.registryReserveTargetLamports ?? "200000000");
6904
7077
  const reserve = BigInt(registryReserve?.lamports ?? "0");
6905
- return { global, treasuryState, registryReserve, target, reserve };
7078
+ return { global, treasuryState, registryReserve, stakingDistributor, target, reserve };
6906
7079
  };
6907
7080
  const buildLaneSummary = () => {
6908
7081
  const lanes: Record<
@@ -6955,6 +7128,7 @@ const satMiningPlugin = {
6955
7128
  pendingTreasurySatRaw: snapshot.treasuryState?.pendingTreasurySatRaw ?? "0",
6956
7129
  pendingTreasurySolLamports: snapshot.treasuryState?.pendingTreasurySolLamports ?? "0",
6957
7130
  pendingDistributorSatRaw: snapshot.treasuryState?.pendingDistributorSatRaw ?? "0",
7131
+ unallocatedStakingRewardRaw: snapshot.stakingDistributor?.unallocatedRewardRaw ?? "0",
6958
7132
  cleanup: cleanupSummary,
6959
7133
  lanes: buildLaneSummary(),
6960
7134
  updatedAt: new Date().toISOString(),
@@ -7029,6 +7203,60 @@ const satMiningPlugin = {
7029
7203
  });
7030
7204
  }
7031
7205
 
7206
+ // Protocol rewards are recorded atomically by the mining claim CPI.
7207
+ // Any remaining vault delta is an unsolicited transfer and must be
7208
+ // quarantined for the fixed treasury, never allocated to stakers.
7209
+ const stakingRewardVaultRaw = BigInt(
7210
+ snapshot.stakingDistributor?.rewardVaultBalanceRaw ?? "0",
7211
+ );
7212
+ const observedStakingRewardRaw = BigInt(
7213
+ snapshot.stakingDistributor?.observedRewardVaultRaw ?? "0",
7214
+ );
7215
+ if (
7216
+ snapshot.stakingDistributor?.statusLabel === "active" &&
7217
+ stakingRewardVaultRaw > observedStakingRewardRaw &&
7218
+ stakingRewardVaultRaw - observedStakingRewardRaw >= minSatRaw
7219
+ ) {
7220
+ const tx = await submitSatSyncBondStakingRewards(state.activeConfig);
7221
+ pushSubmitted({
7222
+ lane: "distributor",
7223
+ action: "syncBondStakingRewards",
7224
+ txHash: tx.txHash,
7225
+ });
7226
+ markActionSuccess("syncBondStakingRewards", tx.txHash, null);
7227
+ snapshot = await readFresh();
7228
+ } else {
7229
+ pushSubmitted({
7230
+ lane: "distributor",
7231
+ action: "syncBondStakingRewards",
7232
+ skipped: "no-unexpected-vault-balance-or-below-threshold",
7233
+ });
7234
+ }
7235
+
7236
+ const unallocatedTreasuryRecipient = snapshot.global?.treasuryRecipient;
7237
+ if (
7238
+ unallocatedTreasuryRecipient &&
7239
+ unallocatedTreasuryRecipient !== defaultPubkey &&
7240
+ BigInt(snapshot.stakingDistributor?.unallocatedRewardRaw ?? "0") >= minSatRaw
7241
+ ) {
7242
+ const tx = await submitSatClaimUnallocatedStakingRewards(state.activeConfig, {
7243
+ recipientOwner: unallocatedTreasuryRecipient,
7244
+ });
7245
+ pushSubmitted({
7246
+ lane: "treasury",
7247
+ action: "claimUnallocatedStakingRewards",
7248
+ txHash: tx.txHash,
7249
+ });
7250
+ markActionSuccess("claimUnallocatedStakingRewards", tx.txHash, null);
7251
+ snapshot = await readFresh();
7252
+ } else {
7253
+ pushSubmitted({
7254
+ lane: "treasury",
7255
+ action: "claimUnallocatedStakingRewards",
7256
+ skipped: "no-recipient-or-below-threshold",
7257
+ });
7258
+ }
7259
+
7032
7260
  if (cleanupMaxCycles > 0 && cleanupBudgetMs > 0 && cleanupMaxTransactions > 0) {
7033
7261
  const maxCleanupCandidates = Math.min(
7034
7262
  50,
@@ -7180,7 +7408,7 @@ const satMiningPlugin = {
7180
7408
  }
7181
7409
  });
7182
7410
 
7183
- api.registerGatewayMethod("sat.initMinerCapital", async ({ params, respond }) => {
7411
+ registerSatSubmissionMethod("sat.initMinerCapital", async ({ params, respond }) => {
7184
7412
  try {
7185
7413
  await ensureSatCapitalActionSignerReady();
7186
7414
  const authority =
@@ -7196,7 +7424,7 @@ const satMiningPlugin = {
7196
7424
  }
7197
7425
  });
7198
7426
 
7199
- api.registerGatewayMethod("sat.depositMinerCapital", async ({ params, respond }) => {
7427
+ registerSatSubmissionMethod("sat.depositMinerCapital", async ({ params, respond }) => {
7200
7428
  try {
7201
7429
  await ensureSatCapitalActionSignerReady();
7202
7430
  const lamports = Number((params as { lamports?: number })?.lamports ?? 0);
@@ -7213,7 +7441,7 @@ const satMiningPlugin = {
7213
7441
  }
7214
7442
  });
7215
7443
 
7216
- api.registerGatewayMethod("sat.withdrawMinerCapital", async ({ params, respond }) => {
7444
+ registerSatSubmissionMethod("sat.withdrawMinerCapital", async ({ params, respond }) => {
7217
7445
  try {
7218
7446
  await ensureSatCapitalActionSignerReady();
7219
7447
  const lamports = Number((params as { lamports?: number })?.lamports ?? 0);
@@ -7228,7 +7456,7 @@ const satMiningPlugin = {
7228
7456
  }
7229
7457
  });
7230
7458
 
7231
- api.registerGatewayMethod("sat.setActiveCommit", async ({ params, respond }) => {
7459
+ registerSatSubmissionMethod("sat.setActiveCommit", async ({ params, respond }) => {
7232
7460
  try {
7233
7461
  await ensureSatCapitalActionSignerReady();
7234
7462
  const lamports = Number((params as { lamports?: number })?.lamports ?? 0);
@@ -7253,38 +7481,147 @@ const satMiningPlugin = {
7253
7481
  }
7254
7482
  });
7255
7483
 
7256
- api.registerGatewayMethod("sat.submitCycle", async ({ params, respond }) => {
7484
+ registerSatSubmissionMethod("sat.commitCycle", async ({ params, respond }) => {
7485
+ const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7486
+ try {
7487
+ const commitmentHex = String(
7488
+ (params as { commitmentHex?: string })?.commitmentHex ?? "",
7489
+ ).trim();
7490
+ if (!/^[0-9a-f]{64}$/i.test(commitmentHex)) {
7491
+ throw new Error("cycle commitment must be a 32-byte hexadecimal digest");
7492
+ }
7493
+ const submitted = await submitSatCommitCycle(state.activeConfig, {
7494
+ cycleId,
7495
+ commitmentHex,
7496
+ });
7497
+ if (Number.isFinite(cycleId) && cycleId >= 0) {
7498
+ const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7499
+ execution.openRoundSubmitted = true;
7500
+ execution.commitSubmitted = true;
7501
+ execution.commitmentHex = commitmentHex.toLowerCase();
7502
+ }
7503
+ markActionSuccess("commitCycle", submitted.txHash, cycleId);
7504
+ await persistRecentActions();
7505
+ respond(true, jsonOk({ submitted }));
7506
+ } catch (error) {
7507
+ if (!isCycleMismatchError(error)) {
7508
+ markActionFailure("commitCycle", error, cycleId);
7509
+ }
7510
+ respondGatewayError(respond, error);
7511
+ }
7512
+ });
7513
+
7514
+ registerSatSubmissionMethod("sat.closeCommitPhase", async ({ params, respond }) => {
7515
+ const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7516
+ try {
7517
+ const submitted = await submitSatCloseCommitPhase(state.activeConfig, { cycleId });
7518
+ invalidateMiningReadCaches();
7519
+ getOrCreateRoundExecutionState(state, cycleId, 0).entropyTargetPinned = true;
7520
+ markActionSuccess("closeCommitPhase", submitted.txHash, cycleId);
7521
+ await persistRecentActions();
7522
+ respond(true, jsonOk({ submitted }));
7523
+ } catch (error) {
7524
+ markActionFailure("closeCommitPhase", error, cycleId);
7525
+ respondGatewayError(respond, error);
7526
+ }
7527
+ });
7528
+
7529
+ registerSatSubmissionMethod("sat.sealCycleEntropy", async ({ params, respond }) => {
7530
+ const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7531
+ try {
7532
+ const cycle = await inspectSatCycle(state.activeConfig, { cycleId });
7533
+ if (cycle.unlockIntervalStartCycleId == null) {
7534
+ throw new Error(`cycle ${cycleId} does not expose its unlock interval start`);
7535
+ }
7536
+ const submitted = await submitSatSealCycleEntropy(state.activeConfig, {
7537
+ cycleId,
7538
+ intervalStartCycleId: cycle.unlockIntervalStartCycleId,
7539
+ });
7540
+ invalidateMiningReadCaches();
7541
+ markActionSuccess("sealCycleEntropy", submitted.txHash, cycleId);
7542
+ await persistRecentActions();
7543
+ respond(true, jsonOk({ submitted }));
7544
+ } catch (error) {
7545
+ markActionFailure("sealCycleEntropy", error, cycleId);
7546
+ respondGatewayError(respond, error);
7547
+ }
7548
+ });
7549
+
7550
+ registerSatSubmissionMethod("sat.revealCycle", async ({ params, respond }) => {
7257
7551
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7258
7552
  try {
7553
+ const nonceBase64 = String((params as { nonceBase64?: string })?.nonceBase64 ?? "").trim();
7259
7554
  const allocationFp = Array.isArray((params as { allocationFp?: number[] })?.allocationFp)
7260
7555
  ? ((params as { allocationFp?: number[] }).allocationFp ?? [])
7261
7556
  : [];
7262
- const request = state.client.buildSubmitCycleRequest({
7557
+ const cycle = await inspectSatCycle(state.activeConfig, { cycleId });
7558
+ if (cycle.unlockIntervalStartCycleId == null) {
7559
+ throw new Error(`cycle ${cycleId} does not expose its unlock interval start`);
7560
+ }
7561
+ const submitted = await submitSatRevealCycle(state.activeConfig, {
7263
7562
  cycleId,
7563
+ intervalStartCycleId: cycle.unlockIntervalStartCycleId,
7564
+ nonceBase64,
7264
7565
  allocationFp,
7265
7566
  });
7266
- const submitted = await submitSatCycle(state.activeConfig, request.params);
7567
+ invalidateMiningReadCaches();
7267
7568
  await capturePendingPlannerCycle(cycleId);
7268
- if (Number.isFinite(cycleId) && cycleId >= 0) {
7269
- const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7270
- execution.openRoundSubmitted = true;
7271
- execution.participationSubmitted = true;
7272
- }
7273
- markActionSuccess("submitCycle", submitted.txHash, cycleId);
7569
+ const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7570
+ execution.openRoundSubmitted = true;
7571
+ execution.commitSubmitted = true;
7572
+ execution.participationSubmitted = true;
7573
+ markActionSuccess("revealCycle", submitted.txHash, cycleId);
7274
7574
  await persistRecentActions();
7275
- respond(true, jsonOk({ request, submitted }));
7575
+ respond(true, jsonOk({ submitted }));
7276
7576
  } catch (error) {
7277
7577
  state.pendingPlannerCycles.delete(cycleId);
7278
- if (isCycleMismatchError(error)) {
7279
- respondGatewayError(respond, error);
7280
- return;
7281
- }
7282
- markActionFailure("submitCycle", error, cycleId);
7578
+ markActionFailure("revealCycle", error, cycleId);
7579
+ respondGatewayError(respond, error);
7580
+ }
7581
+ });
7582
+
7583
+ registerSatSubmissionMethod("sat.releaseUnrevealedCommit", async ({ params, respond }) => {
7584
+ const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7585
+ try {
7586
+ const minerAuthority = String(
7587
+ (params as { minerAuthority?: string })?.minerAuthority ?? "",
7588
+ ).trim();
7589
+ const submitted = await submitSatReleaseUnrevealedCommit(state.activeConfig, {
7590
+ cycleId,
7591
+ minerAuthority,
7592
+ });
7593
+ invalidateMiningReadCaches();
7594
+ markActionSuccess("releaseUnrevealedCommit", submitted.txHash, cycleId);
7595
+ await persistRecentActions();
7596
+ respond(true, jsonOk({ submitted }));
7597
+ } catch (error) {
7598
+ markActionFailure("releaseUnrevealedCommit", error, cycleId);
7599
+ respondGatewayError(respond, error);
7600
+ }
7601
+ });
7602
+
7603
+ registerSatSubmissionMethod("sat.abortEmptyCycle", async ({ params, respond }) => {
7604
+ const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7605
+ try {
7606
+ const submitted = await submitSatAbortEmptyCycle(state.activeConfig, { cycleId });
7607
+ invalidateMiningReadCaches();
7608
+ markActionSuccess("abortEmptyCycle", submitted.txHash, cycleId);
7609
+ await persistRecentActions();
7610
+ respond(true, jsonOk({ submitted }));
7611
+ } catch (error) {
7612
+ markActionFailure("abortEmptyCycle", error, cycleId);
7283
7613
  respondGatewayError(respond, error);
7284
7614
  }
7285
7615
  });
7286
7616
 
7287
- api.registerGatewayMethod("sat.settleCyclePage", async ({ params, respond }) => {
7617
+ registerSatSubmissionMethod("sat.submitCycle", async ({ respond }) => {
7618
+ respondGatewayError(
7619
+ respond,
7620
+ new Error("public allocation submission is retired; update Fased to use commit/reveal"),
7621
+ );
7622
+ });
7623
+
7624
+ registerSatSubmissionMethod("sat.settleCyclePage", async ({ params, respond }) => {
7288
7625
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7289
7626
  try {
7290
7627
  const pageIndex = Number((params as { pageIndex?: number })?.pageIndex ?? 0);
@@ -7319,7 +7656,7 @@ const satMiningPlugin = {
7319
7656
  }
7320
7657
  });
7321
7658
 
7322
- api.registerGatewayMethod("sat.finalizeCycleSettlement", async ({ params, respond }) => {
7659
+ registerSatSubmissionMethod("sat.finalizeCycleSettlement", async ({ params, respond }) => {
7323
7660
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7324
7661
  try {
7325
7662
  const pageCount = Number((params as { pageCount?: number })?.pageCount ?? 1);
@@ -7339,7 +7676,7 @@ const satMiningPlugin = {
7339
7676
  }
7340
7677
  });
7341
7678
 
7342
- api.registerGatewayMethod("sat.scoreCyclePage", async ({ params, respond }) => {
7679
+ registerSatSubmissionMethod("sat.scoreCyclePage", async ({ params, respond }) => {
7343
7680
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7344
7681
  try {
7345
7682
  const pageIndex = Number((params as { pageIndex?: number })?.pageIndex ?? 0);
@@ -7370,7 +7707,7 @@ const satMiningPlugin = {
7370
7707
  }
7371
7708
  });
7372
7709
 
7373
- api.registerGatewayMethod("sat.distributeCyclePage", async ({ params, respond }) => {
7710
+ registerSatSubmissionMethod("sat.distributeCyclePage", async ({ params, respond }) => {
7374
7711
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7375
7712
  try {
7376
7713
  const pageIndex = Number((params as { pageIndex?: number })?.pageIndex ?? 0);
@@ -7406,20 +7743,21 @@ const satMiningPlugin = {
7406
7743
  }
7407
7744
  });
7408
7745
 
7409
- api.registerGatewayMethod("sat.claimCycleRewards", async ({ params, respond }) => {
7746
+ registerSatSubmissionMethod("sat.claimCycleRewards", async ({ params, respond }) => {
7410
7747
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7411
7748
  try {
7412
7749
  const request = state.client.buildClaimCycleRewardsRequest({ cycleId });
7413
7750
  const submitted = await submitSatClaimCycleRewards(state.activeConfig, request.params);
7414
- if (Number.isFinite(cycleId) && cycleId >= 0) {
7415
- const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7416
- execution.claimSubmitted = true;
7417
- }
7418
- markSatClaimBacklogClaimed(state, [cycleId], submitted.txHash);
7419
- markActionSuccess("claimCycleRewards", submitted.txHash, cycleId);
7751
+ const completion = await resolveClaimCompletion([cycleId]);
7752
+ applyClaimCompletion({
7753
+ action: "claimCycleRewards",
7754
+ txHash: submitted.txHash,
7755
+ cycleIds: [cycleId],
7756
+ ...completion,
7757
+ });
7420
7758
  await persistRecentActions();
7421
- void capturePlannerOutcomesForCycles([cycleId], submitted.txHash);
7422
- respond(true, jsonOk({ request, submitted }));
7759
+ void capturePlannerOutcomesForCycles(completion.resolvedCycleIds, submitted.txHash);
7760
+ respond(true, jsonOk({ request, submitted, ...completion }));
7423
7761
  } catch (error) {
7424
7762
  markSatClaimBacklogFailure(state, [cycleId], error);
7425
7763
  markActionFailure("claimCycleRewards", error, cycleId);
@@ -7427,7 +7765,7 @@ const satMiningPlugin = {
7427
7765
  }
7428
7766
  });
7429
7767
 
7430
- api.registerGatewayMethod("sat.claimCycleRewardsBatch", async ({ params, respond }) => {
7768
+ registerSatSubmissionMethod("sat.claimCycleRewardsBatch", async ({ params, respond }) => {
7431
7769
  const cycleIds = Array.isArray((params as { cycleIds?: number[] })?.cycleIds)
7432
7770
  ? ((params as { cycleIds?: number[] }).cycleIds ?? [])
7433
7771
  .map((value) => Number(value))
@@ -7437,15 +7775,16 @@ const satMiningPlugin = {
7437
7775
  try {
7438
7776
  markSatClaimBacklogReady(state, cycleIds, "manual claim batch action");
7439
7777
  const submitted = await submitSatClaimCycleRewardsBatch(state.activeConfig, request.params);
7440
- for (const cycleId of cycleIds) {
7441
- const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7442
- execution.claimSubmitted = true;
7443
- }
7444
- markSatClaimBacklogClaimed(state, cycleIds, submitted.txHash);
7445
- markBatchActionSuccess("claimCycleRewardsBatch", submitted.txHash, cycleIds);
7778
+ const completion = await resolveClaimCompletion(cycleIds);
7779
+ applyClaimCompletion({
7780
+ action: "claimCycleRewardsBatch",
7781
+ txHash: submitted.txHash,
7782
+ cycleIds,
7783
+ ...completion,
7784
+ });
7446
7785
  await persistRecentActions();
7447
- void capturePlannerOutcomesForCycles(cycleIds, submitted.txHash);
7448
- respond(true, jsonOk({ request, submitted }));
7786
+ void capturePlannerOutcomesForCycles(completion.resolvedCycleIds, submitted.txHash);
7787
+ respond(true, jsonOk({ request, submitted, ...completion }));
7449
7788
  } catch (error) {
7450
7789
  if (cycleIds.length > 0 && isInvalidAccountOwnerError(error)) {
7451
7790
  const resolvedCycleIds = await resolveClaimBatchInvalidOwnerCycles(cycleIds);
@@ -7492,7 +7831,7 @@ const satMiningPlugin = {
7492
7831
  }
7493
7832
  });
7494
7833
 
7495
- api.registerGatewayMethod("sat.claimBacklog", async ({ respond }) => {
7834
+ registerSatSubmissionMethod("sat.claimBacklog", async ({ respond }) => {
7496
7835
  const batchCycles = resolveSatClaimBatchCycles(state.activeConfig);
7497
7836
  const cycleIds = collectReadySatClaimBacklogCycleIds(state, batchCycles);
7498
7837
  const request = state.client.buildClaimCycleRewardsBatchRequest({ cycleIds });
@@ -7512,19 +7851,21 @@ const satMiningPlugin = {
7512
7851
  }
7513
7852
  markSatClaimBacklogReady(state, cycleIds, "manual claim backlog action");
7514
7853
  const submitted = await submitSatClaimCycleRewardsBatch(state.activeConfig, request.params);
7515
- for (const cycleId of cycleIds) {
7516
- const execution = getOrCreateRoundExecutionState(state, cycleId, 0);
7517
- execution.claimSubmitted = true;
7518
- }
7519
- markSatClaimBacklogClaimed(state, cycleIds, submitted.txHash);
7520
- markBatchActionSuccess("claimCycleRewardsBatch", submitted.txHash, cycleIds);
7854
+ const completion = await resolveClaimCompletion(cycleIds);
7855
+ applyClaimCompletion({
7856
+ action: "claimCycleRewardsBatch",
7857
+ txHash: submitted.txHash,
7858
+ cycleIds,
7859
+ ...completion,
7860
+ });
7521
7861
  await persistRecentActions();
7522
- void capturePlannerOutcomesForCycles(cycleIds, submitted.txHash);
7862
+ void capturePlannerOutcomesForCycles(completion.resolvedCycleIds, submitted.txHash);
7523
7863
  respond(
7524
7864
  true,
7525
7865
  jsonOk({
7526
7866
  request,
7527
7867
  submitted,
7868
+ ...completion,
7528
7869
  claimBacklog: buildSatClaimBacklogSummary(state),
7529
7870
  }),
7530
7871
  );
@@ -7535,7 +7876,7 @@ const satMiningPlugin = {
7535
7876
  }
7536
7877
  });
7537
7878
 
7538
- api.registerGatewayMethod("sat.retargetUnlock", async ({ params, respond }) => {
7879
+ registerSatSubmissionMethod("sat.retargetUnlock", async ({ params, respond }) => {
7539
7880
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7540
7881
  try {
7541
7882
  const request = state.client.buildRetargetUnlockRequest({ cycleId });
@@ -7548,7 +7889,7 @@ const satMiningPlugin = {
7548
7889
  }
7549
7890
  });
7550
7891
 
7551
- api.registerGatewayMethod("sat.closeResolvedCycleAccounts", async ({ params, respond }) => {
7892
+ registerSatSubmissionMethod("sat.closeResolvedCycleAccounts", async ({ params, respond }) => {
7552
7893
  const cycleId = Number((params as { cycleId?: number })?.cycleId ?? 0);
7553
7894
  try {
7554
7895
  const result = await closeResolvedExactCycleAccounts(cycleId);
@@ -7580,7 +7921,7 @@ const satMiningPlugin = {
7580
7921
  }
7581
7922
  });
7582
7923
 
7583
- api.registerGatewayMethod("sat.compactPendingCycleRange", async ({ params, respond }) => {
7924
+ registerSatSubmissionMethod("sat.compactPendingCycleRange", async ({ params, respond }) => {
7584
7925
  try {
7585
7926
  const maxFrontCycles =
7586
7927
  typeof (params as { maxFrontCycles?: number })?.maxFrontCycles === "number"
@@ -7695,7 +8036,7 @@ const satMiningPlugin = {
7695
8036
  respond(true, jsonOk(await Promise.resolve(readProfile())));
7696
8037
  });
7697
8038
 
7698
- api.registerGatewayMethod("sat.setMinerProfile", async ({ params, respond }) => {
8039
+ registerSatSubmissionMethod("sat.setMinerProfile", async ({ params, respond }) => {
7699
8040
  try {
7700
8041
  const request =
7701
8042
  params && typeof params === "object" && !Array.isArray(params)
@@ -7965,10 +8306,14 @@ const satMiningPlugin = {
7965
8306
  ) {
7966
8307
  return;
7967
8308
  }
7968
- const compacted = await compactPendingCycleRange({
7969
- maxFrontCycles: SAT_PENDING_RANGE_COMPACT_CHUNK_CYCLES,
7970
- maxBackCycles: SAT_PENDING_RANGE_COMPACT_CHUNK_CYCLES,
7971
- }).catch(() => null);
8309
+ const compacted = await runWithSatSubmissionWorkflow(
8310
+ `startup:compact-pending:${authority}:${firstPendingCycleId}:${lastPendingCycleId}`,
8311
+ async () =>
8312
+ await compactPendingCycleRange({
8313
+ maxFrontCycles: SAT_PENDING_RANGE_COMPACT_CHUNK_CYCLES,
8314
+ maxBackCycles: SAT_PENDING_RANGE_COMPACT_CHUNK_CYCLES,
8315
+ }),
8316
+ ).catch(() => null);
7972
8317
  if (compacted?.compacted) {
7973
8318
  api.logger.info(
7974
8319
  `[sat-mining] compacted stale pending range during startup for wallet ${authority}`,
@@ -8081,7 +8426,7 @@ const satMiningPlugin = {
8081
8426
  }, 10_000);
8082
8427
  };
8083
8428
 
8084
- api.registerGatewayMethod("sat.startMining", async ({ params, respond }) => {
8429
+ registerSatSubmissionMethod("sat.startMining", async ({ params, respond }) => {
8085
8430
  try {
8086
8431
  if (state.activeConfig.network === "mainnet-beta") {
8087
8432
  const syncStatus = await getSatMainnetSyncStatus();
@@ -8210,7 +8555,7 @@ const satMiningPlugin = {
8210
8555
  }
8211
8556
  });
8212
8557
 
8213
- api.registerGatewayMethod("sat.stopMining", async ({ respond }) => {
8558
+ registerSatSubmissionMethod("sat.stopMining", async ({ params: _params, respond }) => {
8214
8559
  try {
8215
8560
  const authority = await resolveSatCapitalActionAuthority().catch(
8216
8561
  () => state.activeWalletAddress ?? "",
@@ -8344,7 +8689,7 @@ const satMiningPlugin = {
8344
8689
  }
8345
8690
  });
8346
8691
 
8347
- api.registerGatewayMethod("sat.resolveDispute", async ({ params, respond }) => {
8692
+ registerSatSubmissionMethod("sat.resolveDispute", async ({ params, respond }) => {
8348
8693
  try {
8349
8694
  const request = state.client.buildResolveDisputeRequest({
8350
8695
  disputeAuthority: String(
@@ -8364,7 +8709,7 @@ const satMiningPlugin = {
8364
8709
  }
8365
8710
  });
8366
8711
 
8367
- api.registerGatewayMethod("sat.republishEpochRoots", async ({ params, respond }) => {
8712
+ registerSatSubmissionMethod("sat.republishEpochRoots", async ({ params, respond }) => {
8368
8713
  try {
8369
8714
  const request = state.client.buildRepublishEpochRootsRequest({
8370
8715
  epochId: Number((params as { epochId?: number })?.epochId ?? 0),
@@ -8483,7 +8828,7 @@ const satMiningPlugin = {
8483
8828
  }
8484
8829
  });
8485
8830
 
8486
- api.registerGatewayMethod("sat.submitValidatorAttestation", async ({ params, respond }) => {
8831
+ registerSatSubmissionMethod("sat.submitValidatorAttestation", async ({ params, respond }) => {
8487
8832
  try {
8488
8833
  const request = state.client.buildSubmitValidatorAttestationRequest({
8489
8834
  targetAuthority: String((params as { targetAuthority?: string })?.targetAuthority ?? ""),
@@ -8516,7 +8861,7 @@ const satMiningPlugin = {
8516
8861
  }
8517
8862
  });
8518
8863
 
8519
- api.registerGatewayMethod("sat.openDispute", async ({ params, respond }) => {
8864
+ registerSatSubmissionMethod("sat.openDispute", async ({ params, respond }) => {
8520
8865
  try {
8521
8866
  const request = state.client.buildOpenDisputeRequest({
8522
8867
  targetAuthority: String((params as { targetAuthority?: string })?.targetAuthority ?? ""),