@fased/fased 0.1.62 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +38 -30
- package/config/dependency-ownership.json +1 -1
- package/config/signer-policies/README.md +49 -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 +76 -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-bR-fO5ty.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-ckCxHwjy.js} +3 -3
- package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
- package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
- 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 +235 -67
- 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 +1038 -397
- 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-BYxAt775.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-DIRHG2gJ.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-BOT7kHb6.js} +6779 -3696
- 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-BCFDaqJ-.js} +31 -31
- package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.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-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
- 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 +549 -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-BUTt8cxK.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-D0wHVqjt.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-CC_qN4v0.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-xOTGlzBE.d.ts +486 -0
- package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
- package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
- package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -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-BXsJ1vqe.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 +561 -118
- 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 +90 -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 +90 -36
- 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 +12 -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 +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/index.ts +498 -153
- 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 +50 -5
- package/extensions/sat-mining/src/claim-service.ts +85 -14
- 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 +330 -89
- package/extensions/sat-mining/src/runtime.ts +14 -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 +1199 -428
- package/extensions/sat-mining/src/submission-ledger.ts +433 -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 +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4955 -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 +1430 -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 +169 -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
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { resolveProcessScopedMap } from "../shared/process-scoped-map.js";
|
|
2
|
+
import { acquireFileLock, withFileLock } from "../plugin-sdk/file-lock.js";
|
|
3
|
+
import "../infra/file-lock.js";
|
|
4
|
+
import { ensureWalletStateDir } from "./wallet-runtime-config.js";
|
|
5
|
+
import syncFs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
//#region src/wallet/external-submission-ledger.ts
|
|
10
|
+
const STATES = new Set([
|
|
11
|
+
"reserved",
|
|
12
|
+
"prepared",
|
|
13
|
+
"signed",
|
|
14
|
+
"submitting",
|
|
15
|
+
"unknown",
|
|
16
|
+
"confirmed",
|
|
17
|
+
"failed"
|
|
18
|
+
]);
|
|
19
|
+
const KINDS = new Set([
|
|
20
|
+
"jupiter-swap",
|
|
21
|
+
"jupiter-trigger-auth",
|
|
22
|
+
"jupiter-trigger-create",
|
|
23
|
+
"jupiter-trigger-cancel"
|
|
24
|
+
]);
|
|
25
|
+
const TRANSITIONS = {
|
|
26
|
+
reserved: new Set([
|
|
27
|
+
"reserved",
|
|
28
|
+
"prepared",
|
|
29
|
+
"submitting",
|
|
30
|
+
"failed"
|
|
31
|
+
]),
|
|
32
|
+
prepared: new Set([
|
|
33
|
+
"prepared",
|
|
34
|
+
"signed",
|
|
35
|
+
"unknown",
|
|
36
|
+
"confirmed",
|
|
37
|
+
"failed"
|
|
38
|
+
]),
|
|
39
|
+
signed: new Set([
|
|
40
|
+
"signed",
|
|
41
|
+
"submitting",
|
|
42
|
+
"unknown"
|
|
43
|
+
]),
|
|
44
|
+
submitting: new Set([
|
|
45
|
+
"submitting",
|
|
46
|
+
"prepared",
|
|
47
|
+
"unknown",
|
|
48
|
+
"confirmed",
|
|
49
|
+
"failed"
|
|
50
|
+
]),
|
|
51
|
+
unknown: new Set([
|
|
52
|
+
"unknown",
|
|
53
|
+
"confirmed",
|
|
54
|
+
"failed"
|
|
55
|
+
]),
|
|
56
|
+
confirmed: new Set(["confirmed"]),
|
|
57
|
+
failed: new Set(["failed"])
|
|
58
|
+
};
|
|
59
|
+
const LEDGER_LOCK_OPTIONS = {
|
|
60
|
+
retries: {
|
|
61
|
+
retries: 100,
|
|
62
|
+
factor: 1.15,
|
|
63
|
+
minTimeout: 10,
|
|
64
|
+
maxTimeout: 200,
|
|
65
|
+
randomize: true
|
|
66
|
+
},
|
|
67
|
+
stale: 3e4
|
|
68
|
+
};
|
|
69
|
+
const EXECUTION_LOCK_OPTIONS = {
|
|
70
|
+
retries: {
|
|
71
|
+
retries: 1,
|
|
72
|
+
factor: 1,
|
|
73
|
+
minTimeout: 10,
|
|
74
|
+
maxTimeout: 10,
|
|
75
|
+
randomize: false
|
|
76
|
+
},
|
|
77
|
+
stale: 3e4
|
|
78
|
+
};
|
|
79
|
+
const ACTIVE_EXECUTIONS = resolveProcessScopedMap(Symbol.for("fased.wallet.externalSubmission.activeExecutions"));
|
|
80
|
+
const LEDGER_MUTATION_QUEUES = resolveProcessScopedMap(Symbol.for("fased.wallet.externalSubmission.mutationQueues"));
|
|
81
|
+
async function claimExternalSubmissionExecution(keyRaw, env = process.env) {
|
|
82
|
+
const key = keyRaw.trim();
|
|
83
|
+
if (!key || containsControlCharacter(key)) {
|
|
84
|
+
throw new Error("external submission execution key is invalid");
|
|
85
|
+
}
|
|
86
|
+
const executionKey = `${ledgerPath(env)}\0${key}`;
|
|
87
|
+
if (ACTIVE_EXECUTIONS.has(executionKey)) {
|
|
88
|
+
throw new Error(`external submission ${key} is already executing; wait for its durable result instead of retrying`);
|
|
89
|
+
}
|
|
90
|
+
ACTIVE_EXECUTIONS.set(executionKey, true);
|
|
91
|
+
const claimTarget = path.join(path.dirname(ledgerPath(env)), ".external-submission-executions", createHash("sha256").update(key).digest("hex"));
|
|
92
|
+
let lock;
|
|
93
|
+
try {
|
|
94
|
+
lock = await acquireFileLock(claimTarget, EXECUTION_LOCK_OPTIONS);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
ACTIVE_EXECUTIONS.delete(executionKey);
|
|
97
|
+
throw new Error(`external submission ${key} is already executing; wait for its durable result instead of retrying`, { cause: error });
|
|
98
|
+
}
|
|
99
|
+
let released = false;
|
|
100
|
+
return async () => {
|
|
101
|
+
if (!released) {
|
|
102
|
+
ACTIVE_EXECUTIONS.delete(executionKey);
|
|
103
|
+
released = true;
|
|
104
|
+
await lock.release();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function canonicalJson(value) {
|
|
109
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
110
|
+
return JSON.stringify(value);
|
|
111
|
+
}
|
|
112
|
+
if (typeof value === "number") {
|
|
113
|
+
if (!Number.isFinite(value)) {
|
|
114
|
+
throw new Error("external submission intent contains a non-finite number");
|
|
115
|
+
}
|
|
116
|
+
return JSON.stringify(value);
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
|
|
120
|
+
}
|
|
121
|
+
if (value && typeof value === "object") {
|
|
122
|
+
const record = value;
|
|
123
|
+
const entries = Object.keys(record).filter((key) => record[key] !== undefined).toSorted().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`);
|
|
124
|
+
return `{${entries.join(",")}}`;
|
|
125
|
+
}
|
|
126
|
+
throw new Error("external submission intent contains an unsupported value");
|
|
127
|
+
}
|
|
128
|
+
function containsControlCharacter(value) {
|
|
129
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
130
|
+
if (value.charCodeAt(index) <= 31) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
function externalSubmissionIntentDigest(intent) {
|
|
137
|
+
return `sha256:${createHash("sha256").update(canonicalJson(intent)).digest("hex")}`;
|
|
138
|
+
}
|
|
139
|
+
function createExternalSubmissionKey(params) {
|
|
140
|
+
const walletId = params.walletId.trim();
|
|
141
|
+
if (!walletId) {
|
|
142
|
+
throw new Error("external submission walletId is required");
|
|
143
|
+
}
|
|
144
|
+
const explicitIntentId = params.explicitIntentId?.trim() || undefined;
|
|
145
|
+
if (explicitIntentId && (explicitIntentId.length > 160 || containsControlCharacter(explicitIntentId))) {
|
|
146
|
+
throw new Error("external submission intentId is invalid");
|
|
147
|
+
}
|
|
148
|
+
const intentDigest = externalSubmissionIntentDigest(params.intent);
|
|
149
|
+
const keyDigest = createHash("sha256").update(`${params.kind}\0${walletId}\0${intentDigest}\0${explicitIntentId ?? "default"}`).digest("hex");
|
|
150
|
+
return {
|
|
151
|
+
key: `${params.kind}:${keyDigest}`,
|
|
152
|
+
intentDigest,
|
|
153
|
+
...explicitIntentId ? { explicitIntentId } : {}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function ledgerPath(env) {
|
|
157
|
+
return path.join(ensureWalletStateDir(env).rootDir, "external-submissions.json");
|
|
158
|
+
}
|
|
159
|
+
async function withLedgerMutationLock(env, task) {
|
|
160
|
+
const filePath = ledgerPath(env);
|
|
161
|
+
const previous = LEDGER_MUTATION_QUEUES.get(filePath) ?? Promise.resolve();
|
|
162
|
+
let releaseQueue;
|
|
163
|
+
const turn = new Promise((resolve) => {
|
|
164
|
+
releaseQueue = resolve;
|
|
165
|
+
});
|
|
166
|
+
const queued = previous.then(() => turn, () => turn);
|
|
167
|
+
LEDGER_MUTATION_QUEUES.set(filePath, queued);
|
|
168
|
+
await previous.catch(() => undefined);
|
|
169
|
+
try {
|
|
170
|
+
return await withFileLock(filePath, LEDGER_LOCK_OPTIONS, async () => await task());
|
|
171
|
+
} finally {
|
|
172
|
+
releaseQueue();
|
|
173
|
+
if (LEDGER_MUTATION_QUEUES.get(filePath) === queued) {
|
|
174
|
+
LEDGER_MUTATION_QUEUES.delete(filePath);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
180
|
+
}
|
|
181
|
+
function validateEntry(value) {
|
|
182
|
+
if (!isRecord(value)) {
|
|
183
|
+
throw new Error("external submission ledger contains an invalid entry");
|
|
184
|
+
}
|
|
185
|
+
const state = value.state;
|
|
186
|
+
if (typeof value.key !== "string" || typeof value.kind !== "string" || !KINDS.has(value.kind) || typeof value.walletId !== "string" || typeof value.intentDigest !== "string" || typeof value.createdAt !== "string" || typeof value.updatedAt !== "string" || typeof state !== "string" || !STATES.has(state)) {
|
|
187
|
+
throw new Error("external submission ledger contains an invalid entry");
|
|
188
|
+
}
|
|
189
|
+
if (!value.intentDigest.match(/^sha256:[0-9a-f]{64}$/)) {
|
|
190
|
+
throw new Error("external submission ledger contains an invalid intent digest");
|
|
191
|
+
}
|
|
192
|
+
for (const field of [
|
|
193
|
+
"explicitIntentId",
|
|
194
|
+
"signerRequestId",
|
|
195
|
+
"signerIntentDigest",
|
|
196
|
+
"signerSignature",
|
|
197
|
+
"externalRequestId",
|
|
198
|
+
"transactionDigest",
|
|
199
|
+
"reason"
|
|
200
|
+
]) {
|
|
201
|
+
if (value[field] !== undefined && typeof value[field] !== "string") {
|
|
202
|
+
throw new Error(`external submission ledger contains an invalid ${field}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (value.details !== undefined && !isRecord(value.details)) {
|
|
206
|
+
throw new Error("external submission ledger contains invalid details");
|
|
207
|
+
}
|
|
208
|
+
if (value.result !== undefined && !isRecord(value.result)) {
|
|
209
|
+
throw new Error("external submission ledger contains an invalid result");
|
|
210
|
+
}
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
function loadLedger(env) {
|
|
214
|
+
const filePath = ledgerPath(env);
|
|
215
|
+
if (!syncFs.existsSync(filePath)) {
|
|
216
|
+
return {
|
|
217
|
+
version: 1,
|
|
218
|
+
entries: []
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
let parsed;
|
|
222
|
+
try {
|
|
223
|
+
parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
|
|
224
|
+
} catch (error) {
|
|
225
|
+
throw new Error("external submission ledger is unreadable; refusing a potentially duplicate transaction", { cause: error });
|
|
226
|
+
}
|
|
227
|
+
if (!isRecord(parsed) || parsed.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
228
|
+
throw new Error("external submission ledger has an unsupported format");
|
|
229
|
+
}
|
|
230
|
+
const entries = parsed.entries.map(validateEntry);
|
|
231
|
+
if (new Set(entries.map((entry) => entry.key)).size !== entries.length) {
|
|
232
|
+
throw new Error("external submission ledger contains duplicate idempotency keys");
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
version: 1,
|
|
236
|
+
entries
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function saveLedger(file, env) {
|
|
240
|
+
const filePath = ledgerPath(env);
|
|
241
|
+
const temporary = `${filePath}.tmp-${process.pid}-${randomBytes(6).toString("hex")}`;
|
|
242
|
+
let descriptor;
|
|
243
|
+
try {
|
|
244
|
+
descriptor = syncFs.openSync(temporary, "wx", 384);
|
|
245
|
+
syncFs.writeFileSync(descriptor, `${JSON.stringify(file, null, 2)}\n`, "utf8");
|
|
246
|
+
syncFs.fsyncSync(descriptor);
|
|
247
|
+
syncFs.closeSync(descriptor);
|
|
248
|
+
descriptor = undefined;
|
|
249
|
+
syncFs.renameSync(temporary, filePath);
|
|
250
|
+
syncFs.chmodSync(filePath, 384);
|
|
251
|
+
try {
|
|
252
|
+
const directory = syncFs.openSync(path.dirname(filePath), "r");
|
|
253
|
+
try {
|
|
254
|
+
syncFs.fsyncSync(directory);
|
|
255
|
+
} finally {
|
|
256
|
+
syncFs.closeSync(directory);
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const code = error.code;
|
|
260
|
+
if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EISDIR") {
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} finally {
|
|
265
|
+
if (descriptor !== undefined) {
|
|
266
|
+
syncFs.closeSync(descriptor);
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
syncFs.unlinkSync(temporary);
|
|
270
|
+
} catch {}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function getExternalSubmission(params) {
|
|
274
|
+
const file = loadLedger(params.env ?? process.env);
|
|
275
|
+
return file.entries.find((entry) => entry.key === params.key.trim());
|
|
276
|
+
}
|
|
277
|
+
function getExternalSubmissionByExplicitIntent(params) {
|
|
278
|
+
const kind = params.kind;
|
|
279
|
+
const walletId = params.walletId.trim();
|
|
280
|
+
const explicitIntentId = params.explicitIntentId.trim();
|
|
281
|
+
if (!walletId || !explicitIntentId || containsControlCharacter(explicitIntentId)) {
|
|
282
|
+
throw new Error("external submission explicit intent lookup is invalid");
|
|
283
|
+
}
|
|
284
|
+
const file = loadLedger(params.env ?? process.env);
|
|
285
|
+
return file.entries.find((entry) => entry.kind === kind && entry.walletId === walletId && entry.explicitIntentId === explicitIntentId);
|
|
286
|
+
}
|
|
287
|
+
async function beginExternalSubmission(params) {
|
|
288
|
+
const env = params.env ?? process.env;
|
|
289
|
+
return await withLedgerMutationLock(env, () => {
|
|
290
|
+
const file = loadLedger(env);
|
|
291
|
+
const key = params.key.trim();
|
|
292
|
+
const walletId = params.walletId.trim();
|
|
293
|
+
const existing = file.entries.find((entry) => entry.key === key);
|
|
294
|
+
if (existing) {
|
|
295
|
+
if (existing.kind !== params.kind || existing.walletId !== walletId || existing.intentDigest !== params.intentDigest || (existing.explicitIntentId ?? undefined) !== (params.explicitIntentId?.trim() || undefined)) {
|
|
296
|
+
throw new Error("external submission idempotency key collides with a different intent");
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
entry: existing,
|
|
300
|
+
created: false
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const explicitIntentId = params.explicitIntentId?.trim() || undefined;
|
|
304
|
+
const conflictingExplicitIntent = explicitIntentId ? file.entries.find((entry) => entry.kind === params.kind && entry.walletId === walletId && entry.explicitIntentId === explicitIntentId) : undefined;
|
|
305
|
+
if (conflictingExplicitIntent) {
|
|
306
|
+
throw new Error("external submission intentId is already bound to a different immutable intent");
|
|
307
|
+
}
|
|
308
|
+
const now = new Date().toISOString();
|
|
309
|
+
const entry = {
|
|
310
|
+
key,
|
|
311
|
+
kind: params.kind,
|
|
312
|
+
walletId,
|
|
313
|
+
intentDigest: params.intentDigest,
|
|
314
|
+
...explicitIntentId ? { explicitIntentId } : {},
|
|
315
|
+
state: "reserved",
|
|
316
|
+
...params.details ? { details: params.details } : {},
|
|
317
|
+
createdAt: now,
|
|
318
|
+
updatedAt: now
|
|
319
|
+
};
|
|
320
|
+
file.entries.push(entry);
|
|
321
|
+
saveLedger(file, env);
|
|
322
|
+
return {
|
|
323
|
+
entry,
|
|
324
|
+
created: true
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
async function updateExternalSubmission(params) {
|
|
329
|
+
const env = params.env ?? process.env;
|
|
330
|
+
return await withLedgerMutationLock(env, () => {
|
|
331
|
+
const file = loadLedger(env);
|
|
332
|
+
const entry = file.entries.find((candidate) => candidate.key === params.key.trim());
|
|
333
|
+
if (!entry) {
|
|
334
|
+
throw new Error("external submission ledger entry not found");
|
|
335
|
+
}
|
|
336
|
+
if (!params.expectedStates.includes(entry.state)) {
|
|
337
|
+
throw new Error(`external submission ${entry.key} is ${entry.state}; expected ${params.expectedStates.join(" or ")}`);
|
|
338
|
+
}
|
|
339
|
+
if (!TRANSITIONS[entry.state].has(params.state)) {
|
|
340
|
+
throw new Error(`external submission cannot transition from ${entry.state} to ${params.state}`);
|
|
341
|
+
}
|
|
342
|
+
Object.assign(entry, params.patch ?? {});
|
|
343
|
+
entry.state = params.state;
|
|
344
|
+
entry.updatedAt = new Date().toISOString();
|
|
345
|
+
saveLedger(file, env);
|
|
346
|
+
return entry;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
async function renewConfirmedExternalSubmission(params) {
|
|
350
|
+
const env = params.env ?? process.env;
|
|
351
|
+
return await withLedgerMutationLock(env, () => {
|
|
352
|
+
const file = loadLedger(env);
|
|
353
|
+
const entry = file.entries.find((candidate) => candidate.key === params.key.trim());
|
|
354
|
+
if (!entry || entry.state !== "confirmed") {
|
|
355
|
+
throw new Error("only a confirmed external submission can be renewed");
|
|
356
|
+
}
|
|
357
|
+
const now = new Date().toISOString();
|
|
358
|
+
const renewed = {
|
|
359
|
+
key: entry.key,
|
|
360
|
+
kind: entry.kind,
|
|
361
|
+
walletId: entry.walletId,
|
|
362
|
+
intentDigest: entry.intentDigest,
|
|
363
|
+
...entry.explicitIntentId ? { explicitIntentId: entry.explicitIntentId } : {},
|
|
364
|
+
state: "reserved",
|
|
365
|
+
...params.details ? { details: params.details } : {},
|
|
366
|
+
createdAt: now,
|
|
367
|
+
updatedAt: now
|
|
368
|
+
};
|
|
369
|
+
file.entries[file.entries.indexOf(entry)] = renewed;
|
|
370
|
+
saveLedger(file, env);
|
|
371
|
+
return renewed;
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
//#endregion
|
|
376
|
+
export { beginExternalSubmission, claimExternalSubmissionExecution, createExternalSubmissionKey, externalSubmissionIntentDigest, getExternalSubmission, getExternalSubmissionByExplicitIntent, updateExternalSubmission };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/wallet/legacy-embedded-keystore.ts
|
|
2
|
+
const LEGACY_EMBEDDED_KEYSTORE_PROVIDER_ID = "embedded-keystore";
|
|
3
|
+
const LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE = "embedded-keystore was retired so normal production Fased code no longer reads wallet private keys in Node or the Gateway. " + "On Local, the signer and Gateway share an OS account, so this code-path separation is not a hard compromise boundary; Hosting uses a separate signer account for OS isolation. " + "Migrate one way with the verified native fased-signerd through its signer-only control socket. " + "For a legacy encrypted keystore, run `fased-signerd admin wallet import-legacy --control-socket <absolute-control.sock> --wallet-id <wallet-id> --locked-role <agent|mining|vault> --keystore-path <absolute-0600-keystore> --passphrase-path <absolute-0600-passphrase-file>`. " + "For a Solana CLI keypair, run `fased-signerd admin wallet import --control-socket <absolute-control.sock> --wallet-id <wallet-id> --locked-role <agent|mining|vault> < /absolute/path/to/solana-keypair.json`. " + "After the native import succeeds, run `fased wallet finalize-legacy-migration --wallet-id <wallet-id>`; it verifies the protocol-v2 signer public key before replacing legacy config/registry references without reading the old key files. " + "Run the native command as the signer/control-socket owner; do not pass a private key or passphrase to Fased CLI, Gateway, UI, argv, or environment variables.";
|
|
4
|
+
var LegacyEmbeddedKeystoreMigrationRequiredError = class extends Error {
|
|
5
|
+
constructor(context) {
|
|
6
|
+
super(context?.trim() ? `${context.trim()}: ${LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE}` : LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE);
|
|
7
|
+
this.code = "wallet_legacy_embedded_keystore_migration_required";
|
|
8
|
+
this.name = "LegacyEmbeddedKeystoreMigrationRequiredError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
function throwLegacyEmbeddedKeystoreMigrationRequired(context) {
|
|
12
|
+
throw new LegacyEmbeddedKeystoreMigrationRequiredError(context);
|
|
13
|
+
}
|
|
14
|
+
function hasLegacyEmbeddedKeystoreConfig(cfg, env) {
|
|
15
|
+
if (cfg.wallet?.provider?.id === LEGACY_EMBEDDED_KEYSTORE_PROVIDER_ID) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
const legacyKeystore = cfg.wallet?.keystore;
|
|
19
|
+
if (legacyKeystore && (legacyKeystore.enabled !== undefined || Boolean(legacyKeystore.path?.trim()) || Boolean(legacyKeystore.chainSupport?.length) || legacyKeystore.autoLockSeconds !== undefined || legacyKeystore.requirePasskeyForUnlock !== undefined)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (String(env.FASED_WALLET_PROVIDER ?? "").trim() === LEGACY_EMBEDDED_KEYSTORE_PROVIDER_ID) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
function hasLegacyEmbeddedKeystoreMaterialHint(env) {
|
|
28
|
+
for (const [key, rawValue] of Object.entries(env)) {
|
|
29
|
+
if (typeof rawValue !== "string" || !rawValue.trim()) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (key === "FASED_WALLET_KEYSTORE_PATH" || key === "FASED_WALLET_PASSPHRASE" || key === "FASED_WALLET_PASSPHRASE_FILE" || key === "FASED_WALLET_PRIVATE_KEY" || key === "FASED_WALLET_SOLANA_KEYSTORE_PATH" || key.startsWith("FASED_WALLET_SOLANA_KEYSTORE_PATH__")) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { LEGACY_EMBEDDED_KEYSTORE_MIGRATION_MESSAGE, LegacyEmbeddedKeystoreMigrationRequiredError, hasLegacyEmbeddedKeystoreConfig, hasLegacyEmbeddedKeystoreMaterialHint, throwLegacyEmbeddedKeystoreMigrationRequired };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LocalSocketSignerAdapter } from "./providers/local-socket-signer-adapter.js";
|
|
2
|
+
import { resolveNativeSignerWalletId } from "./native-signer-wallet-id.js";
|
|
3
|
+
|
|
4
|
+
//#region src/wallet/local-socket-signer-archive.ts
|
|
5
|
+
async function lockSignerOwnedWalletForArchive(params) {
|
|
6
|
+
const signerWalletId = resolveNativeSignerWalletId(params.wallet);
|
|
7
|
+
const signer = params.signer ?? new LocalSocketSignerAdapter(params.socketPath);
|
|
8
|
+
const current = await signer.getSignerPolicy(signerWalletId);
|
|
9
|
+
if (current.walletId !== signerWalletId) {
|
|
10
|
+
throw new Error("native signer returned policy state for a different wallet");
|
|
11
|
+
}
|
|
12
|
+
const acknowledged = await signer.tightenSignerPolicy({
|
|
13
|
+
walletId: signerWalletId,
|
|
14
|
+
expectedVersion: current.version,
|
|
15
|
+
policy: {
|
|
16
|
+
walletId: signerWalletId,
|
|
17
|
+
role: current.role,
|
|
18
|
+
operations: [],
|
|
19
|
+
programs: [],
|
|
20
|
+
assets: []
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
if (acknowledged.operations.length !== 0 || acknowledged.programs.length !== 0 || acknowledged.assets.length !== 0) {
|
|
24
|
+
throw new Error("native signer did not durably acknowledge the exact deny-all archive policy");
|
|
25
|
+
}
|
|
26
|
+
return acknowledged;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { lockSignerOwnedWalletForArchive };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { LOCAL_SIGNER_NATIVE_FEE_RESERVATION_LAMPORTS_V2 } from "./local-socket-signer-protocol.js";
|
|
2
|
+
import { callLocalSocketSigner } from "./providers/local-socket-signer-adapter.js";
|
|
3
|
+
|
|
4
|
+
//#region src/wallet/local-socket-signer-lifecycle.ts
|
|
5
|
+
function lockedLocalSignerPolicy(role) {
|
|
6
|
+
return {
|
|
7
|
+
role,
|
|
8
|
+
operations: [],
|
|
9
|
+
programs: [],
|
|
10
|
+
assets: []
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
async function requireSignerOwnedProtocolV2(socketPath) {
|
|
14
|
+
const result = await callLocalSocketSigner(socketPath, { op: "v2.capabilities" });
|
|
15
|
+
const capabilities = result.capabilities;
|
|
16
|
+
const required = [
|
|
17
|
+
"failClosedPolicies",
|
|
18
|
+
"policyHashes",
|
|
19
|
+
"signerOwnedKeys",
|
|
20
|
+
"atomicMultiAssetCaps",
|
|
21
|
+
"signerControlledNativeFeeCaps"
|
|
22
|
+
];
|
|
23
|
+
const missing = required.filter((feature) => !capabilities?.features.includes(feature));
|
|
24
|
+
if (result.ready !== true || capabilities?.protocol.current !== 2 || capabilities.protocol.min > 2 || capabilities.protocol.max < 2 || capabilities.nativeFeeReservationLamports !== LOCAL_SIGNER_NATIVE_FEE_RESERVATION_LAMPORTS_V2 || missing.length > 0) {
|
|
25
|
+
throw new Error(`fased-signerd does not provide the required signer-owned protocol-v2 capabilities${missing.length > 0 ? `: ${missing.join(", ")}` : ""}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function readSignerOwnedWallet(params) {
|
|
29
|
+
const [wallet, policy] = await Promise.all([callLocalSocketSigner(params.socketPath, {
|
|
30
|
+
op: "v2.wallet.get",
|
|
31
|
+
walletId: params.walletId
|
|
32
|
+
}), callLocalSocketSigner(params.socketPath, {
|
|
33
|
+
op: "v2.policy.get",
|
|
34
|
+
walletId: params.walletId
|
|
35
|
+
})]);
|
|
36
|
+
return {
|
|
37
|
+
wallet,
|
|
38
|
+
policy
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a signer-owned key without returning its secret to normal Fased Node code. Local runs the
|
|
43
|
+
* signer under the same OS account, so this code-path separation is not a hard compromise boundary.
|
|
44
|
+
*
|
|
45
|
+
* The application socket may create only this explicit empty/deny-all policy. Policy expansion is
|
|
46
|
+
* a separate signer-admin action, so a compromised Gateway cannot turn key creation into spending.
|
|
47
|
+
*/
|
|
48
|
+
async function createLockedSignerOwnedWallet(params) {
|
|
49
|
+
const walletId = params.walletId.trim();
|
|
50
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(walletId)) {
|
|
51
|
+
throw new Error("walletId must contain only letters, numbers, hyphens, or underscores");
|
|
52
|
+
}
|
|
53
|
+
await requireSignerOwnedProtocolV2(params.socketPath);
|
|
54
|
+
try {
|
|
55
|
+
const existing = await readSignerOwnedWallet({
|
|
56
|
+
socketPath: params.socketPath,
|
|
57
|
+
walletId
|
|
58
|
+
});
|
|
59
|
+
if (!params.allowExisting) {
|
|
60
|
+
throw new Error(`signer-owned wallet already exists: ${walletId}`);
|
|
61
|
+
}
|
|
62
|
+
if (existing.policy.role !== params.role) {
|
|
63
|
+
throw new Error(`signer-owned wallet ${walletId} already has role=${existing.policy.role}, not ${params.role}`);
|
|
64
|
+
}
|
|
65
|
+
return existing;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
if (message.startsWith("signer-owned wallet")) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return await callLocalSocketSigner(params.socketPath, {
|
|
74
|
+
op: "v2.wallet.create",
|
|
75
|
+
walletId,
|
|
76
|
+
request: {
|
|
77
|
+
expectedPolicyVersion: 0,
|
|
78
|
+
policy: lockedLocalSignerPolicy(params.role)
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (!params.allowExisting) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
const existing = await readSignerOwnedWallet({
|
|
86
|
+
socketPath: params.socketPath,
|
|
87
|
+
walletId
|
|
88
|
+
});
|
|
89
|
+
if (existing.policy.role !== params.role) {
|
|
90
|
+
throw new Error(`signer-owned wallet ${walletId} was concurrently created with role=${existing.policy.role}`, { cause: error });
|
|
91
|
+
}
|
|
92
|
+
return existing;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { createLockedSignerOwnedWallet };
|