@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.
- package/CHANGELOG.md +48 -0
- package/README.md +44 -29
- package/config/dependency-ownership.json +1 -1
- package/config/signer-policies/README.md +58 -0
- package/config/signer-policies/agent.json.template +32 -0
- package/config/signer-policies/mining.json.template +69 -0
- package/config/signer-policies/network.json.template +5 -0
- package/config/signer-policies/vault.json.template +70 -0
- package/config/signer-protocol-v2.json +78 -0
- package/config/typescript-noemit-baseline.json +680 -0
- package/dist/agents/auth-profiles/store.js +267 -31
- package/dist/agents/bash-tools.exec.js +10 -4
- package/dist/agents/current-model-catalog.js +3 -3
- package/dist/agents/memory-search.js +7 -1
- package/dist/agents/model-catalog-access.js +1 -2
- package/dist/agents/model-catalog-snapshot.js +1 -1
- package/dist/agents/model-catalog-source.js +1 -1
- package/dist/agents/model-metadata.js +1 -1
- package/dist/agents/model-selection.js +2 -28
- package/dist/agents/models-config.providers.js +6 -6
- package/dist/agents/pi-embedded-runner/compact.js +15 -7
- package/dist/agents/pi-embedded-runner/model.js +1 -1
- package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
- package/dist/agents/pi-embedded-runner/run.js +2 -0
- package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
- package/dist/agents/pi-tool-definition-adapter.js +16 -1
- package/dist/agents/pi-tools.js +2 -1
- package/dist/agents/sandbox/config.js +1 -1
- package/dist/agents/sandbox/context.js +27 -2
- package/dist/agents/skills/env-overrides.js +38 -28
- package/dist/agents/skills/trust.js +93 -0
- package/dist/agents/skills/workspace.js +128 -0
- package/dist/agents/skills-clawhub.js +36 -11
- package/dist/agents/skills-marketplace-scan.js +49 -0
- package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
- package/dist/agents/tools/mining-tool.js +1 -1
- package/dist/agents/tools/session-status-tool.js +1 -1
- package/dist/agents/tools/wallet-action-tool.js +172 -36
- package/dist/agents/tools/wallet-skill-policy.js +65 -23
- package/dist/agents/tools/wallet-tool.js +7 -11
- package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
- package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
- package/dist/auto-reply/reply/directive-handling.model.js +2 -1
- package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
- package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
- package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
- package/dist/auto-reply/reply/model-selection.js +7 -4
- package/dist/auto-reply/reply/session-reset-model.js +4 -4
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/channel-web.js +2 -2
- package/dist/cli/gateway-cli/run.js +8 -0
- package/dist/cli/program/command-registry.js +1 -1
- package/dist/cli/program/register.onboard.js +2 -3
- package/dist/cli/program/register.wallet.js +16 -123
- package/dist/cli/providers-cli.js +1 -1
- package/dist/cli/sat-cli.js +129 -2
- package/dist/cli/update-cli/update-command.js +260 -11
- package/dist/commands/auth-choice.apply.api-providers.js +3 -3
- package/dist/commands/doctor-config-flow.js +1 -1
- package/dist/commands/doctor-legacy-config.js +2 -13
- package/dist/commands/model-picker.js +6 -6
- package/dist/commands/models/auth.js +1 -1
- package/dist/commands/onboard-auth.config-gateways.js +1 -1
- package/dist/commands/onboard-auth.credentials.js +32 -8
- package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
- package/dist/commands/onboard-non-interactive/local.js +5 -1
- package/dist/commands/wallet.js +568 -1911
- package/dist/config/config.js +2 -2
- package/dist/config/io.js +64 -2
- package/dist/config/schema.help.js +8 -7
- package/dist/config/schema.labels.js +5 -4
- package/dist/config/zod-schema.agent-runtime.js +1 -0
- package/dist/config/zod-schema.js +5 -0
- package/dist/control-ui/assets/{app-DLil9VO1.js → app-MaQnPa5G.js} +1511 -1555
- package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
- package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
- package/dist/control-ui/assets/{index-DdE_NIXo.js → index-D4YMr1fA.js} +3 -3
- package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
- package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-qMYs4aD-.js} +70 -50
- package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
- package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
- package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/daemon/systemd-system.js +56 -50
- package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
- package/dist/extensions/sat-mining/src/rpc-read.js +291 -84
- package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
- package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
- package/dist/extensions/sat-mining/src/solana-submit.js +1274 -390
- package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
- package/dist/federation/auto-connect.js +98 -8
- package/dist/federation/marketplace-capability-adapter.js +33 -7
- package/dist/federation/marketplace-delivery-outbox.js +196 -0
- package/dist/federation/marketplace-delivery.js +351 -215
- package/dist/federation/marketplace-direct-payment.js +272 -141
- package/dist/federation/marketplace-escrow.js +607 -249
- package/dist/federation/marketplace-settlement-ledger.js +352 -0
- package/dist/federation/offers.js +9 -7
- package/dist/federation/peer-auth-v2.js +529 -0
- package/dist/gateway/a2a-http.js +425 -96
- package/dist/gateway/a2a-settlement.js +259 -153
- package/dist/gateway/a2a-task-store.js +524 -0
- package/dist/gateway/auth.js +38 -2
- package/dist/gateway/config-reload.js +46 -33
- package/dist/gateway/durable-capacity.js +31 -0
- package/dist/gateway/federation-http.js +540 -135
- package/dist/gateway/federation-marketplace-run-store.js +397 -0
- package/dist/gateway/federation-marketplace.js +535 -230
- package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
- package/dist/gateway/security-path.js +1 -1
- package/dist/gateway/server-http.js +1084 -1205
- package/dist/gateway/server-methods/models.js +1 -1
- package/dist/gateway/server-methods/secrets.js +40 -0
- package/dist/gateway/server-methods.js +1 -2
- package/dist/gateway/server-reload-handlers.js +196 -66
- package/dist/gateway/server-runtime-config.js +1 -1
- package/dist/gateway/server-secrets-runtime.js +288 -0
- package/dist/gateway/server.impl.js +73 -42
- package/dist/gateway/sessions-patch.js +3 -5
- package/dist/index.js +4 -2
- package/dist/infra/fasedhub.js +64 -1
- package/dist/infra/local-source-paired-update.js +538 -0
- package/dist/infra/restart.js +41 -10
- package/dist/infra/update-runner.js +96 -0
- package/dist/light-update-status.js +11 -11
- package/dist/memory/backend-config.js +2 -1
- package/dist/memory/session-files.js +16 -2
- package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
- package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
- package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-I4IngVlJ.js} +27 -27
- package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
- package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
- package/dist/plugin-sdk/channel-plugin-common.js +4 -4
- package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DLQ6_lLK.js} +1 -1
- package/dist/plugin-sdk/command-status.d.ts +2 -2
- package/dist/plugin-sdk/command-status.js +27 -27
- package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
- package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
- package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
- package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-D_8FVI1C.js} +6798 -3695
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +6 -6
- package/dist/plugin-sdk/discord.js +19 -19
- package/dist/plugin-sdk/file-lock.js +35 -4
- package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
- package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
- package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
- package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
- package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +21 -39
- package/dist/plugin-sdk/index.js +29 -29
- package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
- package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
- package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
- package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
- package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
- package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-B4KF4Kpo.js} +31 -31
- package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-Bb6x1KAG.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DCTO8JkL.js} +27 -27
- package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
- package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
- package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-DHPDFZbC.d.ts} +2 -2
- package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
- package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
- package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
- package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
- package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
- package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
- package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
- package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
- package/dist/plugin-sdk/sat-runtime.d.ts +565 -309
- package/dist/plugin-sdk/sat-runtime.js +29 -29
- package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
- package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
- package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
- package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
- package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
- package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
- package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BHmvqgjH.js} +39 -39
- package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
- package/dist/plugin-sdk/slack.d.ts +6 -6
- package/dist/plugin-sdk/slack.js +9 -9
- package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-By5AcorL.js} +3 -3
- package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
- package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-DGnBz1YT.js} +30 -30
- package/dist/plugin-sdk/telegram.d.ts +6 -6
- package/dist/plugin-sdk/telegram.js +8 -8
- package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
- package/dist/plugin-sdk/tmp-fased-dir-EJGTmL1Q.d.ts +486 -0
- package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-BdwdFCD6.d.ts} +2 -3
- package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-BrCpYMxn.d.ts} +2 -2
- package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
- package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
- package/dist/plugin-sdk/{web-CInY-lCv.js → web-DUJwrTYs.js} +32 -32
- package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
- package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +13 -13
- package/dist/plugin-sdk/whatsapp.js +12 -12
- package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
- package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
- package/dist/providers/refresh.js +1 -1
- package/dist/providers/registry.js +1 -1
- package/dist/secrets/apply.js +1 -1
- package/dist/secrets/runtime.js +1 -1
- package/dist/wallet/external-submission-ledger.js +376 -0
- package/dist/wallet/legacy-embedded-keystore.js +40 -0
- package/dist/wallet/local-socket-signer-archive.js +30 -0
- package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
- package/dist/wallet/local-socket-signer-policy.js +166 -0
- package/dist/wallet/local-socket-signer-protocol.js +578 -117
- package/dist/wallet/native-signer-wallet-id.js +25 -0
- package/dist/wallet/providers/alchemy-adapter.js +3 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
- package/dist/wallet/providers/turnkey-adapter.js +292 -34
- package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
- package/dist/wallet/signer-network-admin.js +184 -0
- package/dist/wallet/signer-protocol-v2.generated.js +92 -0
- package/dist/wallet/solana-bond-signing.js +157 -69
- package/dist/wallet/solana-reviewed-transaction.js +375 -0
- package/dist/wallet/solana-swap.js +520 -64
- package/dist/wallet/solana-transaction-inspection.js +106 -4
- package/dist/wallet/solana-trigger.js +658 -320
- package/dist/wallet/turnkey-reviewed-state.js +370 -0
- package/dist/wallet/wallet-approval-auth.js +17 -28
- package/dist/wallet/wallet-atomic-state.js +53 -0
- package/dist/wallet/wallet-canary.js +0 -1
- package/dist/wallet/wallet-inbound-events.js +16 -11
- package/dist/wallet/wallet-policy-simulation.js +1 -1
- package/dist/wallet/wallet-policy.js +93 -37
- package/dist/wallet/wallet-provider-capabilities.js +28 -4
- package/dist/wallet/wallet-provider-registry.js +57 -44
- package/dist/wallet/wallet-provider-resolver.js +62 -63
- package/dist/wallet/wallet-runtime-config.js +28 -41
- package/dist/wallet/wallet-secrets-store.js +22 -0
- package/dist/wallet/wallet-send-approvals.js +1891 -589
- package/dist/wallet/wallet-send-execution-ledger.js +292 -0
- package/dist/wallet/wallet-settlement-links.js +14 -13
- package/dist/wallet/wallet-standard-review.js +353 -0
- package/dist/wallet/wallet-status.js +0 -9
- package/dist/wallet/wallet-task-ledger.js +16 -2
- package/dist/web/auto-reply/heartbeat-runner.js +1 -1
- package/dist/web/auto-reply/monitor.js +2 -2
- package/dist/wizard/host-security-capability.js +14 -23
- package/dist/wizard/onboarding.finalize.js +63 -184
- package/dist/wizard/onboarding.host-security.js +117 -1367
- package/dist/wizard/onboarding.js +172 -217
- package/dist/wizard/onboarding.wallet.js +232 -785
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +18 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +18 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +18 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/index.ts +587 -154
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
- package/extensions/sat-mining/src/audit-store.ts +91 -5
- package/extensions/sat-mining/src/claim-service.ts +85 -14
- package/extensions/sat-mining/src/client.ts +13 -0
- package/extensions/sat-mining/src/config.ts +9 -0
- package/extensions/sat-mining/src/cycle-progress.ts +16 -8
- package/extensions/sat-mining/src/epoch-service.ts +9 -5
- package/extensions/sat-mining/src/gateway-runner.ts +21 -1
- package/extensions/sat-mining/src/protocol-contract.ts +45 -1
- package/extensions/sat-mining/src/recovery-service.ts +312 -0
- package/extensions/sat-mining/src/round-watcher.ts +391 -81
- package/extensions/sat-mining/src/rpc-read.ts +431 -106
- package/extensions/sat-mining/src/runtime.ts +16 -0
- package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
- package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
- package/extensions/sat-mining/src/solana-submit.ts +1544 -436
- package/extensions/sat-mining/src/submission-ledger.ts +434 -0
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +18 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +18 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +18 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +18 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4951 -0
- package/package.json +23 -5
- package/scripts/fased-host-updater.mjs +1421 -0
- package/scripts/fased-host-updaterctl.mjs +186 -0
- package/scripts/fased-managed-service.sh +36 -0
- package/scripts/fased-managed-updater.mjs +3065 -156
- package/scripts/fased-signer-enroll-hosting.sh +275 -0
- package/scripts/fased-signer-network-hosting.sh +143 -0
- package/scripts/fased-signer-owner-policy.mjs +1442 -0
- package/scripts/fased-signer-policy-hosting.sh +50 -0
- package/scripts/fased-signer-policy-local.sh +26 -0
- package/scripts/hosted-release-manifest.mjs +185 -0
- package/scripts/install-fased-signerd.sh +183 -108
- package/scripts/install-managed-runtime.mjs +212 -10
- package/scripts/managed-runtime-layout.mjs +75 -3
- package/scripts/migrate-hosted-signer-v2.mjs +58 -0
- package/scripts/start-managed.sh +173 -360
- package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
- package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
- package/dist/wallet/local-socket-signer-broker.js +0 -224
- package/dist/wallet/local-socket-signer-custody.js +0 -42
- package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
- package/dist/wallet/providers/privy-adapter.js +0 -80
- 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
|
-
|
|
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 {
|
|
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
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
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
|
-
|
|
370
|
+
env: NodeJS.ProcessEnv;
|
|
318
371
|
spec: SatInstructionSubmitSpec;
|
|
319
372
|
}) {
|
|
320
|
-
const
|
|
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
|
-
|
|
326
|
-
programId
|
|
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
|
|
1127
|
+
const baseRequest = await buildLocalSignerInstructionRequest({
|
|
344
1128
|
solana: context.solana,
|
|
345
1129
|
signer: context.signer,
|
|
346
|
-
|
|
1130
|
+
env: context.effectiveEnv,
|
|
347
1131
|
spec: params,
|
|
348
1132
|
});
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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.
|
|
358
|
-
signer:
|
|
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(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
1225
|
+
env: context.effectiveEnv,
|
|
413
1226
|
spec,
|
|
414
1227
|
}),
|
|
415
1228
|
);
|
|
416
1229
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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.
|
|
431
|
-
signer:
|
|
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
|
|
1385
|
+
function buildTopUpRegistryReserveData(params: { targetBalanceLamports: number }) {
|
|
572
1386
|
return Buffer.concat([
|
|
573
|
-
Buffer.from([IX.
|
|
574
|
-
|
|
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
|
|
692
|
-
|
|
693
|
-
|
|
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
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
return
|
|
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
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
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
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
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
|
|
1902
|
+
export async function submitSatTopUpRegistryReserve(
|
|
1051
1903
|
_config: SatMiningConfig,
|
|
1052
|
-
params: {
|
|
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:
|
|
1059
|
-
|
|
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:
|
|
1156
|
-
data: buildInitMinerCapitalData({ 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
|
|
2003
|
+
const authorityKey = new solana.PublicKey(authority);
|
|
1160
2004
|
const [satMinerCapitalState] = solana.PublicKey.findProgramAddressSync(
|
|
1161
|
-
[Buffer.from(SAT_MINER_CAPITAL_STATE_SEED),
|
|
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
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
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 } =
|
|
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(
|
|
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 } =
|
|
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(
|
|
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 {
|
|
1492
|
-
|
|
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
|
|
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: {
|
|
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:
|
|
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
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
return
|
|
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
|
|
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:
|
|
1592
|
-
data:
|
|
1593
|
-
programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
|
|
2577
|
+
env: process.env,
|
|
2578
|
+
data: buildReleaseUnrevealedCommitData(params),
|
|
1594
2579
|
accountResolver: async (solana, signer) => {
|
|
1595
|
-
const
|
|
1596
|
-
|
|
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:
|
|
1599
|
-
{ pubkey:
|
|
1600
|
-
{ pubkey:
|
|
1601
|
-
{ pubkey:
|
|
1602
|
-
{ pubkey:
|
|
1603
|
-
{ pubkey:
|
|
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
|
|
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:
|
|
1616
|
-
data:
|
|
1617
|
-
programId: resolveSatBondProgramIdFromEnv(effectiveEnv),
|
|
2625
|
+
env: process.env,
|
|
2626
|
+
data: buildAbortEmptyCycleData(params),
|
|
1618
2627
|
accountResolver: async (solana, signer) => {
|
|
1619
|
-
const
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
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:
|
|
1630
|
-
{ pubkey:
|
|
1631
|
-
{ pubkey:
|
|
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
|
|
2646
|
+
export async function submitSatRevealCycle(
|
|
1650
2647
|
_config: SatMiningConfig,
|
|
1651
|
-
params: {
|
|
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:
|
|
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
|
|
1662
|
-
|
|
1663
|
-
|
|
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 [
|
|
1694
|
-
[Buffer.from(
|
|
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 [
|
|
1706
|
-
[Buffer.from(
|
|
2704
|
+
const [satRegistryReserve] = solana.PublicKey.findProgramAddressSync(
|
|
2705
|
+
[Buffer.from(SAT_REGISTRY_RESERVE_SEED)],
|
|
1707
2706
|
programId,
|
|
1708
2707
|
);
|
|
1709
|
-
return
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
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:
|
|
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
|
|
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:
|
|
3405
|
+
env: effectiveEnv,
|
|
2326
3406
|
data: buildClaimProtocolDistributorSatData(),
|
|
2327
3407
|
accountResolver: async (solana, signer) => {
|
|
2328
|
-
const programId = new solana.PublicKey(
|
|
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(
|
|
3424
|
+
new solana.PublicKey(resolveSatMintProgramIdFromEnv(effectiveEnv)),
|
|
2345
3425
|
);
|
|
2346
3426
|
const recipientAta = deriveAssociatedTokenAddress(
|
|
2347
3427
|
solana,
|
|
2348
3428
|
recipientOwner,
|
|
2349
|
-
new solana.PublicKey(
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
|
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
|
}
|