@fased/fased 0.1.62 → 0.1.65

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 (342) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +44 -29
  3. package/config/dependency-ownership.json +1 -1
  4. package/config/signer-policies/README.md +58 -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 +78 -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-MaQnPa5G.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-D4YMr1fA.js} +3 -3
  80. package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
  81. package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-qMYs4aD-.js} +70 -50
  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 +291 -84
  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 +1274 -390
  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-I4IngVlJ.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-DLQ6_lLK.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-D_8FVI1C.js} +6798 -3695
  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-B4KF4Kpo.js} +31 -31
  166. package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-Bb6x1KAG.js} +32 -32
  167. package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DCTO8JkL.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-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
  172. package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-DHPDFZbC.d.ts} +2 -2
  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 +565 -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-BHmvqgjH.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-By5AcorL.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-DGnBz1YT.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-EJGTmL1Q.d.ts +486 -0
  208. package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-BdwdFCD6.d.ts} +2 -3
  209. package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-BrCpYMxn.d.ts} +2 -2
  210. package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -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-DUJwrTYs.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 +578 -117
  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 +92 -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 +93 -37
  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 +18 -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 +18 -0
  284. package/extensions/msteams/package.json +1 -1
  285. package/extensions/nextcloud-talk/package.json +1 -1
  286. package/extensions/nostr/CHANGELOG.md +18 -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 +587 -154
  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 +91 -5
  293. package/extensions/sat-mining/src/claim-service.ts +85 -14
  294. package/extensions/sat-mining/src/client.ts +13 -0
  295. package/extensions/sat-mining/src/config.ts +9 -0
  296. package/extensions/sat-mining/src/cycle-progress.ts +16 -8
  297. package/extensions/sat-mining/src/epoch-service.ts +9 -5
  298. package/extensions/sat-mining/src/gateway-runner.ts +21 -1
  299. package/extensions/sat-mining/src/protocol-contract.ts +45 -1
  300. package/extensions/sat-mining/src/recovery-service.ts +312 -0
  301. package/extensions/sat-mining/src/round-watcher.ts +391 -81
  302. package/extensions/sat-mining/src/rpc-read.ts +431 -106
  303. package/extensions/sat-mining/src/runtime.ts +16 -0
  304. package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
  305. package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
  306. package/extensions/sat-mining/src/solana-submit.ts +1544 -436
  307. package/extensions/sat-mining/src/submission-ledger.ts +434 -0
  308. package/extensions/signal/package.json +1 -1
  309. package/extensions/synology-chat/package.json +1 -1
  310. package/extensions/tlon/package.json +1 -1
  311. package/extensions/twitch/CHANGELOG.md +18 -0
  312. package/extensions/twitch/package.json +1 -1
  313. package/extensions/voice-call/CHANGELOG.md +18 -0
  314. package/extensions/voice-call/package.json +1 -1
  315. package/extensions/zalo/CHANGELOG.md +18 -0
  316. package/extensions/zalo/package.json +1 -1
  317. package/extensions/zalouser/CHANGELOG.md +18 -0
  318. package/extensions/zalouser/package.json +1 -1
  319. package/install.sh +4951 -0
  320. package/package.json +23 -5
  321. package/scripts/fased-host-updater.mjs +1421 -0
  322. package/scripts/fased-host-updaterctl.mjs +186 -0
  323. package/scripts/fased-managed-service.sh +36 -0
  324. package/scripts/fased-managed-updater.mjs +3065 -156
  325. package/scripts/fased-signer-enroll-hosting.sh +275 -0
  326. package/scripts/fased-signer-network-hosting.sh +143 -0
  327. package/scripts/fased-signer-owner-policy.mjs +1442 -0
  328. package/scripts/fased-signer-policy-hosting.sh +50 -0
  329. package/scripts/fased-signer-policy-local.sh +26 -0
  330. package/scripts/hosted-release-manifest.mjs +185 -0
  331. package/scripts/install-fased-signerd.sh +183 -108
  332. package/scripts/install-managed-runtime.mjs +212 -10
  333. package/scripts/managed-runtime-layout.mjs +75 -3
  334. package/scripts/migrate-hosted-signer-v2.mjs +58 -0
  335. package/scripts/start-managed.sh +173 -360
  336. package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
  337. package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
  338. package/dist/wallet/local-socket-signer-broker.js +0 -224
  339. package/dist/wallet/local-socket-signer-custody.js +0 -42
  340. package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
  341. package/dist/wallet/providers/privy-adapter.js +0 -80
  342. package/dist/wallet/wallet-custody.js +0 -1836
@@ -1,7 +1,11 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { createHash } from "node:crypto";
1
3
  import { createRequire } from "node:module";
4
+ import { isDeepStrictEqual } from "node:util";
2
5
  import {
3
6
  callLocalSocketSigner,
4
- enforceWalletCustodyForAutonomousSend,
7
+ createSignerReviewApprovalRequest,
8
+ LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE,
5
9
  loadConfig,
6
10
  readWalletProviderRegistry,
7
11
  requireLocalSocketSignerPath,
@@ -12,14 +16,32 @@ import {
12
16
  resolveWalletProviderId,
13
17
  resolveWalletRuntimeConfig,
14
18
  type FasedAgentConfig,
19
+ type WalletProviderJupiterReviewV2,
15
20
  } from "fased/plugin-sdk/sat-runtime";
16
21
  import type { SatMiningConfig } from "./config.js";
17
22
  import { decodeHash32 } from "./hash-spec.js";
18
23
  import {
24
+ resolveSatGenesisProfileContract,
19
25
  SAT_BOND_INSTRUCTION_DISCRIMINATORS,
20
26
  SAT_INSTRUCTION_DISCRIMINATORS,
27
+ SAT_PROTOCOL_CONSTANTS,
21
28
  } from "./protocol-contract.js";
22
- import { inspectSatCycleRegistryMeta, inspectSatMinerCyclesByAddress } from "./rpc-read.js";
29
+ import {
30
+ inspectSatAddressLookupTable,
31
+ inspectSatChainSlot,
32
+ inspectSatCycle,
33
+ inspectSatCycleRegistryMeta,
34
+ inspectSatMinerCyclesByAddress,
35
+ } from "./rpc-read.js";
36
+ import { resolveSatSignerCodec, type SatSignerAction } from "./signer-codec-manifest.js";
37
+ import {
38
+ buildSatSubmissionOperationKey,
39
+ claimSatSubmission,
40
+ digestSatSubmissionIntent,
41
+ updateSatSubmission,
42
+ waitForSatSubmissionLease,
43
+ type SatSubmissionSignerState,
44
+ } from "./submission-ledger.js";
23
45
 
24
46
  const require = createRequire(import.meta.url);
25
47
 
@@ -47,16 +69,46 @@ const SAT_TREASURY_STATE_SEED = "sat_treasury_state";
47
69
  const SAT_REGISTRY_RESERVE_SEED = "sat_registry_reserve";
48
70
  const SAT_REBATE_VAULT_SEED = "sat_rebate_vault";
49
71
  const SAT_TREASURY_VAULT_SEED = "sat_treasury_vault";
72
+ const SAT_UNLOCK_INTERVAL_STATE_SEED = "sat_unlock_interval_state";
50
73
  const SAT_CYCLE_REGISTRY_PAGE_CAPACITY = 64;
51
74
  const MINING_POOL_SEED = "mining_pool";
52
75
  const MINING_STAKE_SEED = "mining_stake";
53
76
  const TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
54
77
  const ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
78
+ const SLOT_HASHES_SYSVAR_ID = "SysvarS1otHashes111111111111111111111111111";
79
+ const SAT_DISTRIBUTION_LOOKUP_MIN_MINERS = 16;
80
+ const SAT_LOOKUP_TABLE_EXTEND_CHUNK_SIZE = 20;
55
81
 
56
82
  const IX = SAT_INSTRUCTION_DISCRIMINATORS;
57
83
 
58
84
  const BOND_IX = SAT_BOND_INSTRUCTION_DISCRIMINATORS;
59
85
 
86
+ const VAULT_BOND_ACTIONS = new Set<SatSignerAction>([
87
+ "updateBondTierPolicy",
88
+ "openBondPosition",
89
+ "increaseBondPosition",
90
+ "requestBondUnlock",
91
+ "cancelBondUnlock",
92
+ "finalizeBondUnlock",
93
+ "syncBondStakingRewards",
94
+ "syncBondStakingPosition",
95
+ "claimBondStakingRewards",
96
+ "claimUnallocatedStakingRewards",
97
+ ]);
98
+
99
+ const satSubmissionWorkflowStorage = new AsyncLocalStorage<string>();
100
+
101
+ export async function runWithSatSubmissionWorkflow<T>(
102
+ workflowId: string,
103
+ task: () => Promise<T>,
104
+ ): Promise<T> {
105
+ const normalized = workflowId.trim();
106
+ if (!normalized || normalized.length > 240 || /[\u0000-\u001f\u007f]/u.test(normalized)) {
107
+ throw new Error("SAT submission idempotency key must contain 1-240 printable characters");
108
+ }
109
+ return await satSubmissionWorkflowStorage.run(normalized, task);
110
+ }
111
+
60
112
  function satSubmitDebug(message: string) {
61
113
  if (String(process.env.FASED_SAT_SUBMIT_DEBUG ?? "").trim() === "1") {
62
114
  console.error(message);
@@ -71,6 +123,21 @@ type SolanaAccountMeta = {
71
123
  isWritable: boolean;
72
124
  };
73
125
 
126
+ type SatSignerSemanticContext = {
127
+ targetAuthority?: string;
128
+ disputeAuthority?: string;
129
+ intervalStartCycleId?: string;
130
+ registryPageIndex?: string;
131
+ minerAuthorities?: string[];
132
+ frontCycleIds?: string[];
133
+ backCycleIds?: string[];
134
+ };
135
+
136
+ type SatResolvedInstruction = {
137
+ keys: SolanaAccountMeta[];
138
+ context?: SatSignerSemanticContext;
139
+ };
140
+
74
141
  let solanaModulePromise: Promise<SolanaModuleLike> | null = null;
75
142
 
76
143
  async function loadSolanaWeb3(): Promise<SolanaModuleLike> {
@@ -115,6 +182,11 @@ function resolveSatWalletId(cfg: FasedAgentConfig): string | undefined {
115
182
  return typeof value === "string" && value.trim() ? value.trim() : undefined;
116
183
  }
117
184
 
185
+ function resolveSatCluster(cfg: FasedAgentConfig): "local" | "devnet" | "mainnet-beta" {
186
+ const value = cfg.plugins?.entries?.["sat-mining"]?.config?.network;
187
+ return value === "local" || value === "mainnet-beta" || value === "devnet" ? value : "devnet";
188
+ }
189
+
118
190
  function resolveSatEffectiveEnv(cfg: FasedAgentConfig, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
119
191
  return {
120
192
  ...env,
@@ -125,92 +197,58 @@ function resolveSatEffectiveEnv(cfg: FasedAgentConfig, env: NodeJS.ProcessEnv):
125
197
  function resolveSatProviderId(cfg: FasedAgentConfig, env: NodeJS.ProcessEnv): string {
126
198
  const effectiveEnv = resolveSatEffectiveEnv(cfg, env);
127
199
  const walletId = resolveSatWalletId(cfg);
200
+ const signerSocket = String(effectiveEnv.FASED_WALLET_LOCAL_SIGNER_SOCKET ?? "").trim();
128
201
  if (walletId) {
129
- const hasSelfHostedSignerMaterial =
130
- String(effectiveEnv.FASED_WALLET_LOCAL_SIGNER_SOCKET ?? "").trim() ||
131
- String(effectiveEnv.FASED_WALLET_LOCAL_SIGNER_BACKEND_SOCKET ?? "").trim() ||
132
- String(
133
- walletEnvValue(effectiveEnv, "FASED_WALLET_SOLANA_KEYSTORE_PATH", walletId) ?? "",
134
- ).trim();
135
- try {
136
- const wallet = readWalletProviderRegistry(effectiveEnv).wallets.find(
137
- (entry) => entry.id === walletId,
202
+ const wallet = readWalletProviderRegistry(effectiveEnv).wallets.find(
203
+ (entry) => entry.id === walletId,
204
+ );
205
+ if (wallet?.providerId === "embedded-keystore") {
206
+ throw new Error(LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE);
207
+ }
208
+ if (wallet?.providerId && wallet.providerId !== "local-socket-signer") {
209
+ return wallet.providerId;
210
+ }
211
+ if (wallet?.providerId === "local-socket-signer" && !signerSocket) {
212
+ throw new Error(
213
+ "SAT mining requires the actual protocol-v2 fased-signerd application socket; legacy keystore paths and backend sockets are not signer capability.",
138
214
  );
139
- if (wallet?.providerId === "local-socket-signer") {
140
- return wallet.providerId;
141
- }
142
- if (hasSelfHostedSignerMaterial) {
143
- return "local-socket-signer";
144
- }
145
- if (wallet?.providerId) {
146
- return wallet.providerId;
147
- }
148
- } catch {}
149
- if (hasSelfHostedSignerMaterial) {
150
- return "local-socket-signer";
215
+ }
216
+ if (wallet?.providerId === "local-socket-signer") {
217
+ return wallet.providerId;
151
218
  }
152
219
  }
153
- return resolveWalletProviderId(cfg, effectiveEnv);
154
- }
155
-
156
- async function enforceSatCustodyAutonomousSigning(
157
- cfg: FasedAgentConfig,
158
- env: NodeJS.ProcessEnv,
159
- ): Promise<void> {
160
- const effectiveEnv = resolveSatEffectiveEnv(cfg, env);
161
- const walletCfg = resolveWalletRuntimeConfig(cfg, effectiveEnv);
162
- const walletId = resolveSatWalletId(cfg);
163
- if (walletCfg.execution.mode !== "autonomous") {
164
- return;
165
- }
166
- const custodyGate = await enforceWalletCustodyForAutonomousSend({
167
- wallet: walletCfg,
168
- env: effectiveEnv,
169
- cfg,
170
- walletId,
171
- approvalHost: String(
172
- effectiveEnv.FASED_WALLET_CUSTODY_ACTIVE_HOST ?? effectiveEnv.FASED_A2A_ORIGIN ?? "127.0.0.1",
173
- ),
174
- });
175
- if (!custodyGate.ok) {
176
- throw new Error(custodyGate.message);
177
- }
178
- }
179
-
180
- function resolveSatRegistrySolanaAddress(cfg: FasedAgentConfig, env: NodeJS.ProcessEnv): string {
181
- const effectiveEnv = resolveSatEffectiveEnv(cfg, env);
182
- const walletId = resolveSatWalletId(cfg);
183
- if (!walletId) {
184
- return "";
220
+ const providerId = resolveWalletProviderId(cfg, effectiveEnv);
221
+ if (providerId === "local-socket-signer" && !signerSocket) {
222
+ throw new Error(
223
+ "SAT mining requires the actual protocol-v2 fased-signerd application socket; configure FASED_WALLET_LOCAL_SIGNER_SOCKET.",
224
+ );
185
225
  }
186
- const wallet = readWalletProviderRegistry(effectiveEnv).wallets.find(
187
- (entry) => entry.id === walletId,
188
- );
189
- return typeof wallet?.addresses?.solana === "string" ? wallet.addresses.solana.trim() : "";
226
+ return providerId;
190
227
  }
191
228
 
192
229
  async function resolveSatLocalSignerAddress(
193
230
  cfg: FasedAgentConfig,
194
231
  env: NodeJS.ProcessEnv,
195
232
  errorMessage: string,
233
+ verifyCapabilities = true,
196
234
  ): Promise<string> {
197
235
  const effectiveEnv = resolveSatEffectiveEnv(cfg, env);
198
236
  const walletId = resolveSatWalletId(cfg);
199
- const result = await callLocalSocketSigner<{ solana?: string }>(
200
- requireLocalSocketSignerPath(effectiveEnv),
201
- {
202
- op: "getAddresses",
203
- ...(walletId ? { walletId } : {}),
204
- },
205
- );
206
- const signer = String(result.solana ?? "").trim();
237
+ if (!walletId) {
238
+ throw new Error("SAT mining local signer address lookup requires an attached walletId");
239
+ }
240
+ const socketPath = requireLocalSocketSignerPath(effectiveEnv);
241
+ if (verifyCapabilities) {
242
+ await requireTypedSatSignerCapabilities(socketPath, "solana.satAction");
243
+ }
244
+ const result = await callLocalSocketSigner<{ publicKey?: string }>(socketPath, {
245
+ op: "v2.wallet.get",
246
+ walletId,
247
+ });
248
+ const signer = String(result.publicKey ?? "").trim();
207
249
  if (signer) {
208
250
  return signer;
209
251
  }
210
- const fallback = resolveSatRegistrySolanaAddress(cfg, env);
211
- if (fallback) {
212
- return fallback;
213
- }
214
252
  throw new Error(errorMessage);
215
253
  }
216
254
 
@@ -275,7 +313,6 @@ function assertDedicatedBondProgram(env: NodeJS.ProcessEnv): void {
275
313
  export async function resolveSatValidatorAuthority(_config: SatMiningConfig) {
276
314
  const cfg = loadConfigForSatRuntime(_config);
277
315
  const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
278
- await enforceSatCustodyAutonomousSigning(cfg, effectiveEnv);
279
316
  if (resolveSatProviderId(cfg, effectiveEnv) !== "local-socket-signer") {
280
317
  throw new Error(
281
318
  "SAT mining unattended signing currently requires local-socket-signer for validator authority resolution",
@@ -291,10 +328,25 @@ export async function resolveSatValidatorAuthority(_config: SatMiningConfig) {
291
328
  type SatInstructionSubmitSpec = {
292
329
  data: Buffer;
293
330
  programId?: string;
331
+ addressLookupTables?: string[];
332
+ manageAddressLookupTable?: { lookupTableAddress?: string };
294
333
  accountResolver: (
295
334
  solana: SolanaModuleLike,
296
335
  signer: import("@solana/web3.js").PublicKey,
297
- ) => Promise<SolanaAccountMeta[]>;
336
+ ) => Promise<SolanaAccountMeta[] | SatResolvedInstruction>;
337
+ };
338
+
339
+ type SatInstructionSubmitResult = {
340
+ txHash: string;
341
+ signer: string;
342
+ signerState: SatSignerOperation["state"];
343
+ requestId: string;
344
+ transactionVersion: "legacy" | "v0";
345
+ lookupTableAddress?: string;
346
+ lookupTableCreated?: boolean;
347
+ lookupTableExtended?: boolean;
348
+ lookupTableAddressCount?: number;
349
+ lookupTableTransactionHashes?: string[];
298
350
  };
299
351
 
300
352
  async function prepareLocalSignerSubmitContext(cfg: FasedAgentConfig, env: NodeJS.ProcessEnv) {
@@ -306,6 +358,7 @@ async function prepareLocalSignerSubmitContext(cfg: FasedAgentConfig, env: NodeJ
306
358
  cfg,
307
359
  effectiveEnv,
308
360
  "local-socket-signer returned no Solana address for SAT mining wallet",
361
+ false,
309
362
  );
310
363
  const signer = new solana.PublicKey(signerAddress);
311
364
  return { effectiveEnv, solana, walletId, socketPath, signerAddress, signer };
@@ -314,22 +367,753 @@ async function prepareLocalSignerSubmitContext(cfg: FasedAgentConfig, env: NodeJ
314
367
  async function buildLocalSignerInstructionRequest(params: {
315
368
  solana: SolanaModuleLike;
316
369
  signer: import("@solana/web3.js").PublicKey;
317
- walletId?: string;
370
+ env: NodeJS.ProcessEnv;
318
371
  spec: SatInstructionSubmitSpec;
319
372
  }) {
320
- const keys = await params.spec.accountResolver(params.solana, params.signer);
373
+ const resolved = await params.spec.accountResolver(params.solana, params.signer);
374
+ const keys = Array.isArray(resolved) ? resolved : resolved.keys;
375
+ const context = Array.isArray(resolved) ? undefined : resolved.context;
376
+ const programId = params.spec.programId ?? resolveSatProgramIdFromEnv(params.env);
377
+ const mainProgramId = resolveSatProgramIdFromEnv(params.env);
378
+ const bondProgramId = resolveSatBondProgramIdFromEnv(params.env).trim() || undefined;
379
+ const codec = resolveSatSignerCodec({
380
+ programId,
381
+ mainProgramId,
382
+ bondProgramId,
383
+ data: params.spec.data,
384
+ });
321
385
  satSubmitDebug(
322
- `[sat-submit-debug] data_len=${params.spec.data.length} disc=${params.spec.data[0] ?? -1} keys=${keys.length}`,
386
+ `[sat-submit-debug] action=${codec.action} data_len=${params.spec.data.length} disc=${params.spec.data[0] ?? -1} keys=${keys.length}`,
323
387
  );
324
388
  return {
325
- ...(params.walletId ? { walletId: params.walletId } : {}),
326
- programId: params.spec.programId ?? SAT_PROGRAM_ID(),
389
+ action: codec.action,
390
+ programId,
327
391
  dataBase64: params.spec.data.toString("base64"),
328
392
  keys: keys.map((key) => ({
329
393
  pubkey: key.pubkey.toBase58(),
330
394
  isSigner: key.isSigner,
331
395
  isWritable: key.isWritable,
332
396
  })),
397
+ ...(params.spec.addressLookupTables?.length
398
+ ? { addressLookupTables: params.spec.addressLookupTables }
399
+ : {}),
400
+ ...(context ? { context } : {}),
401
+ };
402
+ }
403
+
404
+ type SatSignerOperation = {
405
+ requestId: string;
406
+ state: "reserved" | "broadcast" | "confirmed" | "failed" | "unknown";
407
+ signature?: string;
408
+ error?: string;
409
+ };
410
+
411
+ const REQUIRED_SAT_SIGNER_FEATURES = [
412
+ "failClosedPolicies",
413
+ "policyHashes",
414
+ "durableCaps",
415
+ "atomicIdempotency",
416
+ "ambiguousBroadcastReconciliation",
417
+ "signerOwnedKeys",
418
+ "typedSolanaTransactions",
419
+ "typedSATActions",
420
+ ] as const;
421
+
422
+ async function requireTypedSatSignerCapabilities(
423
+ socketPath: string,
424
+ intentType: "solana.satAction" | "solana.satLookupTable" | "solana.vaultBondAction",
425
+ ) {
426
+ const result = await callLocalSocketSigner<{
427
+ ready?: boolean;
428
+ capabilities?: {
429
+ protocol?: { current?: number; min?: number; max?: number };
430
+ intentTypes?: string[];
431
+ operationStates?: string[];
432
+ features?: string[];
433
+ };
434
+ }>(socketPath, { op: "v2.capabilities" });
435
+ const capabilities = result.capabilities;
436
+ const protocol = capabilities?.protocol;
437
+ const features = new Set(capabilities?.features ?? []);
438
+ const states = new Set(capabilities?.operationStates ?? []);
439
+ const missingFeatures = REQUIRED_SAT_SIGNER_FEATURES.filter((feature) => !features.has(feature));
440
+ const missingStates = ["reserved", "broadcast", "confirmed", "failed", "unknown"].filter(
441
+ (state) => !states.has(state),
442
+ );
443
+ const missingVaultReviewFeatures =
444
+ intentType === "solana.vaultBondAction"
445
+ ? [
446
+ "signerOwnedReviewPrepareExecute",
447
+ "exactPreparedTransactions",
448
+ "reviewedVaultBondActions",
449
+ "signerOwnedStateRecheck",
450
+ "durableReviewAuthorization",
451
+ ].filter((feature) => !features.has(feature))
452
+ : [];
453
+ const missingLookupFeatures =
454
+ intentType === "solana.satLookupTable" && !features.has("typedSATAddressLookupTables")
455
+ ? ["typedSATAddressLookupTables"]
456
+ : [];
457
+ if (
458
+ result.ready !== true ||
459
+ protocol?.current !== 2 ||
460
+ typeof protocol.min !== "number" ||
461
+ protocol.min > 2 ||
462
+ typeof protocol.max !== "number" ||
463
+ protocol.max < 2 ||
464
+ !capabilities?.intentTypes?.includes(intentType) ||
465
+ missingFeatures.length > 0 ||
466
+ missingLookupFeatures.length > 0 ||
467
+ (intentType === "solana.vaultBondAction" && !features.has("typedVaultBondActions")) ||
468
+ missingVaultReviewFeatures.length > 0 ||
469
+ missingStates.length > 0
470
+ ) {
471
+ throw new Error(
472
+ `local-socket-signer does not support the required typed SAT protocol-v2 contract${
473
+ missingFeatures.length > 0 ? `; missing features: ${missingFeatures.join(", ")}` : ""
474
+ }${missingVaultReviewFeatures.length > 0 ? `; missing reviewed Vault features: ${missingVaultReviewFeatures.join(", ")}` : ""}${
475
+ missingLookupFeatures.length > 0
476
+ ? `; missing SAT lookup features: ${missingLookupFeatures.join(", ")}`
477
+ : ""
478
+ }${missingStates.length > 0 ? `; missing states: ${missingStates.join(", ")}` : ""}`,
479
+ );
480
+ }
481
+ }
482
+
483
+ async function reconcileTypedSatOperation(params: {
484
+ socketPath: string;
485
+ walletId: string;
486
+ requestId: string;
487
+ operation?: SatSignerOperation;
488
+ }) {
489
+ let operation =
490
+ params.operation ??
491
+ (await callLocalSocketSigner<SatSignerOperation>(params.socketPath, {
492
+ op: "v2.operation.get",
493
+ walletId: params.walletId,
494
+ request: { requestId: params.requestId },
495
+ }));
496
+ if (operation.state === "broadcast" || operation.state === "unknown") {
497
+ try {
498
+ operation = await callLocalSocketSigner<SatSignerOperation>(params.socketPath, {
499
+ op: "v2.operation.reconcile",
500
+ walletId: params.walletId,
501
+ request: { requestId: params.requestId },
502
+ });
503
+ } catch {
504
+ // The durable signature and ambiguous state remain authoritative. Never
505
+ // replace this with a second request ID or another broadcast attempt.
506
+ }
507
+ }
508
+ return operation;
509
+ }
510
+
511
+ function assertSatSignerOperationIdentity(
512
+ operation: SatSignerOperation,
513
+ requestId: string,
514
+ ): SatSignerOperation {
515
+ if (operation.requestId !== requestId) {
516
+ throw new Error(
517
+ `SAT signer returned request ${operation.requestId || "<empty>"} while reconciling ${requestId}`,
518
+ );
519
+ }
520
+ return operation;
521
+ }
522
+
523
+ function signerStateForLedger(state: SatSignerOperation["state"]): SatSubmissionSignerState {
524
+ return state;
525
+ }
526
+
527
+ type SatLookupTableAction = "create" | "extend" | "deactivate" | "close";
528
+
529
+ function assertSatLookupTableAction(value: string): asserts value is SatLookupTableAction {
530
+ if (value !== "create" && value !== "extend" && value !== "deactivate" && value !== "close") {
531
+ throw new Error(`unsupported SAT lookup-table action ${value}`);
532
+ }
533
+ }
534
+
535
+ class SatSubmissionUnresolvedError extends Error {
536
+ readonly requestId: string;
537
+ readonly signature?: string;
538
+
539
+ constructor(params: { requestId: string; state: string; signature?: string; detail?: string }) {
540
+ super(
541
+ `SAT signer operation ${params.requestId} remains ${params.state}${
542
+ params.signature ? ` with signature ${params.signature}` : ""
543
+ }; it is unresolved and must be reconciled with the same idempotency key before any new submission${
544
+ params.detail ? ` (${params.detail})` : ""
545
+ }`,
546
+ );
547
+ this.name = "SatSubmissionUnresolvedError";
548
+ this.requestId = params.requestId;
549
+ this.signature = params.signature;
550
+ }
551
+ }
552
+
553
+ async function executeTypedSatIntent(params: {
554
+ socketPath: string;
555
+ walletId: string;
556
+ action: SatSignerAction | "cleanupBatch" | "create" | "extend" | "deactivate" | "close";
557
+ instruction?: Awaited<ReturnType<typeof buildLocalSignerInstructionRequest>>;
558
+ instructions?: Array<Awaited<ReturnType<typeof buildLocalSignerInstructionRequest>>>;
559
+ lookupTable?: { address: string; recentSlot?: string; addresses?: string[] };
560
+ cluster: "local" | "devnet" | "mainnet-beta";
561
+ env: NodeJS.ProcessEnv;
562
+ }) {
563
+ const isLookupTable = params.lookupTable != null;
564
+ const isVaultBond =
565
+ !isLookupTable &&
566
+ params.action !== "cleanupBatch" &&
567
+ VAULT_BOND_ACTIONS.has(params.action as SatSignerAction);
568
+ const intentType = isLookupTable
569
+ ? "solana.satLookupTable"
570
+ : isVaultBond
571
+ ? "solana.vaultBondAction"
572
+ : "solana.satAction";
573
+ await requireTypedSatSignerCapabilities(params.socketPath, intentType);
574
+ const intent = isLookupTable
575
+ ? (() => {
576
+ if (params.instruction || params.instructions || !params.lookupTable) {
577
+ throw new Error("typed SAT lookup-table execution accepts only semantic lookup details");
578
+ }
579
+ const action = params.action;
580
+ assertSatLookupTableAction(action);
581
+ return {
582
+ type: "solana.satLookupTable" as const,
583
+ action,
584
+ lookupTable: params.lookupTable,
585
+ };
586
+ })()
587
+ : isVaultBond
588
+ ? (() => {
589
+ if (!params.instruction || params.instructions) {
590
+ throw new Error("typed Vault bond execution requires exactly one semantic instruction");
591
+ }
592
+ return {
593
+ type: "solana.vaultBondAction" as const,
594
+ cluster: params.cluster,
595
+ ...params.instruction,
596
+ };
597
+ })()
598
+ : {
599
+ type: "solana.satAction" as const,
600
+ action: params.action,
601
+ ...(params.instruction ?? {}),
602
+ ...(params.instructions ? { instructions: params.instructions } : {}),
603
+ };
604
+ const policy = await callLocalSocketSigner<{ hash: string }>(params.socketPath, {
605
+ op: "v2.policy.get",
606
+ walletId: params.walletId,
607
+ });
608
+ const intentDigest = digestSatSubmissionIntent({
609
+ walletId: params.walletId,
610
+ policyHash: policy.hash,
611
+ intent,
612
+ });
613
+ const operationKey = buildSatSubmissionOperationKey(intent);
614
+ const workflowId =
615
+ satSubmissionWorkflowStorage.getStore() ?? `derived:${operationKey}:${intentDigest}`;
616
+ let claim = await claimSatSubmission({
617
+ walletId: params.walletId,
618
+ workflowId,
619
+ operationKey,
620
+ intentDigest,
621
+ action: params.action,
622
+ env: params.env,
623
+ });
624
+ if (!claim.claimed) {
625
+ await waitForSatSubmissionLease({
626
+ walletId: params.walletId,
627
+ requestId: claim.record.requestId,
628
+ env: params.env,
629
+ });
630
+ claim = await claimSatSubmission({
631
+ walletId: params.walletId,
632
+ workflowId,
633
+ operationKey,
634
+ intentDigest,
635
+ action: params.action,
636
+ env: params.env,
637
+ owner: claim.owner,
638
+ });
639
+ if (!claim.claimed) {
640
+ throw new Error(
641
+ `SAT submission ${claim.record.requestId} could not acquire its durable execution lease`,
642
+ );
643
+ }
644
+ }
645
+ const requestId = claim.record.requestId;
646
+ let resumedReviewedOperation: SatSignerOperation | undefined;
647
+ if (intent.type === "solana.vaultBondAction") {
648
+ let reviewWasSigned = false;
649
+ try {
650
+ let review: WalletProviderJupiterReviewV2;
651
+ try {
652
+ review = await callLocalSocketSigner<WalletProviderJupiterReviewV2>(params.socketPath, {
653
+ op: "v2.review.get",
654
+ walletId: params.walletId,
655
+ request: { requestId },
656
+ });
657
+ } catch (lookupError) {
658
+ if (!String(lookupError).includes("signer review not found")) {
659
+ throw lookupError;
660
+ }
661
+ review = await callLocalSocketSigner<WalletProviderJupiterReviewV2>(params.socketPath, {
662
+ op: "v2.review.prepare",
663
+ walletId: params.walletId,
664
+ request: {
665
+ requestId,
666
+ policyHash: policy.hash,
667
+ mode: "reviewed",
668
+ intent,
669
+ },
670
+ });
671
+ }
672
+ if (
673
+ review.requestId !== requestId ||
674
+ review.policyHash !== policy.hash ||
675
+ review.mode !== "reviewed" ||
676
+ review.intentType !== intent.type ||
677
+ !isDeepStrictEqual(review.semanticIntent, intent)
678
+ ) {
679
+ throw new Error(`Vault bond review ${requestId} does not match the exact SAT intent`);
680
+ }
681
+ if (review.state === "prepared") {
682
+ const approval = createSignerReviewApprovalRequest({
683
+ review,
684
+ role: "vault",
685
+ walletId: params.walletId,
686
+ requestedBy: "sat-mining-vault",
687
+ assetSymbol: "SAT",
688
+ assetName: "SAT bond",
689
+ memo: `Reviewed Vault bond action: ${intent.action}`,
690
+ env: params.env,
691
+ });
692
+ await updateSatSubmission({
693
+ walletId: params.walletId,
694
+ requestId,
695
+ intentDigest,
696
+ state: "reserved",
697
+ error: `review ${approval.id} pending`,
698
+ owner: claim.owner,
699
+ releaseLease: true,
700
+ env: params.env,
701
+ });
702
+ throw new Error(
703
+ `Vault bond review ${approval.id} is pending in Wallet Approvals for ${intent.action}; approve it there with the signer-owned passkey`,
704
+ );
705
+ }
706
+ reviewWasSigned = true;
707
+ resumedReviewedOperation = assertSatSignerOperationIdentity(
708
+ await reconcileTypedSatOperation({
709
+ socketPath: params.socketPath,
710
+ walletId: params.walletId,
711
+ requestId,
712
+ }),
713
+ requestId,
714
+ );
715
+ } catch (error) {
716
+ await updateSatSubmission({
717
+ walletId: params.walletId,
718
+ requestId,
719
+ intentDigest,
720
+ state: reviewWasSigned ? "unknown" : "reserved",
721
+ error: error instanceof Error ? error.message : String(error),
722
+ owner: claim.owner,
723
+ releaseLease: true,
724
+ env: params.env,
725
+ }).catch(() => undefined);
726
+ throw error;
727
+ }
728
+ }
729
+ const executeExactOrRecover = async (): Promise<SatSignerOperation> => {
730
+ try {
731
+ return await callLocalSocketSigner<SatSignerOperation>(params.socketPath, {
732
+ op: "v2.execute",
733
+ walletId: params.walletId,
734
+ request: {
735
+ requestId,
736
+ policyHash: policy.hash,
737
+ intent,
738
+ },
739
+ });
740
+ } catch (executeError) {
741
+ try {
742
+ return await callLocalSocketSigner<SatSignerOperation>(params.socketPath, {
743
+ op: "v2.operation.get",
744
+ walletId: params.walletId,
745
+ request: { requestId },
746
+ });
747
+ } catch (lookupError) {
748
+ const detail = `${executeError instanceof Error ? executeError.message : String(executeError)}; ${
749
+ lookupError instanceof Error ? lookupError.message : String(lookupError)
750
+ }`;
751
+ await updateSatSubmission({
752
+ walletId: params.walletId,
753
+ requestId,
754
+ intentDigest,
755
+ state:
756
+ claim.record.state === "confirmed" || claim.record.state === "failed"
757
+ ? claim.record.state
758
+ : "unknown",
759
+ ...(claim.record.signature ? { signature: claim.record.signature } : {}),
760
+ error: detail,
761
+ owner: claim.owner,
762
+ releaseLease: true,
763
+ env: params.env,
764
+ });
765
+ throw new SatSubmissionUnresolvedError({ requestId, state: "unknown", detail });
766
+ }
767
+ }
768
+ };
769
+ let operation: SatSignerOperation;
770
+ if (resumedReviewedOperation) {
771
+ operation = resumedReviewedOperation;
772
+ } else if (!claim.created) {
773
+ const callerStateWasAmbiguous =
774
+ claim.record.state === "broadcast" || claim.record.state === "unknown";
775
+ try {
776
+ operation = assertSatSignerOperationIdentity(
777
+ await callLocalSocketSigner<SatSignerOperation>(params.socketPath, {
778
+ op: "v2.operation.get",
779
+ walletId: params.walletId,
780
+ request: { requestId },
781
+ }),
782
+ requestId,
783
+ );
784
+ operation = assertSatSignerOperationIdentity(
785
+ await reconcileTypedSatOperation({
786
+ socketPath: params.socketPath,
787
+ walletId: params.walletId,
788
+ requestId,
789
+ operation,
790
+ }),
791
+ requestId,
792
+ );
793
+ } catch (lookupError) {
794
+ if (claim.record.signature) {
795
+ await updateSatSubmission({
796
+ walletId: params.walletId,
797
+ requestId,
798
+ intentDigest,
799
+ state: claim.record.state === "confirmed" ? "confirmed" : "unknown",
800
+ signature: claim.record.signature,
801
+ error: lookupError instanceof Error ? lookupError.message : String(lookupError),
802
+ owner: claim.owner,
803
+ releaseLease: true,
804
+ env: params.env,
805
+ });
806
+ throw new SatSubmissionUnresolvedError({
807
+ requestId,
808
+ state: claim.record.state === "confirmed" ? "confirmed-but-unverified" : "unknown",
809
+ signature: claim.record.signature,
810
+ detail: lookupError instanceof Error ? lookupError.message : String(lookupError),
811
+ });
812
+ }
813
+ if (claim.record.state === "failed" || claim.record.state === "confirmed") {
814
+ const detail = lookupError instanceof Error ? lookupError.message : String(lookupError);
815
+ await updateSatSubmission({
816
+ walletId: params.walletId,
817
+ requestId,
818
+ intentDigest,
819
+ state: claim.record.state,
820
+ error: detail,
821
+ owner: claim.owner,
822
+ releaseLease: true,
823
+ env: params.env,
824
+ });
825
+ if (claim.record.state === "failed") {
826
+ throw new Error(claim.record.error || `SAT signer operation ${requestId} failed`);
827
+ }
828
+ throw new SatSubmissionUnresolvedError({
829
+ requestId,
830
+ state: "confirmed-without-signature",
831
+ detail,
832
+ });
833
+ }
834
+ operation = await executeExactOrRecover();
835
+ }
836
+ if (operation.state === "reserved" && !operation.signature) {
837
+ if (callerStateWasAmbiguous) {
838
+ const detail = `signer regressed to reserved after caller persisted ${claim.record.state}`;
839
+ await updateSatSubmission({
840
+ walletId: params.walletId,
841
+ requestId,
842
+ intentDigest,
843
+ state: "unknown",
844
+ ...(claim.record.signature ? { signature: claim.record.signature } : {}),
845
+ error: detail,
846
+ owner: claim.owner,
847
+ releaseLease: true,
848
+ env: params.env,
849
+ });
850
+ throw new SatSubmissionUnresolvedError({
851
+ requestId,
852
+ state: "unknown",
853
+ signature: claim.record.signature,
854
+ detail,
855
+ });
856
+ }
857
+ operation = await executeExactOrRecover();
858
+ }
859
+ } else {
860
+ operation = await executeExactOrRecover();
861
+ }
862
+ try {
863
+ operation = assertSatSignerOperationIdentity(operation, requestId);
864
+ operation = assertSatSignerOperationIdentity(
865
+ await reconcileTypedSatOperation({
866
+ socketPath: params.socketPath,
867
+ walletId: params.walletId,
868
+ requestId,
869
+ operation,
870
+ }),
871
+ requestId,
872
+ );
873
+ } catch (error) {
874
+ const detail = error instanceof Error ? error.message : String(error);
875
+ await updateSatSubmission({
876
+ walletId: params.walletId,
877
+ requestId,
878
+ intentDigest,
879
+ state:
880
+ claim.record.state === "confirmed" || claim.record.state === "failed"
881
+ ? claim.record.state
882
+ : "unknown",
883
+ ...(claim.record.signature ? { signature: claim.record.signature } : {}),
884
+ error: detail,
885
+ owner: claim.owner,
886
+ releaseLease: true,
887
+ env: params.env,
888
+ });
889
+ throw new SatSubmissionUnresolvedError({ requestId, state: "unknown", detail });
890
+ }
891
+ await updateSatSubmission({
892
+ walletId: params.walletId,
893
+ requestId,
894
+ intentDigest,
895
+ state: signerStateForLedger(operation.state),
896
+ ...(operation.signature ? { signature: operation.signature } : {}),
897
+ ...(operation.error ? { error: operation.error } : {}),
898
+ owner: claim.owner,
899
+ releaseLease: true,
900
+ env: params.env,
901
+ });
902
+ if (operation.state === "failed") {
903
+ throw new Error(operation.error || `SAT signer operation ${requestId} failed`);
904
+ }
905
+ if (operation.state !== "confirmed" || !operation.signature) {
906
+ throw new SatSubmissionUnresolvedError({
907
+ requestId,
908
+ state: operation.state,
909
+ signature: operation.signature,
910
+ detail: operation.error,
911
+ });
912
+ }
913
+ return { ...operation, signature: operation.signature };
914
+ }
915
+
916
+ type SatLookupSubmitContext = Awaited<ReturnType<typeof prepareLocalSignerSubmitContext>> & {
917
+ walletId: string;
918
+ };
919
+
920
+ function assertSatLookupTableEnabled(env: NodeJS.ProcessEnv): void {
921
+ if (String(env.FASED_SAT_ENABLE_ALT_V0 ?? "").trim() !== "1") {
922
+ throw new Error("SAT ALT/v0 support is disabled; set FASED_SAT_ENABLE_ALT_V0=1");
923
+ }
924
+ }
925
+
926
+ async function executeTypedSatLookupOperation(params: {
927
+ context: SatLookupSubmitContext;
928
+ cfg: FasedAgentConfig;
929
+ action: "create" | "extend" | "deactivate" | "close";
930
+ address: string;
931
+ recentSlot?: number;
932
+ addresses?: string[];
933
+ }) {
934
+ return await executeTypedSatIntent({
935
+ socketPath: params.context.socketPath,
936
+ walletId: params.context.walletId,
937
+ action: params.action,
938
+ lookupTable: {
939
+ address: params.address,
940
+ ...(params.recentSlot == null ? {} : { recentSlot: String(params.recentSlot) }),
941
+ ...(params.addresses?.length ? { addresses: params.addresses } : {}),
942
+ },
943
+ cluster: resolveSatCluster(params.cfg),
944
+ env: params.context.effectiveEnv,
945
+ });
946
+ }
947
+
948
+ async function readValidatedSatLookupTable(params: {
949
+ config: SatMiningConfig;
950
+ address: string;
951
+ authority: string;
952
+ }) {
953
+ const state = await inspectSatAddressLookupTable(params.config, { address: params.address });
954
+ if (!state) {
955
+ return null;
956
+ }
957
+ if (state.authority !== params.authority) {
958
+ throw new Error("SAT distribution lookup table is not controlled by the Mining signer");
959
+ }
960
+ if (!state.active) {
961
+ throw new Error("SAT distribution lookup table is not active");
962
+ }
963
+ return state;
964
+ }
965
+
966
+ async function waitForSatLookupTable(params: {
967
+ config: SatMiningConfig;
968
+ address: string;
969
+ authority: string;
970
+ requireNextSlot: boolean;
971
+ }) {
972
+ let lastError: unknown;
973
+ for (let attempt = 0; attempt < 24; attempt += 1) {
974
+ try {
975
+ const state = await readValidatedSatLookupTable(params);
976
+ if (state) {
977
+ const currentSlot = await inspectSatChainSlot(params.config);
978
+ if (!params.requireNextSlot || currentSlot > state.lastExtendedSlot) {
979
+ return state;
980
+ }
981
+ }
982
+ } catch (error) {
983
+ lastError = error;
984
+ }
985
+ await new Promise((resolve) => setTimeout(resolve, 250));
986
+ }
987
+ throw new Error(
988
+ `SAT distribution lookup table did not become active for use within 6s${
989
+ lastError instanceof Error ? `: ${lastError.message}` : ""
990
+ }`,
991
+ );
992
+ }
993
+
994
+ async function ensureSatDistributionLookupTable(params: {
995
+ context: SatLookupSubmitContext;
996
+ cfg: FasedAgentConfig;
997
+ config: SatMiningConfig;
998
+ lookupTableAddress?: string;
999
+ addresses: string[];
1000
+ }) {
1001
+ assertSatLookupTableEnabled(params.context.effectiveEnv);
1002
+ const desiredAddresses = [...new Set(params.addresses.map((entry) => entry.trim()))].filter(
1003
+ Boolean,
1004
+ );
1005
+ if (desiredAddresses.length === 0 || desiredAddresses.length > 256) {
1006
+ throw new Error("SAT distribution lookup table requires 1-256 exact account addresses");
1007
+ }
1008
+ let lookupTable = params.lookupTableAddress?.trim() ?? "";
1009
+ let state = lookupTable
1010
+ ? await readValidatedSatLookupTable({
1011
+ config: params.config,
1012
+ address: lookupTable,
1013
+ authority: params.context.signerAddress,
1014
+ })
1015
+ : null;
1016
+ let created = false;
1017
+ const transactionHashes: string[] = [];
1018
+ if (!lookupTable) {
1019
+ const currentSlot = await inspectSatChainSlot(params.config);
1020
+ const recentSlot = Math.max(0, currentSlot - 1);
1021
+ const [, derivedAddress] = params.context.solana.AddressLookupTableProgram.createLookupTable({
1022
+ authority: params.context.signer,
1023
+ payer: params.context.signer,
1024
+ recentSlot,
1025
+ });
1026
+ lookupTable = derivedAddress.toBase58();
1027
+ state = await readValidatedSatLookupTable({
1028
+ config: params.config,
1029
+ address: lookupTable,
1030
+ authority: params.context.signerAddress,
1031
+ });
1032
+ if (!state) {
1033
+ try {
1034
+ const submitted = await executeTypedSatLookupOperation({
1035
+ context: params.context,
1036
+ cfg: params.cfg,
1037
+ action: "create",
1038
+ address: lookupTable,
1039
+ recentSlot,
1040
+ });
1041
+ transactionHashes.push(submitted.signature);
1042
+ created = true;
1043
+ } catch (error) {
1044
+ if (error instanceof SatSubmissionUnresolvedError) {
1045
+ throw error;
1046
+ }
1047
+ try {
1048
+ state = await waitForSatLookupTable({
1049
+ config: params.config,
1050
+ address: lookupTable,
1051
+ authority: params.context.signerAddress,
1052
+ requireNextSlot: false,
1053
+ });
1054
+ } catch {
1055
+ throw error;
1056
+ }
1057
+ }
1058
+ state ??= await waitForSatLookupTable({
1059
+ config: params.config,
1060
+ address: lookupTable,
1061
+ authority: params.context.signerAddress,
1062
+ requireNextSlot: false,
1063
+ });
1064
+ }
1065
+ }
1066
+ if (!state) {
1067
+ throw new Error("SAT distribution lookup table was not found at the confirmed commitment");
1068
+ }
1069
+ const existing = new Set(state.addresses);
1070
+ const missing = desiredAddresses.filter((entry) => !existing.has(entry));
1071
+ for (let offset = 0; offset < missing.length; offset += SAT_LOOKUP_TABLE_EXTEND_CHUNK_SIZE) {
1072
+ const addresses = missing.slice(offset, offset + SAT_LOOKUP_TABLE_EXTEND_CHUNK_SIZE);
1073
+ try {
1074
+ const submitted = await executeTypedSatLookupOperation({
1075
+ context: params.context,
1076
+ cfg: params.cfg,
1077
+ action: "extend",
1078
+ address: lookupTable,
1079
+ addresses,
1080
+ });
1081
+ transactionHashes.push(submitted.signature);
1082
+ } catch (error) {
1083
+ if (error instanceof SatSubmissionUnresolvedError) {
1084
+ throw error;
1085
+ }
1086
+ const concurrentState = await waitForSatLookupTable({
1087
+ config: params.config,
1088
+ address: lookupTable,
1089
+ authority: params.context.signerAddress,
1090
+ requireNextSlot: false,
1091
+ }).catch(() => null);
1092
+ if (
1093
+ !concurrentState ||
1094
+ addresses.some((address) => !concurrentState.addresses.includes(address))
1095
+ ) {
1096
+ throw error;
1097
+ }
1098
+ }
1099
+ }
1100
+ const ready = await waitForSatLookupTable({
1101
+ config: params.config,
1102
+ address: lookupTable,
1103
+ authority: params.context.signerAddress,
1104
+ requireNextSlot: true,
1105
+ });
1106
+ for (const address of desiredAddresses) {
1107
+ if (!ready.addresses.includes(address)) {
1108
+ throw new Error(`SAT distribution lookup table did not persist required account ${address}`);
1109
+ }
1110
+ }
1111
+ return {
1112
+ lookupTable,
1113
+ created,
1114
+ extended: missing.length > 0,
1115
+ addressCount: ready.addresses.length,
1116
+ transactionHashes,
333
1117
  };
334
1118
  }
335
1119
 
@@ -338,39 +1122,67 @@ async function submitInstructionViaLocalSigner(
338
1122
  cfg: FasedAgentConfig;
339
1123
  env: NodeJS.ProcessEnv;
340
1124
  } & SatInstructionSubmitSpec,
341
- ) {
1125
+ ): Promise<SatInstructionSubmitResult> {
342
1126
  const context = await prepareLocalSignerSubmitContext(params.cfg, params.env);
343
- const request = await buildLocalSignerInstructionRequest({
1127
+ const baseRequest = await buildLocalSignerInstructionRequest({
344
1128
  solana: context.solana,
345
1129
  signer: context.signer,
346
- walletId: context.walletId,
1130
+ env: context.effectiveEnv,
347
1131
  spec: params,
348
1132
  });
349
- const submitted = await callLocalSocketSigner<{ txHash: string; signer?: string }>(
350
- context.socketPath,
351
- {
352
- op: "sendSolanaInstruction",
353
- request,
354
- },
355
- );
1133
+ if (!context.walletId) {
1134
+ throw new Error("typed SAT signing requires an explicit mining walletId");
1135
+ }
1136
+ let managedLookupTable: Awaited<ReturnType<typeof ensureSatDistributionLookupTable>> | undefined;
1137
+ if (params.manageAddressLookupTable) {
1138
+ managedLookupTable = await ensureSatDistributionLookupTable({
1139
+ context: { ...context, walletId: context.walletId },
1140
+ cfg: params.cfg,
1141
+ config: params.cfg as unknown as SatMiningConfig,
1142
+ lookupTableAddress: params.manageAddressLookupTable.lookupTableAddress,
1143
+ addresses: baseRequest.keys.filter((key) => !key.isSigner).map((key) => key.pubkey),
1144
+ });
1145
+ }
1146
+ const request = managedLookupTable
1147
+ ? { ...baseRequest, addressLookupTables: [managedLookupTable.lookupTable] }
1148
+ : baseRequest;
1149
+ const submitted = await executeTypedSatIntent({
1150
+ socketPath: context.socketPath,
1151
+ walletId: context.walletId,
1152
+ action: request.action,
1153
+ instruction: request,
1154
+ cluster: resolveSatCluster(params.cfg),
1155
+ env: context.effectiveEnv,
1156
+ });
356
1157
  return {
357
- txHash: submitted.txHash,
358
- signer: submitted.signer ?? context.signerAddress,
1158
+ txHash: submitted.signature,
1159
+ signer: context.signerAddress,
1160
+ signerState: submitted.state,
1161
+ requestId: submitted.requestId,
1162
+ ...(request.addressLookupTables?.length
1163
+ ? {
1164
+ transactionVersion: "v0" as const,
1165
+ lookupTableAddress: request.addressLookupTables[0],
1166
+ }
1167
+ : { transactionVersion: "legacy" as const }),
1168
+ ...(managedLookupTable
1169
+ ? {
1170
+ lookupTableCreated: managedLookupTable.created,
1171
+ lookupTableExtended: managedLookupTable.extended,
1172
+ lookupTableAddressCount: managedLookupTable.addressCount,
1173
+ lookupTableTransactionHashes: managedLookupTable.transactionHashes,
1174
+ }
1175
+ : {}),
359
1176
  };
360
1177
  }
361
1178
 
362
- async function submitInstruction(params: {
363
- cfg: FasedAgentConfig;
364
- env: NodeJS.ProcessEnv;
365
- data: Buffer;
366
- programId?: string;
367
- accountResolver: (
368
- solana: SolanaModuleLike,
369
- signer: import("@solana/web3.js").PublicKey,
370
- ) => Promise<import("@solana/web3.js").AccountMeta[]>;
371
- }) {
1179
+ async function submitInstruction(
1180
+ params: {
1181
+ cfg: FasedAgentConfig;
1182
+ env: NodeJS.ProcessEnv;
1183
+ } & SatInstructionSubmitSpec,
1184
+ ) {
372
1185
  const effectiveEnv = resolveSatEffectiveEnv(params.cfg, params.env);
373
- await enforceSatCustodyAutonomousSigning(params.cfg, effectiveEnv);
374
1186
  if (resolveSatProviderId(params.cfg, effectiveEnv) !== "local-socket-signer") {
375
1187
  throw new Error("SAT mining unattended submission currently requires local-socket-signer");
376
1188
  }
@@ -379,6 +1191,8 @@ async function submitInstruction(params: {
379
1191
  env: effectiveEnv,
380
1192
  data: params.data,
381
1193
  programId: params.programId,
1194
+ addressLookupTables: params.addressLookupTables,
1195
+ manageAddressLookupTable: params.manageAddressLookupTable,
382
1196
  accountResolver: params.accountResolver,
383
1197
  });
384
1198
  }
@@ -396,7 +1210,6 @@ async function submitInstructionBatch(params: {
396
1210
  throw new Error("SAT cleanup batch exceeds signer limit");
397
1211
  }
398
1212
  const effectiveEnv = resolveSatEffectiveEnv(params.cfg, params.env);
399
- await enforceSatCustodyAutonomousSigning(params.cfg, effectiveEnv);
400
1213
  if (resolveSatProviderId(params.cfg, effectiveEnv) !== "local-socket-signer") {
401
1214
  throw new Error(
402
1215
  "SAT mining unattended batch submission currently requires local-socket-signer",
@@ -409,26 +1222,27 @@ async function submitInstructionBatch(params: {
409
1222
  await buildLocalSignerInstructionRequest({
410
1223
  solana: context.solana,
411
1224
  signer: context.signer,
412
- walletId: context.walletId,
1225
+ env: context.effectiveEnv,
413
1226
  spec,
414
1227
  }),
415
1228
  );
416
1229
  }
417
- const submitted = await callLocalSocketSigner<{
418
- txHash: string;
419
- signer?: string;
420
- metadata?: Record<string, unknown>;
421
- }>(context.socketPath, {
422
- op: "sendSolanaInstructions",
423
- request: {
424
- ...(context.walletId ? { walletId: context.walletId } : {}),
425
- purpose: params.purpose,
426
- instructions,
427
- },
1230
+ if (!context.walletId) {
1231
+ throw new Error("typed SAT cleanup signing requires an explicit mining walletId");
1232
+ }
1233
+ const submitted = await executeTypedSatIntent({
1234
+ socketPath: context.socketPath,
1235
+ walletId: context.walletId,
1236
+ action: "cleanupBatch",
1237
+ instructions,
1238
+ cluster: resolveSatCluster(params.cfg),
1239
+ env: context.effectiveEnv,
428
1240
  });
429
1241
  return {
430
- txHash: submitted.txHash,
431
- signer: submitted.signer ?? context.signerAddress,
1242
+ txHash: submitted.signature,
1243
+ signer: context.signerAddress,
1244
+ signerState: submitted.state,
1245
+ requestId: submitted.requestId,
432
1246
  instructionCount: instructions.length,
433
1247
  };
434
1248
  }
@@ -568,11 +1382,10 @@ function buildMiningCrankData() {
568
1382
  return Buffer.from([IX.miningCrank]);
569
1383
  }
570
1384
 
571
- function buildBootstrapData(params: { authority: string; initialStake: number }) {
1385
+ function buildTopUpRegistryReserveData(params: { targetBalanceLamports: number }) {
572
1386
  return Buffer.concat([
573
- Buffer.from([IX.bootstrap]),
574
- encodePubkey(params.authority),
575
- encodeU64(params.initialStake),
1387
+ Buffer.from([IX.topUpRegistryReserve]),
1388
+ encodeU64(params.targetBalanceLamports),
576
1389
  ]);
577
1390
  }
578
1391
 
@@ -596,23 +1409,6 @@ function buildSetActiveCommitData(params: { lamports: number }) {
596
1409
  return Buffer.concat([Buffer.from([IX.setActiveCommit]), encodeU64(params.lamports)]);
597
1410
  }
598
1411
 
599
- function buildInitBondTierPolicyData(params: {
600
- updateAuthority: string;
601
- basicMinRaw: number;
602
- operatorMinRaw: number;
603
- unlockDelaySlots: number;
604
- scheduledEffectiveSlot?: number;
605
- }) {
606
- return Buffer.concat([
607
- Buffer.from([BOND_IX.initTierPolicy]),
608
- encodePubkey(params.updateAuthority),
609
- encodeU64(params.basicMinRaw),
610
- encodeU64(params.operatorMinRaw),
611
- encodeU64(params.unlockDelaySlots),
612
- encodeU64(params.scheduledEffectiveSlot ?? 0),
613
- ]);
614
- }
615
-
616
1412
  function buildUpdateBondTierPolicyData(params: {
617
1413
  updateAuthority: string;
618
1414
  basicMinRaw: number;
@@ -661,18 +1457,6 @@ function buildFinalizeBondUnlockData(env: NodeJS.ProcessEnv = process.env) {
661
1457
  return Buffer.from([BOND_IX.finalizeBondUnlock]);
662
1458
  }
663
1459
 
664
- function buildInitBondStakingDistributorData(
665
- params: { updateAuthority: string; minStakeRaw: number },
666
- env: NodeJS.ProcessEnv = process.env,
667
- ) {
668
- assertDedicatedBondProgram(env);
669
- return Buffer.concat([
670
- Buffer.from([BOND_IX.initStakingDistributor]),
671
- encodePubkey(params.updateAuthority),
672
- encodeU64(params.minStakeRaw),
673
- ]);
674
- }
675
-
676
1460
  function buildSyncBondStakingRewardsData(env: NodeJS.ProcessEnv = process.env) {
677
1461
  assertDedicatedBondProgram(env);
678
1462
  return Buffer.from([BOND_IX.syncStakingRewards]);
@@ -688,26 +1472,96 @@ function buildClaimBondStakingRewardsData(env: NodeJS.ProcessEnv = process.env)
688
1472
  return Buffer.from([BOND_IX.claimStakingRewards]);
689
1473
  }
690
1474
 
691
- function buildSubmitCycleData(params: { cycleId: number; allocationFp: number[] }) {
692
- if (params.allocationFp.length !== 25) {
693
- throw new Error(`expected 25 allocation buckets, got ${params.allocationFp.length}`);
1475
+ function buildClaimUnallocatedStakingRewardsData(env: NodeJS.ProcessEnv = process.env) {
1476
+ assertDedicatedBondProgram(env);
1477
+ return Buffer.from([BOND_IX.claimUnallocatedStakingRewards]);
1478
+ }
1479
+
1480
+ function encodeAllocationFp(allocationFp: number[]): Buffer {
1481
+ if (allocationFp.length !== 25) {
1482
+ throw new Error(`expected 25 allocation buckets, got ${allocationFp.length}`);
694
1483
  }
695
- const body = Buffer.concat([
696
- Buffer.from([IX.submitCycle]),
697
- encodeU64(params.cycleId),
698
- Buffer.concat(
699
- params.allocationFp.map((value) => {
700
- const out = Buffer.alloc(4);
701
- out.writeUInt32LE(value);
702
- return out;
703
- }),
704
- ),
1484
+ return Buffer.concat(
1485
+ allocationFp.map((value) => {
1486
+ if (!Number.isSafeInteger(value) || value < 0 || value > 0xffff_ffff) {
1487
+ throw new Error(`invalid allocation bucket value: ${value}`);
1488
+ }
1489
+ const out = Buffer.alloc(4);
1490
+ out.writeUInt32LE(value);
1491
+ return out;
1492
+ }),
1493
+ );
1494
+ }
1495
+
1496
+ export function buildSatCycleCommitment(params: {
1497
+ authority: string;
1498
+ cycleId: number;
1499
+ committedLamports: number;
1500
+ nonce: Buffer;
1501
+ allocationFp: number[];
1502
+ programId?: string;
1503
+ }): Buffer {
1504
+ if (params.nonce.length !== 32) {
1505
+ throw new Error(`expected 32-byte cycle nonce, got ${params.nonce.length}`);
1506
+ }
1507
+ const allocation = encodeAllocationFp(params.allocationFp);
1508
+ return createHash("sha256")
1509
+ .update(
1510
+ Buffer.concat([
1511
+ Buffer.from("sat-cycle-commit-v1"),
1512
+ encodePubkey(params.programId ?? SAT_PROGRAM_ID()),
1513
+ encodePubkey(params.authority),
1514
+ encodeU64(params.cycleId),
1515
+ encodeU64(params.committedLamports),
1516
+ params.nonce,
1517
+ allocation,
1518
+ ]),
1519
+ )
1520
+ .digest();
1521
+ }
1522
+
1523
+ function buildCommitCycleData(params: { cycleId: number; commitment: Buffer }) {
1524
+ if (params.commitment.length !== 32) {
1525
+ throw new Error(`expected 32-byte cycle commitment, got ${params.commitment.length}`);
1526
+ }
1527
+ return Buffer.concat([
1528
+ Buffer.from([IX.commitCycle]),
1529
+ encodeU64(params.cycleId),
1530
+ params.commitment,
1531
+ ]);
1532
+ }
1533
+
1534
+ function buildCloseCommitPhaseData(params: { cycleId: number }) {
1535
+ return Buffer.concat([Buffer.from([IX.closeCommitPhase]), encodeU64(params.cycleId)]);
1536
+ }
1537
+
1538
+ function buildSealCycleEntropyData(params: { cycleId: number }) {
1539
+ return Buffer.concat([Buffer.from([IX.sealCycleEntropy]), encodeU64(params.cycleId)]);
1540
+ }
1541
+
1542
+ function buildRevealCycleData(params: { cycleId: number; nonce: Buffer; allocationFp: number[] }) {
1543
+ if (params.nonce.length !== 32) {
1544
+ throw new Error(`expected 32-byte cycle nonce, got ${params.nonce.length}`);
1545
+ }
1546
+ return Buffer.concat([
1547
+ Buffer.from([IX.revealCycle]),
1548
+ encodeU64(params.cycleId),
1549
+ params.nonce,
1550
+ encodeAllocationFp(params.allocationFp),
705
1551
  Buffer.alloc(4),
706
1552
  ]);
707
- satSubmitDebug(
708
- `[sat-submit-build] allocs=${params.allocationFp.length} len=${body.length} cycle=${params.cycleId}`,
709
- );
710
- return body;
1553
+ }
1554
+
1555
+ function buildReleaseUnrevealedCommitData(params: { cycleId: number; minerAuthority: string }) {
1556
+ return Buffer.concat([
1557
+ Buffer.from([IX.releaseUnrevealedCommit]),
1558
+ encodeU64(params.cycleId),
1559
+ encodePubkey(params.minerAuthority),
1560
+ ]);
1561
+ }
1562
+
1563
+ function buildAbortEmptyCycleData(params: { cycleId: number }) {
1564
+ return Buffer.concat([Buffer.from([IX.abortEmptyCycle]), encodeU64(params.cycleId)]);
711
1565
  }
712
1566
 
713
1567
  function buildClaimCycleRewardsData(params: { cycleId: number }) {
@@ -728,17 +1582,6 @@ function buildClaimCycleRewardsBatchData(params: { cycleIds: number[] }) {
728
1582
  ]);
729
1583
  }
730
1584
 
731
- function buildSetProtocolRecipientsData(params: {
732
- treasuryRecipient: string;
733
- distributorRecipient: string;
734
- }) {
735
- return Buffer.concat([
736
- Buffer.from([IX.setProtocolRecipients]),
737
- encodePubkey(params.treasuryRecipient),
738
- encodePubkey(params.distributorRecipient),
739
- ]);
740
- }
741
-
742
1585
  function buildClaimProtocolTreasuryData() {
743
1586
  return Buffer.from([IX.claimProtocolTreasury]);
744
1587
  }
@@ -924,13 +1767,16 @@ export async function submitSatValidatorAttestation(
924
1767
  [Buffer.from(MINING_STAKE_SEED), targetAuthority.toBuffer()],
925
1768
  programId,
926
1769
  );
927
- return [
928
- { pubkey: signer, isSigner: true, isWritable: true },
929
- { pubkey: satEpoch, isSigner: false, isWritable: true },
930
- { pubkey: satValidatorAttestation, isSigner: false, isWritable: true },
931
- { pubkey: miningStake, isSigner: false, isWritable: true },
932
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
933
- ];
1770
+ return {
1771
+ keys: [
1772
+ { pubkey: signer, isSigner: true, isWritable: true },
1773
+ { pubkey: satEpoch, isSigner: false, isWritable: true },
1774
+ { pubkey: satValidatorAttestation, isSigner: false, isWritable: true },
1775
+ { pubkey: miningStake, isSigner: false, isWritable: true },
1776
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1777
+ ],
1778
+ context: { targetAuthority: targetAuthority.toBase58() },
1779
+ };
934
1780
  },
935
1781
  });
936
1782
  }
@@ -967,13 +1813,16 @@ export async function submitSatOpenDispute(
967
1813
  [Buffer.from(MINING_STAKE_SEED), targetAuthority.toBuffer()],
968
1814
  programId,
969
1815
  );
970
- return [
971
- { pubkey: signer, isSigner: true, isWritable: true },
972
- { pubkey: satEpoch, isSigner: false, isWritable: true },
973
- { pubkey: satDispute, isSigner: false, isWritable: true },
974
- { pubkey: miningStake, isSigner: false, isWritable: true },
975
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
976
- ];
1816
+ return {
1817
+ keys: [
1818
+ { pubkey: signer, isSigner: true, isWritable: true },
1819
+ { pubkey: satEpoch, isSigner: false, isWritable: true },
1820
+ { pubkey: satDispute, isSigner: false, isWritable: true },
1821
+ { pubkey: miningStake, isSigner: false, isWritable: true },
1822
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1823
+ ],
1824
+ context: { targetAuthority: targetAuthority.toBase58() },
1825
+ };
977
1826
  },
978
1827
  });
979
1828
  }
@@ -1009,12 +1858,15 @@ export async function submitSatResolveDispute(
1009
1858
  ],
1010
1859
  programId,
1011
1860
  );
1012
- return [
1013
- { pubkey: signer, isSigner: true, isWritable: true },
1014
- { pubkey: miningPool, isSigner: false, isWritable: false },
1015
- { pubkey: satEpoch, isSigner: false, isWritable: true },
1016
- { pubkey: satDispute, isSigner: false, isWritable: true },
1017
- ];
1861
+ return {
1862
+ keys: [
1863
+ { pubkey: signer, isSigner: true, isWritable: true },
1864
+ { pubkey: miningPool, isSigner: false, isWritable: false },
1865
+ { pubkey: satEpoch, isSigner: false, isWritable: true },
1866
+ { pubkey: satDispute, isSigner: false, isWritable: true },
1867
+ ],
1868
+ context: { disputeAuthority: disputeAuthority.toBase58() },
1869
+ };
1018
1870
  },
1019
1871
  });
1020
1872
  }
@@ -1047,53 +1899,37 @@ export async function submitSatRepublishEpochRoots(
1047
1899
  });
1048
1900
  }
1049
1901
 
1050
- export async function submitSatBootstrap(
1902
+ export async function submitSatTopUpRegistryReserve(
1051
1903
  _config: SatMiningConfig,
1052
- params: { authority?: string; initialStake?: number } = {},
1904
+ params: { targetBalanceLamports: number },
1053
1905
  ) {
1054
1906
  const cfg = loadConfigForSatRuntime(_config);
1907
+ const targetBalanceLamports = Math.max(0, Math.floor(params.targetBalanceLamports));
1908
+ if (!Number.isSafeInteger(targetBalanceLamports)) {
1909
+ throw new Error("registry reserve target must be a safe integer lamport amount");
1910
+ }
1911
+ const profile = resolveSatGenesisProfileContract(_config.network);
1912
+ if (BigInt(targetBalanceLamports) > profile.registryReserveMaxLamports) {
1913
+ throw new Error(
1914
+ `registry reserve target exceeds ${profile.cluster} genesis maximum ${profile.registryReserveMaxLamports}`,
1915
+ );
1916
+ }
1055
1917
  return submitInstruction({
1056
1918
  cfg,
1057
1919
  env: process.env,
1058
- data: buildBootstrapData({
1059
- authority: params.authority ?? "",
1060
- initialStake: Math.max(0, Math.floor(params.initialStake ?? 0)),
1920
+ data: buildTopUpRegistryReserveData({
1921
+ targetBalanceLamports,
1061
1922
  }),
1062
1923
  accountResolver: async (solana, signer) => {
1063
1924
  const programId = new solana.PublicKey(SAT_PROGRAM_ID());
1064
- const [satGlobalState] = solana.PublicKey.findProgramAddressSync(
1065
- [Buffer.from(SAT_GLOBAL_STATE_SEED)],
1066
- programId,
1067
- );
1068
- const [treasury] = solana.PublicKey.findProgramAddressSync(
1069
- [Buffer.from("treasury")],
1070
- programId,
1071
- );
1072
- const [satTreasuryState] = solana.PublicKey.findProgramAddressSync(
1073
- [Buffer.from(SAT_TREASURY_STATE_SEED)],
1074
- programId,
1075
- );
1076
1925
  const [satRegistryReserve] = solana.PublicKey.findProgramAddressSync(
1077
1926
  [Buffer.from(SAT_REGISTRY_RESERVE_SEED)],
1078
1927
  programId,
1079
1928
  );
1080
- const [satRebateVault] = solana.PublicKey.findProgramAddressSync(
1081
- [Buffer.from(SAT_REBATE_VAULT_SEED)],
1082
- programId,
1083
- );
1084
- const [satTreasuryVault] = solana.PublicKey.findProgramAddressSync(
1085
- [Buffer.from(SAT_TREASURY_VAULT_SEED)],
1086
- programId,
1087
- );
1088
1929
  return [
1089
1930
  { pubkey: signer, isSigner: true, isWritable: true },
1090
- { pubkey: satGlobalState, isSigner: false, isWritable: true },
1091
- { pubkey: treasury, isSigner: false, isWritable: true },
1092
- { pubkey: satTreasuryState, isSigner: false, isWritable: true },
1093
1931
  { pubkey: satRegistryReserve, isSigner: false, isWritable: true },
1094
1932
  { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1095
- { pubkey: satRebateVault, isSigner: false, isWritable: true },
1096
- { pubkey: satTreasuryVault, isSigner: false, isWritable: true },
1097
1933
  ];
1098
1934
  },
1099
1935
  });
@@ -1150,15 +1986,23 @@ export async function submitSatInitMinerCapital(
1150
1986
  params: { authority?: string },
1151
1987
  ) {
1152
1988
  const cfg = loadConfigForSatRuntime(_config);
1989
+ const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1990
+ const authority =
1991
+ params.authority?.trim() ||
1992
+ (await resolveSatLocalSignerAddress(
1993
+ cfg,
1994
+ effectiveEnv,
1995
+ "local-socket-signer returned no Solana address for SAT miner capital authority",
1996
+ ));
1153
1997
  return submitInstruction({
1154
1998
  cfg,
1155
- env: process.env,
1156
- data: buildInitMinerCapitalData({ authority: params.authority ?? "" }),
1999
+ env: effectiveEnv,
2000
+ data: buildInitMinerCapitalData({ authority }),
1157
2001
  accountResolver: async (solana, signer) => {
1158
2002
  const programId = new solana.PublicKey(SAT_PROGRAM_ID());
1159
- const authority = params.authority?.trim() ? new solana.PublicKey(params.authority) : signer;
2003
+ const authorityKey = new solana.PublicKey(authority);
1160
2004
  const [satMinerCapitalState] = solana.PublicKey.findProgramAddressSync(
1161
- [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), authority.toBuffer()],
2005
+ [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), authorityKey.toBuffer()],
1162
2006
  programId,
1163
2007
  );
1164
2008
  return [
@@ -1281,47 +2125,6 @@ function resolveSatBondAccounts(
1281
2125
  };
1282
2126
  }
1283
2127
 
1284
- export async function submitSatInitBondTierPolicy(
1285
- _config: SatMiningConfig,
1286
- params: {
1287
- updateAuthority?: string;
1288
- basicMinRaw: number;
1289
- operatorMinRaw: number;
1290
- unlockDelaySlots: number;
1291
- scheduledEffectiveSlot?: number;
1292
- },
1293
- ) {
1294
- const cfg = loadConfigForSatRuntime(_config);
1295
- const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1296
- if (!hasDedicatedBondProgram(effectiveEnv)) {
1297
- throw new Error("SAT bond tier policy init requires FASED_SAT_BOND_PROGRAM_ID");
1298
- }
1299
- const defaultUpdateAuthority =
1300
- resolveSatRegistrySolanaAddress(cfg, effectiveEnv) ||
1301
- (await resolveSatLocalSignerAddress(
1302
- cfg,
1303
- effectiveEnv,
1304
- "local-socket-signer returned no Solana address for SAT bond policy authority",
1305
- ));
1306
- return submitInstruction({
1307
- cfg,
1308
- env: effectiveEnv,
1309
- data: buildInitBondTierPolicyData({
1310
- ...params,
1311
- updateAuthority: params.updateAuthority ?? defaultUpdateAuthority,
1312
- }),
1313
- programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1314
- accountResolver: async (solana, signer) => {
1315
- const { bondTierPolicy } = resolveSatBondAccounts(solana, signer, effectiveEnv);
1316
- return [
1317
- { pubkey: signer, isSigner: true, isWritable: true },
1318
- { pubkey: bondTierPolicy, isSigner: false, isWritable: true },
1319
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1320
- ];
1321
- },
1322
- });
1323
- }
1324
-
1325
2128
  export async function submitSatUpdateBondTierPolicy(
1326
2129
  _config: SatMiningConfig,
1327
2130
  params: {
@@ -1337,13 +2140,11 @@ export async function submitSatUpdateBondTierPolicy(
1337
2140
  if (!hasDedicatedBondProgram(effectiveEnv)) {
1338
2141
  throw new Error("SAT bond tier policy update requires FASED_SAT_BOND_PROGRAM_ID");
1339
2142
  }
1340
- const defaultUpdateAuthority =
1341
- resolveSatRegistrySolanaAddress(cfg, effectiveEnv) ||
1342
- (await resolveSatLocalSignerAddress(
1343
- cfg,
1344
- effectiveEnv,
1345
- "local-socket-signer returned no Solana address for SAT bond policy authority",
1346
- ));
2143
+ const defaultUpdateAuthority = await resolveSatLocalSignerAddress(
2144
+ cfg,
2145
+ effectiveEnv,
2146
+ "local-socket-signer returned no Solana address for SAT bond policy authority",
2147
+ );
1347
2148
  return submitInstruction({
1348
2149
  cfg,
1349
2150
  env: effectiveEnv,
@@ -1446,12 +2247,17 @@ export async function submitSatRequestBondUnlock(_config: SatMiningConfig) {
1446
2247
  data: buildRequestBondUnlockData(effectiveEnv),
1447
2248
  programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1448
2249
  accountResolver: async (solana, signer) => {
1449
- const { bondTierPolicy, bondPosition } = resolveSatBondAccounts(solana, signer, effectiveEnv);
2250
+ const { bondTierPolicy, bondPosition, bondStakingDistributor, bondStakingPosition } =
2251
+ resolveSatBondAccounts(solana, signer, effectiveEnv);
1450
2252
  const accounts = [
1451
2253
  { pubkey: signer, isSigner: true, isWritable: true },
1452
2254
  { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
1453
2255
  ];
1454
- accounts.push({ pubkey: bondPosition, isSigner: false, isWritable: true });
2256
+ accounts.push(
2257
+ { pubkey: bondPosition, isSigner: false, isWritable: true },
2258
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2259
+ { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
2260
+ );
1455
2261
  return accounts;
1456
2262
  },
1457
2263
  });
@@ -1467,12 +2273,17 @@ export async function submitSatCancelBondUnlock(_config: SatMiningConfig) {
1467
2273
  data: buildCancelBondUnlockData(effectiveEnv),
1468
2274
  programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1469
2275
  accountResolver: async (solana, signer) => {
1470
- const { bondTierPolicy, bondPosition } = resolveSatBondAccounts(solana, signer, effectiveEnv);
2276
+ const { bondTierPolicy, bondPosition, bondStakingDistributor, bondStakingPosition } =
2277
+ resolveSatBondAccounts(solana, signer, effectiveEnv);
1471
2278
  const accounts = [
1472
2279
  { pubkey: signer, isSigner: true, isWritable: true },
1473
2280
  { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
1474
2281
  ];
1475
- accounts.push({ pubkey: bondPosition, isSigner: false, isWritable: true });
2282
+ accounts.push(
2283
+ { pubkey: bondPosition, isSigner: false, isWritable: true },
2284
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2285
+ { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
2286
+ );
1476
2287
  return accounts;
1477
2288
  },
1478
2289
  });
@@ -1488,14 +2299,23 @@ export async function submitSatFinalizeBondUnlock(_config: SatMiningConfig) {
1488
2299
  data: buildFinalizeBondUnlockData(effectiveEnv),
1489
2300
  programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1490
2301
  accountResolver: async (solana, signer) => {
1491
- const { bondTierPolicy, bondPosition, signerTokenAccount, bondVault, mint } =
1492
- resolveSatBondAccounts(solana, signer, effectiveEnv);
2302
+ const {
2303
+ bondTierPolicy,
2304
+ bondPosition,
2305
+ bondStakingDistributor,
2306
+ bondStakingPosition,
2307
+ signerTokenAccount,
2308
+ bondVault,
2309
+ mint,
2310
+ } = resolveSatBondAccounts(solana, signer, effectiveEnv);
1493
2311
  const accounts = [
1494
2312
  { pubkey: signer, isSigner: true, isWritable: true },
1495
2313
  { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
1496
2314
  ];
1497
2315
  accounts.push(
1498
2316
  { pubkey: bondPosition, isSigner: false, isWritable: true },
2317
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2318
+ { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
1499
2319
  { pubkey: bondVault, isSigner: false, isWritable: true },
1500
2320
  { pubkey: signerTokenAccount, isSigner: false, isWritable: true },
1501
2321
  { pubkey: mint, isSigner: false, isWritable: true },
@@ -1512,28 +2332,105 @@ export async function submitSatFinalizeBondUnlock(_config: SatMiningConfig) {
1512
2332
  });
1513
2333
  }
1514
2334
 
1515
- export async function submitSatInitBondStakingDistributor(
2335
+ export async function submitSatSyncBondStakingRewards(_config: SatMiningConfig) {
2336
+ const cfg = loadConfigForSatRuntime(_config);
2337
+ const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
2338
+ assertDedicatedBondProgram(effectiveEnv);
2339
+ return submitInstruction({
2340
+ cfg,
2341
+ env: effectiveEnv,
2342
+ data: buildSyncBondStakingRewardsData(effectiveEnv),
2343
+ programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
2344
+ accountResolver: async (solana, signer) => {
2345
+ const { bondStakingDistributor, bondStakingRewardVault, mint } = resolveSatBondAccounts(
2346
+ solana,
2347
+ signer,
2348
+ effectiveEnv,
2349
+ );
2350
+ return [
2351
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2352
+ { pubkey: bondStakingRewardVault, isSigner: false, isWritable: false },
2353
+ { pubkey: mint, isSigner: false, isWritable: false },
2354
+ ];
2355
+ },
2356
+ });
2357
+ }
2358
+
2359
+ export async function submitSatSyncBondStakingPosition(_config: SatMiningConfig) {
2360
+ const cfg = loadConfigForSatRuntime(_config);
2361
+ const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
2362
+ assertDedicatedBondProgram(effectiveEnv);
2363
+ return submitInstruction({
2364
+ cfg,
2365
+ env: effectiveEnv,
2366
+ data: buildSyncBondStakingPositionData(effectiveEnv),
2367
+ programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
2368
+ accountResolver: async (solana, signer) => {
2369
+ const { bondTierPolicy, bondStakingDistributor, bondStakingPosition, bondPosition } =
2370
+ resolveSatBondAccounts(solana, signer, effectiveEnv);
2371
+ return [
2372
+ { pubkey: signer, isSigner: true, isWritable: true },
2373
+ { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
2374
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2375
+ { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
2376
+ { pubkey: bondPosition, isSigner: false, isWritable: false },
2377
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2378
+ ];
2379
+ },
2380
+ });
2381
+ }
2382
+
2383
+ export async function submitSatClaimBondStakingRewards(_config: SatMiningConfig) {
2384
+ const cfg = loadConfigForSatRuntime(_config);
2385
+ const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
2386
+ assertDedicatedBondProgram(effectiveEnv);
2387
+ return submitInstruction({
2388
+ cfg,
2389
+ env: effectiveEnv,
2390
+ data: buildClaimBondStakingRewardsData(effectiveEnv),
2391
+ programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
2392
+ accountResolver: async (solana, signer) => {
2393
+ const {
2394
+ bondTierPolicy,
2395
+ bondStakingDistributor,
2396
+ bondStakingPosition,
2397
+ bondPosition,
2398
+ bondStakingRewardVault,
2399
+ signerTokenAccount,
2400
+ mint,
2401
+ } = resolveSatBondAccounts(solana, signer, effectiveEnv);
2402
+ return [
2403
+ { pubkey: signer, isSigner: true, isWritable: true },
2404
+ { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
2405
+ { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
2406
+ { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
2407
+ { pubkey: bondPosition, isSigner: false, isWritable: false },
2408
+ { pubkey: bondStakingRewardVault, isSigner: false, isWritable: true },
2409
+ { pubkey: signerTokenAccount, isSigner: false, isWritable: true },
2410
+ { pubkey: mint, isSigner: false, isWritable: true },
2411
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2412
+ { pubkey: new solana.PublicKey(TOKEN_PROGRAM_ID), isSigner: false, isWritable: false },
2413
+ {
2414
+ pubkey: new solana.PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID),
2415
+ isSigner: false,
2416
+ isWritable: false,
2417
+ },
2418
+ ];
2419
+ },
2420
+ });
2421
+ }
2422
+
2423
+ export async function submitSatClaimUnallocatedStakingRewards(
1516
2424
  _config: SatMiningConfig,
1517
- params: { minStakeRaw: number; updateAuthority?: string },
2425
+ params: { recipientOwner: string },
1518
2426
  ) {
1519
2427
  const cfg = loadConfigForSatRuntime(_config);
1520
2428
  const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1521
2429
  assertDedicatedBondProgram(effectiveEnv);
1522
- const defaultUpdateAuthority = await resolveSatLocalSignerAddress(
1523
- cfg,
1524
- effectiveEnv,
1525
- "local-socket-signer returned no Solana address for SAT bond staking distributor authority",
1526
- );
1527
2430
  return submitInstruction({
1528
2431
  cfg,
1529
2432
  env: effectiveEnv,
1530
- data: buildInitBondStakingDistributorData(
1531
- {
1532
- minStakeRaw: params.minStakeRaw,
1533
- updateAuthority: params.updateAuthority ?? defaultUpdateAuthority,
1534
- },
1535
- effectiveEnv,
1536
- ),
2433
+ data: buildClaimUnallocatedStakingRewardsData(effectiveEnv),
1537
2434
  programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1538
2435
  accountResolver: async (solana, signer) => {
1539
2436
  const { bondStakingDistributor, bondStakingRewardVault, mint } = resolveSatBondAccounts(
@@ -1541,10 +2438,14 @@ export async function submitSatInitBondStakingDistributor(
1541
2438
  signer,
1542
2439
  effectiveEnv,
1543
2440
  );
2441
+ const recipientOwner = new solana.PublicKey(params.recipientOwner);
2442
+ const recipientTokenAccount = deriveAssociatedTokenAddress(solana, recipientOwner, mint);
1544
2443
  return [
1545
2444
  { pubkey: signer, isSigner: true, isWritable: true },
1546
2445
  { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
1547
2446
  { pubkey: bondStakingRewardVault, isSigner: false, isWritable: true },
2447
+ { pubkey: recipientTokenAccount, isSigner: false, isWritable: true },
2448
+ { pubkey: recipientOwner, isSigner: false, isWritable: false },
1548
2449
  { pubkey: mint, isSigner: false, isWritable: true },
1549
2450
  { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1550
2451
  { pubkey: new solana.PublicKey(TOKEN_PROGRAM_ID), isSigner: false, isWritable: false },
@@ -1552,116 +2453,222 @@ export async function submitSatInitBondStakingDistributor(
1552
2453
  pubkey: new solana.PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID),
1553
2454
  isSigner: false,
1554
2455
  isWritable: false,
1555
- },
1556
- ];
2456
+ },
2457
+ ];
2458
+ },
2459
+ });
2460
+ }
2461
+
2462
+ export async function submitSatCommitCycle(
2463
+ _config: SatMiningConfig,
2464
+ params: { cycleId: number; commitmentHex: string },
2465
+ ) {
2466
+ const cfg = loadConfigForSatRuntime(_config);
2467
+ const commitment = Buffer.from(params.commitmentHex, "hex");
2468
+ return submitInstruction({
2469
+ cfg,
2470
+ env: process.env,
2471
+ data: buildCommitCycleData({ cycleId: params.cycleId, commitment }),
2472
+ accountResolver: async (solana, signer) => {
2473
+ const programId = new solana.PublicKey(SAT_PROGRAM_ID());
2474
+ const [satCycleState] = solana.PublicKey.findProgramAddressSync(
2475
+ [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
2476
+ programId,
2477
+ );
2478
+ const [satMinerCycleState] = solana.PublicKey.findProgramAddressSync(
2479
+ [Buffer.from(SAT_MINER_CYCLE_STATE_SEED), signer.toBuffer(), encodeU64(params.cycleId)],
2480
+ programId,
2481
+ );
2482
+ const [satMinerCapitalState] = solana.PublicKey.findProgramAddressSync(
2483
+ [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), signer.toBuffer()],
2484
+ programId,
2485
+ );
2486
+ return [
2487
+ { pubkey: signer, isSigner: true, isWritable: true },
2488
+ { pubkey: satCycleState, isSigner: false, isWritable: true },
2489
+ { pubkey: satMinerCycleState, isSigner: false, isWritable: true },
2490
+ { pubkey: satMinerCapitalState, isSigner: false, isWritable: true },
2491
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2492
+ ];
2493
+ },
2494
+ });
2495
+ }
2496
+
2497
+ async function submitSatCyclePhaseInstruction(
2498
+ _config: SatMiningConfig,
2499
+ params: { cycleId: number; phase: "close" | "seal"; intervalStartCycleId?: number },
2500
+ ) {
2501
+ const cfg = loadConfigForSatRuntime(_config);
2502
+ return submitInstruction({
2503
+ cfg,
2504
+ env: process.env,
2505
+ data:
2506
+ params.phase === "close"
2507
+ ? buildCloseCommitPhaseData(params)
2508
+ : buildSealCycleEntropyData(params),
2509
+ accountResolver: async (solana, signer) => {
2510
+ const programId = new solana.PublicKey(SAT_PROGRAM_ID());
2511
+ const [satCycleState] = solana.PublicKey.findProgramAddressSync(
2512
+ [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
2513
+ programId,
2514
+ );
2515
+ const accounts = [
2516
+ { pubkey: signer, isSigner: true, isWritable: false },
2517
+ { pubkey: satCycleState, isSigner: false, isWritable: true },
2518
+ ];
2519
+ let intervalStartCycleIdForSigner: number | undefined;
2520
+ if (params.phase === "seal") {
2521
+ const cycle =
2522
+ params.intervalStartCycleId == null
2523
+ ? await inspectSatCycle(_config, { cycleId: params.cycleId })
2524
+ : null;
2525
+ const intervalStartCycleId =
2526
+ params.intervalStartCycleId ?? cycle?.unlockIntervalStartCycleId;
2527
+ if (intervalStartCycleId == null || !Number.isSafeInteger(intervalStartCycleId)) {
2528
+ throw new Error(`SAT cycle ${params.cycleId} does not expose its unlock interval start`);
2529
+ }
2530
+ intervalStartCycleIdForSigner = intervalStartCycleId;
2531
+ const [satUnlockIntervalState] = solana.PublicKey.findProgramAddressSync(
2532
+ [Buffer.from(SAT_UNLOCK_INTERVAL_STATE_SEED), encodeU64(intervalStartCycleId)],
2533
+ programId,
2534
+ );
2535
+ accounts.push({
2536
+ pubkey: satUnlockIntervalState,
2537
+ isSigner: false,
2538
+ isWritable: true,
2539
+ });
2540
+ accounts.push({
2541
+ pubkey: new solana.PublicKey(SLOT_HASHES_SYSVAR_ID),
2542
+ isSigner: false,
2543
+ isWritable: false,
2544
+ });
2545
+ }
2546
+ return {
2547
+ keys: accounts,
2548
+ ...(intervalStartCycleIdForSigner == null
2549
+ ? {}
2550
+ : { context: { intervalStartCycleId: String(intervalStartCycleIdForSigner) } }),
2551
+ };
1557
2552
  },
1558
2553
  });
1559
2554
  }
1560
2555
 
1561
- export async function submitSatSyncBondStakingRewards(_config: SatMiningConfig) {
1562
- const cfg = loadConfigForSatRuntime(_config);
1563
- const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1564
- assertDedicatedBondProgram(effectiveEnv);
1565
- return submitInstruction({
1566
- cfg,
1567
- env: effectiveEnv,
1568
- data: buildSyncBondStakingRewardsData(effectiveEnv),
1569
- programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
1570
- accountResolver: async (solana, signer) => {
1571
- const { bondStakingDistributor, bondStakingRewardVault, mint } = resolveSatBondAccounts(
1572
- solana,
1573
- signer,
1574
- effectiveEnv,
1575
- );
1576
- return [
1577
- { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
1578
- { pubkey: bondStakingRewardVault, isSigner: false, isWritable: false },
1579
- { pubkey: mint, isSigner: false, isWritable: false },
1580
- ];
1581
- },
1582
- });
2556
+ export async function submitSatCloseCommitPhase(
2557
+ _config: SatMiningConfig,
2558
+ params: { cycleId: number },
2559
+ ) {
2560
+ return submitSatCyclePhaseInstruction(_config, { ...params, phase: "close" });
1583
2561
  }
1584
2562
 
1585
- export async function submitSatSyncBondStakingPosition(_config: SatMiningConfig) {
2563
+ export async function submitSatSealCycleEntropy(
2564
+ _config: SatMiningConfig,
2565
+ params: { cycleId: number; intervalStartCycleId?: number },
2566
+ ) {
2567
+ return submitSatCyclePhaseInstruction(_config, { ...params, phase: "seal" });
2568
+ }
2569
+
2570
+ export async function submitSatReleaseUnrevealedCommit(
2571
+ _config: SatMiningConfig,
2572
+ params: { cycleId: number; minerAuthority: string },
2573
+ ) {
1586
2574
  const cfg = loadConfigForSatRuntime(_config);
1587
- const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1588
- assertDedicatedBondProgram(effectiveEnv);
1589
2575
  return submitInstruction({
1590
2576
  cfg,
1591
- env: effectiveEnv,
1592
- data: buildSyncBondStakingPositionData(effectiveEnv),
1593
- programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
2577
+ env: process.env,
2578
+ data: buildReleaseUnrevealedCommitData(params),
1594
2579
  accountResolver: async (solana, signer) => {
1595
- const { bondTierPolicy, bondStakingDistributor, bondStakingPosition, bondPosition } =
1596
- resolveSatBondAccounts(solana, signer, effectiveEnv);
2580
+ const programId = new solana.PublicKey(SAT_PROGRAM_ID());
2581
+ const minerAuthority = new solana.PublicKey(params.minerAuthority);
2582
+ const [satCycleState] = solana.PublicKey.findProgramAddressSync(
2583
+ [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
2584
+ programId,
2585
+ );
2586
+ const [satMinerCycleState] = solana.PublicKey.findProgramAddressSync(
2587
+ [
2588
+ Buffer.from(SAT_MINER_CYCLE_STATE_SEED),
2589
+ minerAuthority.toBuffer(),
2590
+ encodeU64(params.cycleId),
2591
+ ],
2592
+ programId,
2593
+ );
2594
+ const [satMinerCapitalState] = solana.PublicKey.findProgramAddressSync(
2595
+ [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), minerAuthority.toBuffer()],
2596
+ programId,
2597
+ );
2598
+ const [satTreasuryState] = solana.PublicKey.findProgramAddressSync(
2599
+ [Buffer.from(SAT_TREASURY_STATE_SEED)],
2600
+ programId,
2601
+ );
2602
+ const [satTreasuryVault] = solana.PublicKey.findProgramAddressSync(
2603
+ [Buffer.from(SAT_TREASURY_VAULT_SEED)],
2604
+ programId,
2605
+ );
1597
2606
  return [
1598
- { pubkey: signer, isSigner: true, isWritable: true },
1599
- { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
1600
- { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
1601
- { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
1602
- { pubkey: bondPosition, isSigner: false, isWritable: false },
1603
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2607
+ { pubkey: signer, isSigner: true, isWritable: false },
2608
+ { pubkey: satCycleState, isSigner: false, isWritable: true },
2609
+ { pubkey: satMinerCycleState, isSigner: false, isWritable: true },
2610
+ { pubkey: satMinerCapitalState, isSigner: false, isWritable: true },
2611
+ { pubkey: satTreasuryState, isSigner: false, isWritable: true },
2612
+ { pubkey: satTreasuryVault, isSigner: false, isWritable: true },
1604
2613
  ];
1605
2614
  },
1606
2615
  });
1607
2616
  }
1608
2617
 
1609
- export async function submitSatClaimBondStakingRewards(_config: SatMiningConfig) {
2618
+ export async function submitSatAbortEmptyCycle(
2619
+ _config: SatMiningConfig,
2620
+ params: { cycleId: number },
2621
+ ) {
1610
2622
  const cfg = loadConfigForSatRuntime(_config);
1611
- const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
1612
- assertDedicatedBondProgram(effectiveEnv);
1613
2623
  return submitInstruction({
1614
2624
  cfg,
1615
- env: effectiveEnv,
1616
- data: buildClaimBondStakingRewardsData(effectiveEnv),
1617
- programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
2625
+ env: process.env,
2626
+ data: buildAbortEmptyCycleData(params),
1618
2627
  accountResolver: async (solana, signer) => {
1619
- const {
1620
- bondTierPolicy,
1621
- bondStakingDistributor,
1622
- bondStakingPosition,
1623
- bondPosition,
1624
- bondStakingRewardVault,
1625
- signerTokenAccount,
1626
- mint,
1627
- } = resolveSatBondAccounts(solana, signer, effectiveEnv);
2628
+ const programId = new solana.PublicKey(SAT_PROGRAM_ID());
2629
+ const [satCycleState] = solana.PublicKey.findProgramAddressSync(
2630
+ [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
2631
+ programId,
2632
+ );
2633
+ const [satCycleRegistryMeta] = solana.PublicKey.findProgramAddressSync(
2634
+ [Buffer.from(SAT_CYCLE_REGISTRY_META_SEED), encodeU64(params.cycleId)],
2635
+ programId,
2636
+ );
1628
2637
  return [
1629
- { pubkey: signer, isSigner: true, isWritable: true },
1630
- { pubkey: bondTierPolicy, isSigner: false, isWritable: false },
1631
- { pubkey: bondStakingDistributor, isSigner: false, isWritable: true },
1632
- { pubkey: bondStakingPosition, isSigner: false, isWritable: true },
1633
- { pubkey: bondPosition, isSigner: false, isWritable: false },
1634
- { pubkey: bondStakingRewardVault, isSigner: false, isWritable: true },
1635
- { pubkey: signerTokenAccount, isSigner: false, isWritable: true },
1636
- { pubkey: mint, isSigner: false, isWritable: true },
1637
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1638
- { pubkey: new solana.PublicKey(TOKEN_PROGRAM_ID), isSigner: false, isWritable: false },
1639
- {
1640
- pubkey: new solana.PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID),
1641
- isSigner: false,
1642
- isWritable: false,
1643
- },
2638
+ { pubkey: signer, isSigner: true, isWritable: false },
2639
+ { pubkey: satCycleState, isSigner: false, isWritable: true },
2640
+ { pubkey: satCycleRegistryMeta, isSigner: false, isWritable: true },
1644
2641
  ];
1645
2642
  },
1646
2643
  });
1647
2644
  }
1648
2645
 
1649
- export async function submitSatCycle(
2646
+ export async function submitSatRevealCycle(
1650
2647
  _config: SatMiningConfig,
1651
- params: { cycleId: number; allocationFp: number[] },
2648
+ params: {
2649
+ cycleId: number;
2650
+ intervalStartCycleId?: number;
2651
+ nonceBase64: string;
2652
+ allocationFp: number[];
2653
+ },
1652
2654
  ) {
1653
2655
  const cfg = loadConfigForSatRuntime(_config);
2656
+ const nonce = Buffer.from(params.nonceBase64, "base64");
1654
2657
  return submitInstruction({
1655
2658
  cfg,
1656
2659
  env: process.env,
1657
- data: buildSubmitCycleData(params),
2660
+ data: buildRevealCycleData({ ...params, nonce }),
1658
2661
  accountResolver: async (solana, signer) => {
1659
2662
  const programId = new solana.PublicKey(SAT_PROGRAM_ID());
1660
2663
  const pageIndex = await resolveSatCycleRegistryPageIndex(_config, params.cycleId);
1661
- const [satGlobalState] = solana.PublicKey.findProgramAddressSync(
1662
- [Buffer.from(SAT_GLOBAL_STATE_SEED)],
1663
- programId,
1664
- );
2664
+ const cycle =
2665
+ params.intervalStartCycleId == null
2666
+ ? await inspectSatCycle(_config, { cycleId: params.cycleId })
2667
+ : null;
2668
+ const intervalStartCycleId = params.intervalStartCycleId ?? cycle?.unlockIntervalStartCycleId;
2669
+ if (intervalStartCycleId == null || !Number.isSafeInteger(intervalStartCycleId)) {
2670
+ throw new Error(`SAT cycle ${params.cycleId} does not expose its unlock interval start`);
2671
+ }
1665
2672
  const [satCycleState] = solana.PublicKey.findProgramAddressSync(
1666
2673
  [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
1667
2674
  programId,
@@ -1690,37 +2697,32 @@ export async function submitSatCycle(
1690
2697
  [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), signer.toBuffer()],
1691
2698
  programId,
1692
2699
  );
1693
- const [satRegistryReserve] = solana.PublicKey.findProgramAddressSync(
1694
- [Buffer.from(SAT_REGISTRY_RESERVE_SEED)],
1695
- programId,
1696
- );
1697
- const [satTreasuryState] = solana.PublicKey.findProgramAddressSync(
1698
- [Buffer.from(SAT_TREASURY_STATE_SEED)],
1699
- programId,
1700
- );
1701
- const [satRebateVault] = solana.PublicKey.findProgramAddressSync(
1702
- [Buffer.from(SAT_REBATE_VAULT_SEED)],
2700
+ const [satUnlockIntervalState] = solana.PublicKey.findProgramAddressSync(
2701
+ [Buffer.from(SAT_UNLOCK_INTERVAL_STATE_SEED), encodeU64(intervalStartCycleId)],
1703
2702
  programId,
1704
2703
  );
1705
- const [satTreasuryVault] = solana.PublicKey.findProgramAddressSync(
1706
- [Buffer.from(SAT_TREASURY_VAULT_SEED)],
2704
+ const [satRegistryReserve] = solana.PublicKey.findProgramAddressSync(
2705
+ [Buffer.from(SAT_REGISTRY_RESERVE_SEED)],
1707
2706
  programId,
1708
2707
  );
1709
- return [
1710
- { pubkey: signer, isSigner: true, isWritable: true },
1711
- { pubkey: satGlobalState, isSigner: false, isWritable: true },
1712
- { pubkey: satCycleState, isSigner: false, isWritable: true },
1713
- { pubkey: satCycleRegistryMeta, isSigner: false, isWritable: true },
1714
- { pubkey: satCycleRegistryPage, isSigner: false, isWritable: true },
1715
- { pubkey: satCycleSettlementProgress, isSigner: false, isWritable: true },
1716
- { pubkey: satMinerCycleState, isSigner: false, isWritable: true },
1717
- { pubkey: satMinerCapitalState, isSigner: false, isWritable: true },
1718
- { pubkey: satRegistryReserve, isSigner: false, isWritable: true },
1719
- { pubkey: satTreasuryState, isSigner: false, isWritable: true },
1720
- { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
1721
- { pubkey: satRebateVault, isSigner: false, isWritable: true },
1722
- { pubkey: satTreasuryVault, isSigner: false, isWritable: true },
1723
- ];
2708
+ return {
2709
+ keys: [
2710
+ { pubkey: signer, isSigner: true, isWritable: true },
2711
+ { pubkey: satCycleState, isSigner: false, isWritable: true },
2712
+ { pubkey: satCycleRegistryMeta, isSigner: false, isWritable: true },
2713
+ { pubkey: satCycleRegistryPage, isSigner: false, isWritable: true },
2714
+ { pubkey: satCycleSettlementProgress, isSigner: false, isWritable: true },
2715
+ { pubkey: satMinerCycleState, isSigner: false, isWritable: true },
2716
+ { pubkey: satMinerCapitalState, isSigner: false, isWritable: true },
2717
+ { pubkey: satUnlockIntervalState, isSigner: false, isWritable: true },
2718
+ { pubkey: satRegistryReserve, isSigner: false, isWritable: true },
2719
+ { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2720
+ ],
2721
+ context: {
2722
+ intervalStartCycleId: String(intervalStartCycleId),
2723
+ registryPageIndex: String(pageIndex),
2724
+ },
2725
+ };
1724
2726
  },
1725
2727
  });
1726
2728
  }
@@ -1801,7 +2803,29 @@ export async function submitSatSettleCyclePage(
1801
2803
  isWritable: true,
1802
2804
  });
1803
2805
  }
1804
- return accounts;
2806
+ const minerCycleAddresses = params.minerCycleAccounts ?? [];
2807
+ const minerCycles =
2808
+ minerCycleAddresses.length > 0
2809
+ ? await inspectSatMinerCyclesByAddress(_config, {
2810
+ addresses: minerCycleAddresses,
2811
+ })
2812
+ : [];
2813
+ const minerAuthorities = minerCycles.map((entry, index) => {
2814
+ const authority = String(entry?.authority ?? "").trim();
2815
+ if (!authority) {
2816
+ throw new Error(
2817
+ `SAT settleCyclePage could not resolve miner authority for ${minerCycleAddresses[index]}`,
2818
+ );
2819
+ }
2820
+ return authority;
2821
+ });
2822
+ if (minerAuthorities.length !== minerCycleAddresses.length) {
2823
+ throw new Error("SAT settleCyclePage miner authority count mismatch");
2824
+ }
2825
+ return {
2826
+ keys: accounts,
2827
+ ...(minerAuthorities.length > 0 ? { context: { minerAuthorities } } : {}),
2828
+ };
1805
2829
  },
1806
2830
  });
1807
2831
  }
@@ -1941,20 +2965,58 @@ export async function submitSatScoreCyclePage(
1941
2965
  isWritable: true,
1942
2966
  });
1943
2967
  }
1944
- return accounts;
2968
+ const minerCycleAddresses = params.minerCycleAccounts ?? [];
2969
+ const minerCycles =
2970
+ minerCycleAddresses.length > 0
2971
+ ? await inspectSatMinerCyclesByAddress(_config, {
2972
+ addresses: minerCycleAddresses,
2973
+ })
2974
+ : [];
2975
+ const minerAuthorities = minerCycles.map((entry, index) => {
2976
+ const authority = String(entry?.authority ?? "").trim();
2977
+ if (!authority) {
2978
+ throw new Error(
2979
+ `SAT scoreCyclePage could not resolve miner authority for ${minerCycleAddresses[index]}`,
2980
+ );
2981
+ }
2982
+ return authority;
2983
+ });
2984
+ if (minerAuthorities.length !== minerCycleAddresses.length) {
2985
+ throw new Error("SAT scoreCyclePage miner authority count mismatch");
2986
+ }
2987
+ return {
2988
+ keys: accounts,
2989
+ ...(minerAuthorities.length > 0 ? { context: { minerAuthorities } } : {}),
2990
+ };
1945
2991
  },
1946
2992
  });
1947
2993
  }
1948
2994
 
1949
2995
  export async function submitSatDistributeCyclePage(
1950
2996
  _config: SatMiningConfig,
1951
- params: { cycleId: number; pageIndex: number; chunkIndex: number; minerCycleAccounts?: string[] },
2997
+ params: {
2998
+ cycleId: number;
2999
+ pageIndex: number;
3000
+ chunkIndex: number;
3001
+ minerCycleAccounts?: string[];
3002
+ lookupTableAddress?: string;
3003
+ },
1952
3004
  ) {
1953
3005
  const cfg = loadConfigForSatRuntime(_config);
3006
+ const lookupTableAddress = params.lookupTableAddress?.trim() ?? "";
3007
+ const requiresLookupTable =
3008
+ (params.minerCycleAccounts?.length ?? 0) >= SAT_DISTRIBUTION_LOOKUP_MIN_MINERS;
1954
3009
  return submitInstruction({
1955
3010
  cfg,
1956
3011
  env: process.env,
1957
3012
  data: buildDistributeCyclePageData(params),
3013
+ ...(lookupTableAddress || requiresLookupTable
3014
+ ? {
3015
+ manageAddressLookupTable: {
3016
+ ...(lookupTableAddress ? { lookupTableAddress } : {}),
3017
+ },
3018
+ }
3019
+ : {}),
1958
3020
  accountResolver: async (solana, signer) => {
1959
3021
  const programId = new solana.PublicKey(SAT_PROGRAM_ID());
1960
3022
  const [satCycleState] = solana.PublicKey.findProgramAddressSync(
@@ -1993,16 +3055,21 @@ export async function submitSatDistributeCyclePage(
1993
3055
  [Buffer.from(SAT_REBATE_VAULT_SEED)],
1994
3056
  programId,
1995
3057
  );
3058
+ const [satTreasuryVault] = solana.PublicKey.findProgramAddressSync(
3059
+ [Buffer.from(SAT_TREASURY_VAULT_SEED)],
3060
+ programId,
3061
+ );
1996
3062
  const accounts = [
1997
3063
  { pubkey: signer, isSigner: true, isWritable: true },
1998
3064
  { pubkey: satCycleState, isSigner: false, isWritable: true },
1999
3065
  { pubkey: satCycleRegistryPage, isSigner: false, isWritable: false },
2000
3066
  { pubkey: satCycleSettlementProgress, isSigner: false, isWritable: true },
2001
- { pubkey: satGlobalState, isSigner: false, isWritable: true },
3067
+ { pubkey: satGlobalState, isSigner: false, isWritable: false },
2002
3068
  { pubkey: satTreasuryState, isSigner: false, isWritable: true },
2003
3069
  { pubkey: satSignerMinerCycleState, isSigner: false, isWritable: false },
2004
3070
  { pubkey: satSignerMinerCapitalState, isSigner: false, isWritable: true },
2005
3071
  { pubkey: satRebateVault, isSigner: false, isWritable: true },
3072
+ { pubkey: satTreasuryVault, isSigner: false, isWritable: true },
2006
3073
  ];
2007
3074
  const minerCycleAccounts = params.minerCycleAccounts ?? [];
2008
3075
  const minerCycles =
@@ -2011,6 +3078,7 @@ export async function submitSatDistributeCyclePage(
2011
3078
  addresses: minerCycleAccounts,
2012
3079
  }).catch(() => [])
2013
3080
  : [];
3081
+ const minerAuthorities: string[] = [];
2014
3082
  for (const [index, minerCycleAccount] of minerCycleAccounts.entries()) {
2015
3083
  const satMinerCycleState = new solana.PublicKey(minerCycleAccount);
2016
3084
  const minerCycle = minerCycles[index] ?? null;
@@ -2022,6 +3090,7 @@ export async function submitSatDistributeCyclePage(
2022
3090
  `SAT distributeCyclePage could not resolve miner authority for ${minerCycleAccount}`,
2023
3091
  );
2024
3092
  }
3093
+ minerAuthorities.push(authorityKey.toBase58());
2025
3094
  const [satMinerCapitalState] = solana.PublicKey.findProgramAddressSync(
2026
3095
  [Buffer.from(SAT_MINER_CAPITAL_STATE_SEED), authorityKey.toBuffer()],
2027
3096
  programId,
@@ -2029,11 +3098,43 @@ export async function submitSatDistributeCyclePage(
2029
3098
  accounts.push({ pubkey: satMinerCycleState, isSigner: false, isWritable: true });
2030
3099
  accounts.push({ pubkey: satMinerCapitalState, isSigner: false, isWritable: true });
2031
3100
  }
2032
- return accounts;
3101
+ return {
3102
+ keys: accounts,
3103
+ ...(minerAuthorities.length > 0 ? { context: { minerAuthorities } } : {}),
3104
+ };
2033
3105
  },
2034
3106
  });
2035
3107
  }
2036
3108
 
3109
+ export async function submitSatCleanupDistributionLookupTable(
3110
+ _config: SatMiningConfig,
3111
+ params: { lookupTableAddress: string; action: "deactivate" | "close" },
3112
+ ) {
3113
+ const cfg = loadConfigForSatRuntime(_config);
3114
+ const context = await prepareLocalSignerSubmitContext(cfg, process.env);
3115
+ assertSatLookupTableEnabled(context.effectiveEnv);
3116
+ if (!context.walletId) {
3117
+ throw new Error("typed SAT lookup-table cleanup requires an explicit mining walletId");
3118
+ }
3119
+ const lookupTable = params.lookupTableAddress.trim();
3120
+ if (!lookupTable) {
3121
+ throw new Error("SAT distribution lookup table address is required");
3122
+ }
3123
+ const submitted = await executeTypedSatLookupOperation({
3124
+ context: { ...context, walletId: context.walletId },
3125
+ cfg,
3126
+ action: params.action,
3127
+ address: lookupTable,
3128
+ });
3129
+ return {
3130
+ lookupTable,
3131
+ action: params.action,
3132
+ transactionHashes: [submitted.signature],
3133
+ signerState: submitted.state,
3134
+ requestId: submitted.requestId,
3135
+ };
3136
+ }
3137
+
2037
3138
  export async function submitSatClaimCycleRewards(
2038
3139
  _config: SatMiningConfig,
2039
3140
  params: { cycleId: number },
@@ -2188,29 +3289,6 @@ export async function submitSatClaimCycleRewardsBatch(
2188
3289
  });
2189
3290
  }
2190
3291
 
2191
- export async function submitSatSetProtocolRecipients(
2192
- _config: SatMiningConfig,
2193
- params: { treasuryRecipient: string; distributorRecipient: string },
2194
- ) {
2195
- const cfg = loadConfigForSatRuntime(_config);
2196
- return submitInstruction({
2197
- cfg,
2198
- env: process.env,
2199
- data: buildSetProtocolRecipientsData(params),
2200
- accountResolver: async (solana, signer) => {
2201
- const programId = new solana.PublicKey(SAT_PROGRAM_ID());
2202
- const [satGlobalState] = solana.PublicKey.findProgramAddressSync(
2203
- [Buffer.from(SAT_GLOBAL_STATE_SEED)],
2204
- programId,
2205
- );
2206
- return [
2207
- { pubkey: signer, isSigner: true, isWritable: true },
2208
- { pubkey: satGlobalState, isSigner: false, isWritable: true },
2209
- ];
2210
- },
2211
- });
2212
- }
2213
-
2214
3292
  export async function submitSatClaimProtocolTreasury(
2215
3293
  _config: SatMiningConfig,
2216
3294
  params: { recipientOwner: string },
@@ -2320,12 +3398,14 @@ export async function submitSatClaimProtocolDistributorSat(
2320
3398
  params: { recipientOwner: string },
2321
3399
  ) {
2322
3400
  const cfg = loadConfigForSatRuntime(_config);
3401
+ const effectiveEnv = resolveSatEffectiveEnv(cfg, process.env);
3402
+ assertDedicatedBondProgram(effectiveEnv);
2323
3403
  return submitInstruction({
2324
3404
  cfg,
2325
- env: process.env,
3405
+ env: effectiveEnv,
2326
3406
  data: buildClaimProtocolDistributorSatData(),
2327
3407
  accountResolver: async (solana, signer) => {
2328
- const programId = new solana.PublicKey(SAT_PROGRAM_ID());
3408
+ const programId = new solana.PublicKey(resolveSatProgramIdFromEnv(effectiveEnv));
2329
3409
  const recipientOwner = new solana.PublicKey(params.recipientOwner);
2330
3410
  const [satGlobalState] = solana.PublicKey.findProgramAddressSync(
2331
3411
  [Buffer.from(SAT_GLOBAL_STATE_SEED)],
@@ -2341,12 +3421,12 @@ export async function submitSatClaimProtocolDistributorSat(
2341
3421
  );
2342
3422
  const [mintAuthority] = solana.PublicKey.findProgramAddressSync(
2343
3423
  [Buffer.from("authority")],
2344
- new solana.PublicKey(SAT_MINT_PROGRAM_ID()),
3424
+ new solana.PublicKey(resolveSatMintProgramIdFromEnv(effectiveEnv)),
2345
3425
  );
2346
3426
  const recipientAta = deriveAssociatedTokenAddress(
2347
3427
  solana,
2348
3428
  recipientOwner,
2349
- new solana.PublicKey(SAT_MINT_ADDRESS()),
3429
+ new solana.PublicKey(resolveSatMintAddressFromEnv(effectiveEnv)),
2350
3430
  );
2351
3431
  return [
2352
3432
  { pubkey: signer, isSigner: true, isWritable: true },
@@ -2355,7 +3435,11 @@ export async function submitSatClaimProtocolDistributorSat(
2355
3435
  { pubkey: satTreasuryState, isSigner: false, isWritable: true },
2356
3436
  { pubkey: recipientOwner, isSigner: false, isWritable: true },
2357
3437
  { pubkey: mintAuthority, isSigner: false, isWritable: true },
2358
- { pubkey: new solana.PublicKey(SAT_MINT_ADDRESS()), isSigner: false, isWritable: true },
3438
+ {
3439
+ pubkey: new solana.PublicKey(resolveSatMintAddressFromEnv(effectiveEnv)),
3440
+ isSigner: false,
3441
+ isWritable: true,
3442
+ },
2359
3443
  { pubkey: recipientAta, isSigner: false, isWritable: true },
2360
3444
  { pubkey: solana.SystemProgram.programId, isSigner: false, isWritable: false },
2361
3445
  { pubkey: new solana.PublicKey(TOKEN_PROGRAM_ID), isSigner: false, isWritable: false },
@@ -2364,7 +3448,16 @@ export async function submitSatClaimProtocolDistributorSat(
2364
3448
  isSigner: false,
2365
3449
  isWritable: false,
2366
3450
  },
2367
- { pubkey: new solana.PublicKey(SAT_MINT_PROGRAM_ID()), isSigner: false, isWritable: false },
3451
+ {
3452
+ pubkey: new solana.PublicKey(resolveSatMintProgramIdFromEnv(effectiveEnv)),
3453
+ isSigner: false,
3454
+ isWritable: false,
3455
+ },
3456
+ {
3457
+ pubkey: new solana.PublicKey(resolveSatBondProgramIdFromEnv(effectiveEnv)),
3458
+ isSigner: false,
3459
+ isWritable: false,
3460
+ },
2368
3461
  ];
2369
3462
  },
2370
3463
  });
@@ -2389,10 +3482,19 @@ export async function submitSatRetargetUnlock(
2389
3482
  [Buffer.from(SAT_CYCLE_STATE_SEED), encodeU64(params.cycleId)],
2390
3483
  programId,
2391
3484
  );
3485
+ const intervalStartCycleId = Math.max(
3486
+ 0,
3487
+ params.cycleId + 1 - SAT_PROTOCOL_CONSTANTS.cycleUnlockRetargetIntervalCycles,
3488
+ );
3489
+ const [satUnlockIntervalState] = solana.PublicKey.findProgramAddressSync(
3490
+ [Buffer.from(SAT_UNLOCK_INTERVAL_STATE_SEED), encodeU64(intervalStartCycleId)],
3491
+ programId,
3492
+ );
2392
3493
  return [
2393
3494
  { pubkey: signer, isSigner: true, isWritable: true },
2394
3495
  { pubkey: satGlobalState, isSigner: false, isWritable: true },
2395
3496
  { pubkey: satCycleState, isSigner: false, isWritable: false },
3497
+ { pubkey: satUnlockIntervalState, isSigner: false, isWritable: true },
2396
3498
  ];
2397
3499
  },
2398
3500
  });
@@ -2624,7 +3726,13 @@ export async function submitSatCompactPendingCycleRange(
2624
3726
  isWritable: false,
2625
3727
  });
2626
3728
  }
2627
- return accounts;
3729
+ return {
3730
+ keys: accounts,
3731
+ context: {
3732
+ frontCycleIds: params.frontCycleIds.map(String),
3733
+ backCycleIds: params.backCycleIds.map(String),
3734
+ },
3735
+ };
2628
3736
  },
2629
3737
  });
2630
3738
  }